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 <rte_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_priv *priv; 119 int ret; 120 121 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); 122 if (!rte_eth_dev_is_valid_port(param->port_id)) { 123 rte_errno = ENODEV; 124 DRV_LOG(ERR, "port %u invalid port ID", param->port_id); 125 return -rte_errno; 126 } 127 dev = &rte_eth_devices[param->port_id]; 128 priv = dev->data->dev_private; 129 switch (param->type) { 130 case MLX5_MP_REQ_START_RXTX: 131 DRV_LOG(INFO, "port %u starting datapath", dev->data->port_id); 132 rte_mb(); 133 dev->rx_pkt_burst = mlx5_select_rx_function(dev); 134 dev->tx_pkt_burst = mlx5_select_tx_function(dev); 135 mp_init_msg(&priv->mp_id, &mp_res, param->type); 136 res->result = 0; 137 ret = rte_mp_reply(&mp_res, peer); 138 break; 139 case MLX5_MP_REQ_STOP_RXTX: 140 DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id); 141 dev->rx_pkt_burst = removed_rx_burst; 142 dev->tx_pkt_burst = removed_tx_burst; 143 rte_mb(); 144 mp_init_msg(&priv->mp_id, &mp_res, param->type); 145 res->result = 0; 146 ret = rte_mp_reply(&mp_res, peer); 147 break; 148 default: 149 rte_errno = EINVAL; 150 DRV_LOG(ERR, "port %u invalid mp request type", 151 dev->data->port_id); 152 return -rte_errno; 153 } 154 return ret; 155 } 156 157 /** 158 * Broadcast request of stopping/starting data-path to secondary processes. 159 * 160 * @param[in] dev 161 * Pointer to Ethernet structure. 162 * @param[in] type 163 * Request type. 164 */ 165 static void 166 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx5_mp_req_type type) 167 { 168 struct rte_mp_msg mp_req; 169 struct rte_mp_msg *mp_res; 170 struct rte_mp_reply mp_rep; 171 struct mlx5_mp_param *res; 172 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 173 struct mlx5_priv *priv = dev->data->dev_private; 174 int ret; 175 int i; 176 177 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 178 if (!mlx5_shared_data->secondary_cnt) 179 return; 180 if (type != MLX5_MP_REQ_START_RXTX && type != MLX5_MP_REQ_STOP_RXTX) { 181 DRV_LOG(ERR, "port %u unknown request (req_type %d)", 182 dev->data->port_id, type); 183 return; 184 } 185 mp_init_msg(&priv->mp_id, &mp_req, type); 186 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 187 if (ret) { 188 if (rte_errno != ENOTSUP) 189 DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)", 190 dev->data->port_id, type); 191 goto exit; 192 } 193 if (mp_rep.nb_sent != mp_rep.nb_received) { 194 DRV_LOG(ERR, 195 "port %u not all secondaries responded (req_type %d)", 196 dev->data->port_id, type); 197 goto exit; 198 } 199 for (i = 0; i < mp_rep.nb_received; i++) { 200 mp_res = &mp_rep.msgs[i]; 201 res = (struct mlx5_mp_param *)mp_res->param; 202 if (res->result) { 203 DRV_LOG(ERR, "port %u request failed on secondary #%d", 204 dev->data->port_id, i); 205 goto exit; 206 } 207 } 208 exit: 209 mlx5_free(mp_rep.msgs); 210 } 211 212 /** 213 * Broadcast request of starting data-path to secondary processes. The request 214 * is synchronous. 215 * 216 * @param[in] dev 217 * Pointer to Ethernet structure. 218 */ 219 void 220 mlx5_mp_os_req_start_rxtx(struct rte_eth_dev *dev) 221 { 222 mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX); 223 } 224 225 /** 226 * Broadcast request of stopping data-path to secondary processes. The request 227 * is synchronous. 228 * 229 * @param[in] dev 230 * Pointer to Ethernet structure. 231 */ 232 void 233 mlx5_mp_os_req_stop_rxtx(struct rte_eth_dev *dev) 234 { 235 mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX); 236 } 237 238 /** 239 * Request Verbs Rx/Tx queue stop or start to the primary process. 240 * 241 * @param[in] dev 242 * Pointer to Ethernet structure. 243 * @param queue_id 244 * Queue ID to control. 245 * @param req_type 246 * request type 247 * MLX5_MP_REQ_QUEUE_RX_START - start Rx queue 248 * MLX5_MP_REQ_QUEUE_TX_START - stop Tx queue 249 * MLX5_MP_REQ_QUEUE_RX_STOP - stop Rx queue 250 * MLX5_MP_REQ_QUEUE_TX_STOP - stop Tx queue 251 * @return 252 * 0 on success, a negative errno value otherwise and 253 * rte_errno is set. 254 */ 255 int 256 mlx5_mp_os_req_queue_control(struct rte_eth_dev *dev, uint16_t queue_id, 257 enum mlx5_mp_req_type req_type) 258 { 259 struct rte_mp_msg mp_req; 260 struct rte_mp_msg *mp_res; 261 struct rte_mp_reply mp_rep; 262 struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param; 263 struct mlx5_mp_param *res; 264 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 265 struct mlx5_priv *priv; 266 int ret; 267 268 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); 269 priv = dev->data->dev_private; 270 mp_init_msg(&priv->mp_id, &mp_req, req_type); 271 req->args.queue_id.queue_id = queue_id; 272 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 273 if (ret) { 274 DRV_LOG(ERR, "port %u request to primary process failed", 275 dev->data->port_id); 276 return -rte_errno; 277 } 278 MLX5_ASSERT(mp_rep.nb_received == 1); 279 mp_res = &mp_rep.msgs[0]; 280 res = (struct mlx5_mp_param *)mp_res->param; 281 ret = res->result; 282 free(mp_rep.msgs); 283 return ret; 284 } 285