1*2bfe3f2eSlogwang /*- 2*2bfe3f2eSlogwang * BSD LICENSE 3*2bfe3f2eSlogwang * 4*2bfe3f2eSlogwang * Copyright 2017 6WIND S.A. 5*2bfe3f2eSlogwang * Copyright 2017 Mellanox. 6*2bfe3f2eSlogwang * 7*2bfe3f2eSlogwang * Redistribution and use in source and binary forms, with or without 8*2bfe3f2eSlogwang * modification, are permitted provided that the following conditions 9*2bfe3f2eSlogwang * are met: 10*2bfe3f2eSlogwang * 11*2bfe3f2eSlogwang * * Redistributions of source code must retain the above copyright 12*2bfe3f2eSlogwang * notice, this list of conditions and the following disclaimer. 13*2bfe3f2eSlogwang * * Redistributions in binary form must reproduce the above copyright 14*2bfe3f2eSlogwang * notice, this list of conditions and the following disclaimer in 15*2bfe3f2eSlogwang * the documentation and/or other materials provided with the 16*2bfe3f2eSlogwang * distribution. 17*2bfe3f2eSlogwang * * Neither the name of 6WIND S.A. nor the names of its 18*2bfe3f2eSlogwang * contributors may be used to endorse or promote products derived 19*2bfe3f2eSlogwang * from this software without specific prior written permission. 20*2bfe3f2eSlogwang * 21*2bfe3f2eSlogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*2bfe3f2eSlogwang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*2bfe3f2eSlogwang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24*2bfe3f2eSlogwang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25*2bfe3f2eSlogwang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*2bfe3f2eSlogwang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27*2bfe3f2eSlogwang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*2bfe3f2eSlogwang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*2bfe3f2eSlogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*2bfe3f2eSlogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31*2bfe3f2eSlogwang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*2bfe3f2eSlogwang */ 33*2bfe3f2eSlogwang 34*2bfe3f2eSlogwang #include <string.h> 35*2bfe3f2eSlogwang #include <errno.h> 36*2bfe3f2eSlogwang 37*2bfe3f2eSlogwang #include <rte_debug.h> 38*2bfe3f2eSlogwang #include <rte_devargs.h> 39*2bfe3f2eSlogwang #include <rte_malloc.h> 40*2bfe3f2eSlogwang #include <rte_kvargs.h> 41*2bfe3f2eSlogwang 42*2bfe3f2eSlogwang #include "failsafe_private.h" 43*2bfe3f2eSlogwang 44*2bfe3f2eSlogwang #define DEVARGS_MAXLEN 4096 45*2bfe3f2eSlogwang 46*2bfe3f2eSlogwang /* Callback used when a new device is found in devargs */ 47*2bfe3f2eSlogwang typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params, 48*2bfe3f2eSlogwang uint8_t head); 49*2bfe3f2eSlogwang 50*2bfe3f2eSlogwang uint64_t hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS; 51*2bfe3f2eSlogwang int mac_from_arg = 0; 52*2bfe3f2eSlogwang 53*2bfe3f2eSlogwang const char *pmd_failsafe_init_parameters[] = { 54*2bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 55*2bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG, 56*2bfe3f2eSlogwang NULL, 57*2bfe3f2eSlogwang }; 58*2bfe3f2eSlogwang 59*2bfe3f2eSlogwang /* 60*2bfe3f2eSlogwang * input: text. 61*2bfe3f2eSlogwang * output: 0: if text[0] != '(', 62*2bfe3f2eSlogwang * 0: if there are no corresponding ')' 63*2bfe3f2eSlogwang * n: distance to corresponding ')' otherwise 64*2bfe3f2eSlogwang */ 65*2bfe3f2eSlogwang static size_t 66*2bfe3f2eSlogwang closing_paren(const char *text) 67*2bfe3f2eSlogwang { 68*2bfe3f2eSlogwang int nb_open = 0; 69*2bfe3f2eSlogwang size_t i = 0; 70*2bfe3f2eSlogwang 71*2bfe3f2eSlogwang while (text[i] != '\0') { 72*2bfe3f2eSlogwang if (text[i] == '(') 73*2bfe3f2eSlogwang nb_open++; 74*2bfe3f2eSlogwang if (text[i] == ')') 75*2bfe3f2eSlogwang nb_open--; 76*2bfe3f2eSlogwang if (nb_open == 0) 77*2bfe3f2eSlogwang return i; 78*2bfe3f2eSlogwang i++; 79*2bfe3f2eSlogwang } 80*2bfe3f2eSlogwang return 0; 81*2bfe3f2eSlogwang } 82*2bfe3f2eSlogwang 83*2bfe3f2eSlogwang static int 84*2bfe3f2eSlogwang fs_parse_device(struct sub_device *sdev, char *args) 85*2bfe3f2eSlogwang { 86*2bfe3f2eSlogwang struct rte_devargs *d; 87*2bfe3f2eSlogwang int ret; 88*2bfe3f2eSlogwang 89*2bfe3f2eSlogwang d = &sdev->devargs; 90*2bfe3f2eSlogwang DEBUG("%s", args); 91*2bfe3f2eSlogwang ret = rte_eal_devargs_parse(args, d); 92*2bfe3f2eSlogwang if (ret) { 93*2bfe3f2eSlogwang DEBUG("devargs parsing failed with code %d", ret); 94*2bfe3f2eSlogwang return ret; 95*2bfe3f2eSlogwang } 96*2bfe3f2eSlogwang sdev->bus = d->bus; 97*2bfe3f2eSlogwang sdev->state = DEV_PARSED; 98*2bfe3f2eSlogwang return 0; 99*2bfe3f2eSlogwang } 100*2bfe3f2eSlogwang 101*2bfe3f2eSlogwang static void 102*2bfe3f2eSlogwang fs_sanitize_cmdline(char *args) 103*2bfe3f2eSlogwang { 104*2bfe3f2eSlogwang char *nl; 105*2bfe3f2eSlogwang 106*2bfe3f2eSlogwang nl = strrchr(args, '\n'); 107*2bfe3f2eSlogwang if (nl) 108*2bfe3f2eSlogwang nl[0] = '\0'; 109*2bfe3f2eSlogwang } 110*2bfe3f2eSlogwang 111*2bfe3f2eSlogwang static int 112*2bfe3f2eSlogwang fs_execute_cmd(struct sub_device *sdev, char *cmdline) 113*2bfe3f2eSlogwang { 114*2bfe3f2eSlogwang FILE *fp; 115*2bfe3f2eSlogwang /* store possible newline as well */ 116*2bfe3f2eSlogwang char output[DEVARGS_MAXLEN + 1]; 117*2bfe3f2eSlogwang size_t len; 118*2bfe3f2eSlogwang int ret; 119*2bfe3f2eSlogwang 120*2bfe3f2eSlogwang RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL); 121*2bfe3f2eSlogwang if (sdev->cmdline == NULL) { 122*2bfe3f2eSlogwang size_t i; 123*2bfe3f2eSlogwang 124*2bfe3f2eSlogwang len = strlen(cmdline) + 1; 125*2bfe3f2eSlogwang sdev->cmdline = calloc(1, len); 126*2bfe3f2eSlogwang if (sdev->cmdline == NULL) { 127*2bfe3f2eSlogwang ERROR("Command line allocation failed"); 128*2bfe3f2eSlogwang return -ENOMEM; 129*2bfe3f2eSlogwang } 130*2bfe3f2eSlogwang snprintf(sdev->cmdline, len, "%s", cmdline); 131*2bfe3f2eSlogwang /* Replace all commas in the command line by spaces */ 132*2bfe3f2eSlogwang for (i = 0; i < len; i++) 133*2bfe3f2eSlogwang if (sdev->cmdline[i] == ',') 134*2bfe3f2eSlogwang sdev->cmdline[i] = ' '; 135*2bfe3f2eSlogwang } 136*2bfe3f2eSlogwang DEBUG("'%s'", sdev->cmdline); 137*2bfe3f2eSlogwang fp = popen(sdev->cmdline, "r"); 138*2bfe3f2eSlogwang if (fp == NULL) { 139*2bfe3f2eSlogwang ret = -errno; 140*2bfe3f2eSlogwang ERROR("popen: %s", strerror(errno)); 141*2bfe3f2eSlogwang return ret; 142*2bfe3f2eSlogwang } 143*2bfe3f2eSlogwang /* We only read one line */ 144*2bfe3f2eSlogwang if (fgets(output, sizeof(output) - 1, fp) == NULL) { 145*2bfe3f2eSlogwang DEBUG("Could not read command output"); 146*2bfe3f2eSlogwang ret = -ENODEV; 147*2bfe3f2eSlogwang goto ret_pclose; 148*2bfe3f2eSlogwang } 149*2bfe3f2eSlogwang fs_sanitize_cmdline(output); 150*2bfe3f2eSlogwang if (output[0] == '\0') { 151*2bfe3f2eSlogwang ret = -ENODEV; 152*2bfe3f2eSlogwang goto ret_pclose; 153*2bfe3f2eSlogwang } 154*2bfe3f2eSlogwang ret = fs_parse_device(sdev, output); 155*2bfe3f2eSlogwang if (ret) 156*2bfe3f2eSlogwang ERROR("Parsing device '%s' failed", output); 157*2bfe3f2eSlogwang ret_pclose: 158*2bfe3f2eSlogwang if (pclose(fp) == -1) 159*2bfe3f2eSlogwang ERROR("pclose: %s", strerror(errno)); 160*2bfe3f2eSlogwang return ret; 161*2bfe3f2eSlogwang } 162*2bfe3f2eSlogwang 163*2bfe3f2eSlogwang static int 164*2bfe3f2eSlogwang fs_parse_device_param(struct rte_eth_dev *dev, const char *param, 165*2bfe3f2eSlogwang uint8_t head) 166*2bfe3f2eSlogwang { 167*2bfe3f2eSlogwang struct fs_priv *priv; 168*2bfe3f2eSlogwang struct sub_device *sdev; 169*2bfe3f2eSlogwang char *args = NULL; 170*2bfe3f2eSlogwang size_t a, b; 171*2bfe3f2eSlogwang int ret; 172*2bfe3f2eSlogwang 173*2bfe3f2eSlogwang priv = PRIV(dev); 174*2bfe3f2eSlogwang a = 0; 175*2bfe3f2eSlogwang b = 0; 176*2bfe3f2eSlogwang ret = 0; 177*2bfe3f2eSlogwang while (param[b] != '(' && 178*2bfe3f2eSlogwang param[b] != '\0') 179*2bfe3f2eSlogwang b++; 180*2bfe3f2eSlogwang a = b; 181*2bfe3f2eSlogwang b += closing_paren(¶m[b]); 182*2bfe3f2eSlogwang if (a == b) { 183*2bfe3f2eSlogwang ERROR("Dangling parenthesis"); 184*2bfe3f2eSlogwang return -EINVAL; 185*2bfe3f2eSlogwang } 186*2bfe3f2eSlogwang a += 1; 187*2bfe3f2eSlogwang args = strndup(¶m[a], b - a); 188*2bfe3f2eSlogwang if (args == NULL) { 189*2bfe3f2eSlogwang ERROR("Not enough memory for parameter parsing"); 190*2bfe3f2eSlogwang return -ENOMEM; 191*2bfe3f2eSlogwang } 192*2bfe3f2eSlogwang sdev = &priv->subs[head]; 193*2bfe3f2eSlogwang if (strncmp(param, "dev", 3) == 0) { 194*2bfe3f2eSlogwang ret = fs_parse_device(sdev, args); 195*2bfe3f2eSlogwang if (ret) 196*2bfe3f2eSlogwang goto free_args; 197*2bfe3f2eSlogwang } else if (strncmp(param, "exec", 4) == 0) { 198*2bfe3f2eSlogwang ret = fs_execute_cmd(sdev, args); 199*2bfe3f2eSlogwang if (ret == -ENODEV) { 200*2bfe3f2eSlogwang DEBUG("Reading device info from command line failed"); 201*2bfe3f2eSlogwang ret = 0; 202*2bfe3f2eSlogwang } 203*2bfe3f2eSlogwang if (ret) 204*2bfe3f2eSlogwang goto free_args; 205*2bfe3f2eSlogwang } else { 206*2bfe3f2eSlogwang ERROR("Unrecognized device type: %.*s", (int)b, param); 207*2bfe3f2eSlogwang return -EINVAL; 208*2bfe3f2eSlogwang } 209*2bfe3f2eSlogwang free_args: 210*2bfe3f2eSlogwang free(args); 211*2bfe3f2eSlogwang return ret; 212*2bfe3f2eSlogwang } 213*2bfe3f2eSlogwang 214*2bfe3f2eSlogwang static int 215*2bfe3f2eSlogwang fs_parse_sub_devices(parse_cb *cb, 216*2bfe3f2eSlogwang struct rte_eth_dev *dev, const char *params) 217*2bfe3f2eSlogwang { 218*2bfe3f2eSlogwang size_t a, b; 219*2bfe3f2eSlogwang uint8_t head; 220*2bfe3f2eSlogwang int ret; 221*2bfe3f2eSlogwang 222*2bfe3f2eSlogwang a = 0; 223*2bfe3f2eSlogwang head = 0; 224*2bfe3f2eSlogwang ret = 0; 225*2bfe3f2eSlogwang while (params[a] != '\0') { 226*2bfe3f2eSlogwang b = a; 227*2bfe3f2eSlogwang while (params[b] != '(' && 228*2bfe3f2eSlogwang params[b] != ',' && 229*2bfe3f2eSlogwang params[b] != '\0') 230*2bfe3f2eSlogwang b++; 231*2bfe3f2eSlogwang if (b == a) { 232*2bfe3f2eSlogwang ERROR("Invalid parameter"); 233*2bfe3f2eSlogwang return -EINVAL; 234*2bfe3f2eSlogwang } 235*2bfe3f2eSlogwang if (params[b] == ',') { 236*2bfe3f2eSlogwang a = b + 1; 237*2bfe3f2eSlogwang continue; 238*2bfe3f2eSlogwang } 239*2bfe3f2eSlogwang if (params[b] == '(') { 240*2bfe3f2eSlogwang size_t start = b; 241*2bfe3f2eSlogwang 242*2bfe3f2eSlogwang b += closing_paren(¶ms[b]); 243*2bfe3f2eSlogwang if (b == start) { 244*2bfe3f2eSlogwang ERROR("Dangling parenthesis"); 245*2bfe3f2eSlogwang return -EINVAL; 246*2bfe3f2eSlogwang } 247*2bfe3f2eSlogwang ret = (*cb)(dev, ¶ms[a], head); 248*2bfe3f2eSlogwang if (ret) 249*2bfe3f2eSlogwang return ret; 250*2bfe3f2eSlogwang head += 1; 251*2bfe3f2eSlogwang b += 1; 252*2bfe3f2eSlogwang if (params[b] == '\0') 253*2bfe3f2eSlogwang return 0; 254*2bfe3f2eSlogwang } 255*2bfe3f2eSlogwang a = b + 1; 256*2bfe3f2eSlogwang } 257*2bfe3f2eSlogwang return 0; 258*2bfe3f2eSlogwang } 259*2bfe3f2eSlogwang 260*2bfe3f2eSlogwang static int 261*2bfe3f2eSlogwang fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN]) 262*2bfe3f2eSlogwang { 263*2bfe3f2eSlogwang char buffer[DEVARGS_MAXLEN] = {0}; 264*2bfe3f2eSlogwang size_t a, b; 265*2bfe3f2eSlogwang int i; 266*2bfe3f2eSlogwang 267*2bfe3f2eSlogwang a = 0; 268*2bfe3f2eSlogwang i = 0; 269*2bfe3f2eSlogwang while (params[a] != '\0') { 270*2bfe3f2eSlogwang b = a; 271*2bfe3f2eSlogwang while (params[b] != '(' && 272*2bfe3f2eSlogwang params[b] != ',' && 273*2bfe3f2eSlogwang params[b] != '\0') 274*2bfe3f2eSlogwang b++; 275*2bfe3f2eSlogwang if (b == a) { 276*2bfe3f2eSlogwang ERROR("Invalid parameter"); 277*2bfe3f2eSlogwang return -EINVAL; 278*2bfe3f2eSlogwang } 279*2bfe3f2eSlogwang if (params[b] == ',' || params[b] == '\0') { 280*2bfe3f2eSlogwang size_t len = b - a; 281*2bfe3f2eSlogwang 282*2bfe3f2eSlogwang if (i > 0) 283*2bfe3f2eSlogwang len += 1; 284*2bfe3f2eSlogwang snprintf(&buffer[i], len + 1, "%s%s", 285*2bfe3f2eSlogwang i ? "," : "", ¶ms[a]); 286*2bfe3f2eSlogwang i += len; 287*2bfe3f2eSlogwang } else if (params[b] == '(') { 288*2bfe3f2eSlogwang size_t start = b; 289*2bfe3f2eSlogwang 290*2bfe3f2eSlogwang b += closing_paren(¶ms[b]); 291*2bfe3f2eSlogwang if (b == start) 292*2bfe3f2eSlogwang return -EINVAL; 293*2bfe3f2eSlogwang b += 1; 294*2bfe3f2eSlogwang if (params[b] == '\0') 295*2bfe3f2eSlogwang goto out; 296*2bfe3f2eSlogwang } 297*2bfe3f2eSlogwang a = b + 1; 298*2bfe3f2eSlogwang } 299*2bfe3f2eSlogwang out: 300*2bfe3f2eSlogwang snprintf(params, DEVARGS_MAXLEN, "%s", buffer); 301*2bfe3f2eSlogwang return 0; 302*2bfe3f2eSlogwang } 303*2bfe3f2eSlogwang 304*2bfe3f2eSlogwang static int 305*2bfe3f2eSlogwang fs_get_u64_arg(const char *key __rte_unused, 306*2bfe3f2eSlogwang const char *value, void *out) 307*2bfe3f2eSlogwang { 308*2bfe3f2eSlogwang uint64_t *u64 = out; 309*2bfe3f2eSlogwang char *endptr = NULL; 310*2bfe3f2eSlogwang 311*2bfe3f2eSlogwang if ((value == NULL) || (out == NULL)) 312*2bfe3f2eSlogwang return -EINVAL; 313*2bfe3f2eSlogwang errno = 0; 314*2bfe3f2eSlogwang *u64 = strtoull(value, &endptr, 0); 315*2bfe3f2eSlogwang if (errno != 0) 316*2bfe3f2eSlogwang return -errno; 317*2bfe3f2eSlogwang if (endptr == value) 318*2bfe3f2eSlogwang return -1; 319*2bfe3f2eSlogwang return 0; 320*2bfe3f2eSlogwang } 321*2bfe3f2eSlogwang 322*2bfe3f2eSlogwang static int 323*2bfe3f2eSlogwang fs_get_mac_addr_arg(const char *key __rte_unused, 324*2bfe3f2eSlogwang const char *value, void *out) 325*2bfe3f2eSlogwang { 326*2bfe3f2eSlogwang struct ether_addr *ea = out; 327*2bfe3f2eSlogwang int ret; 328*2bfe3f2eSlogwang 329*2bfe3f2eSlogwang if ((value == NULL) || (out == NULL)) 330*2bfe3f2eSlogwang return -EINVAL; 331*2bfe3f2eSlogwang ret = sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 332*2bfe3f2eSlogwang &ea->addr_bytes[0], &ea->addr_bytes[1], 333*2bfe3f2eSlogwang &ea->addr_bytes[2], &ea->addr_bytes[3], 334*2bfe3f2eSlogwang &ea->addr_bytes[4], &ea->addr_bytes[5]); 335*2bfe3f2eSlogwang return ret != ETHER_ADDR_LEN; 336*2bfe3f2eSlogwang } 337*2bfe3f2eSlogwang 338*2bfe3f2eSlogwang int 339*2bfe3f2eSlogwang failsafe_args_parse(struct rte_eth_dev *dev, const char *params) 340*2bfe3f2eSlogwang { 341*2bfe3f2eSlogwang struct fs_priv *priv; 342*2bfe3f2eSlogwang char mut_params[DEVARGS_MAXLEN] = ""; 343*2bfe3f2eSlogwang struct rte_kvargs *kvlist = NULL; 344*2bfe3f2eSlogwang unsigned int arg_count; 345*2bfe3f2eSlogwang size_t n; 346*2bfe3f2eSlogwang int ret; 347*2bfe3f2eSlogwang 348*2bfe3f2eSlogwang priv = PRIV(dev); 349*2bfe3f2eSlogwang ret = 0; 350*2bfe3f2eSlogwang priv->subs_tx = FAILSAFE_MAX_ETHPORTS; 351*2bfe3f2eSlogwang /* default parameters */ 352*2bfe3f2eSlogwang n = snprintf(mut_params, sizeof(mut_params), "%s", params); 353*2bfe3f2eSlogwang if (n >= sizeof(mut_params)) { 354*2bfe3f2eSlogwang ERROR("Parameter string too long (>=%zu)", 355*2bfe3f2eSlogwang sizeof(mut_params)); 356*2bfe3f2eSlogwang return -ENOMEM; 357*2bfe3f2eSlogwang } 358*2bfe3f2eSlogwang ret = fs_parse_sub_devices(fs_parse_device_param, 359*2bfe3f2eSlogwang dev, params); 360*2bfe3f2eSlogwang if (ret < 0) 361*2bfe3f2eSlogwang return ret; 362*2bfe3f2eSlogwang ret = fs_remove_sub_devices_definition(mut_params); 363*2bfe3f2eSlogwang if (ret < 0) 364*2bfe3f2eSlogwang return ret; 365*2bfe3f2eSlogwang if (strnlen(mut_params, sizeof(mut_params)) > 0) { 366*2bfe3f2eSlogwang kvlist = rte_kvargs_parse(mut_params, 367*2bfe3f2eSlogwang pmd_failsafe_init_parameters); 368*2bfe3f2eSlogwang if (kvlist == NULL) { 369*2bfe3f2eSlogwang ERROR("Error parsing parameters, usage:\n" 370*2bfe3f2eSlogwang PMD_FAILSAFE_PARAM_STRING); 371*2bfe3f2eSlogwang return -1; 372*2bfe3f2eSlogwang } 373*2bfe3f2eSlogwang /* PLUG_IN event poll timer */ 374*2bfe3f2eSlogwang arg_count = rte_kvargs_count(kvlist, 375*2bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG); 376*2bfe3f2eSlogwang if (arg_count == 1) { 377*2bfe3f2eSlogwang ret = rte_kvargs_process(kvlist, 378*2bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 379*2bfe3f2eSlogwang &fs_get_u64_arg, &hotplug_poll); 380*2bfe3f2eSlogwang if (ret < 0) 381*2bfe3f2eSlogwang goto free_kvlist; 382*2bfe3f2eSlogwang } 383*2bfe3f2eSlogwang /* MAC addr */ 384*2bfe3f2eSlogwang arg_count = rte_kvargs_count(kvlist, 385*2bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG); 386*2bfe3f2eSlogwang if (arg_count > 0) { 387*2bfe3f2eSlogwang ret = rte_kvargs_process(kvlist, 388*2bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG, 389*2bfe3f2eSlogwang &fs_get_mac_addr_arg, 390*2bfe3f2eSlogwang &dev->data->mac_addrs[0]); 391*2bfe3f2eSlogwang if (ret < 0) 392*2bfe3f2eSlogwang goto free_kvlist; 393*2bfe3f2eSlogwang 394*2bfe3f2eSlogwang mac_from_arg = 1; 395*2bfe3f2eSlogwang } 396*2bfe3f2eSlogwang } 397*2bfe3f2eSlogwang PRIV(dev)->state = DEV_PARSED; 398*2bfe3f2eSlogwang free_kvlist: 399*2bfe3f2eSlogwang rte_kvargs_free(kvlist); 400*2bfe3f2eSlogwang return ret; 401*2bfe3f2eSlogwang } 402*2bfe3f2eSlogwang 403*2bfe3f2eSlogwang void 404*2bfe3f2eSlogwang failsafe_args_free(struct rte_eth_dev *dev) 405*2bfe3f2eSlogwang { 406*2bfe3f2eSlogwang struct sub_device *sdev; 407*2bfe3f2eSlogwang uint8_t i; 408*2bfe3f2eSlogwang 409*2bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) { 410*2bfe3f2eSlogwang free(sdev->cmdline); 411*2bfe3f2eSlogwang sdev->cmdline = NULL; 412*2bfe3f2eSlogwang free(sdev->devargs.args); 413*2bfe3f2eSlogwang sdev->devargs.args = NULL; 414*2bfe3f2eSlogwang } 415*2bfe3f2eSlogwang } 416*2bfe3f2eSlogwang 417*2bfe3f2eSlogwang static int 418*2bfe3f2eSlogwang fs_count_device(struct rte_eth_dev *dev, const char *param, 419*2bfe3f2eSlogwang uint8_t head __rte_unused) 420*2bfe3f2eSlogwang { 421*2bfe3f2eSlogwang size_t b = 0; 422*2bfe3f2eSlogwang 423*2bfe3f2eSlogwang while (param[b] != '(' && 424*2bfe3f2eSlogwang param[b] != '\0') 425*2bfe3f2eSlogwang b++; 426*2bfe3f2eSlogwang if (strncmp(param, "dev", b) != 0 && 427*2bfe3f2eSlogwang strncmp(param, "exec", b) != 0) { 428*2bfe3f2eSlogwang ERROR("Unrecognized device type: %.*s", (int)b, param); 429*2bfe3f2eSlogwang return -EINVAL; 430*2bfe3f2eSlogwang } 431*2bfe3f2eSlogwang PRIV(dev)->subs_tail += 1; 432*2bfe3f2eSlogwang return 0; 433*2bfe3f2eSlogwang } 434*2bfe3f2eSlogwang 435*2bfe3f2eSlogwang int 436*2bfe3f2eSlogwang failsafe_args_count_subdevice(struct rte_eth_dev *dev, 437*2bfe3f2eSlogwang const char *params) 438*2bfe3f2eSlogwang { 439*2bfe3f2eSlogwang return fs_parse_sub_devices(fs_count_device, 440*2bfe3f2eSlogwang dev, params); 441*2bfe3f2eSlogwang } 442*2bfe3f2eSlogwang 443*2bfe3f2eSlogwang static int 444*2bfe3f2eSlogwang fs_parse_sub_device(struct sub_device *sdev) 445*2bfe3f2eSlogwang { 446*2bfe3f2eSlogwang struct rte_devargs *da; 447*2bfe3f2eSlogwang char devstr[DEVARGS_MAXLEN] = ""; 448*2bfe3f2eSlogwang 449*2bfe3f2eSlogwang da = &sdev->devargs; 450*2bfe3f2eSlogwang snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args); 451*2bfe3f2eSlogwang return fs_parse_device(sdev, devstr); 452*2bfe3f2eSlogwang } 453*2bfe3f2eSlogwang 454*2bfe3f2eSlogwang int 455*2bfe3f2eSlogwang failsafe_args_parse_subs(struct rte_eth_dev *dev) 456*2bfe3f2eSlogwang { 457*2bfe3f2eSlogwang struct sub_device *sdev; 458*2bfe3f2eSlogwang uint8_t i; 459*2bfe3f2eSlogwang int ret = 0; 460*2bfe3f2eSlogwang 461*2bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) { 462*2bfe3f2eSlogwang if (sdev->state >= DEV_PARSED) 463*2bfe3f2eSlogwang continue; 464*2bfe3f2eSlogwang if (sdev->cmdline) 465*2bfe3f2eSlogwang ret = fs_execute_cmd(sdev, sdev->cmdline); 466*2bfe3f2eSlogwang else 467*2bfe3f2eSlogwang ret = fs_parse_sub_device(sdev); 468*2bfe3f2eSlogwang if (ret == 0) 469*2bfe3f2eSlogwang sdev->state = DEV_PARSED; 470*2bfe3f2eSlogwang } 471*2bfe3f2eSlogwang return 0; 472*2bfe3f2eSlogwang } 473