Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
3 : : */
4 : :
5 : : #include <stdlib.h>
6 : : #include <rte_eal.h>
7 : : #include <rte_ethdev.h>
8 : : #include <ethdev_driver.h>
9 : : #include <rte_log.h>
10 : : #include <rte_malloc.h>
11 : : #include <rte_memzone.h>
12 : : #include <rte_string_fns.h>
13 : :
14 : : #include "sxe2_mp.h"
15 : : #include "sxe2_stats.h"
16 : : #include "sxe2_common_log.h"
17 : :
18 : : /* The shared qstats array must hold every queue the primary may write. */
19 : : static_assert(SXE2_RXQ_STATS_MAP_MAX_NUM <= SXE2_MP_MAX_QSTATS &&
20 : : SXE2_TXQ_STATS_MAP_MAX_NUM <= SXE2_MP_MAX_QSTATS,
21 : : "shared qstats array too small for per-queue stats");
22 : :
23 : : static RTE_ATOMIC(uint16_t)primary_ethdev_cnt;
24 : : static RTE_ATOMIC(uint16_t)secondary_ethdev_cnt;
25 : : static const struct rte_memzone *sxe2_mp_mz;
26 : :
27 : : static int32_t sxe2_mp_acquire_token(void);
28 : : static void sxe2_mp_release_token(void);
29 : :
30 : : static int32_t sxe2_mp_primary_handle(const struct rte_mp_msg *mp_msg,
31 : : const void *peer);
32 : :
33 : : static int32_t sxe2_mp_secondary_handle(const struct rte_mp_msg *mp_msg,
34 : : const void *peer);
35 : :
36 : : static int32_t
37 : 0 : sxe2_mp_do_primary_work(struct sxe2_mp_param *param)
38 : : {
39 : 0 : struct rte_eth_dev *dev;
40 : 0 : struct sxe2_mp_shared_data *mz_data;
41 : 0 : int32_t ret = 0;
42 : 0 : int32_t cnt = 0;
43 : :
44 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(param->port_id)) {
45 : 0 : PMD_LOG_ERR(DRV, "primary process: invalid port_id %u",
46 : : param->port_id);
47 : 0 : ret = -EINVAL;
48 : 0 : goto out;
49 : : }
50 : :
51 : 0 : dev = &rte_eth_devices[param->port_id];
52 : :
53 [ # # ]: 0 : if (sxe2_mp_mz == NULL) {
54 : 0 : sxe2_mp_mz = rte_memzone_lookup(SXE2_MP_MZ_NAME);
55 [ # # ]: 0 : if (sxe2_mp_mz == NULL) {
56 : 0 : PMD_LOG_ERR(DRV, "Failed to lookup memzone %s",
57 : : SXE2_MP_MZ_NAME);
58 : 0 : ret = -ENOENT;
59 : 0 : goto out;
60 : : }
61 : : }
62 : :
63 : 0 : mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
64 [ # # # # ]: 0 : switch (param->type) {
65 : 0 : case SXE2_MP_REQ_GET_STATS:
66 : 0 : memset(&mz_data->payload.stats_blk, 0, sizeof(mz_data->payload.stats_blk));
67 : 0 : ret = sxe2_stats_info_get(dev,
68 : : &mz_data->payload.stats_blk.stats,
69 : 0 : mz_data->payload.stats_blk.qstats);
70 : 0 : break;
71 : 0 : case SXE2_MP_REQ_GET_XSTATS:
72 : 0 : cnt = sxe2_xstats_info_get(dev,
73 : 0 : mz_data->payload.xstats_blk.xstats,
74 : : SXE2_MP_MAX_XSTATS);
75 : :
76 [ # # ]: 0 : if (cnt >= 0) {
77 : 0 : mz_data->payload.xstats_blk.xstats_num = (uint32_t)cnt;
78 : 0 : ret = 0;
79 : : } else {
80 : 0 : mz_data->payload.xstats_blk.xstats_num = 0;
81 : 0 : ret = cnt;
82 : : }
83 : : break;
84 : 0 : case SXE2_MP_REQ_RESET_STATS:
85 : 0 : ret = sxe2_stats_hw_reset(dev);
86 : 0 : break;
87 : 0 : default:
88 : 0 : PMD_LOG_ERR(DRV, "primary process: unrecognized msg type: %d",
89 : : param->type);
90 : 0 : ret = -EINVAL;
91 : 0 : break;
92 : : }
93 : :
94 : 0 : out:
95 : 0 : param->result = ret;
96 : 0 : return ret;
97 : : }
98 : :
99 : : static int32_t
100 : 0 : sxe2_mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
101 : : {
102 : 0 : struct rte_mp_msg reply;
103 : 0 : struct sxe2_mp_param *reply_param = (struct sxe2_mp_param *)reply.param;
104 : 0 : const struct sxe2_mp_param *param =
105 : : (const struct sxe2_mp_param *)mp_msg->param;
106 : 0 : struct sxe2_mp_param param_copy;
107 : :
108 : 0 : memset(&reply, 0, sizeof(reply));
109 : 0 : (void)strlcpy(reply.name, SXE2_MP_NAME, sizeof(reply.name));
110 : 0 : reply.len_param = sizeof(*reply_param);
111 : :
112 : 0 : param_copy = *param;
113 : 0 : (void)sxe2_mp_do_primary_work(¶m_copy);
114 : :
115 : 0 : reply_param->result = param_copy.result;
116 : 0 : reply_param->type = param->type;
117 : 0 : reply_param->port_id = param->port_id;
118 : :
119 : 0 : return rte_mp_reply(&reply, peer);
120 : : }
121 : :
122 : : static int32_t
123 : 0 : sxe2_mp_secondary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
124 : : const void *peer __rte_unused)
125 : : {
126 : 0 : PMD_LOG_WARN(DRV, "the secondary process handler should not be called");
127 : 0 : return 0;
128 : : }
129 : :
130 : : static int32_t
131 : 0 : sxe2_mp_init_primary(__rte_unused struct rte_eth_dev *dev)
132 : : {
133 : 0 : int32_t ret;
134 : :
135 [ # # ]: 0 : if (sxe2_mp_mz == NULL) {
136 : 0 : sxe2_mp_mz = rte_memzone_reserve(SXE2_MP_MZ_NAME,
137 : : sizeof(struct sxe2_mp_shared_data),
138 : 0 : rte_socket_id(), 0);
139 [ # # # # ]: 0 : if (sxe2_mp_mz == NULL && rte_errno != EEXIST) {
140 : 0 : PMD_LOG_ERR(DRV, "Failed to reserve memzone %s, error: %d",
141 : : SXE2_MP_MZ_NAME, -rte_errno);
142 : 0 : ret = -rte_errno;
143 : 0 : goto out;
144 : : }
145 : :
146 : 0 : sxe2_mp_mz = rte_memzone_lookup(SXE2_MP_MZ_NAME);
147 [ # # ]: 0 : if (sxe2_mp_mz == NULL) {
148 : 0 : PMD_LOG_ERR(DRV, "Failed to lookup memzone %s", SXE2_MP_MZ_NAME);
149 : 0 : ret = -ENOENT;
150 : 0 : goto out;
151 : : }
152 : :
153 : 0 : struct sxe2_mp_shared_data *mz =
154 : : (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
155 : 0 : rte_atomic_store_explicit(&mz->in_use, 0, rte_memory_order_release);
156 : : }
157 : :
158 : 0 : ret = rte_mp_action_register(SXE2_MP_NAME, sxe2_mp_primary_handle);
159 [ # # # # ]: 0 : if (ret && rte_errno == ENOTSUP) {
160 : 0 : PMD_LOG_INFO(DRV, "Primary not support IPC.");
161 : 0 : ret = 0;
162 : 0 : goto out;
163 [ # # # # ]: 0 : } else if (ret && rte_errno != EEXIST) {
164 : 0 : PMD_LOG_ERR(DRV, "Failed to register MP primary handle, error: %d",
165 : : -rte_errno);
166 : 0 : goto out;
167 : : }
168 : :
169 : 0 : rte_atomic_fetch_add_explicit(&primary_ethdev_cnt, 1, rte_memory_order_relaxed);
170 : :
171 : 0 : ret = 0;
172 : 0 : out:
173 : 0 : return ret;
174 : : }
175 : :
176 : : static int32_t
177 : 0 : sxe2_mp_init_secondary(__rte_unused struct rte_eth_dev *dev)
178 : : {
179 : 0 : int32_t ret;
180 : :
181 : 0 : sxe2_mp_mz = rte_memzone_lookup(SXE2_MP_MZ_NAME);
182 [ # # ]: 0 : if (sxe2_mp_mz == NULL) {
183 : 0 : PMD_LOG_ERR(DRV, "Failed to lookup memzone %s", SXE2_MP_MZ_NAME);
184 : 0 : ret = -ENOENT;
185 : 0 : goto out;
186 : : }
187 : :
188 : 0 : ret = rte_mp_action_register(SXE2_MP_NAME, sxe2_mp_secondary_handle);
189 [ # # # # ]: 0 : if (ret && rte_errno != EEXIST) {
190 : 0 : PMD_LOG_ERR(DRV, "Failed to register MP secondary handle, error: %d",
191 : : -rte_errno);
192 : 0 : goto out;
193 : : }
194 : :
195 : 0 : rte_atomic_fetch_add_explicit(&secondary_ethdev_cnt, 1, rte_memory_order_relaxed);
196 : :
197 : 0 : ret = 0;
198 : 0 : out:
199 : 0 : return ret;
200 : : }
201 : :
202 : : int32_t
203 : 0 : sxe2_mp_init(struct rte_eth_dev *dev)
204 : : {
205 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY)
206 : 0 : return sxe2_mp_init_primary(dev);
207 : : else
208 : 0 : return sxe2_mp_init_secondary(dev);
209 : : }
210 : :
211 : : void
212 : 0 : sxe2_mp_uninit(__rte_unused struct rte_eth_dev *dev)
213 : : {
214 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
215 [ # # ]: 0 : if (rte_atomic_fetch_sub_explicit(&primary_ethdev_cnt, 1,
216 : : rte_memory_order_acq_rel) == 1) {
217 : 0 : rte_mp_action_unregister(SXE2_MP_NAME);
218 [ # # ]: 0 : if (sxe2_mp_mz != NULL) {
219 : 0 : rte_memzone_free(sxe2_mp_mz);
220 : 0 : sxe2_mp_mz = NULL;
221 : : }
222 : : }
223 : : } else {
224 [ # # ]: 0 : if (rte_atomic_fetch_sub_explicit(&secondary_ethdev_cnt, 1,
225 : : rte_memory_order_acq_rel) == 1)
226 : 0 : rte_mp_action_unregister(SXE2_MP_NAME);
227 : : }
228 : 0 : }
229 : :
230 : 0 : static int32_t sxe2_mp_acquire_token(void)
231 : : {
232 : 0 : struct sxe2_mp_shared_data *mz;
233 : 0 : uint16_t expected;
234 : :
235 : 0 : if (sxe2_mp_mz == NULL)
236 : : return -EINVAL;
237 : :
238 : 0 : mz = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
239 : :
240 [ # # # # ]: 0 : for (int32_t i = 0; i < SXE2_MP_MAX_SPIN; i++) {
241 : 0 : expected = 0;
242 [ # # # # ]: 0 : if (rte_atomic_compare_exchange_strong_explicit(&mz->in_use, &expected, 1,
243 : : rte_memory_order_acquire, rte_memory_order_relaxed))
244 : : return 0;
245 : :
246 : 0 : rte_pause();
247 : : }
248 : : return -EBUSY;
249 : : }
250 : :
251 : 0 : static void sxe2_mp_release_token(void)
252 : : {
253 : 0 : struct sxe2_mp_shared_data *mz;
254 : :
255 : 0 : if (sxe2_mp_mz == NULL)
256 : : return;
257 : :
258 : 0 : mz = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
259 : 0 : rte_atomic_store_explicit(&mz->in_use, 0, rte_memory_order_release);
260 : : }
261 : :
262 : 0 : int32_t sxe2_mp_request_simple(struct rte_eth_dev *dev,
263 : : enum sxe2_mp_req_type type,
264 : : int32_t *result_out)
265 : : {
266 : 0 : struct rte_mp_msg msg;
267 : 0 : struct rte_mp_reply reply = { 0 };
268 : 0 : struct timespec ts = { .tv_sec = SXE2_MP_MSG_TIMEOUT, .tv_nsec = 0 };
269 : 0 : struct sxe2_mp_param *param = (struct sxe2_mp_param *)msg.param;
270 : 0 : struct sxe2_mp_shared_data *mz_data;
271 : 0 : int32_t ret = 0;
272 : :
273 : 0 : mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
274 : :
275 : 0 : memset(&mz_data->payload, 0, sizeof(mz_data->payload));
276 : 0 : memset(&msg, 0, sizeof(msg));
277 : 0 : (void)strlcpy(msg.name, SXE2_MP_NAME, sizeof(msg.name));
278 : 0 : msg.len_param = sizeof(*param);
279 : 0 : param->type = type;
280 : 0 : param->port_id = dev->data->port_id;
281 : :
282 : 0 : ret = rte_mp_request_sync(&msg, &reply, &ts);
283 [ # # ]: 0 : if (ret != 0) {
284 : 0 : PMD_LOG_ERR(DRV,
285 : : "IPC request(type=%d) failed for port %u: %s",
286 : : type, dev->data->port_id, rte_strerror(rte_errno));
287 : 0 : ret = -rte_errno;
288 : 0 : goto out;
289 : : }
290 : :
291 [ # # ]: 0 : if (reply.nb_received == 0) {
292 : 0 : PMD_LOG_ERR(DRV, "No response received from primary for type=%d, port %u",
293 : : type, dev->data->port_id);
294 : 0 : ret = -ENOENT;
295 : 0 : goto out;
296 : : }
297 : :
298 : 0 : *result_out = ((struct sxe2_mp_param *)reply.msgs[0].param)->result;
299 : :
300 : 0 : out:
301 : 0 : free(reply.msgs);
302 : :
303 : 0 : return ret;
304 : : }
305 : :
306 : 0 : int32_t sxe2_mp_req_get_stats(struct rte_eth_dev *dev,
307 : : struct rte_eth_stats *stats,
308 : : struct eth_queue_stats *qstats)
309 : : {
310 : 0 : struct sxe2_mp_shared_data *mz_data;
311 : 0 : int32_t mp_ret;
312 : 0 : int32_t ret;
313 : 0 : int32_t token_acquired = 0;
314 : :
315 [ # # ]: 0 : if (sxe2_mp_mz == NULL)
316 : : return -EINVAL;
317 : :
318 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
319 : 0 : PMD_LOG_WARN(DRV, "Primary process direct execution for port %u",
320 : : dev->data->port_id);
321 : 0 : return sxe2_stats_info_get(dev, stats, qstats);
322 : : }
323 : :
324 [ # # ]: 0 : int32_t token_ret = sxe2_mp_acquire_token();
325 [ # # ]: 0 : if (token_ret != 0)
326 : 0 : return token_ret;
327 : 0 : token_acquired = 1;
328 : :
329 : 0 : mp_ret = sxe2_mp_request_simple(dev, SXE2_MP_REQ_GET_STATS, &ret);
330 [ # # ]: 0 : if (mp_ret != 0) {
331 : 0 : ret = mp_ret;
332 : 0 : goto out;
333 : : }
334 : :
335 [ # # ]: 0 : if (ret != 0) {
336 : 0 : PMD_LOG_ERR(DRV, "Primary failed to exec request (type=%d), result: %d for port %u",
337 : : SXE2_MP_REQ_GET_STATS, ret, dev->data->port_id);
338 : 0 : goto out;
339 : : }
340 : :
341 : 0 : mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
342 [ # # ]: 0 : memcpy(stats, &mz_data->payload.stats_blk.stats, sizeof(*stats));
343 [ # # ]: 0 : if (qstats != NULL) {
344 : 0 : uint16_t nb_queues = RTE_MAX(dev->data->nb_rx_queues,
345 : : dev->data->nb_tx_queues);
346 : :
347 : : /* The caller's array is sized for the configured queues, but
348 : : * the primary only fills in the queues firmware has counters for.
349 : : */
350 : 0 : memcpy(qstats, mz_data->payload.stats_blk.qstats,
351 : 0 : RTE_MIN_T(nb_queues, SXE2_MP_MAX_QSTATS, uint16_t) *
352 : : sizeof(*qstats));
353 : : }
354 : 0 : PMD_LOG_DEBUG(DRV, "sxe2_mp: stats received via IPC for port %u",
355 : : dev->data->port_id);
356 : 0 : ret = 0;
357 : 0 : out:
358 : 0 : if (token_acquired)
359 [ # # ]: 0 : sxe2_mp_release_token();
360 : 0 : return ret;
361 : : }
362 : :
363 : 0 : int32_t sxe2_mp_req_get_xstats(struct rte_eth_dev *dev,
364 : : struct rte_eth_xstat *xstats, uint32_t usr_cnt)
365 : : {
366 : 0 : struct sxe2_mp_shared_data *mz_data;
367 : 0 : int32_t ret;
368 : 0 : int32_t mp_ret;
369 : 0 : int32_t token_acquired = 0;
370 : :
371 [ # # ]: 0 : if (sxe2_mp_mz == NULL)
372 : : return -EINVAL;
373 : :
374 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
375 : 0 : PMD_LOG_WARN(DRV, "Primary process direct execution for port %u",
376 : : dev->data->port_id);
377 : 0 : return sxe2_xstats_info_get(dev, xstats, usr_cnt);
378 : : }
379 : :
380 [ # # ]: 0 : int32_t token_ret = sxe2_mp_acquire_token();
381 [ # # ]: 0 : if (token_ret != 0)
382 : 0 : return token_ret;
383 : 0 : token_acquired = 1;
384 : :
385 : 0 : mp_ret = sxe2_mp_request_simple(dev, SXE2_MP_REQ_GET_XSTATS, &ret);
386 [ # # ]: 0 : if (mp_ret != 0) {
387 : 0 : ret = mp_ret;
388 : 0 : goto out;
389 : : }
390 : :
391 [ # # ]: 0 : if (ret != 0) {
392 : 0 : PMD_LOG_ERR(DRV, "Primary failed to exec request (type=%d), result: %d for port %u",
393 : : SXE2_MP_REQ_GET_XSTATS, ret, dev->data->port_id);
394 : 0 : goto out;
395 : : }
396 : :
397 : 0 : mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
398 [ # # ]: 0 : if (usr_cnt < mz_data->payload.xstats_blk.xstats_num) {
399 : 0 : PMD_LOG_ERR(DRV, "user usr_cnt:%u less than xstats cnt:%u.",
400 : : usr_cnt, mz_data->payload.xstats_blk.xstats_num);
401 : 0 : ret = (int32_t)mz_data->payload.xstats_blk.xstats_num;
402 : 0 : goto out;
403 : : }
404 : :
405 : 0 : memcpy(xstats, mz_data->payload.xstats_blk.xstats,
406 : 0 : mz_data->payload.xstats_blk.xstats_num *
407 : : sizeof(struct rte_eth_xstat));
408 : 0 : ret = (int32_t)mz_data->payload.xstats_blk.xstats_num;
409 : :
410 : 0 : PMD_LOG_DEBUG(DRV,
411 : : "xstats received via IPC for port %u (cnt=%d)",
412 : : dev->data->port_id, ret);
413 : 0 : out:
414 : 0 : if (token_acquired)
415 [ # # ]: 0 : sxe2_mp_release_token();
416 : 0 : return ret;
417 : : }
418 : :
419 : : int32_t
420 : 0 : sxe2_mp_req_reset_stats(struct rte_eth_dev *dev)
421 : : {
422 : 0 : int32_t mp_ret;
423 : 0 : int32_t ret = 0;
424 : :
425 [ # # ]: 0 : if (sxe2_mp_mz == NULL)
426 : : return -EINVAL;
427 : :
428 : 0 : mp_ret = sxe2_mp_request_simple(dev, SXE2_MP_REQ_RESET_STATS, &ret);
429 [ # # ]: 0 : if (mp_ret != 0)
430 : : return mp_ret;
431 : :
432 [ # # ]: 0 : if (ret != 0) {
433 : 0 : PMD_LOG_ERR(DRV,
434 : : "Primary failed SXE2_MP_REQ_RESET_STATS, result: %d for port %u",
435 : : ret, dev->data->port_id);
436 : 0 : return ret;
437 : : }
438 : : return 0;
439 : : }
|