Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <stdbool.h>
9 : : #include <stdint.h>
10 : :
11 : : #include <sys/queue.h>
12 : :
13 : : #include "testpmd.h"
14 : :
15 : : /* Hairpin ports configuration mode. */
16 : : uint32_t hairpin_mode;
17 : :
18 : : bool hairpin_multiport_mode;
19 : :
20 : : queueid_t nb_hairpinq; /**< Number of hairpin queues per port. */
21 : :
22 : : static LIST_HEAD(, hairpin_map) hairpin_map_head = LIST_HEAD_INITIALIZER();
23 : :
24 : : struct hairpin_map {
25 : : LIST_ENTRY(hairpin_map) entry; /**< List entry. */
26 : : portid_t rx_port; /**< Hairpin Rx port ID. */
27 : : portid_t tx_port; /**< Hairpin Tx port ID. */
28 : : uint16_t rxq_head; /**< Hairpin Rx queue head. */
29 : : uint16_t txq_head; /**< Hairpin Tx queue head. */
30 : : uint16_t qnum; /**< Hairpin queues number. */
31 : : };
32 : :
33 : : void
34 : 0 : hairpin_add_multiport_map(struct hairpin_map *map)
35 : : {
36 : 0 : LIST_INSERT_HEAD(&hairpin_map_head, map, entry);
37 : 0 : }
38 : :
39 : : /*
40 : : * Get the allowed maximum number of hairpin queues.
41 : : * *pid return the port id which has minimal value of
42 : : * max_hairpin_queues in all ports.
43 : : */
44 : : queueid_t
45 : 0 : get_allowed_max_nb_hairpinq(portid_t *pid)
46 : : {
47 : : queueid_t allowed_max_hairpinq = RTE_MAX_QUEUES_PER_PORT;
48 : : portid_t pi;
49 : : struct rte_eth_hairpin_cap cap;
50 : :
51 : 0 : RTE_ETH_FOREACH_DEV(pi) {
52 : 0 : if (rte_eth_dev_hairpin_capability_get(pi, &cap) != 0) {
53 : 0 : *pid = pi;
54 : 0 : return 0;
55 : : }
56 : 0 : if (cap.max_nb_queues < allowed_max_hairpinq) {
57 : : allowed_max_hairpinq = cap.max_nb_queues;
58 : 0 : *pid = pi;
59 : : }
60 : : }
61 : : return allowed_max_hairpinq;
62 : : }
63 : :
64 : : /*
65 : : * Check input hairpin is valid or not.
66 : : * If input hairpin is not greater than any of maximum number
67 : : * of hairpin queues of all ports, it is valid.
68 : : * if valid, return 0, else return -1
69 : : */
70 : : int
71 : 0 : check_nb_hairpinq(queueid_t hairpinq)
72 : : {
73 : : queueid_t allowed_max_hairpinq;
74 : 0 : portid_t pid = 0;
75 : :
76 : 0 : allowed_max_hairpinq = get_allowed_max_nb_hairpinq(&pid);
77 : 0 : if (hairpinq > allowed_max_hairpinq) {
78 : 0 : fprintf(stderr,
79 : : "Fail: input hairpin (%u) can't be greater than max_hairpin_queues (%u) of port %u\n",
80 : : hairpinq, allowed_max_hairpinq, pid);
81 : 0 : return -1;
82 : : }
83 : : return 0;
84 : : }
85 : :
86 : : #define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8)
87 : : #define HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9)
88 : :
89 : : #define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12)
90 : : #define HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13)
91 : :
92 : : #define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16)
93 : : #define HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17)
94 : :
95 : : static int
96 : 0 : port_config_hairpin_rxq(portid_t pi, uint16_t peer_tx_port,
97 : : queueid_t rxq_head, queueid_t txq_head,
98 : : uint16_t qcount, uint32_t manual_bind)
99 : : {
100 : : int diag;
101 : : queueid_t i, qi;
102 : 0 : struct rte_port *port = &ports[pi];
103 : 0 : struct rte_eth_hairpin_conf hairpin_conf = {
104 : : .peer_count = 1,
105 : : .peers[0].port = peer_tx_port,
106 : : .manual_bind = manual_bind,
107 : 0 : .tx_explicit = !!(hairpin_mode & 0x10),
108 : 0 : .force_memory = !!(hairpin_mode & HAIRPIN_MODE_RX_FORCE_MEMORY),
109 : : .use_locked_device_memory =
110 : 0 : !!(hairpin_mode & HAIRPIN_MODE_RX_LOCKED_MEMORY),
111 : 0 : .use_rte_memory = !!(hairpin_mode & HAIRPIN_MODE_RX_RTE_MEMORY),
112 : : };
113 : :
114 : 0 : for (qi = rxq_head, i = 0; qi < rxq_head + qcount; qi++, i++) {
115 : 0 : hairpin_conf.peers[0].queue = i + txq_head;
116 : 0 : diag = rte_eth_rx_hairpin_queue_setup(pi, qi, nb_rxd, &hairpin_conf);
117 : 0 : if (diag == 0)
118 : : continue;
119 : :
120 : : /* Fail to setup rx queue, return */
121 : 0 : if (port->port_status == RTE_PORT_HANDLING)
122 : 0 : port->port_status = RTE_PORT_STOPPED;
123 : : else
124 : 0 : fprintf(stderr,
125 : : "Port %d can not be set back to stopped\n", pi);
126 : 0 : fprintf(stderr,
127 : : "Port %u failed to configure hairpin on rxq %u.\n"
128 : : "Peer port: %u peer txq: %u\n",
129 : : pi, qi, peer_tx_port, i);
130 : : /* try to reconfigure queues next time */
131 : 0 : port->need_reconfig_queues = 1;
132 : 0 : return -1;
133 : : }
134 : : return 0;
135 : : }
136 : :
137 : : static int
138 : 0 : port_config_hairpin_txq(portid_t pi, uint16_t peer_rx_port,
139 : : queueid_t rxq_head, queueid_t txq_head,
140 : : uint16_t qcount, uint32_t manual_bind)
141 : : {
142 : : int diag;
143 : : queueid_t i, qi;
144 : 0 : struct rte_port *port = &ports[pi];
145 : 0 : struct rte_eth_hairpin_conf hairpin_conf = {
146 : : .peer_count = 1,
147 : : .peers[0].port = peer_rx_port,
148 : : .manual_bind = manual_bind,
149 : 0 : .tx_explicit = !!(hairpin_mode & 0x10),
150 : 0 : .force_memory = !!(hairpin_mode & HAIRPIN_MODE_TX_FORCE_MEMORY),
151 : : .use_locked_device_memory =
152 : 0 : !!(hairpin_mode & HAIRPIN_MODE_TX_LOCKED_MEMORY),
153 : 0 : .use_rte_memory = !!(hairpin_mode & HAIRPIN_MODE_TX_RTE_MEMORY),
154 : : };
155 : :
156 : 0 : for (qi = txq_head, i = 0; qi < txq_head + qcount; qi++, i++) {
157 : 0 : hairpin_conf.peers[0].queue = i + rxq_head;
158 : 0 : diag = rte_eth_tx_hairpin_queue_setup(pi, qi, nb_txd, &hairpin_conf);
159 : 0 : if (diag == 0)
160 : : continue;
161 : :
162 : : /* Fail to setup rx queue, return */
163 : 0 : if (port->port_status == RTE_PORT_HANDLING)
164 : 0 : port->port_status = RTE_PORT_STOPPED;
165 : : else
166 : 0 : fprintf(stderr,
167 : : "Port %d can not be set back to stopped\n", pi);
168 : 0 : fprintf(stderr,
169 : : "Port %d failed to configure hairpin on txq %u.\n"
170 : : "Peer port: %u peer rxq: %u\n",
171 : : pi, qi, peer_rx_port, i);
172 : : /* try to reconfigure queues next time */
173 : 0 : port->need_reconfig_queues = 1;
174 : 0 : return -1;
175 : : }
176 : : return 0;
177 : : }
178 : :
179 : : static int
180 : 0 : setup_legacy_hairpin_queues(portid_t pi, portid_t p_pi, uint16_t cnt_pi)
181 : : {
182 : : int diag;
183 : : uint16_t peer_rx_port = pi;
184 : : uint16_t peer_tx_port = pi;
185 : : uint32_t manual = 1;
186 : :
187 : 0 : if (!(hairpin_mode & 0xf)) {
188 : : peer_rx_port = pi;
189 : : peer_tx_port = pi;
190 : : manual = 0;
191 : 0 : } else if (hairpin_mode & 0x1) {
192 : 0 : peer_tx_port = rte_eth_find_next_owned_by(pi + 1,
193 : : RTE_ETH_DEV_NO_OWNER);
194 : 0 : if (peer_tx_port >= RTE_MAX_ETHPORTS)
195 : 0 : peer_tx_port = rte_eth_find_next_owned_by(0,
196 : : RTE_ETH_DEV_NO_OWNER);
197 : 0 : if (p_pi != RTE_MAX_ETHPORTS) {
198 : : peer_rx_port = p_pi;
199 : : } else {
200 : : uint16_t next_pi;
201 : :
202 : : /* Last port will be the peer RX port of the first. */
203 : 0 : RTE_ETH_FOREACH_DEV(next_pi)
204 : : peer_rx_port = next_pi;
205 : : }
206 : : manual = 1;
207 : 0 : } else if (hairpin_mode & 0x2) {
208 : 0 : if (cnt_pi & 0x1) {
209 : : peer_rx_port = p_pi;
210 : : } else {
211 : 0 : peer_rx_port = rte_eth_find_next_owned_by(pi + 1,
212 : : RTE_ETH_DEV_NO_OWNER);
213 : 0 : if (peer_rx_port >= RTE_MAX_ETHPORTS)
214 : : peer_rx_port = pi;
215 : : }
216 : : peer_tx_port = peer_rx_port;
217 : : manual = 1;
218 : : }
219 : 0 : diag = port_config_hairpin_txq(pi, peer_rx_port, nb_rxq, nb_txq,
220 : : nb_hairpinq, manual);
221 : 0 : if (diag)
222 : : return diag;
223 : 0 : diag = port_config_hairpin_rxq(pi, peer_tx_port, nb_rxq, nb_txq,
224 : : nb_hairpinq, manual);
225 : 0 : if (diag)
226 : 0 : return diag;
227 : : return 0;
228 : : }
229 : :
230 : : static int
231 : 0 : setup_mapped_harpin_queues(portid_t pi)
232 : : {
233 : : int ret = 0;
234 : : struct hairpin_map *map;
235 : :
236 : 0 : LIST_FOREACH(map, &hairpin_map_head, entry) {
237 : 0 : if (map->rx_port == pi) {
238 : 0 : ret = port_config_hairpin_rxq(pi, map->tx_port,
239 : 0 : map->rxq_head,
240 : 0 : map->txq_head,
241 : 0 : map->qnum, true);
242 : 0 : if (ret)
243 : 0 : return ret;
244 : : }
245 : 0 : if (map->tx_port == pi) {
246 : 0 : ret = port_config_hairpin_txq(pi, map->rx_port,
247 : 0 : map->rxq_head,
248 : 0 : map->txq_head,
249 : 0 : map->qnum, true);
250 : 0 : if (ret)
251 : 0 : return ret;
252 : : }
253 : : }
254 : : return 0;
255 : : }
256 : :
257 : : /* Configure the Rx and Tx hairpin queues for the selected port. */
258 : : int
259 : 0 : setup_hairpin_queues(portid_t pi, portid_t p_pi, uint16_t cnt_pi)
260 : : {
261 : 0 : if (hairpin_multiport_mode)
262 : 0 : return setup_mapped_harpin_queues(pi);
263 : :
264 : 0 : return setup_legacy_hairpin_queues(pi, p_pi, cnt_pi);
265 : : }
266 : :
267 : : int
268 : 0 : hairpin_bind(uint16_t cfg_pi, portid_t *pl, portid_t *peer_pl)
269 : : {
270 : : uint16_t i;
271 : : portid_t pi;
272 : : int peer_pi;
273 : : int diag;
274 : : int j;
275 : :
276 : : /* bind all started hairpin ports */
277 : 0 : for (i = 0; i < cfg_pi; i++) {
278 : 0 : pi = pl[i];
279 : : /* bind current Tx to all peer Rx */
280 : 0 : peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
281 : : RTE_MAX_ETHPORTS, 1);
282 : 0 : if (peer_pi < 0)
283 : 0 : return peer_pi;
284 : 0 : for (j = 0; j < peer_pi; j++) {
285 : 0 : if (!port_is_started(peer_pl[j]))
286 : 0 : continue;
287 : 0 : diag = rte_eth_hairpin_bind(pi, peer_pl[j]);
288 : 0 : if (diag < 0) {
289 : 0 : fprintf(stderr,
290 : : "Error during binding hairpin Tx port %u to %u: %s\n",
291 : 0 : pi, peer_pl[j],
292 : : rte_strerror(-diag));
293 : 0 : return -1;
294 : : }
295 : : }
296 : : /* bind all peer Tx to current Rx */
297 : 0 : peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
298 : : RTE_MAX_ETHPORTS, 0);
299 : 0 : if (peer_pi < 0)
300 : 0 : return peer_pi;
301 : 0 : for (j = 0; j < peer_pi; j++) {
302 : 0 : if (!port_is_started(peer_pl[j]))
303 : 0 : continue;
304 : 0 : diag = rte_eth_hairpin_bind(peer_pl[j], pi);
305 : 0 : if (diag < 0) {
306 : 0 : fprintf(stderr,
307 : : "Error during binding hairpin Tx port %u to %u: %s\n",
308 : 0 : peer_pl[j], pi,
309 : : rte_strerror(-diag));
310 : 0 : return -1;
311 : : }
312 : : }
313 : : }
314 : : return 0;
315 : : }
316 : :
317 : : void
318 : 0 : hairpin_map_usage(void)
319 : : {
320 : : printf(" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n"
321 : : " rxpi - Rx port index.\n"
322 : : " rxq - Rx queue.\n"
323 : : " txpi - Tx port index.\n"
324 : : " txq - Tx queue.\n"
325 : : " n - hairpin queues number.\n");
326 : 0 : }
327 : :
328 : : int
329 : 0 : parse_hairpin_map(const char *hpmap)
330 : : {
331 : : /*
332 : : * Testpmd hairpin map format:
333 : : * <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number>
334 : : */
335 : : int ret;
336 : 0 : struct hairpin_map *map = calloc(1, sizeof(*map));
337 : :
338 : 0 : if (!map)
339 : : return -ENOMEM;
340 : :
341 : 0 : ret = sscanf(hpmap, "%hu:%hu:%hu:%hu:%hu",
342 : : &map->rx_port, &map->rxq_head,
343 : : &map->tx_port, &map->txq_head, &map->qnum);
344 : 0 : if (ret != 5) {
345 : 0 : free(map);
346 : 0 : return -EINVAL;
347 : : }
348 : : hairpin_add_multiport_map(map);
349 : 0 : return 0;
350 : : }
|