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