1*d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause 22bfe3f2eSlogwang * Copyright 2017 6WIND S.A. 3*d30ea906Sjfb8856606 * Copyright 2017 Mellanox Technologies, Ltd 42bfe3f2eSlogwang */ 52bfe3f2eSlogwang 6*d30ea906Sjfb8856606 #include <fcntl.h> 7*d30ea906Sjfb8856606 #include <stdio.h> 8*d30ea906Sjfb8856606 #include <stdlib.h> 92bfe3f2eSlogwang #include <string.h> 10*d30ea906Sjfb8856606 #include <unistd.h> 112bfe3f2eSlogwang #include <errno.h> 122bfe3f2eSlogwang 132bfe3f2eSlogwang #include <rte_debug.h> 142bfe3f2eSlogwang #include <rte_devargs.h> 152bfe3f2eSlogwang #include <rte_malloc.h> 162bfe3f2eSlogwang #include <rte_kvargs.h> 17*d30ea906Sjfb8856606 #include <rte_string_fns.h> 182bfe3f2eSlogwang 192bfe3f2eSlogwang #include "failsafe_private.h" 202bfe3f2eSlogwang 212bfe3f2eSlogwang /* Callback used when a new device is found in devargs */ 222bfe3f2eSlogwang typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params, 232bfe3f2eSlogwang uint8_t head); 242bfe3f2eSlogwang 25*d30ea906Sjfb8856606 uint64_t failsafe_hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS; 26*d30ea906Sjfb8856606 int failsafe_mac_from_arg; 272bfe3f2eSlogwang 28*d30ea906Sjfb8856606 static const char * const pmd_failsafe_init_parameters[] = { 292bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 302bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG, 312bfe3f2eSlogwang NULL, 322bfe3f2eSlogwang }; 332bfe3f2eSlogwang 342bfe3f2eSlogwang /* 352bfe3f2eSlogwang * input: text. 362bfe3f2eSlogwang * output: 0: if text[0] != '(', 372bfe3f2eSlogwang * 0: if there are no corresponding ')' 382bfe3f2eSlogwang * n: distance to corresponding ')' otherwise 392bfe3f2eSlogwang */ 402bfe3f2eSlogwang static size_t 412bfe3f2eSlogwang closing_paren(const char *text) 422bfe3f2eSlogwang { 432bfe3f2eSlogwang int nb_open = 0; 442bfe3f2eSlogwang size_t i = 0; 452bfe3f2eSlogwang 462bfe3f2eSlogwang while (text[i] != '\0') { 472bfe3f2eSlogwang if (text[i] == '(') 482bfe3f2eSlogwang nb_open++; 492bfe3f2eSlogwang if (text[i] == ')') 502bfe3f2eSlogwang nb_open--; 512bfe3f2eSlogwang if (nb_open == 0) 522bfe3f2eSlogwang return i; 532bfe3f2eSlogwang i++; 542bfe3f2eSlogwang } 552bfe3f2eSlogwang return 0; 562bfe3f2eSlogwang } 572bfe3f2eSlogwang 582bfe3f2eSlogwang static int 592bfe3f2eSlogwang fs_parse_device(struct sub_device *sdev, char *args) 602bfe3f2eSlogwang { 612bfe3f2eSlogwang struct rte_devargs *d; 622bfe3f2eSlogwang int ret; 632bfe3f2eSlogwang 642bfe3f2eSlogwang d = &sdev->devargs; 652bfe3f2eSlogwang DEBUG("%s", args); 66*d30ea906Sjfb8856606 ret = rte_devargs_parse(d, args); 672bfe3f2eSlogwang if (ret) { 682bfe3f2eSlogwang DEBUG("devargs parsing failed with code %d", ret); 692bfe3f2eSlogwang return ret; 702bfe3f2eSlogwang } 712bfe3f2eSlogwang sdev->bus = d->bus; 722bfe3f2eSlogwang sdev->state = DEV_PARSED; 732bfe3f2eSlogwang return 0; 742bfe3f2eSlogwang } 752bfe3f2eSlogwang 762bfe3f2eSlogwang static void 772bfe3f2eSlogwang fs_sanitize_cmdline(char *args) 782bfe3f2eSlogwang { 792bfe3f2eSlogwang char *nl; 802bfe3f2eSlogwang 812bfe3f2eSlogwang nl = strrchr(args, '\n'); 822bfe3f2eSlogwang if (nl) 832bfe3f2eSlogwang nl[0] = '\0'; 842bfe3f2eSlogwang } 852bfe3f2eSlogwang 862bfe3f2eSlogwang static int 872bfe3f2eSlogwang fs_execute_cmd(struct sub_device *sdev, char *cmdline) 882bfe3f2eSlogwang { 892bfe3f2eSlogwang FILE *fp; 902bfe3f2eSlogwang /* store possible newline as well */ 912bfe3f2eSlogwang char output[DEVARGS_MAXLEN + 1]; 922bfe3f2eSlogwang size_t len; 932bfe3f2eSlogwang int ret; 942bfe3f2eSlogwang 952bfe3f2eSlogwang RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL); 962bfe3f2eSlogwang if (sdev->cmdline == NULL) { 972bfe3f2eSlogwang size_t i; 982bfe3f2eSlogwang 992bfe3f2eSlogwang len = strlen(cmdline) + 1; 1002bfe3f2eSlogwang sdev->cmdline = calloc(1, len); 1012bfe3f2eSlogwang if (sdev->cmdline == NULL) { 1022bfe3f2eSlogwang ERROR("Command line allocation failed"); 1032bfe3f2eSlogwang return -ENOMEM; 1042bfe3f2eSlogwang } 1052bfe3f2eSlogwang snprintf(sdev->cmdline, len, "%s", cmdline); 1062bfe3f2eSlogwang /* Replace all commas in the command line by spaces */ 1072bfe3f2eSlogwang for (i = 0; i < len; i++) 1082bfe3f2eSlogwang if (sdev->cmdline[i] == ',') 1092bfe3f2eSlogwang sdev->cmdline[i] = ' '; 1102bfe3f2eSlogwang } 1112bfe3f2eSlogwang DEBUG("'%s'", sdev->cmdline); 1122bfe3f2eSlogwang fp = popen(sdev->cmdline, "r"); 1132bfe3f2eSlogwang if (fp == NULL) { 1142bfe3f2eSlogwang ret = -errno; 1152bfe3f2eSlogwang ERROR("popen: %s", strerror(errno)); 1162bfe3f2eSlogwang return ret; 1172bfe3f2eSlogwang } 1182bfe3f2eSlogwang /* We only read one line */ 1192bfe3f2eSlogwang if (fgets(output, sizeof(output) - 1, fp) == NULL) { 1202bfe3f2eSlogwang DEBUG("Could not read command output"); 1212bfe3f2eSlogwang ret = -ENODEV; 1222bfe3f2eSlogwang goto ret_pclose; 1232bfe3f2eSlogwang } 1242bfe3f2eSlogwang fs_sanitize_cmdline(output); 1252bfe3f2eSlogwang if (output[0] == '\0') { 1262bfe3f2eSlogwang ret = -ENODEV; 1272bfe3f2eSlogwang goto ret_pclose; 1282bfe3f2eSlogwang } 1292bfe3f2eSlogwang ret = fs_parse_device(sdev, output); 1302bfe3f2eSlogwang if (ret) 1312bfe3f2eSlogwang ERROR("Parsing device '%s' failed", output); 1322bfe3f2eSlogwang ret_pclose: 1332bfe3f2eSlogwang if (pclose(fp) == -1) 1342bfe3f2eSlogwang ERROR("pclose: %s", strerror(errno)); 1352bfe3f2eSlogwang return ret; 1362bfe3f2eSlogwang } 1372bfe3f2eSlogwang 1382bfe3f2eSlogwang static int 139*d30ea906Sjfb8856606 fs_read_fd(struct sub_device *sdev, char *fd_str) 140*d30ea906Sjfb8856606 { 141*d30ea906Sjfb8856606 FILE *fp = NULL; 142*d30ea906Sjfb8856606 int fd = -1; 143*d30ea906Sjfb8856606 /* store possible newline as well */ 144*d30ea906Sjfb8856606 char output[DEVARGS_MAXLEN + 1]; 145*d30ea906Sjfb8856606 int err = -ENODEV; 146*d30ea906Sjfb8856606 int oflags; 147*d30ea906Sjfb8856606 int lcount; 148*d30ea906Sjfb8856606 149*d30ea906Sjfb8856606 RTE_ASSERT(fd_str != NULL || sdev->fd_str != NULL); 150*d30ea906Sjfb8856606 if (sdev->fd_str == NULL) { 151*d30ea906Sjfb8856606 sdev->fd_str = strdup(fd_str); 152*d30ea906Sjfb8856606 if (sdev->fd_str == NULL) { 153*d30ea906Sjfb8856606 ERROR("Command line allocation failed"); 154*d30ea906Sjfb8856606 return -ENOMEM; 155*d30ea906Sjfb8856606 } 156*d30ea906Sjfb8856606 } 157*d30ea906Sjfb8856606 errno = 0; 158*d30ea906Sjfb8856606 fd = strtol(fd_str, &fd_str, 0); 159*d30ea906Sjfb8856606 if (errno || *fd_str || fd < 0) { 160*d30ea906Sjfb8856606 ERROR("Parsing FD number failed"); 161*d30ea906Sjfb8856606 goto error; 162*d30ea906Sjfb8856606 } 163*d30ea906Sjfb8856606 /* Fiddle with copy of file descriptor */ 164*d30ea906Sjfb8856606 fd = dup(fd); 165*d30ea906Sjfb8856606 if (fd == -1) 166*d30ea906Sjfb8856606 goto error; 167*d30ea906Sjfb8856606 oflags = fcntl(fd, F_GETFL); 168*d30ea906Sjfb8856606 if (oflags == -1) 169*d30ea906Sjfb8856606 goto error; 170*d30ea906Sjfb8856606 if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1) 171*d30ea906Sjfb8856606 goto error; 172*d30ea906Sjfb8856606 fp = fdopen(fd, "r"); 173*d30ea906Sjfb8856606 if (fp == NULL) 174*d30ea906Sjfb8856606 goto error; 175*d30ea906Sjfb8856606 fd = -1; 176*d30ea906Sjfb8856606 /* Only take the last line into account */ 177*d30ea906Sjfb8856606 lcount = 0; 178*d30ea906Sjfb8856606 while (fgets(output, sizeof(output), fp)) 179*d30ea906Sjfb8856606 ++lcount; 180*d30ea906Sjfb8856606 if (lcount == 0) 181*d30ea906Sjfb8856606 goto error; 182*d30ea906Sjfb8856606 else if (ferror(fp) && errno != EAGAIN) 183*d30ea906Sjfb8856606 goto error; 184*d30ea906Sjfb8856606 /* Line must end with a newline character */ 185*d30ea906Sjfb8856606 fs_sanitize_cmdline(output); 186*d30ea906Sjfb8856606 if (output[0] == '\0') 187*d30ea906Sjfb8856606 goto error; 188*d30ea906Sjfb8856606 err = fs_parse_device(sdev, output); 189*d30ea906Sjfb8856606 if (err) 190*d30ea906Sjfb8856606 ERROR("Parsing device '%s' failed", output); 191*d30ea906Sjfb8856606 error: 192*d30ea906Sjfb8856606 if (fp) 193*d30ea906Sjfb8856606 fclose(fp); 194*d30ea906Sjfb8856606 if (fd != -1) 195*d30ea906Sjfb8856606 close(fd); 196*d30ea906Sjfb8856606 return err; 197*d30ea906Sjfb8856606 } 198*d30ea906Sjfb8856606 199*d30ea906Sjfb8856606 static int 2002bfe3f2eSlogwang fs_parse_device_param(struct rte_eth_dev *dev, const char *param, 2012bfe3f2eSlogwang uint8_t head) 2022bfe3f2eSlogwang { 2032bfe3f2eSlogwang struct fs_priv *priv; 2042bfe3f2eSlogwang struct sub_device *sdev; 2052bfe3f2eSlogwang char *args = NULL; 2062bfe3f2eSlogwang size_t a, b; 2072bfe3f2eSlogwang int ret; 2082bfe3f2eSlogwang 2092bfe3f2eSlogwang priv = PRIV(dev); 2102bfe3f2eSlogwang a = 0; 2112bfe3f2eSlogwang b = 0; 2122bfe3f2eSlogwang ret = 0; 2132bfe3f2eSlogwang while (param[b] != '(' && 2142bfe3f2eSlogwang param[b] != '\0') 2152bfe3f2eSlogwang b++; 2162bfe3f2eSlogwang a = b; 2172bfe3f2eSlogwang b += closing_paren(¶m[b]); 2182bfe3f2eSlogwang if (a == b) { 2192bfe3f2eSlogwang ERROR("Dangling parenthesis"); 2202bfe3f2eSlogwang return -EINVAL; 2212bfe3f2eSlogwang } 2222bfe3f2eSlogwang a += 1; 2232bfe3f2eSlogwang args = strndup(¶m[a], b - a); 2242bfe3f2eSlogwang if (args == NULL) { 2252bfe3f2eSlogwang ERROR("Not enough memory for parameter parsing"); 2262bfe3f2eSlogwang return -ENOMEM; 2272bfe3f2eSlogwang } 2282bfe3f2eSlogwang sdev = &priv->subs[head]; 2292bfe3f2eSlogwang if (strncmp(param, "dev", 3) == 0) { 2302bfe3f2eSlogwang ret = fs_parse_device(sdev, args); 2312bfe3f2eSlogwang if (ret) 2322bfe3f2eSlogwang goto free_args; 2332bfe3f2eSlogwang } else if (strncmp(param, "exec", 4) == 0) { 2342bfe3f2eSlogwang ret = fs_execute_cmd(sdev, args); 2352bfe3f2eSlogwang if (ret == -ENODEV) { 2362bfe3f2eSlogwang DEBUG("Reading device info from command line failed"); 2372bfe3f2eSlogwang ret = 0; 2382bfe3f2eSlogwang } 2392bfe3f2eSlogwang if (ret) 2402bfe3f2eSlogwang goto free_args; 241*d30ea906Sjfb8856606 } else if (strncmp(param, "fd(", 3) == 0) { 242*d30ea906Sjfb8856606 ret = fs_read_fd(sdev, args); 243*d30ea906Sjfb8856606 if (ret == -ENODEV) { 244*d30ea906Sjfb8856606 DEBUG("Reading device info from FD failed"); 245*d30ea906Sjfb8856606 ret = 0; 246*d30ea906Sjfb8856606 } 247*d30ea906Sjfb8856606 if (ret) 248*d30ea906Sjfb8856606 goto free_args; 2492bfe3f2eSlogwang } else { 2502bfe3f2eSlogwang ERROR("Unrecognized device type: %.*s", (int)b, param); 2512bfe3f2eSlogwang return -EINVAL; 2522bfe3f2eSlogwang } 2532bfe3f2eSlogwang free_args: 2542bfe3f2eSlogwang free(args); 2552bfe3f2eSlogwang return ret; 2562bfe3f2eSlogwang } 2572bfe3f2eSlogwang 2582bfe3f2eSlogwang static int 2592bfe3f2eSlogwang fs_parse_sub_devices(parse_cb *cb, 2602bfe3f2eSlogwang struct rte_eth_dev *dev, const char *params) 2612bfe3f2eSlogwang { 2622bfe3f2eSlogwang size_t a, b; 2632bfe3f2eSlogwang uint8_t head; 2642bfe3f2eSlogwang int ret; 2652bfe3f2eSlogwang 2662bfe3f2eSlogwang a = 0; 2672bfe3f2eSlogwang head = 0; 2682bfe3f2eSlogwang ret = 0; 2692bfe3f2eSlogwang while (params[a] != '\0') { 2702bfe3f2eSlogwang b = a; 2712bfe3f2eSlogwang while (params[b] != '(' && 2722bfe3f2eSlogwang params[b] != ',' && 2732bfe3f2eSlogwang params[b] != '\0') 2742bfe3f2eSlogwang b++; 2752bfe3f2eSlogwang if (b == a) { 2762bfe3f2eSlogwang ERROR("Invalid parameter"); 2772bfe3f2eSlogwang return -EINVAL; 2782bfe3f2eSlogwang } 2792bfe3f2eSlogwang if (params[b] == ',') { 2802bfe3f2eSlogwang a = b + 1; 2812bfe3f2eSlogwang continue; 2822bfe3f2eSlogwang } 2832bfe3f2eSlogwang if (params[b] == '(') { 2842bfe3f2eSlogwang size_t start = b; 2852bfe3f2eSlogwang 2862bfe3f2eSlogwang b += closing_paren(¶ms[b]); 2872bfe3f2eSlogwang if (b == start) { 2882bfe3f2eSlogwang ERROR("Dangling parenthesis"); 2892bfe3f2eSlogwang return -EINVAL; 2902bfe3f2eSlogwang } 2912bfe3f2eSlogwang ret = (*cb)(dev, ¶ms[a], head); 2922bfe3f2eSlogwang if (ret) 2932bfe3f2eSlogwang return ret; 2942bfe3f2eSlogwang head += 1; 2952bfe3f2eSlogwang b += 1; 2962bfe3f2eSlogwang if (params[b] == '\0') 2972bfe3f2eSlogwang return 0; 2982bfe3f2eSlogwang } 2992bfe3f2eSlogwang a = b + 1; 3002bfe3f2eSlogwang } 3012bfe3f2eSlogwang return 0; 3022bfe3f2eSlogwang } 3032bfe3f2eSlogwang 3042bfe3f2eSlogwang static int 3052bfe3f2eSlogwang fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN]) 3062bfe3f2eSlogwang { 3072bfe3f2eSlogwang char buffer[DEVARGS_MAXLEN] = {0}; 3082bfe3f2eSlogwang size_t a, b; 3092bfe3f2eSlogwang int i; 3102bfe3f2eSlogwang 3112bfe3f2eSlogwang a = 0; 3122bfe3f2eSlogwang i = 0; 3132bfe3f2eSlogwang while (params[a] != '\0') { 3142bfe3f2eSlogwang b = a; 3152bfe3f2eSlogwang while (params[b] != '(' && 3162bfe3f2eSlogwang params[b] != ',' && 3172bfe3f2eSlogwang params[b] != '\0') 3182bfe3f2eSlogwang b++; 3192bfe3f2eSlogwang if (b == a) { 3202bfe3f2eSlogwang ERROR("Invalid parameter"); 3212bfe3f2eSlogwang return -EINVAL; 3222bfe3f2eSlogwang } 3232bfe3f2eSlogwang if (params[b] == ',' || params[b] == '\0') { 3242bfe3f2eSlogwang size_t len = b - a; 3252bfe3f2eSlogwang 3262bfe3f2eSlogwang if (i > 0) 3272bfe3f2eSlogwang len += 1; 3282bfe3f2eSlogwang snprintf(&buffer[i], len + 1, "%s%s", 3292bfe3f2eSlogwang i ? "," : "", ¶ms[a]); 3302bfe3f2eSlogwang i += len; 3312bfe3f2eSlogwang } else if (params[b] == '(') { 3322bfe3f2eSlogwang size_t start = b; 3332bfe3f2eSlogwang 3342bfe3f2eSlogwang b += closing_paren(¶ms[b]); 3352bfe3f2eSlogwang if (b == start) 3362bfe3f2eSlogwang return -EINVAL; 3372bfe3f2eSlogwang b += 1; 3382bfe3f2eSlogwang if (params[b] == '\0') 3392bfe3f2eSlogwang goto out; 3402bfe3f2eSlogwang } 3412bfe3f2eSlogwang a = b + 1; 3422bfe3f2eSlogwang } 3432bfe3f2eSlogwang out: 344*d30ea906Sjfb8856606 strlcpy(params, buffer, DEVARGS_MAXLEN); 3452bfe3f2eSlogwang return 0; 3462bfe3f2eSlogwang } 3472bfe3f2eSlogwang 3482bfe3f2eSlogwang static int 3492bfe3f2eSlogwang fs_get_u64_arg(const char *key __rte_unused, 3502bfe3f2eSlogwang const char *value, void *out) 3512bfe3f2eSlogwang { 3522bfe3f2eSlogwang uint64_t *u64 = out; 3532bfe3f2eSlogwang char *endptr = NULL; 3542bfe3f2eSlogwang 3552bfe3f2eSlogwang if ((value == NULL) || (out == NULL)) 3562bfe3f2eSlogwang return -EINVAL; 3572bfe3f2eSlogwang errno = 0; 3582bfe3f2eSlogwang *u64 = strtoull(value, &endptr, 0); 3592bfe3f2eSlogwang if (errno != 0) 3602bfe3f2eSlogwang return -errno; 3612bfe3f2eSlogwang if (endptr == value) 3622bfe3f2eSlogwang return -1; 3632bfe3f2eSlogwang return 0; 3642bfe3f2eSlogwang } 3652bfe3f2eSlogwang 3662bfe3f2eSlogwang static int 3672bfe3f2eSlogwang fs_get_mac_addr_arg(const char *key __rte_unused, 3682bfe3f2eSlogwang const char *value, void *out) 3692bfe3f2eSlogwang { 3702bfe3f2eSlogwang struct ether_addr *ea = out; 3712bfe3f2eSlogwang int ret; 3722bfe3f2eSlogwang 3732bfe3f2eSlogwang if ((value == NULL) || (out == NULL)) 3742bfe3f2eSlogwang return -EINVAL; 3752bfe3f2eSlogwang ret = sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 3762bfe3f2eSlogwang &ea->addr_bytes[0], &ea->addr_bytes[1], 3772bfe3f2eSlogwang &ea->addr_bytes[2], &ea->addr_bytes[3], 3782bfe3f2eSlogwang &ea->addr_bytes[4], &ea->addr_bytes[5]); 3792bfe3f2eSlogwang return ret != ETHER_ADDR_LEN; 3802bfe3f2eSlogwang } 3812bfe3f2eSlogwang 3822bfe3f2eSlogwang int 3832bfe3f2eSlogwang failsafe_args_parse(struct rte_eth_dev *dev, const char *params) 3842bfe3f2eSlogwang { 3852bfe3f2eSlogwang struct fs_priv *priv; 3862bfe3f2eSlogwang char mut_params[DEVARGS_MAXLEN] = ""; 3872bfe3f2eSlogwang struct rte_kvargs *kvlist = NULL; 3882bfe3f2eSlogwang unsigned int arg_count; 3892bfe3f2eSlogwang size_t n; 3902bfe3f2eSlogwang int ret; 3912bfe3f2eSlogwang 3922bfe3f2eSlogwang priv = PRIV(dev); 3932bfe3f2eSlogwang ret = 0; 3942bfe3f2eSlogwang priv->subs_tx = FAILSAFE_MAX_ETHPORTS; 3952bfe3f2eSlogwang /* default parameters */ 396*d30ea906Sjfb8856606 n = strlcpy(mut_params, params, sizeof(mut_params)); 3972bfe3f2eSlogwang if (n >= sizeof(mut_params)) { 3982bfe3f2eSlogwang ERROR("Parameter string too long (>=%zu)", 3992bfe3f2eSlogwang sizeof(mut_params)); 4002bfe3f2eSlogwang return -ENOMEM; 4012bfe3f2eSlogwang } 4022bfe3f2eSlogwang ret = fs_parse_sub_devices(fs_parse_device_param, 4032bfe3f2eSlogwang dev, params); 4042bfe3f2eSlogwang if (ret < 0) 4052bfe3f2eSlogwang return ret; 4062bfe3f2eSlogwang ret = fs_remove_sub_devices_definition(mut_params); 4072bfe3f2eSlogwang if (ret < 0) 4082bfe3f2eSlogwang return ret; 4092bfe3f2eSlogwang if (strnlen(mut_params, sizeof(mut_params)) > 0) { 4102bfe3f2eSlogwang kvlist = rte_kvargs_parse(mut_params, 4112bfe3f2eSlogwang pmd_failsafe_init_parameters); 4122bfe3f2eSlogwang if (kvlist == NULL) { 4132bfe3f2eSlogwang ERROR("Error parsing parameters, usage:\n" 4142bfe3f2eSlogwang PMD_FAILSAFE_PARAM_STRING); 4152bfe3f2eSlogwang return -1; 4162bfe3f2eSlogwang } 4172bfe3f2eSlogwang /* PLUG_IN event poll timer */ 4182bfe3f2eSlogwang arg_count = rte_kvargs_count(kvlist, 4192bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG); 4202bfe3f2eSlogwang if (arg_count == 1) { 4212bfe3f2eSlogwang ret = rte_kvargs_process(kvlist, 4222bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 423*d30ea906Sjfb8856606 &fs_get_u64_arg, &failsafe_hotplug_poll); 4242bfe3f2eSlogwang if (ret < 0) 4252bfe3f2eSlogwang goto free_kvlist; 4262bfe3f2eSlogwang } 4272bfe3f2eSlogwang /* MAC addr */ 4282bfe3f2eSlogwang arg_count = rte_kvargs_count(kvlist, 4292bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG); 4302bfe3f2eSlogwang if (arg_count > 0) { 4312bfe3f2eSlogwang ret = rte_kvargs_process(kvlist, 4322bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG, 4332bfe3f2eSlogwang &fs_get_mac_addr_arg, 4342bfe3f2eSlogwang &dev->data->mac_addrs[0]); 4352bfe3f2eSlogwang if (ret < 0) 4362bfe3f2eSlogwang goto free_kvlist; 4372bfe3f2eSlogwang 438*d30ea906Sjfb8856606 failsafe_mac_from_arg = 1; 4392bfe3f2eSlogwang } 4402bfe3f2eSlogwang } 4412bfe3f2eSlogwang PRIV(dev)->state = DEV_PARSED; 4422bfe3f2eSlogwang free_kvlist: 4432bfe3f2eSlogwang rte_kvargs_free(kvlist); 4442bfe3f2eSlogwang return ret; 4452bfe3f2eSlogwang } 4462bfe3f2eSlogwang 4472bfe3f2eSlogwang void 4482bfe3f2eSlogwang failsafe_args_free(struct rte_eth_dev *dev) 4492bfe3f2eSlogwang { 4502bfe3f2eSlogwang struct sub_device *sdev; 4512bfe3f2eSlogwang uint8_t i; 4522bfe3f2eSlogwang 4532bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) { 4542bfe3f2eSlogwang free(sdev->cmdline); 4552bfe3f2eSlogwang sdev->cmdline = NULL; 456*d30ea906Sjfb8856606 free(sdev->fd_str); 457*d30ea906Sjfb8856606 sdev->fd_str = NULL; 4582bfe3f2eSlogwang free(sdev->devargs.args); 4592bfe3f2eSlogwang sdev->devargs.args = NULL; 4602bfe3f2eSlogwang } 4612bfe3f2eSlogwang } 4622bfe3f2eSlogwang 4632bfe3f2eSlogwang static int 4642bfe3f2eSlogwang fs_count_device(struct rte_eth_dev *dev, const char *param, 4652bfe3f2eSlogwang uint8_t head __rte_unused) 4662bfe3f2eSlogwang { 4672bfe3f2eSlogwang size_t b = 0; 4682bfe3f2eSlogwang 4692bfe3f2eSlogwang while (param[b] != '(' && 4702bfe3f2eSlogwang param[b] != '\0') 4712bfe3f2eSlogwang b++; 4722bfe3f2eSlogwang if (strncmp(param, "dev", b) != 0 && 473*d30ea906Sjfb8856606 strncmp(param, "exec", b) != 0 && 474*d30ea906Sjfb8856606 strncmp(param, "fd(", b) != 0) { 4752bfe3f2eSlogwang ERROR("Unrecognized device type: %.*s", (int)b, param); 4762bfe3f2eSlogwang return -EINVAL; 4772bfe3f2eSlogwang } 4782bfe3f2eSlogwang PRIV(dev)->subs_tail += 1; 4792bfe3f2eSlogwang return 0; 4802bfe3f2eSlogwang } 4812bfe3f2eSlogwang 4822bfe3f2eSlogwang int 4832bfe3f2eSlogwang failsafe_args_count_subdevice(struct rte_eth_dev *dev, 4842bfe3f2eSlogwang const char *params) 4852bfe3f2eSlogwang { 4862bfe3f2eSlogwang return fs_parse_sub_devices(fs_count_device, 4872bfe3f2eSlogwang dev, params); 4882bfe3f2eSlogwang } 4892bfe3f2eSlogwang 4902bfe3f2eSlogwang static int 4912bfe3f2eSlogwang fs_parse_sub_device(struct sub_device *sdev) 4922bfe3f2eSlogwang { 4932bfe3f2eSlogwang struct rte_devargs *da; 4942bfe3f2eSlogwang char devstr[DEVARGS_MAXLEN] = ""; 4952bfe3f2eSlogwang 4962bfe3f2eSlogwang da = &sdev->devargs; 4972bfe3f2eSlogwang snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args); 4982bfe3f2eSlogwang return fs_parse_device(sdev, devstr); 4992bfe3f2eSlogwang } 5002bfe3f2eSlogwang 5012bfe3f2eSlogwang int 5022bfe3f2eSlogwang failsafe_args_parse_subs(struct rte_eth_dev *dev) 5032bfe3f2eSlogwang { 5042bfe3f2eSlogwang struct sub_device *sdev; 5052bfe3f2eSlogwang uint8_t i; 5062bfe3f2eSlogwang int ret = 0; 5072bfe3f2eSlogwang 5082bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) { 5092bfe3f2eSlogwang if (sdev->state >= DEV_PARSED) 5102bfe3f2eSlogwang continue; 5112bfe3f2eSlogwang if (sdev->cmdline) 5122bfe3f2eSlogwang ret = fs_execute_cmd(sdev, sdev->cmdline); 513*d30ea906Sjfb8856606 else if (sdev->fd_str) 514*d30ea906Sjfb8856606 ret = fs_read_fd(sdev, sdev->fd_str); 5152bfe3f2eSlogwang else 5162bfe3f2eSlogwang ret = fs_parse_sub_device(sdev); 5172bfe3f2eSlogwang if (ret == 0) 5182bfe3f2eSlogwang sdev->state = DEV_PARSED; 5192bfe3f2eSlogwang } 5202bfe3f2eSlogwang return 0; 5212bfe3f2eSlogwang } 522