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