1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 2a46f8d58SGaetan Rivet * Copyright 2017 6WIND S.A. 35feecc57SShahaf Shuler * Copyright 2017 Mellanox Technologies, Ltd 4a46f8d58SGaetan Rivet */ 5a46f8d58SGaetan Rivet 6d1b961dbSMatan Azrad #include <fcntl.h> 7d1b961dbSMatan Azrad #include <stdio.h> 8d1b961dbSMatan Azrad #include <stdlib.h> 9a46f8d58SGaetan Rivet #include <string.h> 10d1b961dbSMatan Azrad #include <unistd.h> 11ebea83f8SGaetan Rivet #include <errno.h> 12a46f8d58SGaetan Rivet 13a0194d82SGaetan Rivet #include <rte_debug.h> 14a46f8d58SGaetan Rivet #include <rte_devargs.h> 15a46f8d58SGaetan Rivet #include <rte_malloc.h> 16a46f8d58SGaetan Rivet #include <rte_kvargs.h> 17c022cb40SBruce Richardson #include <rte_string_fns.h> 18a46f8d58SGaetan Rivet 19a46f8d58SGaetan Rivet #include "failsafe_private.h" 20a46f8d58SGaetan Rivet 21a46f8d58SGaetan Rivet /* Callback used when a new device is found in devargs */ 22a46f8d58SGaetan Rivet typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params, 23a46f8d58SGaetan Rivet uint8_t head); 24a46f8d58SGaetan Rivet 25520dd992SFerruh Yigit uint64_t failsafe_hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS; 26520dd992SFerruh Yigit int failsafe_mac_from_arg; 27a46f8d58SGaetan Rivet 28b74fd6b8SFerruh Yigit static const char * const pmd_failsafe_init_parameters[] = { 29ebea83f8SGaetan Rivet PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 30a46f8d58SGaetan Rivet PMD_FAILSAFE_MAC_KVARG, 31a46f8d58SGaetan Rivet NULL, 32a46f8d58SGaetan Rivet }; 33a46f8d58SGaetan Rivet 34a46f8d58SGaetan Rivet /* 35a46f8d58SGaetan Rivet * input: text. 36a46f8d58SGaetan Rivet * output: 0: if text[0] != '(', 37a46f8d58SGaetan Rivet * 0: if there are no corresponding ')' 38a46f8d58SGaetan Rivet * n: distance to corresponding ')' otherwise 39a46f8d58SGaetan Rivet */ 40a46f8d58SGaetan Rivet static size_t 41a46f8d58SGaetan Rivet closing_paren(const char *text) 42a46f8d58SGaetan Rivet { 43a46f8d58SGaetan Rivet int nb_open = 0; 44a46f8d58SGaetan Rivet size_t i = 0; 45a46f8d58SGaetan Rivet 46a46f8d58SGaetan Rivet while (text[i] != '\0') { 47a46f8d58SGaetan Rivet if (text[i] == '(') 48a46f8d58SGaetan Rivet nb_open++; 49a46f8d58SGaetan Rivet if (text[i] == ')') 50a46f8d58SGaetan Rivet nb_open--; 51a46f8d58SGaetan Rivet if (nb_open == 0) 52a46f8d58SGaetan Rivet return i; 53a46f8d58SGaetan Rivet i++; 54a46f8d58SGaetan Rivet } 55a46f8d58SGaetan Rivet return 0; 56a46f8d58SGaetan Rivet } 57a46f8d58SGaetan Rivet 58a46f8d58SGaetan Rivet static int 59a46f8d58SGaetan Rivet fs_parse_device(struct sub_device *sdev, char *args) 60a46f8d58SGaetan Rivet { 61a46f8d58SGaetan Rivet struct rte_devargs *d; 62a46f8d58SGaetan Rivet int ret; 63a46f8d58SGaetan Rivet 64a46f8d58SGaetan Rivet d = &sdev->devargs; 65a46f8d58SGaetan Rivet DEBUG("%s", args); 66a23bc2c4SGaetan Rivet ret = rte_devargs_parse(d, args); 67a46f8d58SGaetan Rivet if (ret) { 68a46f8d58SGaetan Rivet DEBUG("devargs parsing failed with code %d", ret); 69a46f8d58SGaetan Rivet return ret; 70a46f8d58SGaetan Rivet } 71a46f8d58SGaetan Rivet sdev->bus = d->bus; 72a46f8d58SGaetan Rivet sdev->state = DEV_PARSED; 73a46f8d58SGaetan Rivet return 0; 74a46f8d58SGaetan Rivet } 75a46f8d58SGaetan Rivet 76a0194d82SGaetan Rivet static void 77a0194d82SGaetan Rivet fs_sanitize_cmdline(char *args) 78a0194d82SGaetan Rivet { 7979da7b91SGaetan Rivet char *nl; 80a0194d82SGaetan Rivet 8179da7b91SGaetan Rivet nl = strrchr(args, '\n'); 8279da7b91SGaetan Rivet if (nl) 8379da7b91SGaetan Rivet nl[0] = '\0'; 84a0194d82SGaetan Rivet } 85a0194d82SGaetan Rivet 86a0194d82SGaetan Rivet static int 87a0194d82SGaetan Rivet fs_execute_cmd(struct sub_device *sdev, char *cmdline) 88a0194d82SGaetan Rivet { 89a0194d82SGaetan Rivet FILE *fp; 90a0194d82SGaetan Rivet /* store possible newline as well */ 91a0194d82SGaetan Rivet char output[DEVARGS_MAXLEN + 1]; 92a0194d82SGaetan Rivet size_t len; 934853f2beSGaetan Rivet int ret; 94a0194d82SGaetan Rivet 95a0194d82SGaetan Rivet RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL); 96a0194d82SGaetan Rivet if (sdev->cmdline == NULL) { 97a0194d82SGaetan Rivet size_t i; 98a0194d82SGaetan Rivet 99a0194d82SGaetan Rivet len = strlen(cmdline) + 1; 100a0194d82SGaetan Rivet sdev->cmdline = calloc(1, len); 101a0194d82SGaetan Rivet if (sdev->cmdline == NULL) { 102a0194d82SGaetan Rivet ERROR("Command line allocation failed"); 103a0194d82SGaetan Rivet return -ENOMEM; 104a0194d82SGaetan Rivet } 105f9acaf84SBruce Richardson strlcpy(sdev->cmdline, cmdline, len); 106a0194d82SGaetan Rivet /* Replace all commas in the command line by spaces */ 107a0194d82SGaetan Rivet for (i = 0; i < len; i++) 108a0194d82SGaetan Rivet if (sdev->cmdline[i] == ',') 109a0194d82SGaetan Rivet sdev->cmdline[i] = ' '; 110a0194d82SGaetan Rivet } 111a0194d82SGaetan Rivet DEBUG("'%s'", sdev->cmdline); 112a0194d82SGaetan Rivet fp = popen(sdev->cmdline, "r"); 113a0194d82SGaetan Rivet if (fp == NULL) { 1144853f2beSGaetan Rivet ret = -errno; 115a0194d82SGaetan Rivet ERROR("popen: %s", strerror(errno)); 116a0194d82SGaetan Rivet return ret; 117a0194d82SGaetan Rivet } 118a0194d82SGaetan Rivet /* We only read one line */ 119a0194d82SGaetan Rivet if (fgets(output, sizeof(output) - 1, fp) == NULL) { 120a0194d82SGaetan Rivet DEBUG("Could not read command output"); 12135ffe420SRaslan Darawsheh ret = -ENODEV; 12235ffe420SRaslan Darawsheh goto ret_pclose; 123a0194d82SGaetan Rivet } 124a0194d82SGaetan Rivet fs_sanitize_cmdline(output); 12579da7b91SGaetan Rivet if (output[0] == '\0') { 12679da7b91SGaetan Rivet ret = -ENODEV; 12779da7b91SGaetan Rivet goto ret_pclose; 12879da7b91SGaetan Rivet } 129a0194d82SGaetan Rivet ret = fs_parse_device(sdev, output); 1304853f2beSGaetan Rivet if (ret) 131a0194d82SGaetan Rivet ERROR("Parsing device '%s' failed", output); 132a0194d82SGaetan Rivet ret_pclose: 1334853f2beSGaetan Rivet if (pclose(fp) == -1) 134a0194d82SGaetan Rivet ERROR("pclose: %s", strerror(errno)); 135a0194d82SGaetan Rivet return ret; 136a0194d82SGaetan Rivet } 137a0194d82SGaetan Rivet 138a46f8d58SGaetan Rivet static int 139d1b961dbSMatan Azrad fs_read_fd(struct sub_device *sdev, char *fd_str) 140d1b961dbSMatan Azrad { 141d1b961dbSMatan Azrad FILE *fp = NULL; 142d1b961dbSMatan Azrad int fd = -1; 143d1b961dbSMatan Azrad /* store possible newline as well */ 144d1b961dbSMatan Azrad char output[DEVARGS_MAXLEN + 1]; 145d1b961dbSMatan Azrad int err = -ENODEV; 146d1b961dbSMatan Azrad int oflags; 147d1b961dbSMatan Azrad int lcount; 148d1b961dbSMatan Azrad 149d1b961dbSMatan Azrad RTE_ASSERT(fd_str != NULL || sdev->fd_str != NULL); 150d1b961dbSMatan Azrad if (sdev->fd_str == NULL) { 151d1b961dbSMatan Azrad sdev->fd_str = strdup(fd_str); 152d1b961dbSMatan Azrad if (sdev->fd_str == NULL) { 153d1b961dbSMatan Azrad ERROR("Command line allocation failed"); 154d1b961dbSMatan Azrad return -ENOMEM; 155d1b961dbSMatan Azrad } 156d1b961dbSMatan Azrad } 157d1b961dbSMatan Azrad errno = 0; 158d1b961dbSMatan Azrad fd = strtol(fd_str, &fd_str, 0); 159d1b961dbSMatan Azrad if (errno || *fd_str || fd < 0) { 160d1b961dbSMatan Azrad ERROR("Parsing FD number failed"); 161d1b961dbSMatan Azrad goto error; 162d1b961dbSMatan Azrad } 163d1b961dbSMatan Azrad /* Fiddle with copy of file descriptor */ 164d1b961dbSMatan Azrad fd = dup(fd); 165d1b961dbSMatan Azrad if (fd == -1) 166d1b961dbSMatan Azrad goto error; 167d1b961dbSMatan Azrad oflags = fcntl(fd, F_GETFL); 168d1b961dbSMatan Azrad if (oflags == -1) 169d1b961dbSMatan Azrad goto error; 170d1b961dbSMatan Azrad if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1) 171d1b961dbSMatan Azrad goto error; 172d1b961dbSMatan Azrad fp = fdopen(fd, "r"); 173d1b961dbSMatan Azrad if (fp == NULL) 174d1b961dbSMatan Azrad goto error; 175d1b961dbSMatan Azrad fd = -1; 176d1b961dbSMatan Azrad /* Only take the last line into account */ 177d1b961dbSMatan Azrad lcount = 0; 178d1b961dbSMatan Azrad while (fgets(output, sizeof(output), fp)) 179d1b961dbSMatan Azrad ++lcount; 180d1b961dbSMatan Azrad if (lcount == 0) 181d1b961dbSMatan Azrad goto error; 182d1b961dbSMatan Azrad else if (ferror(fp) && errno != EAGAIN) 183d1b961dbSMatan Azrad goto error; 184d1b961dbSMatan Azrad /* Line must end with a newline character */ 185d1b961dbSMatan Azrad fs_sanitize_cmdline(output); 186d1b961dbSMatan Azrad if (output[0] == '\0') 187d1b961dbSMatan Azrad goto error; 188d1b961dbSMatan Azrad err = fs_parse_device(sdev, output); 189d1b961dbSMatan Azrad if (err) 190d1b961dbSMatan Azrad ERROR("Parsing device '%s' failed", output); 191d1b961dbSMatan Azrad error: 192d1b961dbSMatan Azrad if (fp) 193d1b961dbSMatan Azrad fclose(fp); 194d1b961dbSMatan Azrad if (fd != -1) 195d1b961dbSMatan Azrad close(fd); 196d1b961dbSMatan Azrad return err; 197d1b961dbSMatan Azrad } 198d1b961dbSMatan Azrad 199d1b961dbSMatan Azrad static int 200a46f8d58SGaetan Rivet fs_parse_device_param(struct rte_eth_dev *dev, const char *param, 201a46f8d58SGaetan Rivet uint8_t head) 202a46f8d58SGaetan Rivet { 203a46f8d58SGaetan Rivet struct fs_priv *priv; 204a46f8d58SGaetan Rivet struct sub_device *sdev; 205a46f8d58SGaetan Rivet char *args = NULL; 206a46f8d58SGaetan Rivet size_t a, b; 207a46f8d58SGaetan Rivet int ret; 208a46f8d58SGaetan Rivet 209a46f8d58SGaetan Rivet priv = PRIV(dev); 210a46f8d58SGaetan Rivet a = 0; 211a46f8d58SGaetan Rivet b = 0; 212a46f8d58SGaetan Rivet ret = 0; 213a46f8d58SGaetan Rivet while (param[b] != '(' && 214a46f8d58SGaetan Rivet param[b] != '\0') 215a46f8d58SGaetan Rivet b++; 216a46f8d58SGaetan Rivet a = b; 217a46f8d58SGaetan Rivet b += closing_paren(¶m[b]); 218a46f8d58SGaetan Rivet if (a == b) { 219a46f8d58SGaetan Rivet ERROR("Dangling parenthesis"); 220a46f8d58SGaetan Rivet return -EINVAL; 221a46f8d58SGaetan Rivet } 222a46f8d58SGaetan Rivet a += 1; 223a46f8d58SGaetan Rivet args = strndup(¶m[a], b - a); 224a46f8d58SGaetan Rivet if (args == NULL) { 225a46f8d58SGaetan Rivet ERROR("Not enough memory for parameter parsing"); 226a46f8d58SGaetan Rivet return -ENOMEM; 227a46f8d58SGaetan Rivet } 228a46f8d58SGaetan Rivet sdev = &priv->subs[head]; 229a46f8d58SGaetan Rivet if (strncmp(param, "dev", 3) == 0) { 230a46f8d58SGaetan Rivet ret = fs_parse_device(sdev, args); 231a46f8d58SGaetan Rivet if (ret) 232a46f8d58SGaetan Rivet goto free_args; 233a0194d82SGaetan Rivet } else if (strncmp(param, "exec", 4) == 0) { 234a0194d82SGaetan Rivet ret = fs_execute_cmd(sdev, args); 235a0194d82SGaetan Rivet if (ret == -ENODEV) { 236a0194d82SGaetan Rivet DEBUG("Reading device info from command line failed"); 237a0194d82SGaetan Rivet ret = 0; 238a0194d82SGaetan Rivet } 239a0194d82SGaetan Rivet if (ret) 240a0194d82SGaetan Rivet goto free_args; 241d1b961dbSMatan Azrad } else if (strncmp(param, "fd(", 3) == 0) { 242d1b961dbSMatan Azrad ret = fs_read_fd(sdev, args); 243d1b961dbSMatan Azrad if (ret == -ENODEV) { 244d1b961dbSMatan Azrad DEBUG("Reading device info from FD failed"); 245d1b961dbSMatan Azrad ret = 0; 246d1b961dbSMatan Azrad } 247d1b961dbSMatan Azrad if (ret) 248d1b961dbSMatan Azrad goto free_args; 249a46f8d58SGaetan Rivet } else { 250a46f8d58SGaetan Rivet ERROR("Unrecognized device type: %.*s", (int)b, param); 2512ddf2d7aSChengwen Feng ret = -EINVAL; 252a46f8d58SGaetan Rivet } 253a46f8d58SGaetan Rivet free_args: 254a46f8d58SGaetan Rivet free(args); 255a46f8d58SGaetan Rivet return ret; 256a46f8d58SGaetan Rivet } 257a46f8d58SGaetan Rivet 258a46f8d58SGaetan Rivet static int 259a46f8d58SGaetan Rivet fs_parse_sub_devices(parse_cb *cb, 260a46f8d58SGaetan Rivet struct rte_eth_dev *dev, const char *params) 261a46f8d58SGaetan Rivet { 262a46f8d58SGaetan Rivet size_t a, b; 263a46f8d58SGaetan Rivet uint8_t head; 264a46f8d58SGaetan Rivet int ret; 265a46f8d58SGaetan Rivet 266a46f8d58SGaetan Rivet a = 0; 267a46f8d58SGaetan Rivet head = 0; 268a46f8d58SGaetan Rivet ret = 0; 269a46f8d58SGaetan Rivet while (params[a] != '\0') { 270a46f8d58SGaetan Rivet b = a; 271a46f8d58SGaetan Rivet while (params[b] != '(' && 272a46f8d58SGaetan Rivet params[b] != ',' && 273a46f8d58SGaetan Rivet params[b] != '\0') 274a46f8d58SGaetan Rivet b++; 275a46f8d58SGaetan Rivet if (b == a) { 276a46f8d58SGaetan Rivet ERROR("Invalid parameter"); 277a46f8d58SGaetan Rivet return -EINVAL; 278a46f8d58SGaetan Rivet } 279a46f8d58SGaetan Rivet if (params[b] == ',') { 280a46f8d58SGaetan Rivet a = b + 1; 281a46f8d58SGaetan Rivet continue; 282a46f8d58SGaetan Rivet } 283a46f8d58SGaetan Rivet if (params[b] == '(') { 284a46f8d58SGaetan Rivet size_t start = b; 285a46f8d58SGaetan Rivet 286a46f8d58SGaetan Rivet b += closing_paren(¶ms[b]); 287a46f8d58SGaetan Rivet if (b == start) { 288a46f8d58SGaetan Rivet ERROR("Dangling parenthesis"); 289a46f8d58SGaetan Rivet return -EINVAL; 290a46f8d58SGaetan Rivet } 291a46f8d58SGaetan Rivet ret = (*cb)(dev, ¶ms[a], head); 292a46f8d58SGaetan Rivet if (ret) 293a46f8d58SGaetan Rivet return ret; 294a46f8d58SGaetan Rivet head += 1; 295a46f8d58SGaetan Rivet b += 1; 296a46f8d58SGaetan Rivet if (params[b] == '\0') 297a46f8d58SGaetan Rivet return 0; 298a46f8d58SGaetan Rivet } 299a46f8d58SGaetan Rivet a = b + 1; 300a46f8d58SGaetan Rivet } 301a46f8d58SGaetan Rivet return 0; 302a46f8d58SGaetan Rivet } 303a46f8d58SGaetan Rivet 304a46f8d58SGaetan Rivet static int 305a46f8d58SGaetan Rivet fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN]) 306a46f8d58SGaetan Rivet { 307a46f8d58SGaetan Rivet char buffer[DEVARGS_MAXLEN] = {0}; 308a46f8d58SGaetan Rivet size_t a, b; 309a46f8d58SGaetan Rivet int i; 310a46f8d58SGaetan Rivet 311a46f8d58SGaetan Rivet a = 0; 312a46f8d58SGaetan Rivet i = 0; 313a46f8d58SGaetan Rivet while (params[a] != '\0') { 314a46f8d58SGaetan Rivet b = a; 315a46f8d58SGaetan Rivet while (params[b] != '(' && 316a46f8d58SGaetan Rivet params[b] != ',' && 317a46f8d58SGaetan Rivet params[b] != '\0') 318a46f8d58SGaetan Rivet b++; 319a46f8d58SGaetan Rivet if (b == a) { 320a46f8d58SGaetan Rivet ERROR("Invalid parameter"); 321a46f8d58SGaetan Rivet return -EINVAL; 322a46f8d58SGaetan Rivet } 323852be652SMatan Azrad if (params[b] == ',' || params[b] == '\0') { 324852be652SMatan Azrad size_t len = b - a; 325852be652SMatan Azrad 326852be652SMatan Azrad if (i > 0) 327852be652SMatan Azrad len += 1; 328852be652SMatan Azrad snprintf(&buffer[i], len + 1, "%s%s", 329852be652SMatan Azrad i ? "," : "", ¶ms[a]); 330852be652SMatan Azrad i += len; 331852be652SMatan Azrad } else if (params[b] == '(') { 332a46f8d58SGaetan Rivet size_t start = b; 333852be652SMatan Azrad 334a46f8d58SGaetan Rivet b += closing_paren(¶ms[b]); 335a46f8d58SGaetan Rivet if (b == start) 336a46f8d58SGaetan Rivet return -EINVAL; 337a46f8d58SGaetan Rivet b += 1; 338a46f8d58SGaetan Rivet if (params[b] == '\0') 339a46f8d58SGaetan Rivet goto out; 340a46f8d58SGaetan Rivet } 341a46f8d58SGaetan Rivet a = b + 1; 342a46f8d58SGaetan Rivet } 343a46f8d58SGaetan Rivet out: 344c022cb40SBruce Richardson strlcpy(params, buffer, DEVARGS_MAXLEN); 345a46f8d58SGaetan Rivet return 0; 346a46f8d58SGaetan Rivet } 347a46f8d58SGaetan Rivet 348a46f8d58SGaetan Rivet static int 349ebea83f8SGaetan Rivet fs_get_u64_arg(const char *key __rte_unused, 350ebea83f8SGaetan Rivet const char *value, void *out) 351ebea83f8SGaetan Rivet { 352ebea83f8SGaetan Rivet uint64_t *u64 = out; 353ebea83f8SGaetan Rivet char *endptr = NULL; 354ebea83f8SGaetan Rivet 355ebea83f8SGaetan Rivet if ((value == NULL) || (out == NULL)) 356ebea83f8SGaetan Rivet return -EINVAL; 357ebea83f8SGaetan Rivet errno = 0; 358ebea83f8SGaetan Rivet *u64 = strtoull(value, &endptr, 0); 359ebea83f8SGaetan Rivet if (errno != 0) 360ebea83f8SGaetan Rivet return -errno; 361ebea83f8SGaetan Rivet if (endptr == value) 362ebea83f8SGaetan Rivet return -1; 363ebea83f8SGaetan Rivet return 0; 364ebea83f8SGaetan Rivet } 365ebea83f8SGaetan Rivet 366ebea83f8SGaetan Rivet static int 367a46f8d58SGaetan Rivet fs_get_mac_addr_arg(const char *key __rte_unused, 368a46f8d58SGaetan Rivet const char *value, void *out) 369a46f8d58SGaetan Rivet { 3706d13ea8eSOlivier Matz struct rte_ether_addr *ea = out; 371a46f8d58SGaetan Rivet 372a46f8d58SGaetan Rivet if ((value == NULL) || (out == NULL)) 373a46f8d58SGaetan Rivet return -EINVAL; 3741cf34a4eSStephen Hemminger 3751cf34a4eSStephen Hemminger return rte_ether_unformat_addr(value, ea); 376a46f8d58SGaetan Rivet } 377a46f8d58SGaetan Rivet 378a46f8d58SGaetan Rivet int 379a46f8d58SGaetan Rivet failsafe_args_parse(struct rte_eth_dev *dev, const char *params) 380a46f8d58SGaetan Rivet { 381a46f8d58SGaetan Rivet struct fs_priv *priv; 382a46f8d58SGaetan Rivet char mut_params[DEVARGS_MAXLEN] = ""; 383a46f8d58SGaetan Rivet struct rte_kvargs *kvlist = NULL; 384a46f8d58SGaetan Rivet unsigned int arg_count; 385a46f8d58SGaetan Rivet size_t n; 386a46f8d58SGaetan Rivet int ret; 387a46f8d58SGaetan Rivet 388a46f8d58SGaetan Rivet priv = PRIV(dev); 389a46f8d58SGaetan Rivet ret = 0; 390a46f8d58SGaetan Rivet priv->subs_tx = FAILSAFE_MAX_ETHPORTS; 391a46f8d58SGaetan Rivet /* default parameters */ 392c022cb40SBruce Richardson n = strlcpy(mut_params, params, sizeof(mut_params)); 393a46f8d58SGaetan Rivet if (n >= sizeof(mut_params)) { 394a46f8d58SGaetan Rivet ERROR("Parameter string too long (>=%zu)", 395a46f8d58SGaetan Rivet sizeof(mut_params)); 396a46f8d58SGaetan Rivet return -ENOMEM; 397a46f8d58SGaetan Rivet } 398a46f8d58SGaetan Rivet ret = fs_parse_sub_devices(fs_parse_device_param, 399a46f8d58SGaetan Rivet dev, params); 400a46f8d58SGaetan Rivet if (ret < 0) 401a46f8d58SGaetan Rivet return ret; 402a46f8d58SGaetan Rivet ret = fs_remove_sub_devices_definition(mut_params); 403a46f8d58SGaetan Rivet if (ret < 0) 404a46f8d58SGaetan Rivet return ret; 405a46f8d58SGaetan Rivet if (strnlen(mut_params, sizeof(mut_params)) > 0) { 406a46f8d58SGaetan Rivet kvlist = rte_kvargs_parse(mut_params, 407a46f8d58SGaetan Rivet pmd_failsafe_init_parameters); 408a46f8d58SGaetan Rivet if (kvlist == NULL) { 409*f665790aSDavid Marchand ERROR("Error parsing parameters, usage:" 410a46f8d58SGaetan Rivet PMD_FAILSAFE_PARAM_STRING); 411a46f8d58SGaetan Rivet return -1; 412a46f8d58SGaetan Rivet } 413ebea83f8SGaetan Rivet /* PLUG_IN event poll timer */ 414ebea83f8SGaetan Rivet arg_count = rte_kvargs_count(kvlist, 415ebea83f8SGaetan Rivet PMD_FAILSAFE_HOTPLUG_POLL_KVARG); 416ebea83f8SGaetan Rivet if (arg_count == 1) { 417ebea83f8SGaetan Rivet ret = rte_kvargs_process(kvlist, 418ebea83f8SGaetan Rivet PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 419520dd992SFerruh Yigit &fs_get_u64_arg, &failsafe_hotplug_poll); 420ebea83f8SGaetan Rivet if (ret < 0) 421ebea83f8SGaetan Rivet goto free_kvlist; 422ebea83f8SGaetan Rivet } 423a46f8d58SGaetan Rivet /* MAC addr */ 424a46f8d58SGaetan Rivet arg_count = rte_kvargs_count(kvlist, 425a46f8d58SGaetan Rivet PMD_FAILSAFE_MAC_KVARG); 426a46f8d58SGaetan Rivet if (arg_count > 0) { 427a46f8d58SGaetan Rivet ret = rte_kvargs_process(kvlist, 428a46f8d58SGaetan Rivet PMD_FAILSAFE_MAC_KVARG, 429a46f8d58SGaetan Rivet &fs_get_mac_addr_arg, 430a46f8d58SGaetan Rivet &dev->data->mac_addrs[0]); 431a46f8d58SGaetan Rivet if (ret < 0) 432a46f8d58SGaetan Rivet goto free_kvlist; 433852be652SMatan Azrad 434520dd992SFerruh Yigit failsafe_mac_from_arg = 1; 435a46f8d58SGaetan Rivet } 436a46f8d58SGaetan Rivet } 437ebea83f8SGaetan Rivet PRIV(dev)->state = DEV_PARSED; 438a46f8d58SGaetan Rivet free_kvlist: 439a46f8d58SGaetan Rivet rte_kvargs_free(kvlist); 440a46f8d58SGaetan Rivet return ret; 441a46f8d58SGaetan Rivet } 442a46f8d58SGaetan Rivet 443a46f8d58SGaetan Rivet void 444a46f8d58SGaetan Rivet failsafe_args_free(struct rte_eth_dev *dev) 445a46f8d58SGaetan Rivet { 446a46f8d58SGaetan Rivet struct sub_device *sdev; 447a46f8d58SGaetan Rivet uint8_t i; 448a46f8d58SGaetan Rivet 449a46f8d58SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 4509720e325SAdrien Mazarguil free(sdev->cmdline); 451a0194d82SGaetan Rivet sdev->cmdline = NULL; 452d1b961dbSMatan Azrad free(sdev->fd_str); 453d1b961dbSMatan Azrad sdev->fd_str = NULL; 45464051bb1SXueming Li rte_devargs_reset(&sdev->devargs); 455a46f8d58SGaetan Rivet } 456a46f8d58SGaetan Rivet } 457a46f8d58SGaetan Rivet 458a46f8d58SGaetan Rivet static int 459a46f8d58SGaetan Rivet fs_count_device(struct rte_eth_dev *dev, const char *param, 460a46f8d58SGaetan Rivet uint8_t head __rte_unused) 461a46f8d58SGaetan Rivet { 462a46f8d58SGaetan Rivet size_t b = 0; 463a46f8d58SGaetan Rivet 464a46f8d58SGaetan Rivet while (param[b] != '(' && 465a46f8d58SGaetan Rivet param[b] != '\0') 466a46f8d58SGaetan Rivet b++; 467a0194d82SGaetan Rivet if (strncmp(param, "dev", b) != 0 && 468d1b961dbSMatan Azrad strncmp(param, "exec", b) != 0 && 469d1b961dbSMatan Azrad strncmp(param, "fd(", b) != 0) { 470a46f8d58SGaetan Rivet ERROR("Unrecognized device type: %.*s", (int)b, param); 471a46f8d58SGaetan Rivet return -EINVAL; 472a46f8d58SGaetan Rivet } 473a46f8d58SGaetan Rivet PRIV(dev)->subs_tail += 1; 474a46f8d58SGaetan Rivet return 0; 475a46f8d58SGaetan Rivet } 476a46f8d58SGaetan Rivet 477a46f8d58SGaetan Rivet int 478a46f8d58SGaetan Rivet failsafe_args_count_subdevice(struct rte_eth_dev *dev, 479a46f8d58SGaetan Rivet const char *params) 480a46f8d58SGaetan Rivet { 481a46f8d58SGaetan Rivet return fs_parse_sub_devices(fs_count_device, 482a46f8d58SGaetan Rivet dev, params); 483a46f8d58SGaetan Rivet } 484a0194d82SGaetan Rivet 485598fb8aeSGaetan Rivet static int 486598fb8aeSGaetan Rivet fs_parse_sub_device(struct sub_device *sdev) 487598fb8aeSGaetan Rivet { 488598fb8aeSGaetan Rivet struct rte_devargs *da; 489598fb8aeSGaetan Rivet char devstr[DEVARGS_MAXLEN] = ""; 490598fb8aeSGaetan Rivet 491598fb8aeSGaetan Rivet da = &sdev->devargs; 492598fb8aeSGaetan Rivet snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args); 493598fb8aeSGaetan Rivet return fs_parse_device(sdev, devstr); 494598fb8aeSGaetan Rivet } 495598fb8aeSGaetan Rivet 496a0194d82SGaetan Rivet int 497a0194d82SGaetan Rivet failsafe_args_parse_subs(struct rte_eth_dev *dev) 498a0194d82SGaetan Rivet { 499a0194d82SGaetan Rivet struct sub_device *sdev; 500a0194d82SGaetan Rivet uint8_t i; 501a0194d82SGaetan Rivet int ret = 0; 502a0194d82SGaetan Rivet 503a0194d82SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 504a0194d82SGaetan Rivet if (sdev->state >= DEV_PARSED) 505a0194d82SGaetan Rivet continue; 506a0194d82SGaetan Rivet if (sdev->cmdline) 507a0194d82SGaetan Rivet ret = fs_execute_cmd(sdev, sdev->cmdline); 508d1b961dbSMatan Azrad else if (sdev->fd_str) 509d1b961dbSMatan Azrad ret = fs_read_fd(sdev, sdev->fd_str); 510598fb8aeSGaetan Rivet else 511598fb8aeSGaetan Rivet ret = fs_parse_sub_device(sdev); 512a0194d82SGaetan Rivet if (ret == 0) 513a0194d82SGaetan Rivet sdev->state = DEV_PARSED; 514a0194d82SGaetan Rivet } 515a0194d82SGaetan Rivet return 0; 516a0194d82SGaetan Rivet } 517