1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Gaëtan Rivet 3 */ 4 5 #include "rte_ethdev.h" 6 #include "ethdev_driver.h" 7 #include "ethdev_private.h" 8 9 uint16_t 10 eth_dev_to_id(const struct rte_eth_dev *dev) 11 { 12 if (dev == NULL) 13 return RTE_MAX_ETHPORTS; 14 return dev - rte_eth_devices; 15 } 16 17 struct rte_eth_dev * 18 eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp, 19 const void *data) 20 { 21 struct rte_eth_dev *edev; 22 ptrdiff_t idx; 23 24 /* Avoid Undefined Behaviour */ 25 if (start != NULL && 26 (start < &rte_eth_devices[0] || 27 start > &rte_eth_devices[RTE_MAX_ETHPORTS])) 28 return NULL; 29 if (start != NULL) 30 idx = eth_dev_to_id(start) + 1; 31 else 32 idx = 0; 33 for (; idx < RTE_MAX_ETHPORTS; idx++) { 34 edev = &rte_eth_devices[idx]; 35 if (cmp(edev, data) == 0) 36 return edev; 37 } 38 return NULL; 39 } 40 41 /* Put new value into list. */ 42 static int 43 rte_eth_devargs_enlist(uint16_t *list, uint16_t *len_list, 44 const uint16_t max_list, uint16_t val) 45 { 46 uint16_t i; 47 48 for (i = 0; i < *len_list; i++) { 49 if (list[i] == val) 50 return 0; 51 } 52 if (*len_list >= max_list) 53 return -1; 54 list[(*len_list)++] = val; 55 return 0; 56 } 57 58 /* Parse and enlist a range expression of "min-max" or a single value. */ 59 static char * 60 rte_eth_devargs_process_range(char *str, uint16_t *list, uint16_t *len_list, 61 const uint16_t max_list) 62 { 63 uint16_t lo, hi, val; 64 int result, n = 0; 65 char *pos = str; 66 67 result = sscanf(str, "%hu%n-%hu%n", &lo, &n, &hi, &n); 68 if (result == 1) { 69 if (rte_eth_devargs_enlist(list, len_list, max_list, lo) != 0) 70 return NULL; 71 } else if (result == 2) { 72 if (lo > hi) 73 return NULL; 74 for (val = lo; val <= hi; val++) { 75 if (rte_eth_devargs_enlist(list, len_list, max_list, 76 val) != 0) 77 return NULL; 78 } 79 } else 80 return NULL; 81 return pos + n; 82 } 83 84 /* 85 * Parse list of values separated by ",". 86 * Each value could be a range [min-max] or single number. 87 * Examples: 88 * 2 - single 89 * [1,2,3] - single list 90 * [1,3-5,7,9-11] - list with singles and ranges 91 */ 92 static char * 93 rte_eth_devargs_process_list(char *str, uint16_t *list, uint16_t *len_list, 94 const uint16_t max_list) 95 { 96 char *pos = str; 97 98 if (*pos == '[') 99 pos++; 100 while (1) { 101 pos = rte_eth_devargs_process_range(pos, list, len_list, 102 max_list); 103 if (pos == NULL) 104 return NULL; 105 if (*pos != ',') /* end of list */ 106 break; 107 pos++; 108 } 109 if (*str == '[' && *pos != ']') 110 return NULL; 111 if (*pos == ']') 112 pos++; 113 return pos; 114 } 115 116 /* 117 * Parse representor ports from a single value or lists. 118 * 119 * Representor format: 120 * #: range or single number of VF representor - legacy 121 * [[c#]pf#]vf#: VF port representor/s 122 * [[c#]pf#]sf#: SF port representor/s 123 * [c#]pf#: PF port representor/s 124 * 125 * Examples of #: 126 * 2 - single 127 * [1,2,3] - single list 128 * [1,3-5,7,9-11] - list with singles and ranges 129 */ 130 int 131 rte_eth_devargs_parse_representor_ports(char *str, void *data) 132 { 133 struct rte_eth_devargs *eth_da = data; 134 135 if (str[0] == 'c') { 136 str += 1; 137 str = rte_eth_devargs_process_list(str, eth_da->mh_controllers, 138 ð_da->nb_mh_controllers, 139 RTE_DIM(eth_da->mh_controllers)); 140 if (str == NULL) 141 goto done; 142 } 143 if (str[0] == 'p' && str[1] == 'f') { 144 eth_da->type = RTE_ETH_REPRESENTOR_PF; 145 str += 2; 146 str = rte_eth_devargs_process_list(str, eth_da->ports, 147 ð_da->nb_ports, RTE_DIM(eth_da->ports)); 148 if (str == NULL || str[0] == '\0') 149 goto done; 150 } else if (eth_da->nb_mh_controllers > 0) { 151 /* 'c' must followed by 'pf'. */ 152 str = NULL; 153 goto done; 154 } 155 if (str[0] == 'v' && str[1] == 'f') { 156 eth_da->type = RTE_ETH_REPRESENTOR_VF; 157 str += 2; 158 } else if (str[0] == 's' && str[1] == 'f') { 159 eth_da->type = RTE_ETH_REPRESENTOR_SF; 160 str += 2; 161 } else { 162 /* 'pf' must followed by 'vf' or 'sf'. */ 163 if (eth_da->type == RTE_ETH_REPRESENTOR_PF) { 164 str = NULL; 165 goto done; 166 } 167 eth_da->type = RTE_ETH_REPRESENTOR_VF; 168 } 169 str = rte_eth_devargs_process_list(str, eth_da->representor_ports, 170 ð_da->nb_representor_ports, 171 RTE_DIM(eth_da->representor_ports)); 172 done: 173 if (str == NULL) 174 RTE_LOG(ERR, EAL, "wrong representor format: %s\n", str); 175 return str == NULL ? -1 : 0; 176 } 177