diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile index fede05dec5..cbbbe042e5 100644 --- a/drivers/net/hns3/Makefile +++ b/drivers/net/hns3/Makefile @@ -10,6 +10,12 @@ LIB = librte_pmd_hns3.a CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) +CFLAGS += -DALLOW_EXPERIMENTAL_API +# Experimantal APIs: +# - rte_mp_action_register +# - rte_mp_action_unregister +# - rte_mp_reply +# - rte_mp_request_sync LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring LDLIBS += -lrte_ethdev -lrte_net -lrte_hash @@ -34,5 +40,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_intr.c SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_stats.c SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_regs.c SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c +SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_mp.c include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c index acbb5265f4..862a717fdf 100644 --- a/drivers/net/hns3/hns3_ethdev.c +++ b/drivers/net/hns3/hns3_ethdev.c @@ -29,6 +29,7 @@ #include "hns3_intr.h" #include "hns3_regs.h" #include "hns3_dcb.h" +#include "hns3_mp.h" #define HNS3_DEFAULT_PORT_CONF_BURST_SIZE 32 #define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1 @@ -4036,6 +4037,7 @@ hns3_dev_start(struct rte_eth_dev *eth_dev) hw->adapter_state = HNS3_NIC_STARTED; rte_spinlock_unlock(&hw->lock); hns3_set_rxtx_function(eth_dev); + hns3_mp_req_start_rxtx(eth_dev); hns3_info(hw, "hns3 dev start successful!"); return 0; @@ -4072,6 +4074,11 @@ hns3_dev_stop(struct rte_eth_dev *eth_dev) hw->adapter_state = HNS3_NIC_STOPPING; hns3_set_rxtx_function(eth_dev); + rte_wmb(); + /* Disable datapath on secondary process. */ + hns3_mp_req_stop_rxtx(eth_dev); + /* Prevent crashes when queues are still in use. */ + rte_delay_ms(hw->tqps_num); rte_spinlock_lock(&hw->lock); if (rte_atomic16_read(&hw->reset.resetting) == 0) { @@ -4088,6 +4095,12 @@ hns3_dev_close(struct rte_eth_dev *eth_dev) struct hns3_adapter *hns = eth_dev->data->dev_private; struct hns3_hw *hw = &hns->hw; + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + rte_free(eth_dev->process_private); + eth_dev->process_private = NULL; + return; + } + if (hw->adapter_state == HNS3_NIC_STARTED) hns3_dev_stop(eth_dev); @@ -4104,6 +4117,7 @@ hns3_dev_close(struct rte_eth_dev *eth_dev) rte_free(hw->reset.wait_data); rte_free(eth_dev->process_private); eth_dev->process_private = NULL; + hns3_mp_uninit_primary(); hns3_warn(hw, "Close port %d finished", hw->data->port_id); } @@ -4558,6 +4572,10 @@ hns3_stop_service(struct hns3_adapter *hns) hw->mac.link_status = ETH_LINK_DOWN; hns3_set_rxtx_function(eth_dev); + rte_wmb(); + /* Disable datapath on secondary process. */ + hns3_mp_req_stop_rxtx(eth_dev); + rte_delay_ms(hw->tqps_num); rte_spinlock_lock(&hw->lock); if (hns->hw.adapter_state == HNS3_NIC_STARTED || @@ -4590,6 +4608,7 @@ hns3_start_service(struct hns3_adapter *hns) hns3_set_rst_done(hw); eth_dev = &rte_eth_devices[hw->data->port_id]; hns3_set_rxtx_function(eth_dev); + hns3_mp_req_start_rxtx(eth_dev); hns3_service_handler(eth_dev); return 0; } @@ -4776,9 +4795,13 @@ hns3_dev_init(struct rte_eth_dev *eth_dev) hns3_set_rxtx_function(eth_dev); eth_dev->dev_ops = &hns3_eth_dev_ops; - if (rte_eal_process_type() != RTE_PROC_PRIMARY) + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + hns3_mp_init_secondary(); + hw->secondary_cnt++; return 0; + } + hns3_mp_init_primary(); hw->adapter_state = HNS3_NIC_UNINITIALIZED; if (device_id == HNS3_DEV_ID_25GE_RDMA || diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c index 2fecc8427b..121beb58dc 100644 --- a/drivers/net/hns3/hns3_ethdev_vf.c +++ b/drivers/net/hns3/hns3_ethdev_vf.c @@ -31,6 +31,7 @@ #include "hns3_regs.h" #include "hns3_intr.h" #include "hns3_dcb.h" +#include "hns3_mp.h" #define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */ #define HNS3VF_SERVICE_INTERVAL 1000000 /* us */ @@ -1141,6 +1142,11 @@ hns3vf_dev_stop(struct rte_eth_dev *eth_dev) hw->adapter_state = HNS3_NIC_STOPPING; hns3_set_rxtx_function(eth_dev); + rte_wmb(); + /* Disable datapath on secondary process. */ + hns3_mp_req_stop_rxtx(eth_dev); + /* Prevent crashes when queues are still in use. */ + rte_delay_ms(hw->tqps_num); rte_spinlock_lock(&hw->lock); if (rte_atomic16_read(&hw->reset.resetting) == 0) { @@ -1157,6 +1163,9 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev) struct hns3_adapter *hns = eth_dev->data->dev_private; struct hns3_hw *hw = &hns->hw; + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return; + if (hw->adapter_state == HNS3_NIC_STARTED) hns3vf_dev_stop(eth_dev); @@ -1172,6 +1181,7 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev) rte_free(hw->reset.wait_data); rte_free(eth_dev->process_private); eth_dev->process_private = NULL; + hns3_mp_uninit_primary(); hns3_warn(hw, "Close port %d finished", hw->data->port_id); } @@ -1249,6 +1259,7 @@ hns3vf_dev_start(struct rte_eth_dev *eth_dev) hw->adapter_state = HNS3_NIC_STARTED; rte_spinlock_unlock(&hw->lock); hns3_set_rxtx_function(eth_dev); + hns3_mp_req_start_rxtx(eth_dev); return 0; } @@ -1344,6 +1355,10 @@ hns3vf_stop_service(struct hns3_adapter *hns) hw->mac.link_status = ETH_LINK_DOWN; hns3_set_rxtx_function(eth_dev); + rte_wmb(); + /* Disable datapath on secondary process. */ + hns3_mp_req_stop_rxtx(eth_dev); + rte_delay_ms(hw->tqps_num); rte_spinlock_lock(&hw->lock); if (hw->adapter_state == HNS3_NIC_STARTED || @@ -1373,6 +1388,7 @@ hns3vf_start_service(struct hns3_adapter *hns) eth_dev = &rte_eth_devices[hw->data->port_id]; hns3_set_rxtx_function(eth_dev); + hns3_mp_req_start_rxtx(eth_dev); hns3vf_service_handler(eth_dev); return 0; @@ -1578,8 +1594,13 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev) hns3_set_rxtx_function(eth_dev); eth_dev->dev_ops = &hns3vf_eth_dev_ops; - if (rte_eal_process_type() != RTE_PROC_PRIMARY) + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + hns3_mp_init_secondary(); + hw->secondary_cnt++; return 0; + } + + hns3_mp_init_primary(); hw->adapter_state = HNS3_NIC_UNINITIALIZED; hns->is_vf = true; diff --git a/drivers/net/hns3/hns3_mp.c b/drivers/net/hns3/hns3_mp.c new file mode 100644 index 0000000000..596c31064a --- /dev/null +++ b/drivers/net/hns3/hns3_mp.c @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2019 Hisilicon Limited. + */ + +#include + +#include +#include +#include +#include + +#include "hns3_ethdev.h" +#include "hns3_logs.h" +#include "hns3_rxtx.h" +#include "hns3_mp.h" + +/* + * 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; + 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 %u 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); + rte_mb(); + hns3_set_rxtx_function(dev); + mp_init_msg(dev, &mp_res, param->type); + res->result = 0; + ret = rte_mp_reply(&mp_res, peer); + break; + case HNS3_MP_REQ_STOP_RXTX: + PMD_INIT_LOG(INFO, "port %u stopping datapath", + dev->data->port_id); + hns3_set_rxtx_function(dev); + rte_mb(); + mp_init_msg(dev, &mp_res, param->type); + res->result = 0; + ret = rte_mp_reply(&mp_res, peer); + break; + default: + rte_errno = EINVAL; + PMD_INIT_LOG(ERR, "port %u invalid mp request type", + dev->data->port_id); + return -rte_errno; + } + return ret; +} + +/* + * 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 (!hw->secondary_cnt) + return; + if (type != HNS3_MP_REQ_START_RXTX && type != HNS3_MP_REQ_STOP_RXTX) { + 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); +} + +/* + * Initialize by primary process. + */ +void hns3_mp_init_primary(void) +{ + rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle); +} + +/* + * Un-initialize by primary process. + */ +void hns3_mp_uninit_primary(void) +{ + rte_mp_action_unregister(HNS3_MP_NAME); +} + +/* + * Initialize by secondary process. + */ +void hns3_mp_init_secondary(void) +{ + rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle); +} diff --git a/drivers/net/hns3/hns3_mp.h b/drivers/net/hns3/hns3_mp.h new file mode 100644 index 0000000000..aefbeb140e --- /dev/null +++ b/drivers/net/hns3/hns3_mp.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2019 Hisilicon Limited. + */ + +#ifndef _HNS3_MP_H_ +#define _HNS3_MP_H_ + +void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev); +void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev); +void hns3_mp_init_primary(void); +void hns3_mp_uninit_primary(void); +void hns3_mp_init_secondary(void); + +#endif /* _HNS3_MP_H_ */ diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build index 87e1a0c8f6..1a350fc8c6 100644 --- a/drivers/net/hns3/meson.build +++ b/drivers/net/hns3/meson.build @@ -25,5 +25,13 @@ sources = files('hns3_cmd.c', 'hns3_rss.c', 'hns3_rxtx.c', 'hns3_stats.c', - ) + 'hns3_mp.c') + +allow_experimental_apis = true +# Experimantal APIs: +# - rte_mp_action_register +# - rte_mp_action_unregister +# - rte_mp_reply +# - rte_mp_request_sync + deps += ['hash']