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