199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2018 Gaëtan Rivet 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 5*41f2f055SDavid Marchand #include <rte_debug.h> 699a2dd95SBruce Richardson #include "rte_ethdev.h" 799a2dd95SBruce Richardson #include "ethdev_driver.h" 899a2dd95SBruce Richardson #include "ethdev_private.h" 999a2dd95SBruce Richardson 1099a2dd95SBruce Richardson uint16_t 1199a2dd95SBruce Richardson eth_dev_to_id(const struct rte_eth_dev *dev) 1299a2dd95SBruce Richardson { 1399a2dd95SBruce Richardson if (dev == NULL) 1499a2dd95SBruce Richardson return RTE_MAX_ETHPORTS; 1599a2dd95SBruce Richardson return dev - rte_eth_devices; 1699a2dd95SBruce Richardson } 1799a2dd95SBruce Richardson 1899a2dd95SBruce Richardson struct rte_eth_dev * 1999a2dd95SBruce Richardson eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp, 2099a2dd95SBruce Richardson const void *data) 2199a2dd95SBruce Richardson { 2299a2dd95SBruce Richardson struct rte_eth_dev *edev; 2399a2dd95SBruce Richardson ptrdiff_t idx; 2499a2dd95SBruce Richardson 2599a2dd95SBruce Richardson /* Avoid Undefined Behaviour */ 2699a2dd95SBruce Richardson if (start != NULL && 2799a2dd95SBruce Richardson (start < &rte_eth_devices[0] || 2899a2dd95SBruce Richardson start > &rte_eth_devices[RTE_MAX_ETHPORTS])) 2999a2dd95SBruce Richardson return NULL; 3099a2dd95SBruce Richardson if (start != NULL) 3199a2dd95SBruce Richardson idx = eth_dev_to_id(start) + 1; 3299a2dd95SBruce Richardson else 3399a2dd95SBruce Richardson idx = 0; 3499a2dd95SBruce Richardson for (; idx < RTE_MAX_ETHPORTS; idx++) { 3599a2dd95SBruce Richardson edev = &rte_eth_devices[idx]; 3699a2dd95SBruce Richardson if (cmp(edev, data) == 0) 3799a2dd95SBruce Richardson return edev; 3899a2dd95SBruce Richardson } 3999a2dd95SBruce Richardson return NULL; 4099a2dd95SBruce Richardson } 4199a2dd95SBruce Richardson 4299a2dd95SBruce Richardson /* Put new value into list. */ 4399a2dd95SBruce Richardson static int 4499a2dd95SBruce Richardson rte_eth_devargs_enlist(uint16_t *list, uint16_t *len_list, 4599a2dd95SBruce Richardson const uint16_t max_list, uint16_t val) 4699a2dd95SBruce Richardson { 4799a2dd95SBruce Richardson uint16_t i; 4899a2dd95SBruce Richardson 4999a2dd95SBruce Richardson for (i = 0; i < *len_list; i++) { 5099a2dd95SBruce Richardson if (list[i] == val) 5199a2dd95SBruce Richardson return 0; 5299a2dd95SBruce Richardson } 5399a2dd95SBruce Richardson if (*len_list >= max_list) 5499a2dd95SBruce Richardson return -1; 5599a2dd95SBruce Richardson list[(*len_list)++] = val; 5699a2dd95SBruce Richardson return 0; 5799a2dd95SBruce Richardson } 5899a2dd95SBruce Richardson 5999a2dd95SBruce Richardson /* Parse and enlist a range expression of "min-max" or a single value. */ 6099a2dd95SBruce Richardson static char * 6199a2dd95SBruce Richardson rte_eth_devargs_process_range(char *str, uint16_t *list, uint16_t *len_list, 6299a2dd95SBruce Richardson const uint16_t max_list) 6399a2dd95SBruce Richardson { 6499a2dd95SBruce Richardson uint16_t lo, hi, val; 6599a2dd95SBruce Richardson int result, n = 0; 6699a2dd95SBruce Richardson char *pos = str; 6799a2dd95SBruce Richardson 6899a2dd95SBruce Richardson result = sscanf(str, "%hu%n-%hu%n", &lo, &n, &hi, &n); 6999a2dd95SBruce Richardson if (result == 1) { 7099a2dd95SBruce Richardson if (rte_eth_devargs_enlist(list, len_list, max_list, lo) != 0) 7199a2dd95SBruce Richardson return NULL; 7299a2dd95SBruce Richardson } else if (result == 2) { 7399a2dd95SBruce Richardson if (lo > hi) 7499a2dd95SBruce Richardson return NULL; 7599a2dd95SBruce Richardson for (val = lo; val <= hi; val++) { 7699a2dd95SBruce Richardson if (rte_eth_devargs_enlist(list, len_list, max_list, 7799a2dd95SBruce Richardson val) != 0) 7899a2dd95SBruce Richardson return NULL; 7999a2dd95SBruce Richardson } 8099a2dd95SBruce Richardson } else 8199a2dd95SBruce Richardson return NULL; 8299a2dd95SBruce Richardson return pos + n; 8399a2dd95SBruce Richardson } 8499a2dd95SBruce Richardson 8599a2dd95SBruce Richardson /* 8699a2dd95SBruce Richardson * Parse list of values separated by ",". 8799a2dd95SBruce Richardson * Each value could be a range [min-max] or single number. 8899a2dd95SBruce Richardson * Examples: 8999a2dd95SBruce Richardson * 2 - single 9099a2dd95SBruce Richardson * [1,2,3] - single list 9199a2dd95SBruce Richardson * [1,3-5,7,9-11] - list with singles and ranges 9299a2dd95SBruce Richardson */ 9399a2dd95SBruce Richardson static char * 9499a2dd95SBruce Richardson rte_eth_devargs_process_list(char *str, uint16_t *list, uint16_t *len_list, 9599a2dd95SBruce Richardson const uint16_t max_list) 9699a2dd95SBruce Richardson { 9799a2dd95SBruce Richardson char *pos = str; 9899a2dd95SBruce Richardson 9999a2dd95SBruce Richardson if (*pos == '[') 10099a2dd95SBruce Richardson pos++; 10199a2dd95SBruce Richardson while (1) { 10299a2dd95SBruce Richardson pos = rte_eth_devargs_process_range(pos, list, len_list, 10399a2dd95SBruce Richardson max_list); 10499a2dd95SBruce Richardson if (pos == NULL) 10599a2dd95SBruce Richardson return NULL; 10699a2dd95SBruce Richardson if (*pos != ',') /* end of list */ 10799a2dd95SBruce Richardson break; 10899a2dd95SBruce Richardson pos++; 10999a2dd95SBruce Richardson } 11099a2dd95SBruce Richardson if (*str == '[' && *pos != ']') 11199a2dd95SBruce Richardson return NULL; 11299a2dd95SBruce Richardson if (*pos == ']') 11399a2dd95SBruce Richardson pos++; 11499a2dd95SBruce Richardson return pos; 11599a2dd95SBruce Richardson } 11699a2dd95SBruce Richardson 11799a2dd95SBruce Richardson /* 11899a2dd95SBruce Richardson * Parse representor ports from a single value or lists. 11999a2dd95SBruce Richardson * 12099a2dd95SBruce Richardson * Representor format: 12199a2dd95SBruce Richardson * #: range or single number of VF representor - legacy 12299a2dd95SBruce Richardson * [[c#]pf#]vf#: VF port representor/s 12399a2dd95SBruce Richardson * [[c#]pf#]sf#: SF port representor/s 12499a2dd95SBruce Richardson * [c#]pf#: PF port representor/s 12599a2dd95SBruce Richardson * 12699a2dd95SBruce Richardson * Examples of #: 12799a2dd95SBruce Richardson * 2 - single 12899a2dd95SBruce Richardson * [1,2,3] - single list 12999a2dd95SBruce Richardson * [1,3-5,7,9-11] - list with singles and ranges 13099a2dd95SBruce Richardson */ 13199a2dd95SBruce Richardson int 13299a2dd95SBruce Richardson rte_eth_devargs_parse_representor_ports(char *str, void *data) 13399a2dd95SBruce Richardson { 13499a2dd95SBruce Richardson struct rte_eth_devargs *eth_da = data; 13599a2dd95SBruce Richardson 13699a2dd95SBruce Richardson if (str[0] == 'c') { 13799a2dd95SBruce Richardson str += 1; 13899a2dd95SBruce Richardson str = rte_eth_devargs_process_list(str, eth_da->mh_controllers, 13999a2dd95SBruce Richardson ð_da->nb_mh_controllers, 14099a2dd95SBruce Richardson RTE_DIM(eth_da->mh_controllers)); 14199a2dd95SBruce Richardson if (str == NULL) 14299a2dd95SBruce Richardson goto done; 14399a2dd95SBruce Richardson } 14499a2dd95SBruce Richardson if (str[0] == 'p' && str[1] == 'f') { 14599a2dd95SBruce Richardson eth_da->type = RTE_ETH_REPRESENTOR_PF; 14699a2dd95SBruce Richardson str += 2; 14799a2dd95SBruce Richardson str = rte_eth_devargs_process_list(str, eth_da->ports, 14899a2dd95SBruce Richardson ð_da->nb_ports, RTE_DIM(eth_da->ports)); 14999a2dd95SBruce Richardson if (str == NULL || str[0] == '\0') 15099a2dd95SBruce Richardson goto done; 15199a2dd95SBruce Richardson } else if (eth_da->nb_mh_controllers > 0) { 15299a2dd95SBruce Richardson /* 'c' must followed by 'pf'. */ 15399a2dd95SBruce Richardson str = NULL; 15499a2dd95SBruce Richardson goto done; 15599a2dd95SBruce Richardson } 15699a2dd95SBruce Richardson if (str[0] == 'v' && str[1] == 'f') { 15799a2dd95SBruce Richardson eth_da->type = RTE_ETH_REPRESENTOR_VF; 15899a2dd95SBruce Richardson str += 2; 15999a2dd95SBruce Richardson } else if (str[0] == 's' && str[1] == 'f') { 16099a2dd95SBruce Richardson eth_da->type = RTE_ETH_REPRESENTOR_SF; 16199a2dd95SBruce Richardson str += 2; 16299a2dd95SBruce Richardson } else { 16399a2dd95SBruce Richardson /* 'pf' must followed by 'vf' or 'sf'. */ 16499a2dd95SBruce Richardson if (eth_da->type == RTE_ETH_REPRESENTOR_PF) { 16599a2dd95SBruce Richardson str = NULL; 16699a2dd95SBruce Richardson goto done; 16799a2dd95SBruce Richardson } 16899a2dd95SBruce Richardson eth_da->type = RTE_ETH_REPRESENTOR_VF; 16999a2dd95SBruce Richardson } 17099a2dd95SBruce Richardson str = rte_eth_devargs_process_list(str, eth_da->representor_ports, 17199a2dd95SBruce Richardson ð_da->nb_representor_ports, 17299a2dd95SBruce Richardson RTE_DIM(eth_da->representor_ports)); 17399a2dd95SBruce Richardson done: 17499a2dd95SBruce Richardson if (str == NULL) 17599a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "wrong representor format: %s\n", str); 17699a2dd95SBruce Richardson return str == NULL ? -1 : 0; 17799a2dd95SBruce Richardson } 178c87d435aSKonstantin Ananyev 179*41f2f055SDavid Marchand struct dummy_queue { 180*41f2f055SDavid Marchand bool rx_warn_once; 181*41f2f055SDavid Marchand bool tx_warn_once; 182*41f2f055SDavid Marchand }; 183*41f2f055SDavid Marchand static struct dummy_queue *dummy_queues_array[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT]; 184*41f2f055SDavid Marchand static struct dummy_queue per_port_queues[RTE_MAX_ETHPORTS]; 185*41f2f055SDavid Marchand RTE_INIT(dummy_queue_init) 186*41f2f055SDavid Marchand { 187*41f2f055SDavid Marchand uint16_t port_id; 188*41f2f055SDavid Marchand 189*41f2f055SDavid Marchand for (port_id = 0; port_id < RTE_DIM(per_port_queues); port_id++) { 190*41f2f055SDavid Marchand unsigned int q; 191*41f2f055SDavid Marchand 192*41f2f055SDavid Marchand for (q = 0; q < RTE_DIM(dummy_queues_array[port_id]); q++) 193*41f2f055SDavid Marchand dummy_queues_array[port_id][q] = &per_port_queues[port_id]; 194*41f2f055SDavid Marchand } 195*41f2f055SDavid Marchand } 196*41f2f055SDavid Marchand 197c87d435aSKonstantin Ananyev static uint16_t 198*41f2f055SDavid Marchand dummy_eth_rx_burst(void *rxq, 199c87d435aSKonstantin Ananyev __rte_unused struct rte_mbuf **rx_pkts, 200c87d435aSKonstantin Ananyev __rte_unused uint16_t nb_pkts) 201c87d435aSKonstantin Ananyev { 202*41f2f055SDavid Marchand struct dummy_queue *queue = rxq; 203*41f2f055SDavid Marchand uintptr_t port_id; 204*41f2f055SDavid Marchand 205*41f2f055SDavid Marchand port_id = queue - per_port_queues; 206*41f2f055SDavid Marchand if (port_id < RTE_DIM(per_port_queues) && !queue->rx_warn_once) { 207*41f2f055SDavid Marchand RTE_ETHDEV_LOG(ERR, "lcore %u called rx_pkt_burst for not ready port %"PRIuPTR"\n", 208*41f2f055SDavid Marchand rte_lcore_id(), port_id); 209*41f2f055SDavid Marchand rte_dump_stack(); 210*41f2f055SDavid Marchand queue->rx_warn_once = true; 211*41f2f055SDavid Marchand } 212c87d435aSKonstantin Ananyev rte_errno = ENOTSUP; 213c87d435aSKonstantin Ananyev return 0; 214c87d435aSKonstantin Ananyev } 215c87d435aSKonstantin Ananyev 216c87d435aSKonstantin Ananyev static uint16_t 217*41f2f055SDavid Marchand dummy_eth_tx_burst(void *txq, 218c87d435aSKonstantin Ananyev __rte_unused struct rte_mbuf **tx_pkts, 219c87d435aSKonstantin Ananyev __rte_unused uint16_t nb_pkts) 220c87d435aSKonstantin Ananyev { 221*41f2f055SDavid Marchand struct dummy_queue *queue = txq; 222*41f2f055SDavid Marchand uintptr_t port_id; 223*41f2f055SDavid Marchand 224*41f2f055SDavid Marchand port_id = queue - per_port_queues; 225*41f2f055SDavid Marchand if (port_id < RTE_DIM(per_port_queues) && !queue->tx_warn_once) { 226*41f2f055SDavid Marchand RTE_ETHDEV_LOG(ERR, "lcore %u called tx_pkt_burst for not ready port %"PRIuPTR"\n", 227*41f2f055SDavid Marchand rte_lcore_id(), port_id); 228*41f2f055SDavid Marchand rte_dump_stack(); 229*41f2f055SDavid Marchand queue->tx_warn_once = true; 230*41f2f055SDavid Marchand } 231c87d435aSKonstantin Ananyev rte_errno = ENOTSUP; 232c87d435aSKonstantin Ananyev return 0; 233c87d435aSKonstantin Ananyev } 234c87d435aSKonstantin Ananyev 235c87d435aSKonstantin Ananyev void 236c87d435aSKonstantin Ananyev eth_dev_fp_ops_reset(struct rte_eth_fp_ops *fpo) 237c87d435aSKonstantin Ananyev { 238c87d435aSKonstantin Ananyev static void *dummy_data[RTE_MAX_QUEUES_PER_PORT]; 239*41f2f055SDavid Marchand uintptr_t port_id = fpo - rte_eth_fp_ops; 240*41f2f055SDavid Marchand 241*41f2f055SDavid Marchand per_port_queues[port_id].rx_warn_once = false; 242*41f2f055SDavid Marchand per_port_queues[port_id].tx_warn_once = false; 243*41f2f055SDavid Marchand *fpo = (struct rte_eth_fp_ops) { 244c87d435aSKonstantin Ananyev .rx_pkt_burst = dummy_eth_rx_burst, 245c87d435aSKonstantin Ananyev .tx_pkt_burst = dummy_eth_tx_burst, 246*41f2f055SDavid Marchand .rxq = { 247*41f2f055SDavid Marchand .data = (void **)&dummy_queues_array[port_id], 248*41f2f055SDavid Marchand .clbk = dummy_data, 249*41f2f055SDavid Marchand }, 250*41f2f055SDavid Marchand .txq = { 251*41f2f055SDavid Marchand .data = (void **)&dummy_queues_array[port_id], 252*41f2f055SDavid Marchand .clbk = dummy_data, 253*41f2f055SDavid Marchand }, 254c87d435aSKonstantin Ananyev }; 255c87d435aSKonstantin Ananyev } 256c87d435aSKonstantin Ananyev 257c87d435aSKonstantin Ananyev void 258c87d435aSKonstantin Ananyev eth_dev_fp_ops_setup(struct rte_eth_fp_ops *fpo, 259c87d435aSKonstantin Ananyev const struct rte_eth_dev *dev) 260c87d435aSKonstantin Ananyev { 261c87d435aSKonstantin Ananyev fpo->rx_pkt_burst = dev->rx_pkt_burst; 262c87d435aSKonstantin Ananyev fpo->tx_pkt_burst = dev->tx_pkt_burst; 263c87d435aSKonstantin Ananyev fpo->tx_pkt_prepare = dev->tx_pkt_prepare; 264c87d435aSKonstantin Ananyev fpo->rx_queue_count = dev->rx_queue_count; 265c87d435aSKonstantin Ananyev fpo->rx_descriptor_status = dev->rx_descriptor_status; 266c87d435aSKonstantin Ananyev fpo->tx_descriptor_status = dev->tx_descriptor_status; 267c87d435aSKonstantin Ananyev 268c87d435aSKonstantin Ananyev fpo->rxq.data = dev->data->rx_queues; 269c87d435aSKonstantin Ananyev fpo->rxq.clbk = (void **)(uintptr_t)dev->post_rx_burst_cbs; 270c87d435aSKonstantin Ananyev 271c87d435aSKonstantin Ananyev fpo->txq.data = dev->data->tx_queues; 272c87d435aSKonstantin Ananyev fpo->txq.clbk = (void **)(uintptr_t)dev->pre_tx_burst_cbs; 273c87d435aSKonstantin Ananyev } 2747a093523SKonstantin Ananyev 2757a093523SKonstantin Ananyev uint16_t 2767a093523SKonstantin Ananyev rte_eth_call_rx_callbacks(uint16_t port_id, uint16_t queue_id, 2777a093523SKonstantin Ananyev struct rte_mbuf **rx_pkts, uint16_t nb_rx, uint16_t nb_pkts, 2787a093523SKonstantin Ananyev void *opaque) 2797a093523SKonstantin Ananyev { 2807a093523SKonstantin Ananyev const struct rte_eth_rxtx_callback *cb = opaque; 2817a093523SKonstantin Ananyev 2827a093523SKonstantin Ananyev while (cb != NULL) { 2837a093523SKonstantin Ananyev nb_rx = cb->fn.rx(port_id, queue_id, rx_pkts, nb_rx, 2847a093523SKonstantin Ananyev nb_pkts, cb->param); 2857a093523SKonstantin Ananyev cb = cb->next; 2867a093523SKonstantin Ananyev } 2877a093523SKonstantin Ananyev 2887a093523SKonstantin Ananyev return nb_rx; 2897a093523SKonstantin Ananyev } 2907a093523SKonstantin Ananyev 2917a093523SKonstantin Ananyev uint16_t 2927a093523SKonstantin Ananyev rte_eth_call_tx_callbacks(uint16_t port_id, uint16_t queue_id, 2937a093523SKonstantin Ananyev struct rte_mbuf **tx_pkts, uint16_t nb_pkts, void *opaque) 2947a093523SKonstantin Ananyev { 2957a093523SKonstantin Ananyev const struct rte_eth_rxtx_callback *cb = opaque; 2967a093523SKonstantin Ananyev 2977a093523SKonstantin Ananyev while (cb != NULL) { 2987a093523SKonstantin Ananyev nb_pkts = cb->fn.tx(port_id, queue_id, tx_pkts, nb_pkts, 2997a093523SKonstantin Ananyev cb->param); 3007a093523SKonstantin Ananyev cb = cb->next; 3017a093523SKonstantin Ananyev } 3027a093523SKonstantin Ananyev 3037a093523SKonstantin Ananyev return nb_pkts; 3047a093523SKonstantin Ananyev } 305