net/hns3: check multi-process action register result
[dpdk.git] / drivers / net / hns3 / hns3_mp.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2019 Hisilicon Limited.
3  */
4
5 #include <stdbool.h>
6
7 #include <rte_eal.h>
8 #include <rte_ethdev_driver.h>
9 #include <rte_string_fns.h>
10 #include <rte_io.h>
11
12 #include "hns3_ethdev.h"
13 #include "hns3_logs.h"
14 #include "hns3_rxtx.h"
15 #include "hns3_mp.h"
16
17 static bool hns3_inited;
18
19 /*
20  * Initialize IPC message.
21  *
22  * @param[in] dev
23  *   Pointer to Ethernet structure.
24  * @param[out] msg
25  *   Pointer to message to fill in.
26  * @param[in] type
27  *   Message type.
28  */
29 static inline void
30 mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
31             enum hns3_mp_req_type type)
32 {
33         struct hns3_mp_param *param = (struct hns3_mp_param *)msg->param;
34
35         memset(msg, 0, sizeof(*msg));
36         strlcpy(msg->name, HNS3_MP_NAME, sizeof(msg->name));
37         msg->len_param = sizeof(*param);
38         param->type = type;
39         param->port_id = dev->data->port_id;
40 }
41
42 /*
43  * IPC message handler of primary process.
44  *
45  * @param[in] dev
46  *   Pointer to Ethernet structure.
47  * @param[in] peer
48  *   Pointer to the peer socket path.
49  *
50  * @return
51  *   0 on success, a negative errno value otherwise and rte_errno is set.
52  */
53 static int
54 mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
55                   const void *peer __rte_unused)
56 {
57         return 0;
58 }
59
60 /*
61  * IPC message handler of a secondary process.
62  *
63  * @param[in] dev
64  *   Pointer to Ethernet structure.
65  * @param[in] peer
66  *   Pointer to the peer socket path.
67  *
68  * @return
69  *   0 on success, a negative errno value otherwise and rte_errno is set.
70  */
71 static int
72 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
73 {
74         struct rte_mp_msg mp_res;
75         struct hns3_mp_param *res = (struct hns3_mp_param *)mp_res.param;
76         const struct hns3_mp_param *param =
77                 (const struct hns3_mp_param *)mp_msg->param;
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 %u 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                 rte_mb();
92                 hns3_set_rxtx_function(dev);
93                 mp_init_msg(dev, &mp_res, param->type);
94                 res->result = 0;
95                 ret = rte_mp_reply(&mp_res, peer);
96                 break;
97         case HNS3_MP_REQ_STOP_RXTX:
98                 PMD_INIT_LOG(INFO, "port %u stopping datapath",
99                              dev->data->port_id);
100                 hns3_set_rxtx_function(dev);
101                 rte_mb();
102                 mp_init_msg(dev, &mp_res, param->type);
103                 res->result = 0;
104                 ret = rte_mp_reply(&mp_res, peer);
105                 break;
106         default:
107                 rte_errno = EINVAL;
108                 PMD_INIT_LOG(ERR, "port %u invalid mp request type",
109                              dev->data->port_id);
110                 return -rte_errno;
111         }
112         return ret;
113 }
114
115 /*
116  * Broadcast request of stopping/starting data-path to secondary processes.
117  *
118  * @param[in] dev
119  *   Pointer to Ethernet structure.
120  * @param[in] type
121  *   Request type.
122  */
123 static void
124 mp_req_on_rxtx(struct rte_eth_dev *dev, enum hns3_mp_req_type type)
125 {
126         struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
127         struct rte_mp_msg mp_req;
128         struct rte_mp_msg *mp_res;
129         struct rte_mp_reply mp_rep;
130         struct hns3_mp_param *res;
131         struct timespec ts;
132         int ret;
133         int i;
134
135         if (!hw->secondary_cnt)
136                 return;
137         if (type != HNS3_MP_REQ_START_RXTX && type != HNS3_MP_REQ_STOP_RXTX) {
138                 hns3_err(hw, "port %u unknown request (req_type %d)",
139                          dev->data->port_id, type);
140                 return;
141         }
142         mp_init_msg(dev, &mp_req, type);
143         ts.tv_sec = HNS3_MP_REQ_TIMEOUT_SEC;
144         ts.tv_nsec = 0;
145         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
146         if (ret) {
147                 hns3_err(hw, "port %u failed to request stop/start Rx/Tx (%d)",
148                          dev->data->port_id, type);
149                 goto exit;
150         }
151         if (mp_rep.nb_sent != mp_rep.nb_received) {
152                 PMD_INIT_LOG(ERR,
153                         "port %u not all secondaries responded (req_type %d)",
154                         dev->data->port_id, type);
155                 goto exit;
156         }
157         for (i = 0; i < mp_rep.nb_received; i++) {
158                 mp_res = &mp_rep.msgs[i];
159                 res = (struct hns3_mp_param *)mp_res->param;
160                 if (res->result) {
161                         hns3_err(hw, "port %u request failed on secondary #%d",
162                                  dev->data->port_id, i);
163                         goto exit;
164                 }
165         }
166 exit:
167         free(mp_rep.msgs);
168 }
169
170 /*
171  * Broadcast request of starting data-path to secondary processes. The request
172  * is synchronous.
173  *
174  * @param[in] dev
175  *   Pointer to Ethernet structure.
176  */
177 void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev)
178 {
179         mp_req_on_rxtx(dev, HNS3_MP_REQ_START_RXTX);
180 }
181
182 /*
183  * Broadcast request of stopping data-path to secondary processes. The request
184  * is synchronous.
185  *
186  * @param[in] dev
187  *   Pointer to Ethernet structure.
188  */
189 void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev)
190 {
191         mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_RXTX);
192 }
193
194 /*
195  * Initialize by primary process.
196  */
197 int hns3_mp_init_primary(void)
198 {
199         int ret;
200
201         if (!hns3_inited) {
202                 /* primary is allowed to not support IPC */
203                 ret = rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle);
204                 if (ret && rte_errno != ENOTSUP)
205                         return ret;
206
207                 hns3_inited = true;
208         }
209
210         return 0;
211 }
212
213 /*
214  * Un-initialize by primary process.
215  */
216 void hns3_mp_uninit_primary(void)
217 {
218         if (hns3_inited)
219                 rte_mp_action_unregister(HNS3_MP_NAME);
220 }
221
222 /*
223  * Initialize by secondary process.
224  */
225 int hns3_mp_init_secondary(void)
226 {
227         int ret;
228
229         if (!hns3_inited) {
230                 ret = rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle);
231                 if (ret)
232                         return ret;
233
234                 hns3_inited = true;
235         }
236
237         return 0;
238 }