numam-dpdk/drivers/net/hns3/hns3_mp.c
Huisong Li 69f9b420d8 net/hns3: add Tx start/stop multi-process handling
Currently, hns3 PMD has supported start/stop RxTx datapath request message
between the primary and secondary processes. However, there are some cases
only to start/stop Tx datapath. This patch adds start/stop Tx datapath
request for MP.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
2021-08-17 12:59:00 +02:00

269 lines
5.9 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2018-2021 HiSilicon Limited.
*/
#include <rte_eal.h>
#include <ethdev_driver.h>
#include <rte_string_fns.h>
#include <rte_io.h>
#include "hns3_ethdev.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_mp.h"
static bool hns3_inited;
/*
* Initialize IPC message.
*
* @param[in] dev
* Pointer to Ethernet structure.
* @param[out] msg
* Pointer to message to fill in.
* @param[in] type
* Message type.
*/
static inline void
mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
enum hns3_mp_req_type type)
{
struct hns3_mp_param *param = (struct hns3_mp_param *)msg->param;
memset(msg, 0, sizeof(*msg));
strlcpy(msg->name, HNS3_MP_NAME, sizeof(msg->name));
msg->len_param = sizeof(*param);
param->type = type;
param->port_id = dev->data->port_id;
}
/*
* IPC message handler of primary process.
*
* @param[in] dev
* Pointer to Ethernet structure.
* @param[in] peer
* Pointer to the peer socket path.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
const void *peer __rte_unused)
{
return 0;
}
/*
* IPC message handler of a secondary process.
*
* @param[in] dev
* Pointer to Ethernet structure.
* @param[in] peer
* Pointer to the peer socket path.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
{
struct rte_mp_msg mp_res;
struct hns3_mp_param *res = (struct hns3_mp_param *)mp_res.param;
const struct hns3_mp_param *param =
(const struct hns3_mp_param *)mp_msg->param;
eth_tx_prep_t prep = NULL;
struct rte_eth_dev *dev;
int ret;
if (!rte_eth_dev_is_valid_port(param->port_id)) {
rte_errno = ENODEV;
PMD_INIT_LOG(ERR, "port %d invalid port ID", param->port_id);
return -rte_errno;
}
dev = &rte_eth_devices[param->port_id];
switch (param->type) {
case HNS3_MP_REQ_START_RXTX:
PMD_INIT_LOG(INFO, "port %u starting datapath",
dev->data->port_id);
hns3_set_rxtx_function(dev);
break;
case HNS3_MP_REQ_STOP_RXTX:
PMD_INIT_LOG(INFO, "port %u stopping datapath",
dev->data->port_id);
hns3_set_rxtx_function(dev);
break;
case HNS3_MP_REQ_START_TX:
PMD_INIT_LOG(INFO, "port %u starting Tx datapath",
dev->data->port_id);
dev->tx_pkt_burst = hns3_get_tx_function(dev, &prep);
dev->tx_pkt_prepare = prep;
break;
case HNS3_MP_REQ_STOP_TX:
PMD_INIT_LOG(INFO, "port %u stopping Tx datapath",
dev->data->port_id);
dev->tx_pkt_burst = hns3_dummy_rxtx_burst;
dev->tx_pkt_prepare = NULL;
break;
default:
rte_errno = EINVAL;
PMD_INIT_LOG(ERR, "port %u invalid mp request type",
dev->data->port_id);
return -rte_errno;
}
rte_mb();
mp_init_msg(dev, &mp_res, param->type);
res->result = 0;
ret = rte_mp_reply(&mp_res, peer);
return ret;
}
static bool
mp_req_type_is_valid(enum hns3_mp_req_type type)
{
return type == HNS3_MP_REQ_START_RXTX ||
type == HNS3_MP_REQ_STOP_RXTX ||
type == HNS3_MP_REQ_START_TX ||
type == HNS3_MP_REQ_STOP_TX;
}
/*
* Broadcast request of stopping/starting data-path to secondary processes.
*
* @param[in] dev
* Pointer to Ethernet structure.
* @param[in] type
* Request type.
*/
static void
mp_req_on_rxtx(struct rte_eth_dev *dev, enum hns3_mp_req_type type)
{
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct rte_mp_msg mp_req;
struct rte_mp_msg *mp_res;
struct rte_mp_reply mp_rep;
struct hns3_mp_param *res;
struct timespec ts;
int ret;
int i;
if (rte_eal_process_type() == RTE_PROC_SECONDARY || !hw->secondary_cnt)
return;
if (!mp_req_type_is_valid(type)) {
hns3_err(hw, "port %u unknown request (req_type %d)",
dev->data->port_id, type);
return;
}
mp_init_msg(dev, &mp_req, type);
ts.tv_sec = HNS3_MP_REQ_TIMEOUT_SEC;
ts.tv_nsec = 0;
ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
if (ret) {
hns3_err(hw, "port %u failed to request stop/start Rx/Tx (%d)",
dev->data->port_id, type);
goto exit;
}
if (mp_rep.nb_sent != mp_rep.nb_received) {
PMD_INIT_LOG(ERR,
"port %u not all secondaries responded (req_type %d)",
dev->data->port_id, type);
goto exit;
}
for (i = 0; i < mp_rep.nb_received; i++) {
mp_res = &mp_rep.msgs[i];
res = (struct hns3_mp_param *)mp_res->param;
if (res->result) {
hns3_err(hw, "port %u request failed on secondary #%d",
dev->data->port_id, i);
goto exit;
}
}
exit:
free(mp_rep.msgs);
}
/*
* Broadcast request of starting data-path to secondary processes. The request
* is synchronous.
*
* @param[in] dev
* Pointer to Ethernet structure.
*/
void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev)
{
mp_req_on_rxtx(dev, HNS3_MP_REQ_START_RXTX);
}
/*
* Broadcast request of stopping data-path to secondary processes. The request
* is synchronous.
*
* @param[in] dev
* Pointer to Ethernet structure.
*/
void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev)
{
mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_RXTX);
}
void
hns3_mp_req_stop_tx(struct rte_eth_dev *dev)
{
mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_TX);
}
void
hns3_mp_req_start_tx(struct rte_eth_dev *dev)
{
mp_req_on_rxtx(dev, HNS3_MP_REQ_START_TX);
}
/*
* Initialize by primary process.
*/
int hns3_mp_init_primary(void)
{
int ret;
if (!hns3_inited) {
/* primary is allowed to not support IPC */
ret = rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle);
if (ret && rte_errno != ENOTSUP)
return ret;
hns3_inited = true;
}
return 0;
}
/*
* Un-initialize by primary process.
*/
void hns3_mp_uninit_primary(void)
{
if (hns3_inited)
rte_mp_action_unregister(HNS3_MP_NAME);
}
/*
* Initialize by secondary process.
*/
int hns3_mp_init_secondary(void)
{
int ret;
if (!hns3_inited) {
ret = rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle);
if (ret)
return ret;
hns3_inited = true;
}
return 0;
}