1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2019 6WIND S.A. 3 * Copyright 2019 Mellanox Technologies, Ltd 4 */ 5 6 #include <stdio.h> 7 #include <time.h> 8 9 #include <rte_eal.h> 10 #include <ethdev_driver.h> 11 #include <rte_string_fns.h> 12 13 #include <mlx5_common_mp.h> 14 #include <mlx5_common_mr.h> 15 #include <mlx5_malloc.h> 16 17 #include "mlx5.h" 18 #include "mlx5_rxtx.h" 19 #include "mlx5_rx.h" 20 #include "mlx5_tx.h" 21 #include "mlx5_utils.h" 22 23 /** 24 * Handle a port-agnostic message. 25 * 26 * @return 27 * 0 on success, 1 when message is not port-agnostic, (-1) on error. 28 */ 29 static int 30 mlx5_mp_os_handle_port_agnostic(const struct rte_mp_msg *mp_msg, 31 const void *peer) 32 { 33 struct rte_mp_msg mp_res; 34 struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param; 35 const struct mlx5_mp_param *param = 36 (const struct mlx5_mp_param *)mp_msg->param; 37 const struct mlx5_mp_arg_mr_manage *mng = ¶m->args.mr_manage; 38 struct mr_cache_entry entry; 39 uint32_t lkey; 40 41 switch (param->type) { 42 case MLX5_MP_REQ_CREATE_MR: 43 mp_init_port_agnostic_msg(&mp_res, param->type); 44 lkey = mlx5_mr_create(mng->cdev, &mng->cdev->mr_scache, &entry, 45 mng->addr); 46 if (lkey == UINT32_MAX) 47 res->result = -rte_errno; 48 return rte_mp_reply(&mp_res, peer); 49 case MLX5_MP_REQ_MEMPOOL_REGISTER: 50 mp_init_port_agnostic_msg(&mp_res, param->type); 51 res->result = mlx5_mr_mempool_register(mng->cdev, mng->mempool); 52 return rte_mp_reply(&mp_res, peer); 53 case MLX5_MP_REQ_MEMPOOL_UNREGISTER: 54 mp_init_port_agnostic_msg(&mp_res, param->type); 55 res->result = mlx5_mr_mempool_unregister(mng->cdev, 56 mng->mempool); 57 return rte_mp_reply(&mp_res, peer); 58 default: 59 return 1; 60 } 61 return -1; 62 } 63 64 int 65 mlx5_mp_os_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer) 66 { 67 struct rte_mp_msg mp_res; 68 struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param; 69 const struct mlx5_mp_param *param = 70 (const struct mlx5_mp_param *)mp_msg->param; 71 struct rte_eth_dev *dev; 72 struct mlx5_priv *priv; 73 struct mlx5_common_device *cdev; 74 int ret; 75 76 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 77 /* Port-agnostic messages. */ 78 ret = mlx5_mp_os_handle_port_agnostic(mp_msg, peer); 79 if (ret <= 0) 80 return ret; 81 /* Port-specific messages. */ 82 if (!rte_eth_dev_is_valid_port(param->port_id)) { 83 rte_errno = ENODEV; 84 DRV_LOG(ERR, "port %u invalid port ID", param->port_id); 85 return -rte_errno; 86 } 87 dev = &rte_eth_devices[param->port_id]; 88 priv = dev->data->dev_private; 89 cdev = priv->sh->cdev; 90 switch (param->type) { 91 case MLX5_MP_REQ_VERBS_CMD_FD: 92 mp_init_msg(&priv->mp_id, &mp_res, param->type); 93 mp_res.num_fds = 1; 94 mp_res.fds[0] = ((struct ibv_context *)cdev->ctx)->cmd_fd; 95 res->result = 0; 96 ret = rte_mp_reply(&mp_res, peer); 97 break; 98 case MLX5_MP_REQ_QUEUE_STATE_MODIFY: 99 mp_init_msg(&priv->mp_id, &mp_res, param->type); 100 res->result = mlx5_queue_state_modify_primary 101 (dev, ¶m->args.state_modify); 102 ret = rte_mp_reply(&mp_res, peer); 103 break; 104 case MLX5_MP_REQ_QUEUE_RX_STOP: 105 mp_init_msg(&priv->mp_id, &mp_res, param->type); 106 res->result = mlx5_rx_queue_stop_primary 107 (dev, param->args.queue_id.queue_id); 108 ret = rte_mp_reply(&mp_res, peer); 109 break; 110 case MLX5_MP_REQ_QUEUE_RX_START: 111 mp_init_msg(&priv->mp_id, &mp_res, param->type); 112 res->result = mlx5_rx_queue_start_primary 113 (dev, param->args.queue_id.queue_id); 114 ret = rte_mp_reply(&mp_res, peer); 115 break; 116 case MLX5_MP_REQ_QUEUE_TX_STOP: 117 mp_init_msg(&priv->mp_id, &mp_res, param->type); 118 res->result = mlx5_tx_queue_stop_primary 119 (dev, param->args.queue_id.queue_id); 120 ret = rte_mp_reply(&mp_res, peer); 121 break; 122 case MLX5_MP_REQ_QUEUE_TX_START: 123 mp_init_msg(&priv->mp_id, &mp_res, param->type); 124 res->result = mlx5_tx_queue_start_primary 125 (dev, param->args.queue_id.queue_id); 126 ret = rte_mp_reply(&mp_res, peer); 127 break; 128 default: 129 rte_errno = EINVAL; 130 DRV_LOG(ERR, "port %u invalid mp request type", 131 dev->data->port_id); 132 return -rte_errno; 133 } 134 return ret; 135 } 136 137 /** 138 * IPC message handler of a secondary process. 139 * 140 * @param[in] dev 141 * Pointer to Ethernet structure. 142 * @param[in] peer 143 * Pointer to the peer socket path. 144 * 145 * @return 146 * 0 on success, a negative errno value otherwise and rte_errno is set. 147 */ 148 int 149 mlx5_mp_os_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer) 150 { 151 struct rte_mp_msg mp_res; 152 struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param; 153 const struct mlx5_mp_param *param = 154 (const struct mlx5_mp_param *)mp_msg->param; 155 struct rte_eth_dev *dev; 156 struct mlx5_proc_priv *ppriv; 157 struct mlx5_priv *priv; 158 int ret; 159 160 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); 161 if (!rte_eth_dev_is_valid_port(param->port_id)) { 162 rte_errno = ENODEV; 163 DRV_LOG(ERR, "port %u invalid port ID", param->port_id); 164 return -rte_errno; 165 } 166 dev = &rte_eth_devices[param->port_id]; 167 priv = dev->data->dev_private; 168 switch (param->type) { 169 case MLX5_MP_REQ_START_RXTX: 170 DRV_LOG(INFO, "port %u starting datapath", dev->data->port_id); 171 dev->rx_pkt_burst = mlx5_select_rx_function(dev); 172 dev->tx_pkt_burst = mlx5_select_tx_function(dev); 173 ppriv = (struct mlx5_proc_priv *)dev->process_private; 174 /* If Tx queue number changes, re-initialize UAR. */ 175 if (ppriv->uar_table_sz != priv->txqs_n) { 176 mlx5_tx_uar_uninit_secondary(dev); 177 mlx5_proc_priv_uninit(dev); 178 ret = mlx5_proc_priv_init(dev); 179 if (ret) 180 return -rte_errno; 181 ret = mlx5_tx_uar_init_secondary(dev, mp_msg->fds[0]); 182 if (ret) { 183 mlx5_proc_priv_uninit(dev); 184 return -rte_errno; 185 } 186 } 187 rte_mb(); 188 mp_init_msg(&priv->mp_id, &mp_res, param->type); 189 res->result = 0; 190 ret = rte_mp_reply(&mp_res, peer); 191 break; 192 case MLX5_MP_REQ_STOP_RXTX: 193 DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id); 194 dev->rx_pkt_burst = removed_rx_burst; 195 dev->tx_pkt_burst = removed_tx_burst; 196 rte_mb(); 197 mp_init_msg(&priv->mp_id, &mp_res, param->type); 198 res->result = 0; 199 ret = rte_mp_reply(&mp_res, peer); 200 break; 201 default: 202 rte_errno = EINVAL; 203 DRV_LOG(ERR, "port %u invalid mp request type", 204 dev->data->port_id); 205 return -rte_errno; 206 } 207 return ret; 208 } 209 210 /** 211 * Broadcast request of stopping/starting data-path to secondary processes. 212 * 213 * @param[in] dev 214 * Pointer to Ethernet structure. 215 * @param[in] type 216 * Request type. 217 */ 218 static void 219 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx5_mp_req_type type) 220 { 221 struct rte_mp_msg mp_req; 222 struct rte_mp_msg *mp_res; 223 struct rte_mp_reply mp_rep; 224 struct mlx5_mp_param *res; 225 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 226 struct mlx5_priv *priv = dev->data->dev_private; 227 int ret; 228 int i; 229 230 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 231 if (!mlx5_shared_data->secondary_cnt) 232 return; 233 if (type != MLX5_MP_REQ_START_RXTX && type != MLX5_MP_REQ_STOP_RXTX) { 234 DRV_LOG(ERR, "port %u unknown request (req_type %d)", 235 dev->data->port_id, type); 236 return; 237 } 238 mp_init_msg(&priv->mp_id, &mp_req, type); 239 if (type == MLX5_MP_REQ_START_RXTX) { 240 mp_req.num_fds = 1; 241 mp_req.fds[0] = 242 ((struct ibv_context *)priv->sh->cdev->ctx)->cmd_fd; 243 } 244 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 245 if (ret) { 246 if (rte_errno != ENOTSUP) 247 DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)", 248 dev->data->port_id, type); 249 goto exit; 250 } 251 if (mp_rep.nb_sent != mp_rep.nb_received) { 252 DRV_LOG(ERR, 253 "port %u not all secondaries responded (req_type %d)", 254 dev->data->port_id, type); 255 goto exit; 256 } 257 for (i = 0; i < mp_rep.nb_received; i++) { 258 mp_res = &mp_rep.msgs[i]; 259 res = (struct mlx5_mp_param *)mp_res->param; 260 if (res->result) { 261 DRV_LOG(ERR, "port %u request failed on secondary #%d", 262 dev->data->port_id, i); 263 goto exit; 264 } 265 } 266 exit: 267 mlx5_free(mp_rep.msgs); 268 } 269 270 /** 271 * Broadcast request of starting data-path to secondary processes. The request 272 * is synchronous. 273 * 274 * @param[in] dev 275 * Pointer to Ethernet structure. 276 */ 277 void 278 mlx5_mp_os_req_start_rxtx(struct rte_eth_dev *dev) 279 { 280 mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX); 281 } 282 283 /** 284 * Broadcast request of stopping data-path to secondary processes. The request 285 * is synchronous. 286 * 287 * @param[in] dev 288 * Pointer to Ethernet structure. 289 */ 290 void 291 mlx5_mp_os_req_stop_rxtx(struct rte_eth_dev *dev) 292 { 293 mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX); 294 } 295 296 /** 297 * Request Verbs Rx/Tx queue stop or start to the primary process. 298 * 299 * @param[in] dev 300 * Pointer to Ethernet structure. 301 * @param queue_id 302 * Queue ID to control. 303 * @param req_type 304 * request type 305 * MLX5_MP_REQ_QUEUE_RX_START - start Rx queue 306 * MLX5_MP_REQ_QUEUE_TX_START - stop Tx queue 307 * MLX5_MP_REQ_QUEUE_RX_STOP - stop Rx queue 308 * MLX5_MP_REQ_QUEUE_TX_STOP - stop Tx queue 309 * @return 310 * 0 on success, a negative errno value otherwise and 311 * rte_errno is set. 312 */ 313 int 314 mlx5_mp_os_req_queue_control(struct rte_eth_dev *dev, uint16_t queue_id, 315 enum mlx5_mp_req_type req_type) 316 { 317 struct rte_mp_msg mp_req; 318 struct rte_mp_msg *mp_res; 319 struct rte_mp_reply mp_rep; 320 struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param; 321 struct mlx5_mp_param *res; 322 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 323 struct mlx5_priv *priv; 324 int ret; 325 326 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); 327 priv = dev->data->dev_private; 328 mp_init_msg(&priv->mp_id, &mp_req, req_type); 329 req->args.queue_id.queue_id = queue_id; 330 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 331 if (ret) { 332 DRV_LOG(ERR, "port %u request to primary process failed", 333 dev->data->port_id); 334 return -rte_errno; 335 } 336 MLX5_ASSERT(mp_rep.nb_received == 1); 337 mp_res = &mp_rep.msgs[0]; 338 res = (struct mlx5_mp_param *)mp_res->param; 339 ret = res->result; 340 free(mp_rep.msgs); 341 return ret; 342 } 343