1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018-2019 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 struct rte_eth_dev *dev; 77 int ret; 78 79 if (!rte_eth_dev_is_valid_port(param->port_id)) { 80 rte_errno = ENODEV; 81 PMD_INIT_LOG(ERR, "port %d invalid port ID", param->port_id); 82 return -rte_errno; 83 } 84 dev = &rte_eth_devices[param->port_id]; 85 switch (param->type) { 86 case HNS3_MP_REQ_START_RXTX: 87 PMD_INIT_LOG(INFO, "port %u starting datapath", 88 dev->data->port_id); 89 rte_mb(); 90 hns3_set_rxtx_function(dev); 91 mp_init_msg(dev, &mp_res, param->type); 92 res->result = 0; 93 ret = rte_mp_reply(&mp_res, peer); 94 break; 95 case HNS3_MP_REQ_STOP_RXTX: 96 PMD_INIT_LOG(INFO, "port %u stopping datapath", 97 dev->data->port_id); 98 hns3_set_rxtx_function(dev); 99 rte_mb(); 100 mp_init_msg(dev, &mp_res, param->type); 101 res->result = 0; 102 ret = rte_mp_reply(&mp_res, peer); 103 break; 104 default: 105 rte_errno = EINVAL; 106 PMD_INIT_LOG(ERR, "port %u invalid mp request type", 107 dev->data->port_id); 108 return -rte_errno; 109 } 110 return ret; 111 } 112 113 /* 114 * Broadcast request of stopping/starting data-path to secondary processes. 115 * 116 * @param[in] dev 117 * Pointer to Ethernet structure. 118 * @param[in] type 119 * Request type. 120 */ 121 static void 122 mp_req_on_rxtx(struct rte_eth_dev *dev, enum hns3_mp_req_type type) 123 { 124 struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private); 125 struct rte_mp_msg mp_req; 126 struct rte_mp_msg *mp_res; 127 struct rte_mp_reply mp_rep; 128 struct hns3_mp_param *res; 129 struct timespec ts; 130 int ret; 131 int i; 132 133 if (!hw->secondary_cnt) 134 return; 135 if (type != HNS3_MP_REQ_START_RXTX && type != HNS3_MP_REQ_STOP_RXTX) { 136 hns3_err(hw, "port %u unknown request (req_type %d)", 137 dev->data->port_id, type); 138 return; 139 } 140 mp_init_msg(dev, &mp_req, type); 141 ts.tv_sec = HNS3_MP_REQ_TIMEOUT_SEC; 142 ts.tv_nsec = 0; 143 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 144 if (ret) { 145 hns3_err(hw, "port %u failed to request stop/start Rx/Tx (%d)", 146 dev->data->port_id, type); 147 goto exit; 148 } 149 if (mp_rep.nb_sent != mp_rep.nb_received) { 150 PMD_INIT_LOG(ERR, 151 "port %u not all secondaries responded (req_type %d)", 152 dev->data->port_id, type); 153 goto exit; 154 } 155 for (i = 0; i < mp_rep.nb_received; i++) { 156 mp_res = &mp_rep.msgs[i]; 157 res = (struct hns3_mp_param *)mp_res->param; 158 if (res->result) { 159 hns3_err(hw, "port %u request failed on secondary #%d", 160 dev->data->port_id, i); 161 goto exit; 162 } 163 } 164 exit: 165 free(mp_rep.msgs); 166 } 167 168 /* 169 * Broadcast request of starting data-path to secondary processes. The request 170 * is synchronous. 171 * 172 * @param[in] dev 173 * Pointer to Ethernet structure. 174 */ 175 void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev) 176 { 177 mp_req_on_rxtx(dev, HNS3_MP_REQ_START_RXTX); 178 } 179 180 /* 181 * Broadcast request of stopping data-path to secondary processes. The request 182 * is synchronous. 183 * 184 * @param[in] dev 185 * Pointer to Ethernet structure. 186 */ 187 void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev) 188 { 189 mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_RXTX); 190 } 191 192 /* 193 * Initialize by primary process. 194 */ 195 int hns3_mp_init_primary(void) 196 { 197 int ret; 198 199 if (!hns3_inited) { 200 /* primary is allowed to not support IPC */ 201 ret = rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle); 202 if (ret && rte_errno != ENOTSUP) 203 return ret; 204 205 hns3_inited = true; 206 } 207 208 return 0; 209 } 210 211 /* 212 * Un-initialize by primary process. 213 */ 214 void hns3_mp_uninit_primary(void) 215 { 216 if (hns3_inited) 217 rte_mp_action_unregister(HNS3_MP_NAME); 218 } 219 220 /* 221 * Initialize by secondary process. 222 */ 223 int hns3_mp_init_secondary(void) 224 { 225 int ret; 226 227 if (!hns3_inited) { 228 ret = rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle); 229 if (ret) 230 return ret; 231 232 hns3_inited = true; 233 } 234 235 return 0; 236 } 237