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