net/hns3: mark unchecked return of snprintf
[dpdk.git] / drivers / net / hns3 / hns3_mp.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 HiSilicon Limited.
3  */
4
5 #include <rte_eal.h>
6 #include <ethdev_driver.h>
7 #include <rte_string_fns.h>
8 #include <rte_io.h>
9
10 #include "hns3_ethdev.h"
11 #include "hns3_logs.h"
12 #include "hns3_rxtx.h"
13 #include "hns3_mp.h"
14
15 /* local data for primary or secondary process. */
16 static struct hns3_process_local_data process_data;
17
18 /*
19  * Initialize IPC message.
20  *
21  * @param[in] dev
22  *   Pointer to Ethernet structure.
23  * @param[out] msg
24  *   Pointer to message to fill in.
25  * @param[in] type
26  *   Message type.
27  */
28 static inline void
29 mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
30             enum hns3_mp_req_type type)
31 {
32         struct hns3_mp_param *param = (struct hns3_mp_param *)msg->param;
33
34         memset(msg, 0, sizeof(*msg));
35         strlcpy(msg->name, HNS3_MP_NAME, sizeof(msg->name));
36         msg->len_param = sizeof(*param);
37         param->type = type;
38         param->port_id = dev->data->port_id;
39 }
40
41 /*
42  * IPC message handler of primary process.
43  *
44  * @param[in] dev
45  *   Pointer to Ethernet structure.
46  * @param[in] peer
47  *   Pointer to the peer socket path.
48  *
49  * @return
50  *   0 on success, a negative errno value otherwise and rte_errno is set.
51  */
52 static int
53 mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
54                   const void *peer __rte_unused)
55 {
56         return 0;
57 }
58
59 /*
60  * IPC message handler of a secondary process.
61  *
62  * @param[in] dev
63  *   Pointer to Ethernet structure.
64  * @param[in] peer
65  *   Pointer to the peer socket path.
66  *
67  * @return
68  *   0 on success, a negative errno value otherwise and rte_errno is set.
69  */
70 static int
71 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
72 {
73         struct rte_mp_msg mp_res;
74         struct hns3_mp_param *res = (struct hns3_mp_param *)mp_res.param;
75         const struct hns3_mp_param *param =
76                 (const struct hns3_mp_param *)mp_msg->param;
77         eth_tx_prep_t prep = NULL;
78         struct rte_eth_dev *dev;
79         int ret;
80
81         if (!rte_eth_dev_is_valid_port(param->port_id)) {
82                 rte_errno = ENODEV;
83                 PMD_INIT_LOG(ERR, "port %d invalid port ID", param->port_id);
84                 return -rte_errno;
85         }
86         dev = &rte_eth_devices[param->port_id];
87         switch (param->type) {
88         case HNS3_MP_REQ_START_RXTX:
89                 PMD_INIT_LOG(INFO, "port %u starting datapath",
90                              dev->data->port_id);
91                 hns3_set_rxtx_function(dev);
92                 break;
93         case HNS3_MP_REQ_STOP_RXTX:
94                 PMD_INIT_LOG(INFO, "port %u stopping datapath",
95                              dev->data->port_id);
96                 hns3_set_rxtx_function(dev);
97                 break;
98         case HNS3_MP_REQ_START_TX:
99                 PMD_INIT_LOG(INFO, "port %u starting Tx datapath",
100                              dev->data->port_id);
101                 dev->tx_pkt_burst = hns3_get_tx_function(dev, &prep);
102                 dev->tx_pkt_prepare = prep;
103                 break;
104         case HNS3_MP_REQ_STOP_TX:
105                 PMD_INIT_LOG(INFO, "port %u stopping Tx datapath",
106                              dev->data->port_id);
107                 dev->tx_pkt_burst = hns3_dummy_rxtx_burst;
108                 dev->tx_pkt_prepare = NULL;
109                 break;
110         default:
111                 rte_errno = EINVAL;
112                 PMD_INIT_LOG(ERR, "port %u invalid mp request type",
113                              dev->data->port_id);
114                 return -rte_errno;
115         }
116
117         rte_mb();
118         mp_init_msg(dev, &mp_res, param->type);
119         res->result = 0;
120         ret = rte_mp_reply(&mp_res, peer);
121
122         return ret;
123 }
124
125 static bool
126 mp_req_type_is_valid(enum hns3_mp_req_type type)
127 {
128         return type == HNS3_MP_REQ_START_RXTX ||
129                 type == HNS3_MP_REQ_STOP_RXTX ||
130                 type == HNS3_MP_REQ_START_TX ||
131                 type == HNS3_MP_REQ_STOP_TX;
132 }
133
134 /*
135  * Broadcast request of stopping/starting data-path to secondary processes.
136  *
137  * @param[in] dev
138  *   Pointer to Ethernet structure.
139  * @param[in] type
140  *   Request type.
141  */
142 static void
143 mp_req_on_rxtx(struct rte_eth_dev *dev, enum hns3_mp_req_type type)
144 {
145         struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
146         struct rte_mp_msg mp_req;
147         struct rte_mp_msg *mp_res;
148         struct rte_mp_reply mp_rep;
149         struct hns3_mp_param *res;
150         struct timespec ts;
151         int ret;
152         int i;
153
154         if (rte_eal_process_type() == RTE_PROC_SECONDARY ||
155                 __atomic_load_n(&hw->secondary_cnt, __ATOMIC_RELAXED) == 0)
156                 return;
157
158         if (!mp_req_type_is_valid(type)) {
159                 hns3_err(hw, "port %u unknown request (req_type %d)",
160                          dev->data->port_id, type);
161                 return;
162         }
163         mp_init_msg(dev, &mp_req, type);
164         ts.tv_sec = HNS3_MP_REQ_TIMEOUT_SEC;
165         ts.tv_nsec = 0;
166         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
167         if (ret) {
168                 hns3_err(hw, "port %u failed to request stop/start Rx/Tx (%d)",
169                          dev->data->port_id, type);
170                 goto exit;
171         }
172         if (mp_rep.nb_sent != mp_rep.nb_received) {
173                 PMD_INIT_LOG(ERR,
174                         "port %u not all secondaries responded (req_type %d)",
175                         dev->data->port_id, type);
176                 goto exit;
177         }
178         for (i = 0; i < mp_rep.nb_received; i++) {
179                 mp_res = &mp_rep.msgs[i];
180                 res = (struct hns3_mp_param *)mp_res->param;
181                 if (res->result) {
182                         hns3_err(hw, "port %u request failed on secondary #%d",
183                                  dev->data->port_id, i);
184                         goto exit;
185                 }
186         }
187 exit:
188         free(mp_rep.msgs);
189 }
190
191 /*
192  * Broadcast request of starting data-path to secondary processes. The request
193  * is synchronous.
194  *
195  * @param[in] dev
196  *   Pointer to Ethernet structure.
197  */
198 void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev)
199 {
200         mp_req_on_rxtx(dev, HNS3_MP_REQ_START_RXTX);
201 }
202
203 /*
204  * Broadcast request of stopping data-path to secondary processes. The request
205  * is synchronous.
206  *
207  * @param[in] dev
208  *   Pointer to Ethernet structure.
209  */
210 void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev)
211 {
212         mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_RXTX);
213 }
214
215 void
216 hns3_mp_req_stop_tx(struct rte_eth_dev *dev)
217 {
218         mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_TX);
219 }
220
221 void
222 hns3_mp_req_start_tx(struct rte_eth_dev *dev)
223 {
224         mp_req_on_rxtx(dev, HNS3_MP_REQ_START_TX);
225 }
226
227 /*
228  * Initialize by primary process.
229  */
230 static int
231 hns3_mp_init_primary(void)
232 {
233         int ret;
234
235         if (process_data.init_done)
236                 return 0;
237
238         /* primary is allowed to not support IPC */
239         ret = rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle);
240         if (ret && rte_errno != ENOTSUP)
241                 return ret;
242
243         process_data.init_done = true;
244
245         return 0;
246 }
247
248 /*
249  * Initialize by secondary process.
250  */
251 static int
252 hns3_mp_init_secondary(void)
253 {
254         int ret;
255
256         if (process_data.init_done)
257                 return 0;
258
259         ret = rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle);
260         if (ret && rte_errno != ENOTSUP)
261                 return ret;
262
263         process_data.init_done = true;
264
265         return 0;
266 }
267
268 int
269 hns3_mp_init(struct rte_eth_dev *dev)
270 {
271         struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
272         int ret;
273
274         if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
275                 ret = hns3_mp_init_secondary();
276                 if (ret) {
277                         PMD_INIT_LOG(ERR, "Failed to init for secondary process, ret = %d",
278                                      ret);
279                         return ret;
280                 }
281                 __atomic_fetch_add(&hw->secondary_cnt, 1, __ATOMIC_RELAXED);
282         } else {
283                 ret = hns3_mp_init_primary();
284                 if (ret) {
285                         PMD_INIT_LOG(ERR, "Failed to init for primary process, ret = %d",
286                                      ret);
287                         return ret;
288                 }
289         }
290
291         process_data.eth_dev_cnt++;
292
293         return 0;
294 }
295
296 void hns3_mp_uninit(struct rte_eth_dev *dev)
297 {
298         struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
299
300         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
301                 __atomic_fetch_sub(&hw->secondary_cnt, 1, __ATOMIC_RELAXED);
302
303         process_data.eth_dev_cnt--;
304         if (process_data.eth_dev_cnt == 0) {
305                 rte_mp_action_unregister(HNS3_MP_NAME);
306                 process_data.init_done = false;
307         }
308 }