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