1517ed6e2SLong Li /* SPDX-License-Identifier: BSD-3-Clause 2517ed6e2SLong Li * Copyright 2022 Microsoft Corporation 3517ed6e2SLong Li */ 4517ed6e2SLong Li 5517ed6e2SLong Li #include <rte_malloc.h> 6517ed6e2SLong Li #include <ethdev_driver.h> 7517ed6e2SLong Li #include <rte_log.h> 8*7649794dSLong Li #include <stdlib.h> 9517ed6e2SLong Li 10517ed6e2SLong Li #include <infiniband/verbs.h> 11517ed6e2SLong Li 12517ed6e2SLong Li #include "mana.h" 13517ed6e2SLong Li 14517ed6e2SLong Li extern struct mana_shared_data *mana_shared_data; 15517ed6e2SLong Li 160f5db3c6SLong Li /* 170f5db3c6SLong Li * Process MR request from secondary process. 180f5db3c6SLong Li */ 190f5db3c6SLong Li static int 200f5db3c6SLong Li mana_mp_mr_create(struct mana_priv *priv, uintptr_t addr, uint32_t len) 210f5db3c6SLong Li { 220f5db3c6SLong Li struct ibv_mr *ibv_mr; 230f5db3c6SLong Li int ret; 240f5db3c6SLong Li struct mana_mr_cache *mr; 250f5db3c6SLong Li 260f5db3c6SLong Li ibv_mr = ibv_reg_mr(priv->ib_pd, (void *)addr, len, 270f5db3c6SLong Li IBV_ACCESS_LOCAL_WRITE); 280f5db3c6SLong Li 290f5db3c6SLong Li if (!ibv_mr) 300f5db3c6SLong Li return -errno; 310f5db3c6SLong Li 32e2d3a3c0SLong Li DP_LOG(DEBUG, "MR (2nd) lkey %u addr %p len %zu", 330f5db3c6SLong Li ibv_mr->lkey, ibv_mr->addr, ibv_mr->length); 340f5db3c6SLong Li 350f5db3c6SLong Li mr = rte_calloc("MANA MR", 1, sizeof(*mr), 0); 360f5db3c6SLong Li if (!mr) { 370f5db3c6SLong Li DRV_LOG(ERR, "(2nd) Failed to allocate MR"); 380f5db3c6SLong Li ret = -ENOMEM; 390f5db3c6SLong Li goto fail_alloc; 400f5db3c6SLong Li } 410f5db3c6SLong Li mr->lkey = ibv_mr->lkey; 420f5db3c6SLong Li mr->addr = (uintptr_t)ibv_mr->addr; 430f5db3c6SLong Li mr->len = ibv_mr->length; 440f5db3c6SLong Li mr->verb_obj = ibv_mr; 450f5db3c6SLong Li 460f5db3c6SLong Li rte_spinlock_lock(&priv->mr_btree_lock); 470f5db3c6SLong Li ret = mana_mr_btree_insert(&priv->mr_btree, mr); 480f5db3c6SLong Li rte_spinlock_unlock(&priv->mr_btree_lock); 490f5db3c6SLong Li if (ret) { 500f5db3c6SLong Li DRV_LOG(ERR, "(2nd) Failed to add to global MR btree"); 510f5db3c6SLong Li goto fail_btree; 520f5db3c6SLong Li } 530f5db3c6SLong Li 540f5db3c6SLong Li return 0; 550f5db3c6SLong Li 560f5db3c6SLong Li fail_btree: 570f5db3c6SLong Li rte_free(mr); 580f5db3c6SLong Li 590f5db3c6SLong Li fail_alloc: 600f5db3c6SLong Li ibv_dereg_mr(ibv_mr); 610f5db3c6SLong Li 620f5db3c6SLong Li return ret; 630f5db3c6SLong Li } 640f5db3c6SLong Li 65517ed6e2SLong Li static void 66517ed6e2SLong Li mp_init_msg(struct rte_mp_msg *msg, enum mana_mp_req_type type, int port_id) 67517ed6e2SLong Li { 68517ed6e2SLong Li struct mana_mp_param *param; 69517ed6e2SLong Li 70517ed6e2SLong Li strlcpy(msg->name, MANA_MP_NAME, sizeof(msg->name)); 71517ed6e2SLong Li msg->len_param = sizeof(*param); 72517ed6e2SLong Li 73517ed6e2SLong Li param = (struct mana_mp_param *)msg->param; 74517ed6e2SLong Li param->type = type; 75517ed6e2SLong Li param->port_id = port_id; 76517ed6e2SLong Li } 77517ed6e2SLong Li 78517ed6e2SLong Li static int 79517ed6e2SLong Li mana_mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer) 80517ed6e2SLong Li { 81517ed6e2SLong Li struct rte_eth_dev *dev; 82517ed6e2SLong Li const struct mana_mp_param *param = 83517ed6e2SLong Li (const struct mana_mp_param *)mp_msg->param; 84517ed6e2SLong Li struct rte_mp_msg mp_res = { 0 }; 85517ed6e2SLong Li struct mana_mp_param *res = (struct mana_mp_param *)mp_res.param; 86517ed6e2SLong Li int ret; 87517ed6e2SLong Li struct mana_priv *priv; 88517ed6e2SLong Li 89517ed6e2SLong Li if (!rte_eth_dev_is_valid_port(param->port_id)) { 90517ed6e2SLong Li DRV_LOG(ERR, "MP handle port ID %u invalid", param->port_id); 91517ed6e2SLong Li return -ENODEV; 92517ed6e2SLong Li } 93517ed6e2SLong Li 94517ed6e2SLong Li dev = &rte_eth_devices[param->port_id]; 95517ed6e2SLong Li priv = dev->data->dev_private; 96517ed6e2SLong Li 97517ed6e2SLong Li mp_init_msg(&mp_res, param->type, param->port_id); 98517ed6e2SLong Li 99517ed6e2SLong Li switch (param->type) { 1000f5db3c6SLong Li case MANA_MP_REQ_CREATE_MR: 1010f5db3c6SLong Li ret = mana_mp_mr_create(priv, param->addr, param->len); 1020f5db3c6SLong Li res->result = ret; 1030f5db3c6SLong Li ret = rte_mp_reply(&mp_res, peer); 1040f5db3c6SLong Li break; 1050f5db3c6SLong Li 106517ed6e2SLong Li case MANA_MP_REQ_VERBS_CMD_FD: 107517ed6e2SLong Li mp_res.num_fds = 1; 108517ed6e2SLong Li mp_res.fds[0] = priv->ib_ctx->cmd_fd; 109517ed6e2SLong Li res->result = 0; 110517ed6e2SLong Li ret = rte_mp_reply(&mp_res, peer); 111517ed6e2SLong Li break; 112517ed6e2SLong Li 113517ed6e2SLong Li default: 114517ed6e2SLong Li DRV_LOG(ERR, "Port %u unknown primary MP type %u", 115517ed6e2SLong Li param->port_id, param->type); 116517ed6e2SLong Li ret = -EINVAL; 117517ed6e2SLong Li } 118517ed6e2SLong Li 119517ed6e2SLong Li return ret; 120517ed6e2SLong Li } 121517ed6e2SLong Li 122517ed6e2SLong Li static int 123517ed6e2SLong Li mana_mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer) 124517ed6e2SLong Li { 125517ed6e2SLong Li struct rte_mp_msg mp_res = { 0 }; 126517ed6e2SLong Li struct mana_mp_param *res = (struct mana_mp_param *)mp_res.param; 127517ed6e2SLong Li const struct mana_mp_param *param = 128517ed6e2SLong Li (const struct mana_mp_param *)mp_msg->param; 129517ed6e2SLong Li struct rte_eth_dev *dev; 130517ed6e2SLong Li int ret; 131517ed6e2SLong Li 132517ed6e2SLong Li if (!rte_eth_dev_is_valid_port(param->port_id)) { 133517ed6e2SLong Li DRV_LOG(ERR, "MP handle port ID %u invalid", param->port_id); 134517ed6e2SLong Li return -ENODEV; 135517ed6e2SLong Li } 136517ed6e2SLong Li 137517ed6e2SLong Li dev = &rte_eth_devices[param->port_id]; 138517ed6e2SLong Li 139517ed6e2SLong Li mp_init_msg(&mp_res, param->type, param->port_id); 140517ed6e2SLong Li 141517ed6e2SLong Li switch (param->type) { 142517ed6e2SLong Li case MANA_MP_REQ_START_RXTX: 143517ed6e2SLong Li DRV_LOG(INFO, "Port %u starting datapath", dev->data->port_id); 144517ed6e2SLong Li 1457f322844SLong Li dev->tx_pkt_burst = mana_tx_burst; 146eb9994ddSLong Li dev->rx_pkt_burst = mana_rx_burst; 147eb9994ddSLong Li 148517ed6e2SLong Li rte_mb(); 149517ed6e2SLong Li 150517ed6e2SLong Li res->result = 0; 151517ed6e2SLong Li ret = rte_mp_reply(&mp_res, peer); 152517ed6e2SLong Li break; 153517ed6e2SLong Li 154517ed6e2SLong Li case MANA_MP_REQ_STOP_RXTX: 155517ed6e2SLong Li DRV_LOG(INFO, "Port %u stopping datapath", dev->data->port_id); 156517ed6e2SLong Li 157517ed6e2SLong Li dev->tx_pkt_burst = mana_tx_burst_removed; 158517ed6e2SLong Li dev->rx_pkt_burst = mana_rx_burst_removed; 159517ed6e2SLong Li 160517ed6e2SLong Li rte_mb(); 161517ed6e2SLong Li 162517ed6e2SLong Li res->result = 0; 163517ed6e2SLong Li ret = rte_mp_reply(&mp_res, peer); 164517ed6e2SLong Li break; 165517ed6e2SLong Li 166517ed6e2SLong Li default: 167517ed6e2SLong Li DRV_LOG(ERR, "Port %u unknown secondary MP type %u", 168517ed6e2SLong Li param->port_id, param->type); 169517ed6e2SLong Li ret = -EINVAL; 170517ed6e2SLong Li } 171517ed6e2SLong Li 172517ed6e2SLong Li return ret; 173517ed6e2SLong Li } 174517ed6e2SLong Li 175517ed6e2SLong Li int 176517ed6e2SLong Li mana_mp_init_primary(void) 177517ed6e2SLong Li { 178517ed6e2SLong Li int ret; 179517ed6e2SLong Li 180517ed6e2SLong Li ret = rte_mp_action_register(MANA_MP_NAME, mana_mp_primary_handle); 181517ed6e2SLong Li if (ret && rte_errno != ENOTSUP) { 182517ed6e2SLong Li DRV_LOG(ERR, "Failed to register primary handler %d %d", 183517ed6e2SLong Li ret, rte_errno); 184517ed6e2SLong Li return -1; 185517ed6e2SLong Li } 186517ed6e2SLong Li 187517ed6e2SLong Li return 0; 188517ed6e2SLong Li } 189517ed6e2SLong Li 190517ed6e2SLong Li void 191517ed6e2SLong Li mana_mp_uninit_primary(void) 192517ed6e2SLong Li { 193517ed6e2SLong Li rte_mp_action_unregister(MANA_MP_NAME); 194517ed6e2SLong Li } 195517ed6e2SLong Li 196517ed6e2SLong Li int 197517ed6e2SLong Li mana_mp_init_secondary(void) 198517ed6e2SLong Li { 199517ed6e2SLong Li return rte_mp_action_register(MANA_MP_NAME, mana_mp_secondary_handle); 200517ed6e2SLong Li } 201517ed6e2SLong Li 202517ed6e2SLong Li void 203517ed6e2SLong Li mana_mp_uninit_secondary(void) 204517ed6e2SLong Li { 205517ed6e2SLong Li rte_mp_action_unregister(MANA_MP_NAME); 206517ed6e2SLong Li } 207517ed6e2SLong Li 208517ed6e2SLong Li int 209517ed6e2SLong Li mana_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev) 210517ed6e2SLong Li { 211517ed6e2SLong Li struct rte_mp_msg mp_req = { 0 }; 212517ed6e2SLong Li struct rte_mp_msg *mp_res; 213517ed6e2SLong Li struct rte_mp_reply mp_rep; 214517ed6e2SLong Li struct mana_mp_param *res; 215517ed6e2SLong Li struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 216517ed6e2SLong Li int ret; 217517ed6e2SLong Li 218517ed6e2SLong Li mp_init_msg(&mp_req, MANA_MP_REQ_VERBS_CMD_FD, dev->data->port_id); 219517ed6e2SLong Li 220517ed6e2SLong Li ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 221517ed6e2SLong Li if (ret) { 222517ed6e2SLong Li DRV_LOG(ERR, "port %u request to primary process failed", 223517ed6e2SLong Li dev->data->port_id); 224517ed6e2SLong Li return ret; 225517ed6e2SLong Li } 226517ed6e2SLong Li 227517ed6e2SLong Li if (mp_rep.nb_received != 1) { 228517ed6e2SLong Li DRV_LOG(ERR, "primary replied %u messages", mp_rep.nb_received); 229517ed6e2SLong Li ret = -EPROTO; 230517ed6e2SLong Li goto exit; 231517ed6e2SLong Li } 232517ed6e2SLong Li 233517ed6e2SLong Li mp_res = &mp_rep.msgs[0]; 234517ed6e2SLong Li res = (struct mana_mp_param *)mp_res->param; 235517ed6e2SLong Li if (res->result) { 236517ed6e2SLong Li DRV_LOG(ERR, "failed to get CMD FD, port %u", 237517ed6e2SLong Li dev->data->port_id); 238517ed6e2SLong Li ret = res->result; 239517ed6e2SLong Li goto exit; 240517ed6e2SLong Li } 241517ed6e2SLong Li 242517ed6e2SLong Li if (mp_res->num_fds != 1) { 243517ed6e2SLong Li DRV_LOG(ERR, "got FDs %d unexpected", mp_res->num_fds); 244517ed6e2SLong Li ret = -EPROTO; 245517ed6e2SLong Li goto exit; 246517ed6e2SLong Li } 247517ed6e2SLong Li 248517ed6e2SLong Li ret = mp_res->fds[0]; 249517ed6e2SLong Li DRV_LOG(ERR, "port %u command FD from primary is %d", 250517ed6e2SLong Li dev->data->port_id, ret); 251517ed6e2SLong Li exit: 252517ed6e2SLong Li free(mp_rep.msgs); 253517ed6e2SLong Li return ret; 254517ed6e2SLong Li } 255517ed6e2SLong Li 2560f5db3c6SLong Li /* 2570f5db3c6SLong Li * Request the primary process to register a MR. 2580f5db3c6SLong Li */ 2590f5db3c6SLong Li int 2600f5db3c6SLong Li mana_mp_req_mr_create(struct mana_priv *priv, uintptr_t addr, uint32_t len) 2610f5db3c6SLong Li { 2620f5db3c6SLong Li struct rte_mp_msg mp_req = {0}; 2630f5db3c6SLong Li struct rte_mp_msg *mp_res; 2640f5db3c6SLong Li struct rte_mp_reply mp_rep; 2650f5db3c6SLong Li struct mana_mp_param *req = (struct mana_mp_param *)mp_req.param; 2660f5db3c6SLong Li struct mana_mp_param *res; 2670f5db3c6SLong Li struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 2680f5db3c6SLong Li int ret; 2690f5db3c6SLong Li 2700f5db3c6SLong Li mp_init_msg(&mp_req, MANA_MP_REQ_CREATE_MR, priv->port_id); 2710f5db3c6SLong Li req->addr = addr; 2720f5db3c6SLong Li req->len = len; 2730f5db3c6SLong Li 2740f5db3c6SLong Li ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 2750f5db3c6SLong Li if (ret) { 2760f5db3c6SLong Li DRV_LOG(ERR, "Port %u request to primary failed", 2770f5db3c6SLong Li req->port_id); 2780f5db3c6SLong Li return ret; 2790f5db3c6SLong Li } 2800f5db3c6SLong Li 2810f5db3c6SLong Li if (mp_rep.nb_received != 1) 2820f5db3c6SLong Li return -EPROTO; 2830f5db3c6SLong Li 2840f5db3c6SLong Li mp_res = &mp_rep.msgs[0]; 2850f5db3c6SLong Li res = (struct mana_mp_param *)mp_res->param; 2860f5db3c6SLong Li ret = res->result; 2870f5db3c6SLong Li 2880f5db3c6SLong Li free(mp_rep.msgs); 2890f5db3c6SLong Li 2900f5db3c6SLong Li return ret; 2910f5db3c6SLong Li } 2920f5db3c6SLong Li 293517ed6e2SLong Li void 294517ed6e2SLong Li mana_mp_req_on_rxtx(struct rte_eth_dev *dev, enum mana_mp_req_type type) 295517ed6e2SLong Li { 296517ed6e2SLong Li struct rte_mp_msg mp_req = { 0 }; 297517ed6e2SLong Li struct rte_mp_msg *mp_res; 298517ed6e2SLong Li struct rte_mp_reply mp_rep; 299517ed6e2SLong Li struct mana_mp_param *res; 300517ed6e2SLong Li struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; 301517ed6e2SLong Li int i, ret; 302517ed6e2SLong Li 303517ed6e2SLong Li if (type != MANA_MP_REQ_START_RXTX && type != MANA_MP_REQ_STOP_RXTX) { 304517ed6e2SLong Li DRV_LOG(ERR, "port %u unknown request (req_type %d)", 305517ed6e2SLong Li dev->data->port_id, type); 306517ed6e2SLong Li return; 307517ed6e2SLong Li } 308517ed6e2SLong Li 309517ed6e2SLong Li if (!mana_shared_data->secondary_cnt) 310517ed6e2SLong Li return; 311517ed6e2SLong Li 312517ed6e2SLong Li mp_init_msg(&mp_req, type, dev->data->port_id); 313517ed6e2SLong Li 314517ed6e2SLong Li ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); 315517ed6e2SLong Li if (ret) { 316517ed6e2SLong Li if (rte_errno != ENOTSUP) 317517ed6e2SLong Li DRV_LOG(ERR, "port %u failed to request Rx/Tx (%d)", 318517ed6e2SLong Li dev->data->port_id, type); 319517ed6e2SLong Li goto exit; 320517ed6e2SLong Li } 321517ed6e2SLong Li if (mp_rep.nb_sent != mp_rep.nb_received) { 322517ed6e2SLong Li DRV_LOG(ERR, "port %u not all secondaries responded (%d)", 323517ed6e2SLong Li dev->data->port_id, type); 324517ed6e2SLong Li goto exit; 325517ed6e2SLong Li } 326517ed6e2SLong Li for (i = 0; i < mp_rep.nb_received; i++) { 327517ed6e2SLong Li mp_res = &mp_rep.msgs[i]; 328517ed6e2SLong Li res = (struct mana_mp_param *)mp_res->param; 329517ed6e2SLong Li if (res->result) { 330517ed6e2SLong Li DRV_LOG(ERR, "port %u request failed on secondary %d", 331517ed6e2SLong Li dev->data->port_id, i); 332517ed6e2SLong Li goto exit; 333517ed6e2SLong Li } 334517ed6e2SLong Li } 335517ed6e2SLong Li exit: 336517ed6e2SLong Li free(mp_rep.msgs); 337517ed6e2SLong Li } 338