* [dpdk-dev] [PATCH 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 2/9] net/hns3: remove a redundant function declaration Min Hu (Connor)
` (9 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
The patch obtains the upper 32 bits of the Rx/Tx queue DMA address in one
step instead of two steps.
Fixes: bba636698316 ("net/hns3: support Rx/Tx and related operations")
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/hns3_rxtx.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index ceb98025f8..00af73c850 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -322,7 +322,7 @@ hns3_init_rx_queue_hw(struct hns3_rx_queue *rxq)
hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_L_REG, (uint32_t)dma_addr);
hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_H_REG,
- (uint32_t)((dma_addr >> 31) >> 1));
+ (uint32_t)(dma_addr >> 32));
hns3_write_dev(rxq, HNS3_RING_RX_BD_LEN_REG,
hns3_buf_size2type(rx_buf_len));
@@ -337,7 +337,7 @@ hns3_init_tx_queue_hw(struct hns3_tx_queue *txq)
hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_L_REG, (uint32_t)dma_addr);
hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_H_REG,
- (uint32_t)((dma_addr >> 31) >> 1));
+ (uint32_t)(dma_addr >> 32));
hns3_write_dev(txq, HNS3_RING_TX_BD_NUM_REG,
HNS3_CFG_DESC_NUM(txq->nb_tx_desc));
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 2/9] net/hns3: remove a redundant function declaration
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 3/9] net/hns3: modifying code alignment Min Hu (Connor)
` (8 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
This patch removes a redundant function declaration for
hns3_rx_check_vec_support().
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/hns3/hns3_rxtx.h b/drivers/net/hns3/hns3_rxtx.h
index 33ee8c61a0..63bafc68b6 100644
--- a/drivers/net/hns3/hns3_rxtx.h
+++ b/drivers/net/hns3/hns3_rxtx.h
@@ -711,7 +711,6 @@ uint16_t hns3_recv_pkts_vec_sve(void *rx_queue, struct rte_mbuf **rx_pkts,
int hns3_rx_burst_mode_get(struct rte_eth_dev *dev,
__rte_unused uint16_t queue_id,
struct rte_eth_burst_mode *mode);
-int hns3_rx_check_vec_support(struct rte_eth_dev *dev);
uint16_t hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
uint16_t hns3_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 3/9] net/hns3: modifying code alignment
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 2/9] net/hns3: remove a redundant function declaration Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 4/9] net/hns3: use unsigned integer for bitwise operations Min Hu (Connor)
` (7 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
This patch modifies some code alignment issues to make the code style more
consistent.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 00af73c850..7e55b24cb8 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -1907,7 +1907,7 @@ hns3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
*/
if (hns->is_vf || hw->vlan_mode == HNS3_SW_SHIFT_AND_DISCARD_MODE)
rxq->pvid_sw_discard_en = hw->port_base_vlan_cfg.state ==
- HNS3_PORT_BASE_VLAN_ENABLE;
+ HNS3_PORT_BASE_VLAN_ENABLE;
else
rxq->pvid_sw_discard_en = false;
rxq->ptype_en = hns3_dev_get_support(hw, RXD_ADV_LAYOUT) ? true : false;
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 4/9] net/hns3: use unsigned integer for bitwise operations
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (2 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 3/9] net/hns3: modifying code alignment Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 5/9] net/hns3: extract a common file Min Hu (Connor)
` (6 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
Bitwise operations should be used only with unsigned integer. This patch
modifies some code that does not meet this rule.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index ccae75baa0..50e73b00b7 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -2104,7 +2104,7 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
int max_tc = 0;
int i;
- if ((rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
+ if (((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
(tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_DCB ||
tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_ONLY)) {
hns3_err(hw, "VMDQ is not supported, rx_mq_mode = %d, tx_mq_mode = %d.",
@@ -2114,7 +2114,7 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
- if (rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
+ if ((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
if (dcb_rx_conf->nb_tcs > pf->tc_max) {
hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
dcb_rx_conf->nb_tcs, pf->tc_max);
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 5/9] net/hns3: extract a common file
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (3 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 4/9] net/hns3: use unsigned integer for bitwise operations Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 6/9] net/hns3: add hns3 flow header file Min Hu (Connor)
` (5 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
This patch extracts a common file to store the common code for PF and VF
driver.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_cmd.c | 2 +-
drivers/net/hns3/hns3_common.c | 427 +++++++++++++++++++++++++++++
drivers/net/hns3/hns3_common.h | 48 ++++
drivers/net/hns3/hns3_ethdev.c | 430 +-----------------------------
drivers/net/hns3/hns3_ethdev.h | 30 +--
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_intr.c | 2 +-
drivers/net/hns3/hns3_mbx.c | 2 +-
drivers/net/hns3/hns3_rxtx.c | 2 +-
drivers/net/hns3/meson.build | 1 +
10 files changed, 485 insertions(+), 460 deletions(-)
create mode 100644 drivers/net/hns3/hns3_common.c
create mode 100644 drivers/net/hns3/hns3_common.h
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 50769c6226..2ce59d8de6 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -5,7 +5,7 @@
#include <ethdev_pci.h>
#include <rte_io.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_regs.h"
#include "hns3_intr.h"
#include "hns3_logs.h"
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
new file mode 100644
index 0000000000..5fe0ff5ce7
--- /dev/null
+++ b/drivers/net/hns3/hns3_common.c
@@ -0,0 +1,427 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#include <rte_kvargs.h>
+
+#include "hns3_logs.h"
+#include "hns3_common.h"
+
+static int
+hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
+{
+ uint32_t hint = HNS3_IO_FUNC_HINT_NONE;
+
+ RTE_SET_USED(key);
+
+ if (strcmp(value, "vec") == 0)
+ hint = HNS3_IO_FUNC_HINT_VEC;
+ else if (strcmp(value, "sve") == 0)
+ hint = HNS3_IO_FUNC_HINT_SVE;
+ else if (strcmp(value, "simple") == 0)
+ hint = HNS3_IO_FUNC_HINT_SIMPLE;
+ else if (strcmp(value, "common") == 0)
+ hint = HNS3_IO_FUNC_HINT_COMMON;
+
+ /* If the hint is valid then update output parameters */
+ if (hint != HNS3_IO_FUNC_HINT_NONE)
+ *(uint32_t *)extra_args = hint;
+
+ return 0;
+}
+
+static const char *
+hns3_get_io_hint_func_name(uint32_t hint)
+{
+ switch (hint) {
+ case HNS3_IO_FUNC_HINT_VEC:
+ return "vec";
+ case HNS3_IO_FUNC_HINT_SVE:
+ return "sve";
+ case HNS3_IO_FUNC_HINT_SIMPLE:
+ return "simple";
+ case HNS3_IO_FUNC_HINT_COMMON:
+ return "common";
+ default:
+ return "none";
+ }
+}
+
+static int
+hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
+{
+ uint64_t val;
+
+ RTE_SET_USED(key);
+
+ val = strtoull(value, NULL, 16);
+ *(uint64_t *)extra_args = val;
+
+ return 0;
+}
+
+static int
+hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
+{
+ uint32_t val;
+
+ RTE_SET_USED(key);
+
+ val = strtoul(value, NULL, 10);
+ if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
+ *(uint16_t *)extra_args = val;
+
+ return 0;
+}
+
+void
+hns3_parse_devargs(struct rte_eth_dev *dev)
+{
+ uint16_t mbx_time_limit_ms = HNS3_MBX_DEF_TIME_LIMIT_MS;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE;
+ uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t dev_caps_mask = 0;
+ struct rte_kvargs *kvlist;
+
+ if (dev->device->devargs == NULL)
+ return;
+
+ kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL);
+ if (!kvlist)
+ return;
+
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT,
+ &hns3_parse_io_hint_func, &rx_func_hint);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
+ &hns3_parse_io_hint_func, &tx_func_hint);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
+ &hns3_parse_dev_caps_mask, &dev_caps_mask);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
+ &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
+
+ rte_kvargs_free(kvlist);
+
+ if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE)
+ hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT,
+ hns3_get_io_hint_func_name(rx_func_hint));
+ hns->rx_func_hint = rx_func_hint;
+ if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE)
+ hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT,
+ hns3_get_io_hint_func_name(tx_func_hint));
+ hns->tx_func_hint = tx_func_hint;
+
+ if (dev_caps_mask != 0)
+ hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
+ HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
+ hns->dev_caps_mask = dev_caps_mask;
+}
+
+void
+hns3_clock_gettime(struct timeval *tv)
+{
+#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
+#define CLOCK_TYPE CLOCK_MONOTONIC_RAW
+#else
+#define CLOCK_TYPE CLOCK_MONOTONIC
+#endif
+#define NSEC_TO_USEC_DIV 1000
+
+ struct timespec spec;
+ (void)clock_gettime(CLOCK_TYPE, &spec);
+
+ tv->tv_sec = spec.tv_sec;
+ tv->tv_usec = spec.tv_nsec / NSEC_TO_USEC_DIV;
+}
+
+uint64_t
+hns3_clock_calctime_ms(struct timeval *tv)
+{
+ return (uint64_t)tv->tv_sec * MSEC_PER_SEC +
+ tv->tv_usec / USEC_PER_MSEC;
+}
+
+uint64_t
+hns3_clock_gettime_ms(void)
+{
+ struct timeval tv;
+
+ hns3_clock_gettime(&tv);
+ return hns3_clock_calctime_ms(&tv);
+}
+
+void hns3_ether_format_addr(char *buf, uint16_t size,
+ const struct rte_ether_addr *ether_addr)
+{
+ snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
+ ether_addr->addr_bytes[0],
+ ether_addr->addr_bytes[4],
+ ether_addr->addr_bytes[5]);
+}
+
+static int
+hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ uint16_t mac_addrs_capa;
+ uint32_t i;
+ uint32_t j;
+
+ if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
+ hns3_err(hw, "failed to set mc mac addr, nb_mc_addr(%u) "
+ "invalid. valid range: 0~%d",
+ nb_mc_addr, HNS3_MC_MACADDR_NUM);
+ return -EINVAL;
+ }
+
+ /* Check if input mac addresses are valid */
+ for (i = 0; i < nb_mc_addr; i++) {
+ addr = &mc_addr_set[i];
+ if (!rte_is_multicast_ether_addr(addr)) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw,
+ "failed to set mc mac addr, addr(%s) invalid.",
+ mac_str);
+ return -EINVAL;
+ }
+
+ /* Check if there are duplicate addresses */
+ for (j = i + 1; j < nb_mc_addr; j++) {
+ if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
+ hns3_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. two same addrs(%s).",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Check if there are duplicate addresses between mac_addrs
+ * and mc_addr_set
+ */
+ mac_addrs_capa = hns->is_vf ? HNS3_VF_UC_MACADDR_NUM :
+ HNS3_UC_MACADDR_NUM;
+ for (j = 0; j < mac_addrs_capa; j++) {
+ if (rte_is_same_ether_addr(addr,
+ &hw->data->mac_addrs[j])) {
+ hns3_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. addrs(%s) has already "
+ "configured in mac_addr add API",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *addr;
+ int cur_addr_num;
+ int set_addr_num;
+ int num;
+ int ret;
+ int i;
+
+ /* Check if input parameters are valid */
+ ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
+ if (ret)
+ return ret;
+
+ rte_spinlock_lock(&hw->lock);
+ cur_addr_num = hw->mc_addrs_num;
+ for (i = 0; i < cur_addr_num; i++) {
+ num = cur_addr_num - i - 1;
+ addr = &hw->mc_addrs[num];
+ ret = hw->ops.del_mc_mac_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ hw->mc_addrs_num--;
+ }
+
+ set_addr_num = (int)nb_mc_addr;
+ for (i = 0; i < set_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ ret = hw->ops.add_mc_mac_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
+ hw->mc_addrs_num++;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+int
+hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ if (!rte_is_multicast_ether_addr(addr))
+ continue;
+ if (del)
+ ret = hw->ops.del_mc_mac_addr(hw, addr);
+ else
+ ret = hw->ops.add_mc_mac_addr(hw, addr);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_dbg(hw, "failed to %s mc mac addr: %s ret = %d",
+ del ? "Remove" : "Restore", mac_str, ret);
+ }
+ }
+ return ret;
+}
+
+int
+hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_hw_ops *ops = &hw->ops;
+ struct rte_ether_addr *addr;
+ uint16_t mac_addrs_capa;
+ int ret = 0;
+ int i;
+
+ mac_addrs_capa =
+ hns->is_vf ? HNS3_VF_UC_MACADDR_NUM : HNS3_UC_MACADDR_NUM;
+ for (i = 0; i < mac_addrs_capa; i++) {
+ addr = &hw->data->mac_addrs[i];
+ if (rte_is_zero_ether_addr(addr))
+ continue;
+ if (rte_is_multicast_ether_addr(addr))
+ ret = del ? ops->del_mc_mac_addr(hw, addr) :
+ ops->add_mc_mac_addr(hw, addr);
+ else
+ ret = del ? ops->del_uc_mac_addr(hw, addr) :
+ ops->add_uc_mac_addr(hw, addr);
+
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to %s mac addr(%s) index:%d ret = %d.",
+ del ? "remove" : "restore", mac_str, i, ret);
+ }
+ }
+
+ return ret;
+}
+
+static bool
+hns3_find_duplicate_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mc_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ /* Check if there are duplicate addresses in mc_addrs[] */
+ if (rte_is_same_ether_addr(addr, mc_addr)) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to add mc mac addr, same addrs"
+ "(%s) is added by the set_mc_mac_addr_list "
+ "API", mac_str);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int
+hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx, __rte_unused uint32_t pool)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ /*
+ * In hns3 network engine adding UC and MC mac address with different
+ * commands with firmware. We need to determine whether the input
+ * address is a UC or a MC address to call different commands.
+ * By the way, it is recommended calling the API function named
+ * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
+ * using the rte_eth_dev_mac_addr_add API function to set MC mac address
+ * may affect the specifications of UC mac addresses.
+ */
+ if (rte_is_multicast_ether_addr(mac_addr)) {
+ if (hns3_find_duplicate_mc_addr(hw, mac_addr)) {
+ rte_spinlock_unlock(&hw->lock);
+ return -EINVAL;
+ }
+ ret = hw->ops.add_mc_mac_addr(hw, mac_addr);
+ } else {
+ ret = hw->ops.add_uc_mac_addr(hw, mac_addr);
+ }
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to add mac addr(%s), ret = %d", mac_str,
+ ret);
+ }
+
+ return ret;
+}
+
+void
+hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ /* index will be checked by upper level rte interface */
+ struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hw->ops.del_mc_mac_addr(hw, mac_addr);
+ else
+ ret = hw->ops.del_uc_mac_addr(hw, mac_addr);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to remove mac addr(%s), ret = %d", mac_str,
+ ret);
+ }
+}
+
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
new file mode 100644
index 0000000000..094a0bc5ff
--- /dev/null
+++ b/drivers/net/hns3/hns3_common.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#ifndef _HNS3_COMMON_H_
+#define _HNS3_COMMON_H_
+
+#include <sys/time.h>
+
+#include "hns3_ethdev.h"
+
+enum {
+ HNS3_IO_FUNC_HINT_NONE = 0,
+ HNS3_IO_FUNC_HINT_VEC,
+ HNS3_IO_FUNC_HINT_SVE,
+ HNS3_IO_FUNC_HINT_SIMPLE,
+ HNS3_IO_FUNC_HINT_COMMON
+};
+
+#define HNS3_DEVARG_RX_FUNC_HINT "rx_func_hint"
+#define HNS3_DEVARG_TX_FUNC_HINT "tx_func_hint"
+
+#define HNS3_DEVARG_DEV_CAPS_MASK "dev_caps_mask"
+
+#define HNS3_DEVARG_MBX_TIME_LIMIT_MS "mbx_time_limit_ms"
+
+#define MSEC_PER_SEC 1000L
+#define USEC_PER_MSEC 1000L
+
+void hns3_clock_gettime(struct timeval *tv);
+uint64_t hns3_clock_calctime_ms(struct timeval *tv);
+uint64_t hns3_clock_gettime_ms(void);
+
+void hns3_parse_devargs(struct rte_eth_dev *dev);
+
+int hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del);
+int hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del);
+int hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx, __rte_unused uint32_t pool);
+
+void hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx);
+int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr);
+void hns3_ether_format_addr(char *buf, uint16_t size,
+ const struct rte_ether_addr *ether_addr);
+
+#endif /* _HNS3_COMMON_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 50e73b00b7..2f1ecffd5a 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -6,9 +6,9 @@
#include <rte_bus_pci.h>
#include <ethdev_pci.h>
#include <rte_pci.h>
-#include <rte_kvargs.h>
#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_intr.h"
@@ -105,14 +105,6 @@ static int hns3_do_stop(struct hns3_adapter *hns);
static int hns3_check_port_speed(struct hns3_hw *hw, uint32_t link_speeds);
static int hns3_cfg_mac_mode(struct hns3_hw *hw, bool enable);
-void hns3_ether_format_addr(char *buf, uint16_t size,
- const struct rte_ether_addr *ether_addr)
-{
- snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
- ether_addr->addr_bytes[0],
- ether_addr->addr_bytes[4],
- ether_addr->addr_bytes[5]);
-}
static void
hns3_pf_disable_irq0(struct hns3_hw *hw)
@@ -1609,68 +1601,6 @@ hns3_add_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-static bool
-hns3_find_duplicate_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mc_addr)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct rte_ether_addr *addr;
- int i;
-
- for (i = 0; i < hw->mc_addrs_num; i++) {
- addr = &hw->mc_addrs[i];
- /* Check if there are duplicate addresses in mc_addrs[] */
- if (rte_is_same_ether_addr(addr, mc_addr)) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to add mc mac addr, same addrs"
- "(%s) is added by the set_mc_mac_addr_list "
- "API", mac_str);
- return true;
- }
- }
-
- return false;
-}
-
-int
-hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
- __rte_unused uint32_t idx, __rte_unused uint32_t pool)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- int ret;
-
- rte_spinlock_lock(&hw->lock);
-
- /*
- * In hns3 network engine adding UC and MC mac address with different
- * commands with firmware. We need to determine whether the input
- * address is a UC or a MC address to call different commands.
- * By the way, it is recommended calling the API function named
- * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
- * using the rte_eth_dev_mac_addr_add API function to set MC mac address
- * may affect the specifications of UC mac addresses.
- */
- if (rte_is_multicast_ether_addr(mac_addr)) {
- if (hns3_find_duplicate_mc_addr(hw, mac_addr)) {
- rte_spinlock_unlock(&hw->lock);
- return -EINVAL;
- }
- ret = hw->ops.add_mc_mac_addr(hw, mac_addr);
- } else {
- ret = hw->ops.add_uc_mac_addr(hw, mac_addr);
- }
- rte_spinlock_unlock(&hw->lock);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- mac_addr);
- hns3_err(hw, "failed to add mac addr(%s), ret = %d", mac_str,
- ret);
- }
-
- return ret;
-}
-
static int
hns3_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
{
@@ -1699,30 +1629,6 @@ hns3_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-void
-hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- /* index will be checked by upper level rte interface */
- struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- int ret;
-
- rte_spinlock_lock(&hw->lock);
-
- if (rte_is_multicast_ether_addr(mac_addr))
- ret = hw->ops.del_mc_mac_addr(hw, mac_addr);
- else
- ret = hw->ops.del_uc_mac_addr(hw, mac_addr);
- rte_spinlock_unlock(&hw->lock);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- mac_addr);
- hns3_err(hw, "failed to remove mac addr(%s), ret = %d", mac_str,
- ret);
- }
-}
-
static int
hns3_set_default_mac_addr(struct rte_eth_dev *dev,
struct rte_ether_addr *mac_addr)
@@ -1787,41 +1693,6 @@ hns3_set_default_mac_addr(struct rte_eth_dev *dev,
return ret;
}
-int
-hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct hns3_hw *hw = &hns->hw;
- struct hns3_hw_ops *ops = &hw->ops;
- struct rte_ether_addr *addr;
- uint16_t mac_addrs_capa;
- int ret = 0;
- int i;
-
- mac_addrs_capa =
- hns->is_vf ? HNS3_VF_UC_MACADDR_NUM : HNS3_UC_MACADDR_NUM;
- for (i = 0; i < mac_addrs_capa; i++) {
- addr = &hw->data->mac_addrs[i];
- if (rte_is_zero_ether_addr(addr))
- continue;
- if (rte_is_multicast_ether_addr(addr))
- ret = del ? ops->del_mc_mac_addr(hw, addr) :
- ops->add_mc_mac_addr(hw, addr);
- else
- ret = del ? ops->del_uc_mac_addr(hw, addr) :
- ops->add_uc_mac_addr(hw, addr);
-
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to %s mac addr(%s) index:%d ret = %d.",
- del ? "remove" : "restore", mac_str, i, ret);
- }
- }
-
- return ret;
-}
-
static void
hns3_update_desc_vfid(struct hns3_cmd_desc *desc, uint8_t vfid, bool clr)
{
@@ -1947,150 +1818,6 @@ hns3_remove_mc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-static int
-hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr)
-{
- struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct rte_ether_addr *addr;
- uint16_t mac_addrs_capa;
- uint32_t i;
- uint32_t j;
-
- if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
- hns3_err(hw, "failed to set mc mac addr, nb_mc_addr(%u) "
- "invalid. valid range: 0~%d",
- nb_mc_addr, HNS3_MC_MACADDR_NUM);
- return -EINVAL;
- }
-
- /* Check if input mac addresses are valid */
- for (i = 0; i < nb_mc_addr; i++) {
- addr = &mc_addr_set[i];
- if (!rte_is_multicast_ether_addr(addr)) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw,
- "failed to set mc mac addr, addr(%s) invalid.",
- mac_str);
- return -EINVAL;
- }
-
- /* Check if there are duplicate addresses */
- for (j = i + 1; j < nb_mc_addr; j++) {
- if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
- hns3_ether_format_addr(mac_str,
- RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to set mc mac addr, "
- "addrs invalid. two same addrs(%s).",
- mac_str);
- return -EINVAL;
- }
- }
-
- /*
- * Check if there are duplicate addresses between mac_addrs
- * and mc_addr_set
- */
- mac_addrs_capa = hns->is_vf ? HNS3_VF_UC_MACADDR_NUM :
- HNS3_UC_MACADDR_NUM;
- for (j = 0; j < mac_addrs_capa; j++) {
- if (rte_is_same_ether_addr(addr,
- &hw->data->mac_addrs[j])) {
- hns3_ether_format_addr(mac_str,
- RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to set mc mac addr, "
- "addrs invalid. addrs(%s) has already "
- "configured in mac_addr add API",
- mac_str);
- return -EINVAL;
- }
- }
- }
-
- return 0;
-}
-
-int
-hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_ether_addr *addr;
- int cur_addr_num;
- int set_addr_num;
- int num;
- int ret;
- int i;
-
- /* Check if input parameters are valid */
- ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
- if (ret)
- return ret;
-
- rte_spinlock_lock(&hw->lock);
- cur_addr_num = hw->mc_addrs_num;
- for (i = 0; i < cur_addr_num; i++) {
- num = cur_addr_num - i - 1;
- addr = &hw->mc_addrs[num];
- ret = hw->ops.del_mc_mac_addr(hw, addr);
- if (ret) {
- rte_spinlock_unlock(&hw->lock);
- return ret;
- }
-
- hw->mc_addrs_num--;
- }
-
- set_addr_num = (int)nb_mc_addr;
- for (i = 0; i < set_addr_num; i++) {
- addr = &mc_addr_set[i];
- ret = hw->ops.add_mc_mac_addr(hw, addr);
- if (ret) {
- rte_spinlock_unlock(&hw->lock);
- return ret;
- }
-
- rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
- hw->mc_addrs_num++;
- }
- rte_spinlock_unlock(&hw->lock);
-
- return 0;
-}
-
-int
-hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct hns3_hw *hw = &hns->hw;
- struct rte_ether_addr *addr;
- int ret = 0;
- int i;
-
- for (i = 0; i < hw->mc_addrs_num; i++) {
- addr = &hw->mc_addrs[i];
- if (!rte_is_multicast_ether_addr(addr))
- continue;
- if (del)
- ret = hw->ops.del_mc_mac_addr(hw, addr);
- else
- ret = hw->ops.add_mc_mac_addr(hw, addr);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_dbg(hw, "failed to %s mc mac addr: %s ret = %d",
- del ? "Remove" : "Restore", mac_str, ret);
- }
- }
- return ret;
-}
-
static int
hns3_check_mq_mode(struct rte_eth_dev *dev)
{
@@ -7110,161 +6837,6 @@ hns3_get_module_info(struct rte_eth_dev *dev,
return 0;
}
-void
-hns3_clock_gettime(struct timeval *tv)
-{
-#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
-#define CLOCK_TYPE CLOCK_MONOTONIC_RAW
-#else
-#define CLOCK_TYPE CLOCK_MONOTONIC
-#endif
-#define NSEC_TO_USEC_DIV 1000
-
- struct timespec spec;
- (void)clock_gettime(CLOCK_TYPE, &spec);
-
- tv->tv_sec = spec.tv_sec;
- tv->tv_usec = spec.tv_nsec / NSEC_TO_USEC_DIV;
-}
-
-uint64_t
-hns3_clock_calctime_ms(struct timeval *tv)
-{
- return (uint64_t)tv->tv_sec * MSEC_PER_SEC +
- tv->tv_usec / USEC_PER_MSEC;
-}
-
-uint64_t
-hns3_clock_gettime_ms(void)
-{
- struct timeval tv;
-
- hns3_clock_gettime(&tv);
- return hns3_clock_calctime_ms(&tv);
-}
-
-static int
-hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
-{
- uint32_t hint = HNS3_IO_FUNC_HINT_NONE;
-
- RTE_SET_USED(key);
-
- if (strcmp(value, "vec") == 0)
- hint = HNS3_IO_FUNC_HINT_VEC;
- else if (strcmp(value, "sve") == 0)
- hint = HNS3_IO_FUNC_HINT_SVE;
- else if (strcmp(value, "simple") == 0)
- hint = HNS3_IO_FUNC_HINT_SIMPLE;
- else if (strcmp(value, "common") == 0)
- hint = HNS3_IO_FUNC_HINT_COMMON;
-
- /* If the hint is valid then update output parameters */
- if (hint != HNS3_IO_FUNC_HINT_NONE)
- *(uint32_t *)extra_args = hint;
-
- return 0;
-}
-
-static const char *
-hns3_get_io_hint_func_name(uint32_t hint)
-{
- switch (hint) {
- case HNS3_IO_FUNC_HINT_VEC:
- return "vec";
- case HNS3_IO_FUNC_HINT_SVE:
- return "sve";
- case HNS3_IO_FUNC_HINT_SIMPLE:
- return "simple";
- case HNS3_IO_FUNC_HINT_COMMON:
- return "common";
- default:
- return "none";
- }
-}
-
-static int
-hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
-{
- uint64_t val;
-
- RTE_SET_USED(key);
-
- val = strtoull(value, NULL, 16);
- *(uint64_t *)extra_args = val;
-
- return 0;
-}
-
-static int
-hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
-{
- uint32_t val;
-
- RTE_SET_USED(key);
-
- val = strtoul(value, NULL, 10);
-
- /*
- * 500ms is empirical value in process of mailbox communication. If
- * the delay value is set to one lower thanthe empirical value, mailbox
- * communication may fail.
- */
- if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
- *(uint16_t *)extra_args = val;
-
- return 0;
-}
-
-void
-hns3_parse_devargs(struct rte_eth_dev *dev)
-{
- uint16_t mbx_time_limit_ms = HNS3_MBX_DEF_TIME_LIMIT_MS;
- struct hns3_adapter *hns = dev->data->dev_private;
- uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE;
- uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE;
- struct hns3_hw *hw = &hns->hw;
- uint64_t dev_caps_mask = 0;
- struct rte_kvargs *kvlist;
-
- if (dev->device->devargs == NULL)
- return;
-
- kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL);
- if (!kvlist)
- return;
-
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT,
- &hns3_parse_io_hint_func, &rx_func_hint);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
- &hns3_parse_io_hint_func, &tx_func_hint);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
- &hns3_parse_dev_caps_mask, &dev_caps_mask);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
- &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
-
- rte_kvargs_free(kvlist);
-
- if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE)
- hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT,
- hns3_get_io_hint_func_name(rx_func_hint));
- hns->rx_func_hint = rx_func_hint;
- if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE)
- hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT,
- hns3_get_io_hint_func_name(tx_func_hint));
- hns->tx_func_hint = tx_func_hint;
-
- if (dev_caps_mask != 0)
- hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
- HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
- hns->dev_caps_mask = dev_caps_mask;
-
- if (mbx_time_limit_ms != HNS3_MBX_DEF_TIME_LIMIT_MS)
- hns3_warn(hw, "parsed %s = %u.", HNS3_DEVARG_MBX_TIME_LIMIT_MS,
- mbx_time_limit_ms);
- hns->mbx_time_limit_ms = mbx_time_limit_ms;
-}
-
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_configure = hns3_dev_configure,
.dev_start = hns3_dev_start,
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index f3cc88f43e..634018c847 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -6,7 +6,6 @@
#define _HNS3_ETHDEV_H_
#include <pthread.h>
-#include <sys/time.h>
#include <ethdev_driver.h>
#include <rte_byteorder.h>
#include <rte_io.h>
@@ -869,14 +868,6 @@ struct hns3_adapter {
struct hns3_ptype_table ptype_tbl __rte_cache_aligned;
};
-enum {
- HNS3_IO_FUNC_HINT_NONE = 0,
- HNS3_IO_FUNC_HINT_VEC,
- HNS3_IO_FUNC_HINT_SVE,
- HNS3_IO_FUNC_HINT_SIMPLE,
- HNS3_IO_FUNC_HINT_COMMON
-};
-
#define HNS3_DEVARG_RX_FUNC_HINT "rx_func_hint"
#define HNS3_DEVARG_TX_FUNC_HINT "tx_func_hint"
@@ -1011,13 +1002,6 @@ static inline uint32_t hns3_read_reg(void *base, uint32_t reg)
} \
} while (0)
-#define MSEC_PER_SEC 1000L
-#define USEC_PER_MSEC 1000L
-
-void hns3_clock_gettime(struct timeval *tv);
-uint64_t hns3_clock_calctime_ms(struct timeval *tv);
-uint64_t hns3_clock_gettime_ms(void);
-
static inline uint64_t
hns3_atomic_test_bit(unsigned int nr, volatile uint64_t *addr)
{
@@ -1047,28 +1031,20 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
return __atomic_fetch_and(addr, ~mask, __ATOMIC_RELAXED) & mask;
}
+uint32_t hns3_get_speed_capa(struct hns3_hw *hw);
+
int hns3_buffer_alloc(struct hns3_hw *hw);
int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
const struct rte_flow_ops **ops);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
-void hns3_ether_format_addr(char *buf, uint16_t size,
- const struct rte_ether_addr *ether_addr);
int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
struct rte_eth_dev_info *info);
void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
uint32_t link_speed, uint8_t link_duplex);
-void hns3_parse_devargs(struct rte_eth_dev *dev);
void hns3vf_update_push_lsc_cap(struct hns3_hw *hw, bool supported);
-int hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del);
-int hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del);
-int hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
- __rte_unused uint32_t idx, __rte_unused uint32_t pool);
-void hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx);
-int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr);
+
int hns3_restore_ptp(struct hns3_adapter *hns);
int hns3_mbuf_dyn_rx_timestamp_register(struct rte_eth_dev *dev,
struct rte_eth_conf *conf);
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 27701a919e..d06f863249 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -10,6 +10,7 @@
#include <rte_vfio.h>
#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
diff --git a/drivers/net/hns3/hns3_intr.c b/drivers/net/hns3/hns3_intr.c
index 3484c76d23..66dc509086 100644
--- a/drivers/net/hns3/hns3_intr.c
+++ b/drivers/net/hns3/hns3_intr.c
@@ -8,7 +8,7 @@
#include <rte_io.h>
#include <rte_malloc.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_intr.h"
#include "hns3_regs.h"
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index 245652e2ed..b3563d4694 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -5,7 +5,7 @@
#include <ethdev_driver.h>
#include <rte_io.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
#include "hns3_intr.h"
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 7e55b24cb8..d26e262335 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -16,7 +16,7 @@
#include <rte_vect.h>
#endif
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index a99e0dbb74..8a4c7cc100 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -29,6 +29,7 @@ sources = files(
'hns3_mp.c',
'hns3_tm.c',
'hns3_ptp.c',
+ 'hns3_common.c',
)
deps += ['hash']
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 6/9] net/hns3: add hns3 flow header file
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (4 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 5/9] net/hns3: extract a common file Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 7/9] net/hns3: remove magic numbers Min Hu (Connor)
` (4 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
This patch adds a hns3_flow.h to make the code easier to maintain.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 1 +
drivers/net/hns3/hns3_ethdev.h | 3 +--
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_fdir.h | 31 ----------------------
drivers/net/hns3/hns3_flow.c | 1 +
drivers/net/hns3/hns3_flow.h | 44 +++++++++++++++++++++++++++++++
6 files changed, 48 insertions(+), 33 deletions(-)
create mode 100644 drivers/net/hns3/hns3_flow.h
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 2f1ecffd5a..2f4beacb87 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -15,6 +15,7 @@
#include "hns3_regs.h"
#include "hns3_dcb.h"
#include "hns3_mp.h"
+#include "hns3_flow.h"
#define HNS3_SERVICE_INTERVAL 1000000 /* us */
#define HNS3_SERVICE_QUICK_INTERVAL 10
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 634018c847..a28c7c262b 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -17,6 +17,7 @@
#include "hns3_fdir.h"
#include "hns3_stats.h"
#include "hns3_tm.h"
+#include "hns3_flow.h"
/* Vendor ID */
#define PCI_VENDOR_ID_HUAWEI 0x19e5
@@ -1034,8 +1035,6 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
uint32_t hns3_get_speed_capa(struct hns3_hw *hw);
int hns3_buffer_alloc(struct hns3_hw *hw);
-int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
- const struct rte_flow_ops **ops);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index d06f863249..7e60090fd3 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -17,6 +17,7 @@
#include "hns3_intr.h"
#include "hns3_dcb.h"
#include "hns3_mp.h"
+#include "hns3_flow.h"
#define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */
#define HNS3VF_SERVICE_INTERVAL 1000000 /* us */
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index 3f610f7b11..f9efff3b52 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -5,8 +5,6 @@
#ifndef _HNS3_FDIR_H_
#define _HNS3_FDIR_H_
-#include <rte_flow.h>
-
struct hns3_fd_key_cfg {
uint8_t key_sel;
uint8_t inner_sipv6_word_en;
@@ -124,14 +122,6 @@ struct hns3_fd_ad_data {
uint16_t rule_id;
};
-struct hns3_flow_counter {
- LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
- uint32_t shared:1; /* Share counter ID with other flow rules. */
- uint32_t ref_cnt:31; /* Reference counter. */
- uint16_t id; /* Counter ID. */
- uint64_t hits; /* Number of packets matched by the rule. */
-};
-
#define HNS3_RULE_FLAG_FDID 0x1
#define HNS3_RULE_FLAG_VF_ID 0x2
#define HNS3_RULE_FLAG_COUNTER 0x4
@@ -173,21 +163,7 @@ struct hns3_fdir_rule_ele {
struct hns3_fdir_rule fdir_conf;
};
-/* rss filter list structure */
-struct hns3_rss_conf_ele {
- TAILQ_ENTRY(hns3_rss_conf_ele) entries;
- struct hns3_rss_conf filter_info;
-};
-
-/* hns3_flow memory list structure */
-struct hns3_flow_mem {
- TAILQ_ENTRY(hns3_flow_mem) entries;
- struct rte_flow *flow;
-};
-
TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
-TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
-TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
/*
* A structure used to define fields of a FDIR related info.
@@ -199,11 +175,6 @@ struct hns3_fdir_info {
struct hns3_fd_cfg fd_cfg;
};
-struct rte_flow {
- enum rte_filter_type filter_type;
- void *rule;
- uint32_t counter_id;
-};
struct hns3_adapter;
int hns3_init_fd_config(struct hns3_adapter *hns);
@@ -213,8 +184,6 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
struct hns3_fdir_rule *rule, bool del);
int hns3_clear_all_fdir_filter(struct hns3_adapter *hns);
int hns3_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value);
-void hns3_flow_init(struct rte_eth_dev *dev);
-void hns3_flow_uninit(struct rte_eth_dev *dev);
int hns3_restore_all_fdir_filter(struct hns3_adapter *hns);
#endif /* _HNS3_FDIR_H_ */
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index da6918fddd..9f2f9cb6cd 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -8,6 +8,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
+#include "hns3_flow.h"
/* Default default keys */
static uint8_t hns3_hash_key[] = {
diff --git a/drivers/net/hns3/hns3_flow.h b/drivers/net/hns3/hns3_flow.h
new file mode 100644
index 0000000000..2eb451b720
--- /dev/null
+++ b/drivers/net/hns3/hns3_flow.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#ifndef _HNS3_FLOW_H_
+#define _HNS3_FLOW_H_
+
+#include <rte_flow.h>
+
+struct hns3_flow_counter {
+ LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
+ uint32_t shared:1; /* Share counter ID with other flow rules. */
+ uint32_t ref_cnt:31; /* Reference counter. */
+ uint16_t id; /* Counter ID. */
+ uint64_t hits; /* Number of packets matched by the rule. */
+};
+
+struct rte_flow {
+ enum rte_filter_type filter_type;
+ void *rule;
+ uint32_t counter_id;
+};
+
+/* rss filter list structure */
+struct hns3_rss_conf_ele {
+ TAILQ_ENTRY(hns3_rss_conf_ele) entries;
+ struct hns3_rss_conf filter_info;
+};
+
+/* hns3_flow memory list structure */
+struct hns3_flow_mem {
+ TAILQ_ENTRY(hns3_flow_mem) entries;
+ struct rte_flow *flow;
+};
+
+TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
+TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
+
+int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
+ const struct rte_flow_ops **ops);
+void hns3_flow_init(struct rte_eth_dev *dev);
+void hns3_flow_uninit(struct rte_eth_dev *dev);
+
+#endif /* _HNS3_FLOW_H_ */
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 7/9] net/hns3: remove magic numbers
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (5 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 6/9] net/hns3: add hns3 flow header file Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 8/9] net/hns3: fix the return value of the function Min Hu (Connor)
` (3 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
Removing magic numbers with macros.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 4 ++--
drivers/net/hns3/hns3_common.h | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 5fe0ff5ce7..290999f594 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -54,7 +54,7 @@ hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
- val = strtoull(value, NULL, 16);
+ val = strtoull(value, NULL, HNS3_CONVERT_TO_HEXADECIMAL);
*(uint64_t *)extra_args = val;
return 0;
@@ -67,7 +67,7 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
- val = strtoul(value, NULL, 10);
+ val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
*(uint16_t *)extra_args = val;
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 094a0bc5ff..68f9b1b96a 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -9,6 +9,9 @@
#include "hns3_ethdev.h"
+#define HNS3_CONVERT_TO_DECIMAL 10
+#define HNS3_CONVERT_TO_HEXADECIMAL 16
+
enum {
HNS3_IO_FUNC_HINT_NONE = 0,
HNS3_IO_FUNC_HINT_VEC,
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 8/9] net/hns3: fix the return value of the function
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (6 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 7/9] net/hns3: remove magic numbers Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
` (2 subsequent siblings)
10 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Huisong Li <lihuisong@huawei.com>
Fixing the return value of the function to clear static warning.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 290999f594..974219f9bf 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -154,10 +154,10 @@ hns3_clock_gettime_ms(void)
void hns3_ether_format_addr(char *buf, uint16_t size,
const struct rte_ether_addr *ether_addr)
{
- snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
- ether_addr->addr_bytes[0],
- ether_addr->addr_bytes[4],
- ether_addr->addr_bytes[5]);
+ (void)snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
+ ether_addr->addr_bytes[0],
+ ether_addr->addr_bytes[4],
+ ether_addr->addr_bytes[5]);
}
static int
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH 9/9] net/hns3: remove PF/VF duplicate code
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (7 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 8/9] net/hns3: fix the return value of the function Min Hu (Connor)
@ 2021-11-02 3:17 ` Min Hu (Connor)
2021-11-04 14:55 ` Ferruh Yigit
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
10 siblings, 1 reply; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-02 3:17 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, thomas
From: Chengwen Feng <fengchengwen@huawei.com>
This patch remove PF/VF duplicate code of:
1. get firmware version.
2. get device info.
3. rx interrupt related functions.
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 337 +++++++++++++++++++++++++++++-
drivers/net/hns3/hns3_common.h | 10 +
drivers/net/hns3/hns3_ethdev.c | 313 +--------------------------
drivers/net/hns3/hns3_ethdev.h | 14 +-
drivers/net/hns3/hns3_ethdev_vf.c | 325 +---------------------------
drivers/net/hns3/hns3_tm.c | 2 +-
6 files changed, 361 insertions(+), 640 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 974219f9bf..c9797d839d 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -3,9 +3,153 @@
*/
#include <rte_kvargs.h>
+#include <rte_bus_pci.h>
+#include <ethdev_pci.h>
+#include <rte_pci.h>
-#include "hns3_logs.h"
#include "hns3_common.h"
+#include "hns3_logs.h"
+#include "hns3_regs.h"
+#include "hns3_rxtx.h"
+
+int
+hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t version = hw->fw_version;
+ int ret;
+
+ ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+ if (ret < 0)
+ return -EINVAL;
+
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (size_t)ret)
+ return ret;
+ else
+ return 0;
+}
+
+int
+hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t queue_num = hw->tqps_num;
+
+ /*
+ * In interrupt mode, 'max_rx_queues' is set based on the number of
+ * MSI-X interrupt resources of the hardware.
+ */
+ if (hw->data->dev_conf.intr_conf.rxq == 1)
+ queue_num = hw->intr_tqps_num;
+
+ info->max_rx_queues = queue_num;
+ info->max_tx_queues = hw->tqps_num;
+ info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
+ info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
+ info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
+ info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
+ info->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_TCP_CKSUM |
+ DEV_RX_OFFLOAD_UDP_CKSUM |
+ DEV_RX_OFFLOAD_SCTP_CKSUM |
+ DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_OUTER_UDP_CKSUM |
+ DEV_RX_OFFLOAD_SCATTER |
+ DEV_RX_OFFLOAD_VLAN_STRIP |
+ DEV_RX_OFFLOAD_VLAN_FILTER |
+ DEV_RX_OFFLOAD_RSS_HASH |
+ DEV_RX_OFFLOAD_TCP_LRO);
+ info->tx_offload_capa = (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM |
+ DEV_TX_OFFLOAD_MULTI_SEGS |
+ DEV_TX_OFFLOAD_TCP_TSO |
+ DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO |
+ DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
+ DEV_TX_OFFLOAD_MBUF_FAST_FREE |
+ DEV_TX_OFFLOAD_VLAN_INSERT);
+
+ if (!hw->port_base_vlan_cfg.state)
+ info->tx_offload_capa |= DEV_TX_OFFLOAD_QINQ_INSERT;
+
+ if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
+ info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
+ if (hns3_dev_get_support(hw, INDEP_TXRX))
+ info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
+ RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
+
+ if (hns3_dev_get_support(hw, PTP))
+ info->rx_offload_capa |= DEV_RX_OFFLOAD_TIMESTAMP;
+
+ info->rx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
+ info->tx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
+ .nb_mtu_seg_max = hw->max_non_tso_bd_num,
+ };
+
+ info->default_rxconf = (struct rte_eth_rxconf) {
+ .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
+ /*
+ * If there are no available Rx buffer descriptors, incoming
+ * packets are always dropped by hardware based on hns3 network
+ * engine.
+ */
+ .rx_drop_en = 1,
+ .offloads = 0,
+ };
+ info->default_txconf = (struct rte_eth_txconf) {
+ .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
+ .offloads = 0,
+ };
+
+ info->reta_size = hw->rss_ind_tbl_size;
+ info->hash_key_size = HNS3_RSS_KEY_SIZE;
+ info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+
+ info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+ info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+
+ /*
+ * Next is the PF/VF difference section.
+ */
+ if (!hns->is_vf) {
+ info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
+ info->rx_offload_capa |= DEV_RX_OFFLOAD_KEEP_CRC;
+ info->speed_capa = hns3_get_speed_capa(hw);
+ } else {
+ info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
+ }
+
+ return 0;
+}
static int
hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
@@ -68,6 +212,12 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
+
+ /*
+ * 500ms is empirical value in process of mailbox communication. If
+ * the delay value is set to one lower thanthe empirical value, mailbox
+ * communication may fail.
+ */
if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
*(uint16_t *)extra_args = val;
@@ -116,6 +266,11 @@ hns3_parse_devargs(struct rte_eth_dev *dev)
hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
hns->dev_caps_mask = dev_caps_mask;
+
+ if (mbx_time_limit_ms != HNS3_MBX_DEF_TIME_LIMIT_MS)
+ hns3_warn(hw, "parsed %s = %u.", HNS3_DEVARG_MBX_TIME_LIMIT_MS,
+ mbx_time_limit_ms);
+ hns->mbx_time_limit_ms = mbx_time_limit_ms;
}
void
@@ -425,3 +580,183 @@ hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
}
}
+int
+hns3_init_ring_with_vector(struct hns3_hw *hw)
+{
+ uint16_t vec;
+ int ret;
+ int i;
+
+ /*
+ * In hns3 network engine, vector 0 is always the misc interrupt of this
+ * function, vector 1~N can be used respectively for the queues of the
+ * function. Tx and Rx queues with the same number share the interrupt
+ * vector. In the initialization clearing the all hardware mapping
+ * relationship configurations between queues and interrupt vectors is
+ * needed, so some error caused by the residual configurations, such as
+ * the unexpected Tx interrupt, can be avoid.
+ */
+ vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
+ if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
+ vec = vec - 1; /* the last interrupt is reserved */
+ hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
+ for (i = 0; i < hw->intr_tqps_num; i++) {
+ /*
+ * Set gap limiter/rate limiter/quanity limiter algorithm
+ * configuration for interrupt coalesce of queue's interrupt.
+ */
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
+ /*
+ * QL(quantity limiter) is not used currently, just set 0 to
+ * close it.
+ */
+ hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
+
+ ret = hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_TX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to unbind TX ring(%d) with "
+ "vector: %u, ret=%d", i, vec, ret);
+ return ret;
+ }
+
+ ret = hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to unbind RX ring(%d) with "
+ "vector: %u, ret=%d", i, vec, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_map_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint32_t intr_vector;
+ uint16_t q_id;
+ int ret;
+
+ /*
+ * hns3 needs a separate interrupt to be used as event interrupt which
+ * could not be shared with task queue pair, so KERNEL drivers need
+ * support multiple interrupt vectors.
+ */
+ if (dev->data->dev_conf.intr_conf.rxq == 0 ||
+ !rte_intr_cap_multiple(intr_handle))
+ return 0;
+
+ rte_intr_disable(intr_handle);
+ intr_vector = hw->used_rx_queues;
+ /* creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+
+ /* Allocate vector list */
+ if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
+ hw->used_rx_queues)) {
+ hns3_err(hw, "failed to allocate %u rx_queues intr_vec",
+ hw->used_rx_queues);
+ ret = -ENOMEM;
+ goto alloc_intr_vec_error;
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hw->ops.bind_ring_with_vector(hw, vec, true,
+ HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ goto bind_vector_error;
+
+ if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
+ goto bind_vector_error;
+ /*
+ * If there are not enough efds (e.g. not enough interrupt),
+ * remaining queues will be bond to the last interrupt.
+ */
+ if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
+ vec++;
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+bind_vector_error:
+ rte_intr_vec_list_free(intr_handle);
+alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+void
+hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ (void)hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ rte_intr_vec_list_free(intr_handle);
+}
+
+int
+hns3_restore_rx_interrupt(struct hns3_hw *hw)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hw->ops.bind_ring_with_vector(hw,
+ rte_intr_vec_list_index_get(intr_handle,
+ q_id),
+ true, HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 68f9b1b96a..0dbb1c0413 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -30,6 +30,11 @@ enum {
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
+int hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size);
+int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
+ struct rte_eth_dev_info *info);
+
void hns3_clock_gettime(struct timeval *tv);
uint64_t hns3_clock_calctime_ms(struct timeval *tv);
uint64_t hns3_clock_gettime_ms(void);
@@ -48,4 +53,9 @@ int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
void hns3_ether_format_addr(char *buf, uint16_t size,
const struct rte_ether_addr *ether_addr);
+int hns3_init_ring_with_vector(struct hns3_hw *hw);
+int hns3_map_rx_interrupt(struct rte_eth_dev *dev);
+void hns3_unmap_rx_interrupt(struct rte_eth_dev *dev);
+int hns3_restore_rx_interrupt(struct hns3_hw *hw);
+
#endif /* _HNS3_COMMON_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 2f4beacb87..847e660f44 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -1929,62 +1929,6 @@ hns3_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id, bool en,
return 0;
}
-static int
-hns3_init_ring_with_vector(struct hns3_hw *hw)
-{
- uint16_t vec;
- int ret;
- int i;
-
- /*
- * In hns3 network engine, vector 0 is always the misc interrupt of this
- * function, vector 1~N can be used respectively for the queues of the
- * function. Tx and Rx queues with the same number share the interrupt
- * vector. In the initialization clearing the all hardware mapping
- * relationship configurations between queues and interrupt vectors is
- * needed, so some error caused by the residual configurations, such as
- * the unexpected Tx interrupt, can be avoid.
- */
- vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
- if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
- vec = vec - 1; /* the last interrupt is reserved */
- hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
- for (i = 0; i < hw->intr_tqps_num; i++) {
- /*
- * Set gap limiter/rate limiter/quanity limiter algorithm
- * configuration for interrupt coalesce of queue's interrupt.
- */
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
- /*
- * QL(quantity limiter) is not used currently, just set 0 to
- * close it.
- */
- hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
-
- ret = hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_TX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "PF fail to unbind TX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
-
- ret = hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "PF fail to unbind RX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int
hns3_setup_dcb(struct rte_eth_dev *dev)
{
@@ -2255,7 +2199,7 @@ hns3_get_firber_port_speed_capa(uint32_t supported_speed)
return speed_capa;
}
-static uint32_t
+uint32_t
hns3_get_speed_capa(struct hns3_hw *hw)
{
struct hns3_mac *mac = &hw->mac;
@@ -2274,134 +2218,6 @@ hns3_get_speed_capa(struct hns3_hw *hw)
return speed_capa;
}
-int
-hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint16_t queue_num = hw->tqps_num;
-
- /*
- * In interrupt mode, 'max_rx_queues' is set based on the number of
- * MSI-X interrupt resources of the hardware.
- */
- if (hw->data->dev_conf.intr_conf.rxq == 1)
- queue_num = hw->intr_tqps_num;
-
- info->max_rx_queues = queue_num;
- info->max_tx_queues = hw->tqps_num;
- info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
- info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
- info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
- info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
- info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
- info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_KEEP_CRC |
- RTE_ETH_RX_OFFLOAD_SCATTER |
- RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
- RTE_ETH_RX_OFFLOAD_RSS_HASH |
- RTE_ETH_RX_OFFLOAD_TCP_LRO);
- info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
- RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
- hns3_txvlan_cap_get(hw));
-
- if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
- info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
-
- if (hns3_dev_get_support(hw, INDEP_TXRX))
- info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
- RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
-
- if (hns3_dev_get_support(hw, PTP))
- info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
-
- info->rx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- };
-
- info->tx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
- .nb_mtu_seg_max = hw->max_non_tso_bd_num,
- };
-
- info->speed_capa = hns3_get_speed_capa(hw);
- info->default_rxconf = (struct rte_eth_rxconf) {
- .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
- /*
- * If there are no available Rx buffer descriptors, incoming
- * packets are always dropped by hardware based on hns3 network
- * engine.
- */
- .rx_drop_en = 1,
- .offloads = 0,
- };
- info->default_txconf = (struct rte_eth_txconf) {
- .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
- .offloads = 0,
- };
-
- info->reta_size = hw->rss_ind_tbl_size;
- info->hash_key_size = HNS3_RSS_KEY_SIZE;
- info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
-
- info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
- info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
-
- return 0;
-}
-
-static int
-hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
- size_t fw_size)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint32_t version = hw->fw_version;
- int ret;
-
- ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
- hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
- HNS3_FW_VERSION_BYTE3_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
- HNS3_FW_VERSION_BYTE2_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
- HNS3_FW_VERSION_BYTE1_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
- HNS3_FW_VERSION_BYTE0_S));
- if (ret < 0)
- return -EINVAL;
-
- ret += 1; /* add the size of '\0' */
- if (fw_size < (size_t)ret)
- return ret;
- else
- return 0;
-}
-
static int
hns3_update_port_link_info(struct rte_eth_dev *eth_dev)
{
@@ -5280,98 +5096,6 @@ hns3_do_start(struct hns3_adapter *hns, bool reset_queue)
return ret;
}
-static int
-hns3_map_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint16_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint32_t intr_vector;
- uint16_t q_id;
- int ret;
-
- /*
- * hns3 needs a separate interrupt to be used as event interrupt which
- * could not be shared with task queue pair, so KERNEL drivers need
- * support multiple interrupt vectors.
- */
- if (dev->data->dev_conf.intr_conf.rxq == 0 ||
- !rte_intr_cap_multiple(intr_handle))
- return 0;
-
- rte_intr_disable(intr_handle);
- intr_vector = hw->used_rx_queues;
- /* creates event fd for each intr vector when MSIX is used */
- if (rte_intr_efd_enable(intr_handle, intr_vector))
- return -EINVAL;
-
- /* Allocate vector list */
- if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
- hw->used_rx_queues)) {
- hns3_err(hw, "failed to allocate %u rx_queues intr_vec",
- hw->used_rx_queues);
- ret = -ENOMEM;
- goto alloc_intr_vec_error;
- }
-
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
-
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3_bind_ring_with_vector(hw, vec, true,
- HNS3_RING_TYPE_RX, q_id);
- if (ret)
- goto bind_vector_error;
-
- if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
- goto bind_vector_error;
- /*
- * If there are not enough efds (e.g. not enough interrupt),
- * remaining queues will be bond to the last interrupt.
- */
- if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
- vec++;
- }
- rte_intr_enable(intr_handle);
- return 0;
-
-bind_vector_error:
- rte_intr_vec_list_free(intr_handle);
-alloc_intr_vec_error:
- rte_intr_efd_disable(intr_handle);
- return ret;
-}
-
-static int
-hns3_restore_rx_interrupt(struct hns3_hw *hw)
-{
- struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint16_t q_id;
- int ret;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return 0;
-
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3_bind_ring_with_vector(hw,
- rte_intr_vec_list_index_get(intr_handle,
- q_id),
- true, HNS3_RING_TYPE_RX, q_id);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static void
hns3_restore_filter(struct rte_eth_dev *dev)
{
@@ -5502,40 +5226,6 @@ hns3_do_stop(struct hns3_adapter *hns)
return 0;
}
-static void
-hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_adapter *hns = dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t q_id;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return;
-
- /* unmap the ring with vector */
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- (void)hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX,
- q_id);
- if (vec < base + rte_intr_nb_efd_get(intr_handle)
- - 1)
- vec++;
- }
- }
- /* Clean datapath event and queue/vec mapping */
- rte_intr_efd_disable(intr_handle);
- rte_intr_vec_list_free(intr_handle);
-}
-
static int
hns3_dev_stop(struct rte_eth_dev *dev)
{
@@ -6926,6 +6616,7 @@ hns3_init_hw_ops(struct hns3_hw *hw)
hw->ops.del_mc_mac_addr = hns3_remove_mc_mac_addr;
hw->ops.add_uc_mac_addr = hns3_add_uc_mac_addr;
hw->ops.del_uc_mac_addr = hns3_remove_uc_mac_addr;
+ hw->ops.bind_ring_with_vector = hns3_bind_ring_with_vector;
}
static int
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index a28c7c262b..55518a913d 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -437,6 +437,9 @@ struct hns3_hw_ops {
struct rte_ether_addr *mac_addr);
int (*del_uc_mac_addr)(struct hns3_hw *hw,
struct rte_ether_addr *mac_addr);
+ int (*bind_ring_with_vector)(struct hns3_hw *hw, uint16_t vector_id,
+ bool en, enum hns3_ring_type queue_type,
+ uint16_t queue_id);
};
#define HNS3_INTR_MAPPING_VEC_RSV_ONE 0
@@ -1038,8 +1041,6 @@ int hns3_buffer_alloc(struct hns3_hw *hw);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
-int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
- struct rte_eth_dev_info *info);
void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
uint32_t link_speed, uint8_t link_duplex);
void hns3vf_update_push_lsc_cap(struct hns3_hw *hw, bool supported);
@@ -1071,13 +1072,4 @@ is_reset_pending(struct hns3_adapter *hns)
return ret;
}
-static inline uint64_t
-hns3_txvlan_cap_get(struct hns3_hw *hw)
-{
- if (hw->port_base_vlan_cfg.state)
- return RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
- else
- return RTE_ETH_TX_OFFLOAD_VLAN_INSERT | RTE_ETH_TX_OFFLOAD_QINQ_INSERT;
-}
-
#endif /* _HNS3_ETHDEV_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 7e60090fd3..d8a99693e0 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -422,7 +422,7 @@ hns3vf_restore_promisc(struct hns3_adapter *hns)
}
static int
-hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
+hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id,
bool mmap, enum hns3_ring_type queue_type,
uint16_t queue_id)
{
@@ -434,7 +434,7 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
memset(&bind_msg, 0, sizeof(bind_msg));
code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR :
HNS3_MBX_UNMAP_RING_TO_VECTOR;
- bind_msg.vector_id = vector_id;
+ bind_msg.vector_id = (uint8_t)vector_id;
if (queue_type == HNS3_RING_TYPE_RX)
bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX;
@@ -454,62 +454,6 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
return ret;
}
-static int
-hns3vf_init_ring_with_vector(struct hns3_hw *hw)
-{
- uint16_t vec;
- int ret;
- int i;
-
- /*
- * In hns3 network engine, vector 0 is always the misc interrupt of this
- * function, vector 1~N can be used respectively for the queues of the
- * function. Tx and Rx queues with the same number share the interrupt
- * vector. In the initialization clearing the all hardware mapping
- * relationship configurations between queues and interrupt vectors is
- * needed, so some error caused by the residual configurations, such as
- * the unexpected Tx interrupt, can be avoid.
- */
- vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
- if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
- vec = vec - 1; /* the last interrupt is reserved */
- hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
- for (i = 0; i < hw->intr_tqps_num; i++) {
- /*
- * Set gap limiter/rate limiter/quanity limiter algorithm
- * configuration for interrupt coalesce of queue's interrupt.
- */
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
- /*
- * QL(quantity limiter) is not used currently, just set 0 to
- * close it.
- */
- hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
-
- ret = hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_TX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "VF fail to unbind TX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
-
- ret = hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "VF fail to unbind RX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int
hns3vf_dev_configure(struct rte_eth_dev *dev)
{
@@ -649,102 +593,6 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
return 0;
}
-static int
-hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint16_t q_num = hw->tqps_num;
-
- /*
- * In interrupt mode, 'max_rx_queues' is set based on the number of
- * MSI-X interrupt resources of the hardware.
- */
- if (hw->data->dev_conf.intr_conf.rxq == 1)
- q_num = hw->intr_tqps_num;
-
- info->max_rx_queues = q_num;
- info->max_tx_queues = hw->tqps_num;
- info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
- info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
- info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
- info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
- info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
-
- info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCATTER |
- RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
- RTE_ETH_RX_OFFLOAD_RSS_HASH |
- RTE_ETH_RX_OFFLOAD_TCP_LRO);
- info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
- RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
- hns3_txvlan_cap_get(hw));
-
- if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
- info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
-
- if (hns3_dev_get_support(hw, INDEP_TXRX))
- info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
- RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
-
- info->rx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- };
-
- info->tx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
- .nb_mtu_seg_max = hw->max_non_tso_bd_num,
- };
-
- info->default_rxconf = (struct rte_eth_rxconf) {
- .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
- /*
- * If there are no available Rx buffer descriptors, incoming
- * packets are always dropped by hardware based on hns3 network
- * engine.
- */
- .rx_drop_en = 1,
- .offloads = 0,
- };
- info->default_txconf = (struct rte_eth_txconf) {
- .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
- .offloads = 0,
- };
-
- info->reta_size = hw->rss_ind_tbl_size;
- info->hash_key_size = HNS3_RSS_KEY_SIZE;
- info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
-
- info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
- info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
-
- return 0;
-}
-
static void
hns3vf_clear_event_cause(struct hns3_hw *hw, uint32_t regclr)
{
@@ -1633,7 +1481,7 @@ hns3vf_init_hardware(struct hns3_adapter *hns)
* some error caused by the residual configurations, such as the
* unexpected interrupt, can be avoid.
*/
- ret = hns3vf_init_ring_with_vector(hw);
+ ret = hns3_init_ring_with_vector(hw);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init ring intr vector: %d", ret);
goto err_init_hardware;
@@ -1820,41 +1668,6 @@ hns3vf_do_stop(struct hns3_adapter *hns)
return 0;
}
-static void
-hns3vf_unmap_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t q_id;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return;
-
- /* unmap the ring with vector */
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- (void)hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX,
- q_id);
- if (vec < base + rte_intr_nb_efd_get(intr_handle)
- - 1)
- vec++;
- }
- }
- /* Clean datapath event and queue/vec mapping */
- rte_intr_efd_disable(intr_handle);
-
- /* Cleanup vector list */
- rte_intr_vec_list_free(intr_handle);
-}
-
static int
hns3vf_dev_stop(struct rte_eth_dev *dev)
{
@@ -1876,7 +1689,7 @@ hns3vf_dev_stop(struct rte_eth_dev *dev)
if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED) == 0) {
hns3_stop_tqps(hw);
hns3vf_do_stop(hns);
- hns3vf_unmap_rx_interrupt(dev);
+ hns3_unmap_rx_interrupt(dev);
hw->adapter_state = HNS3_NIC_CONFIGURED;
}
hns3_rx_scattered_reset(dev);
@@ -1917,34 +1730,6 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
return ret;
}
-static int
-hns3vf_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
- size_t fw_size)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint32_t version = hw->fw_version;
- int ret;
-
- ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
- hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
- HNS3_FW_VERSION_BYTE3_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
- HNS3_FW_VERSION_BYTE2_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
- HNS3_FW_VERSION_BYTE1_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
- HNS3_FW_VERSION_BYTE0_S));
- if (ret < 0)
- return -EINVAL;
-
- ret += 1; /* add the size of '\0' */
- if (fw_size < (size_t)ret)
- return ret;
- else
- return 0;
-}
-
static int
hns3vf_dev_link_update(struct rte_eth_dev *eth_dev,
__rte_unused int wait_to_complete)
@@ -2006,99 +1791,6 @@ hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue)
return ret;
}
-static int
-hns3vf_map_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint32_t intr_vector;
- uint16_t q_id;
- int ret;
-
- /*
- * hns3 needs a separate interrupt to be used as event interrupt which
- * could not be shared with task queue pair, so KERNEL drivers need
- * support multiple interrupt vectors.
- */
- if (dev->data->dev_conf.intr_conf.rxq == 0 ||
- !rte_intr_cap_multiple(intr_handle))
- return 0;
-
- rte_intr_disable(intr_handle);
- intr_vector = hw->used_rx_queues;
- /* It creates event fd for each intr vector when MSIX is used */
- if (rte_intr_efd_enable(intr_handle, intr_vector))
- return -EINVAL;
-
- /* Allocate vector list */
- if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
- hw->used_rx_queues)) {
- hns3_err(hw, "Failed to allocate %u rx_queues"
- " intr_vec", hw->used_rx_queues);
- ret = -ENOMEM;
- goto vf_alloc_intr_vec_error;
- }
-
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
-
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3vf_bind_ring_with_vector(hw, vec, true,
- HNS3_RING_TYPE_RX, q_id);
- if (ret)
- goto vf_bind_vector_error;
-
- if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
- goto vf_bind_vector_error;
-
- /*
- * If there are not enough efds (e.g. not enough interrupt),
- * remaining queues will be bond to the last interrupt.
- */
- if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
- vec++;
- }
- rte_intr_enable(intr_handle);
- return 0;
-
-vf_bind_vector_error:
- rte_intr_vec_list_free(intr_handle);
-vf_alloc_intr_vec_error:
- rte_intr_efd_disable(intr_handle);
- return ret;
-}
-
-static int
-hns3vf_restore_rx_interrupt(struct hns3_hw *hw)
-{
- struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint16_t q_id;
- int ret;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return 0;
-
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3vf_bind_ring_with_vector(hw,
- rte_intr_vec_list_index_get(intr_handle,
- q_id),
- true, HNS3_RING_TYPE_RX, q_id);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static void
hns3vf_restore_filter(struct rte_eth_dev *dev)
{
@@ -2124,7 +1816,7 @@ hns3vf_dev_start(struct rte_eth_dev *dev)
rte_spinlock_unlock(&hw->lock);
return ret;
}
- ret = hns3vf_map_rx_interrupt(dev);
+ ret = hns3_map_rx_interrupt(dev);
if (ret)
goto map_rx_inter_err;
@@ -2441,7 +2133,7 @@ hns3vf_restore_conf(struct hns3_adapter *hns)
if (ret)
goto err_vlan_table;
- ret = hns3vf_restore_rx_interrupt(hw);
+ ret = hns3_restore_rx_interrupt(hw);
if (ret)
goto err_vlan_table;
@@ -2615,8 +2307,8 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.xstats_reset = hns3_dev_xstats_reset,
.xstats_get_by_id = hns3_dev_xstats_get_by_id,
.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
- .dev_infos_get = hns3vf_dev_infos_get,
- .fw_version_get = hns3vf_fw_version_get,
+ .dev_infos_get = hns3_dev_infos_get,
+ .fw_version_get = hns3_fw_version_get,
.rx_queue_setup = hns3_rx_queue_setup,
.tx_queue_setup = hns3_tx_queue_setup,
.rx_queue_release = hns3_dev_rx_queue_release,
@@ -2665,6 +2357,7 @@ hns3vf_init_hw_ops(struct hns3_hw *hw)
hw->ops.del_mc_mac_addr = hns3vf_remove_mc_mac_addr;
hw->ops.add_uc_mac_addr = hns3vf_add_uc_mac_addr;
hw->ops.del_uc_mac_addr = hns3vf_remove_uc_mac_addr;
+ hw->ops.bind_ring_with_vector = hns3vf_bind_ring_with_vector;
}
static int
diff --git a/drivers/net/hns3/hns3_tm.c b/drivers/net/hns3/hns3_tm.c
index 44b607af7a..e1089b6bd0 100644
--- a/drivers/net/hns3/hns3_tm.c
+++ b/drivers/net/hns3/hns3_tm.c
@@ -4,7 +4,7 @@
#include <rte_malloc.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_dcb.h"
#include "hns3_logs.h"
#include "hns3_tm.h"
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [dpdk-dev] [PATCH 9/9] net/hns3: remove PF/VF duplicate code
2021-11-02 3:17 ` [dpdk-dev] [PATCH 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
@ 2021-11-04 14:55 ` Ferruh Yigit
2021-11-05 2:49 ` Min Hu (Connor)
0 siblings, 1 reply; 38+ messages in thread
From: Ferruh Yigit @ 2021-11-04 14:55 UTC (permalink / raw)
To: Min Hu (Connor), dev; +Cc: thomas
On 11/2/2021 3:17 AM, Min Hu (Connor) wrote:
> From: Chengwen Feng <fengchengwen@huawei.com>
>
> This patch remove PF/VF duplicate code of:
> 1. get firmware version.
> 2. get device info.
> 3. rx interrupt related functions.
>
> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
> Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
<...>
> +int
> +hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
> +{
> + struct hns3_adapter *hns = eth_dev->data->dev_private;
> + struct hns3_hw *hw = &hns->hw;
> + uint16_t queue_num = hw->tqps_num;
> +
> + /*
> + * In interrupt mode, 'max_rx_queues' is set based on the number of
> + * MSI-X interrupt resources of the hardware.
> + */
> + if (hw->data->dev_conf.intr_conf.rxq == 1)
> + queue_num = hw->intr_tqps_num;
> +
> + info->max_rx_queues = queue_num;
> + info->max_tx_queues = hw->tqps_num;
> + info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
> + info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
> + info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
> + info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
> + info->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM |
> + DEV_RX_OFFLOAD_TCP_CKSUM |
> + DEV_RX_OFFLOAD_UDP_CKSUM |
> + DEV_RX_OFFLOAD_SCTP_CKSUM |
> + DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
> + DEV_RX_OFFLOAD_OUTER_UDP_CKSUM |
> + DEV_RX_OFFLOAD_SCATTER |
> + DEV_RX_OFFLOAD_VLAN_STRIP |
> + DEV_RX_OFFLOAD_VLAN_FILTER |
> + DEV_RX_OFFLOAD_RSS_HASH |
> + DEV_RX_OFFLOAD_TCP_LRO);
> + info->tx_offload_capa = (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
> + DEV_TX_OFFLOAD_IPV4_CKSUM |
> + DEV_TX_OFFLOAD_TCP_CKSUM |
> + DEV_TX_OFFLOAD_UDP_CKSUM |
> + DEV_TX_OFFLOAD_SCTP_CKSUM |
> + DEV_TX_OFFLOAD_MULTI_SEGS |
> + DEV_TX_OFFLOAD_TCP_TSO |
> + DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
> + DEV_TX_OFFLOAD_GRE_TNL_TSO |
> + DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
> + DEV_TX_OFFLOAD_MBUF_FAST_FREE |
> + DEV_TX_OFFLOAD_VLAN_INSERT);
The function changed while moving, please be aware renamed macros in upsteram.
Can you please rebase your patch on top of latest next-net?
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [dpdk-dev] [PATCH 9/9] net/hns3: remove PF/VF duplicate code
2021-11-04 14:55 ` Ferruh Yigit
@ 2021-11-05 2:49 ` Min Hu (Connor)
0 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:49 UTC (permalink / raw)
To: Ferruh Yigit, dev; +Cc: thomas
Hi,
在 2021/11/4 22:55, Ferruh Yigit 写道:
> On 11/2/2021 3:17 AM, Min Hu (Connor) wrote:
>> From: Chengwen Feng <fengchengwen@huawei.com>
>>
>> This patch remove PF/VF duplicate code of:
>> 1. get firmware version.
>> 2. get device info.
>> 3. rx interrupt related functions.
>>
>> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
>> Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
>
> <...>
>
>> +int
>> +hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct
>> rte_eth_dev_info *info)
>> +{
>> + struct hns3_adapter *hns = eth_dev->data->dev_private;
>> + struct hns3_hw *hw = &hns->hw;
>> + uint16_t queue_num = hw->tqps_num;
>> +
>> + /*
>> + * In interrupt mode, 'max_rx_queues' is set based on the number of
>> + * MSI-X interrupt resources of the hardware.
>> + */
>> + if (hw->data->dev_conf.intr_conf.rxq == 1)
>> + queue_num = hw->intr_tqps_num;
>> +
>> + info->max_rx_queues = queue_num;
>> + info->max_tx_queues = hw->tqps_num;
>> + info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
>> + info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
>> + info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
>> + info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
>> + info->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM |
>> + DEV_RX_OFFLOAD_TCP_CKSUM |
>> + DEV_RX_OFFLOAD_UDP_CKSUM |
>> + DEV_RX_OFFLOAD_SCTP_CKSUM |
>> + DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
>> + DEV_RX_OFFLOAD_OUTER_UDP_CKSUM |
>> + DEV_RX_OFFLOAD_SCATTER |
>> + DEV_RX_OFFLOAD_VLAN_STRIP |
>> + DEV_RX_OFFLOAD_VLAN_FILTER |
>> + DEV_RX_OFFLOAD_RSS_HASH |
>> + DEV_RX_OFFLOAD_TCP_LRO);
>> + info->tx_offload_capa = (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
>> + DEV_TX_OFFLOAD_IPV4_CKSUM |
>> + DEV_TX_OFFLOAD_TCP_CKSUM |
>> + DEV_TX_OFFLOAD_UDP_CKSUM |
>> + DEV_TX_OFFLOAD_SCTP_CKSUM |
>> + DEV_TX_OFFLOAD_MULTI_SEGS |
>> + DEV_TX_OFFLOAD_TCP_TSO |
>> + DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
>> + DEV_TX_OFFLOAD_GRE_TNL_TSO |
>> + DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
>> + DEV_TX_OFFLOAD_MBUF_FAST_FREE |
>> + DEV_TX_OFFLOAD_VLAN_INSERT);
>
> The function changed while moving, please be aware renamed macros in
> upsteram.
> Can you please rebase your patch on top of latest next-net?
fixed in v2, thanks.
>
> .
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (8 preceding siblings ...)
2021-11-02 3:17 ` [dpdk-dev] [PATCH 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
` (8 more replies)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
10 siblings, 9 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
This patch set contains refactor patches and code check patches.
Chengwen Feng (1):
net/hns3: remove PF/VF duplicate code
Huisong Li (7):
net/hns3: fix the shift of DMA address in Rx/Tx queue
net/hns3: remove a redundant function declaration
net/hns3: modifying code alignment
net/hns3: use unsigned integer for bitwise operations
net/hns3: extract a common file
net/hns3: remove magic numbers
net/hns3: fix the return value of the function
Min Hu (Connor) (1):
net/hns3: add hns3 flow header file
---
v2:
* rebase patch on top of latest next-net
drivers/net/hns3.tar.gz | Bin 0 -> 203522 bytes
drivers/net/hns3/hns3_cmd.c | 2 +-
drivers/net/hns3/hns3_common.c | 763 ++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_common.h | 61 +++
drivers/net/hns3/hns3_ethdev.c | 749 +----------------------------
drivers/net/hns3/hns3_ethdev.h | 47 +-
drivers/net/hns3/hns3_ethdev_vf.c | 328 +------------
drivers/net/hns3/hns3_fdir.h | 31 --
drivers/net/hns3/hns3_flow.c | 1 +
drivers/net/hns3/hns3_flow.h | 44 ++
drivers/net/hns3/hns3_intr.c | 2 +-
drivers/net/hns3/hns3_mbx.c | 2 +-
drivers/net/hns3/hns3_rxtx.c | 8 +-
drivers/net/hns3/hns3_rxtx.h | 1 -
drivers/net/hns3/hns3_tm.c | 2 +-
drivers/net/hns3/meson.build | 1 +
16 files changed, 902 insertions(+), 1140 deletions(-)
create mode 100644 drivers/net/hns3.tar.gz
create mode 100644 drivers/net/hns3/hns3_common.c
create mode 100644 drivers/net/hns3/hns3_common.h
create mode 100644 drivers/net/hns3/hns3_flow.h
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 17:03 ` Ferruh Yigit
2021-11-05 17:05 ` Ferruh Yigit
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 2/9] net/hns3: remove a redundant function declaration Min Hu (Connor)
` (7 subsequent siblings)
8 siblings, 2 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
The patch obtains the upper 32 bits of the Rx/Tx queue DMA address in one
step instead of two steps.
Fixes: bba636698316 ("net/hns3: support Rx/Tx and related operations")
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/hns3_rxtx.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index ceb98025f8..00af73c850 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -322,7 +322,7 @@ hns3_init_rx_queue_hw(struct hns3_rx_queue *rxq)
hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_L_REG, (uint32_t)dma_addr);
hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_H_REG,
- (uint32_t)((dma_addr >> 31) >> 1));
+ (uint32_t)(dma_addr >> 32));
hns3_write_dev(rxq, HNS3_RING_RX_BD_LEN_REG,
hns3_buf_size2type(rx_buf_len));
@@ -337,7 +337,7 @@ hns3_init_tx_queue_hw(struct hns3_tx_queue *txq)
hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_L_REG, (uint32_t)dma_addr);
hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_H_REG,
- (uint32_t)((dma_addr >> 31) >> 1));
+ (uint32_t)(dma_addr >> 32));
hns3_write_dev(txq, HNS3_RING_TX_BD_NUM_REG,
HNS3_CFG_DESC_NUM(txq->nb_tx_desc));
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 2/9] net/hns3: remove a redundant function declaration
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 3/9] net/hns3: modifying code alignment Min Hu (Connor)
` (6 subsequent siblings)
8 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
This patch removes a redundant function declaration for
hns3_rx_check_vec_support().
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/hns3/hns3_rxtx.h b/drivers/net/hns3/hns3_rxtx.h
index 33ee8c61a0..63bafc68b6 100644
--- a/drivers/net/hns3/hns3_rxtx.h
+++ b/drivers/net/hns3/hns3_rxtx.h
@@ -711,7 +711,6 @@ uint16_t hns3_recv_pkts_vec_sve(void *rx_queue, struct rte_mbuf **rx_pkts,
int hns3_rx_burst_mode_get(struct rte_eth_dev *dev,
__rte_unused uint16_t queue_id,
struct rte_eth_burst_mode *mode);
-int hns3_rx_check_vec_support(struct rte_eth_dev *dev);
uint16_t hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
uint16_t hns3_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 3/9] net/hns3: modifying code alignment
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 2/9] net/hns3: remove a redundant function declaration Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 4/9] net/hns3: use unsigned integer for bitwise operations Min Hu (Connor)
` (5 subsequent siblings)
8 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
This patch modifies some code alignment issues to make the code style more
consistent.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 00af73c850..7e55b24cb8 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -1907,7 +1907,7 @@ hns3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
*/
if (hns->is_vf || hw->vlan_mode == HNS3_SW_SHIFT_AND_DISCARD_MODE)
rxq->pvid_sw_discard_en = hw->port_base_vlan_cfg.state ==
- HNS3_PORT_BASE_VLAN_ENABLE;
+ HNS3_PORT_BASE_VLAN_ENABLE;
else
rxq->pvid_sw_discard_en = false;
rxq->ptype_en = hns3_dev_get_support(hw, RXD_ADV_LAYOUT) ? true : false;
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 4/9] net/hns3: use unsigned integer for bitwise operations
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (2 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 3/9] net/hns3: modifying code alignment Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 5/9] net/hns3: extract a common file Min Hu (Connor)
` (4 subsequent siblings)
8 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
Bitwise operations should be used only with unsigned integer. This patch
modifies some code that does not meet this rule.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index c5543c48ef..ddf85a1705 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -2104,7 +2104,7 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
int max_tc = 0;
int i;
- if ((rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
+ if (((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
(tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_DCB ||
tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_ONLY)) {
hns3_err(hw, "VMDQ is not supported, rx_mq_mode = %d, tx_mq_mode = %d.",
@@ -2114,7 +2114,7 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
- if (rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
+ if ((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
if (dcb_rx_conf->nb_tcs > pf->tc_max) {
hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
dcb_rx_conf->nb_tcs, pf->tc_max);
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 5/9] net/hns3: extract a common file
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (3 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 4/9] net/hns3: use unsigned integer for bitwise operations Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 17:11 ` Ferruh Yigit
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 6/9] net/hns3: add hns3 flow header file Min Hu (Connor)
` (3 subsequent siblings)
8 siblings, 1 reply; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
This patch extracts a common file to store the common code for PF and VF
driver.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_cmd.c | 2 +-
drivers/net/hns3/hns3_common.c | 427 +++++++++++++++++++++++++++++
drivers/net/hns3/hns3_common.h | 48 ++++
drivers/net/hns3/hns3_ethdev.c | 430 +-----------------------------
drivers/net/hns3/hns3_ethdev.h | 30 +--
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_intr.c | 2 +-
drivers/net/hns3/hns3_mbx.c | 2 +-
drivers/net/hns3/hns3_rxtx.c | 2 +-
drivers/net/hns3/meson.build | 1 +
10 files changed, 485 insertions(+), 460 deletions(-)
create mode 100644 drivers/net/hns3/hns3_common.c
create mode 100644 drivers/net/hns3/hns3_common.h
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 50769c6226..2ce59d8de6 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -5,7 +5,7 @@
#include <ethdev_pci.h>
#include <rte_io.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_regs.h"
#include "hns3_intr.h"
#include "hns3_logs.h"
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
new file mode 100644
index 0000000000..5fe0ff5ce7
--- /dev/null
+++ b/drivers/net/hns3/hns3_common.c
@@ -0,0 +1,427 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#include <rte_kvargs.h>
+
+#include "hns3_logs.h"
+#include "hns3_common.h"
+
+static int
+hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
+{
+ uint32_t hint = HNS3_IO_FUNC_HINT_NONE;
+
+ RTE_SET_USED(key);
+
+ if (strcmp(value, "vec") == 0)
+ hint = HNS3_IO_FUNC_HINT_VEC;
+ else if (strcmp(value, "sve") == 0)
+ hint = HNS3_IO_FUNC_HINT_SVE;
+ else if (strcmp(value, "simple") == 0)
+ hint = HNS3_IO_FUNC_HINT_SIMPLE;
+ else if (strcmp(value, "common") == 0)
+ hint = HNS3_IO_FUNC_HINT_COMMON;
+
+ /* If the hint is valid then update output parameters */
+ if (hint != HNS3_IO_FUNC_HINT_NONE)
+ *(uint32_t *)extra_args = hint;
+
+ return 0;
+}
+
+static const char *
+hns3_get_io_hint_func_name(uint32_t hint)
+{
+ switch (hint) {
+ case HNS3_IO_FUNC_HINT_VEC:
+ return "vec";
+ case HNS3_IO_FUNC_HINT_SVE:
+ return "sve";
+ case HNS3_IO_FUNC_HINT_SIMPLE:
+ return "simple";
+ case HNS3_IO_FUNC_HINT_COMMON:
+ return "common";
+ default:
+ return "none";
+ }
+}
+
+static int
+hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
+{
+ uint64_t val;
+
+ RTE_SET_USED(key);
+
+ val = strtoull(value, NULL, 16);
+ *(uint64_t *)extra_args = val;
+
+ return 0;
+}
+
+static int
+hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
+{
+ uint32_t val;
+
+ RTE_SET_USED(key);
+
+ val = strtoul(value, NULL, 10);
+ if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
+ *(uint16_t *)extra_args = val;
+
+ return 0;
+}
+
+void
+hns3_parse_devargs(struct rte_eth_dev *dev)
+{
+ uint16_t mbx_time_limit_ms = HNS3_MBX_DEF_TIME_LIMIT_MS;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE;
+ uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t dev_caps_mask = 0;
+ struct rte_kvargs *kvlist;
+
+ if (dev->device->devargs == NULL)
+ return;
+
+ kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL);
+ if (!kvlist)
+ return;
+
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT,
+ &hns3_parse_io_hint_func, &rx_func_hint);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
+ &hns3_parse_io_hint_func, &tx_func_hint);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
+ &hns3_parse_dev_caps_mask, &dev_caps_mask);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
+ &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
+
+ rte_kvargs_free(kvlist);
+
+ if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE)
+ hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT,
+ hns3_get_io_hint_func_name(rx_func_hint));
+ hns->rx_func_hint = rx_func_hint;
+ if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE)
+ hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT,
+ hns3_get_io_hint_func_name(tx_func_hint));
+ hns->tx_func_hint = tx_func_hint;
+
+ if (dev_caps_mask != 0)
+ hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
+ HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
+ hns->dev_caps_mask = dev_caps_mask;
+}
+
+void
+hns3_clock_gettime(struct timeval *tv)
+{
+#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
+#define CLOCK_TYPE CLOCK_MONOTONIC_RAW
+#else
+#define CLOCK_TYPE CLOCK_MONOTONIC
+#endif
+#define NSEC_TO_USEC_DIV 1000
+
+ struct timespec spec;
+ (void)clock_gettime(CLOCK_TYPE, &spec);
+
+ tv->tv_sec = spec.tv_sec;
+ tv->tv_usec = spec.tv_nsec / NSEC_TO_USEC_DIV;
+}
+
+uint64_t
+hns3_clock_calctime_ms(struct timeval *tv)
+{
+ return (uint64_t)tv->tv_sec * MSEC_PER_SEC +
+ tv->tv_usec / USEC_PER_MSEC;
+}
+
+uint64_t
+hns3_clock_gettime_ms(void)
+{
+ struct timeval tv;
+
+ hns3_clock_gettime(&tv);
+ return hns3_clock_calctime_ms(&tv);
+}
+
+void hns3_ether_format_addr(char *buf, uint16_t size,
+ const struct rte_ether_addr *ether_addr)
+{
+ snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
+ ether_addr->addr_bytes[0],
+ ether_addr->addr_bytes[4],
+ ether_addr->addr_bytes[5]);
+}
+
+static int
+hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ uint16_t mac_addrs_capa;
+ uint32_t i;
+ uint32_t j;
+
+ if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
+ hns3_err(hw, "failed to set mc mac addr, nb_mc_addr(%u) "
+ "invalid. valid range: 0~%d",
+ nb_mc_addr, HNS3_MC_MACADDR_NUM);
+ return -EINVAL;
+ }
+
+ /* Check if input mac addresses are valid */
+ for (i = 0; i < nb_mc_addr; i++) {
+ addr = &mc_addr_set[i];
+ if (!rte_is_multicast_ether_addr(addr)) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw,
+ "failed to set mc mac addr, addr(%s) invalid.",
+ mac_str);
+ return -EINVAL;
+ }
+
+ /* Check if there are duplicate addresses */
+ for (j = i + 1; j < nb_mc_addr; j++) {
+ if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
+ hns3_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. two same addrs(%s).",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Check if there are duplicate addresses between mac_addrs
+ * and mc_addr_set
+ */
+ mac_addrs_capa = hns->is_vf ? HNS3_VF_UC_MACADDR_NUM :
+ HNS3_UC_MACADDR_NUM;
+ for (j = 0; j < mac_addrs_capa; j++) {
+ if (rte_is_same_ether_addr(addr,
+ &hw->data->mac_addrs[j])) {
+ hns3_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. addrs(%s) has already "
+ "configured in mac_addr add API",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *addr;
+ int cur_addr_num;
+ int set_addr_num;
+ int num;
+ int ret;
+ int i;
+
+ /* Check if input parameters are valid */
+ ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
+ if (ret)
+ return ret;
+
+ rte_spinlock_lock(&hw->lock);
+ cur_addr_num = hw->mc_addrs_num;
+ for (i = 0; i < cur_addr_num; i++) {
+ num = cur_addr_num - i - 1;
+ addr = &hw->mc_addrs[num];
+ ret = hw->ops.del_mc_mac_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ hw->mc_addrs_num--;
+ }
+
+ set_addr_num = (int)nb_mc_addr;
+ for (i = 0; i < set_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ ret = hw->ops.add_mc_mac_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
+ hw->mc_addrs_num++;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+int
+hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ if (!rte_is_multicast_ether_addr(addr))
+ continue;
+ if (del)
+ ret = hw->ops.del_mc_mac_addr(hw, addr);
+ else
+ ret = hw->ops.add_mc_mac_addr(hw, addr);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_dbg(hw, "failed to %s mc mac addr: %s ret = %d",
+ del ? "Remove" : "Restore", mac_str, ret);
+ }
+ }
+ return ret;
+}
+
+int
+hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_hw_ops *ops = &hw->ops;
+ struct rte_ether_addr *addr;
+ uint16_t mac_addrs_capa;
+ int ret = 0;
+ int i;
+
+ mac_addrs_capa =
+ hns->is_vf ? HNS3_VF_UC_MACADDR_NUM : HNS3_UC_MACADDR_NUM;
+ for (i = 0; i < mac_addrs_capa; i++) {
+ addr = &hw->data->mac_addrs[i];
+ if (rte_is_zero_ether_addr(addr))
+ continue;
+ if (rte_is_multicast_ether_addr(addr))
+ ret = del ? ops->del_mc_mac_addr(hw, addr) :
+ ops->add_mc_mac_addr(hw, addr);
+ else
+ ret = del ? ops->del_uc_mac_addr(hw, addr) :
+ ops->add_uc_mac_addr(hw, addr);
+
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to %s mac addr(%s) index:%d ret = %d.",
+ del ? "remove" : "restore", mac_str, i, ret);
+ }
+ }
+
+ return ret;
+}
+
+static bool
+hns3_find_duplicate_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mc_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ /* Check if there are duplicate addresses in mc_addrs[] */
+ if (rte_is_same_ether_addr(addr, mc_addr)) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to add mc mac addr, same addrs"
+ "(%s) is added by the set_mc_mac_addr_list "
+ "API", mac_str);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int
+hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx, __rte_unused uint32_t pool)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ /*
+ * In hns3 network engine adding UC and MC mac address with different
+ * commands with firmware. We need to determine whether the input
+ * address is a UC or a MC address to call different commands.
+ * By the way, it is recommended calling the API function named
+ * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
+ * using the rte_eth_dev_mac_addr_add API function to set MC mac address
+ * may affect the specifications of UC mac addresses.
+ */
+ if (rte_is_multicast_ether_addr(mac_addr)) {
+ if (hns3_find_duplicate_mc_addr(hw, mac_addr)) {
+ rte_spinlock_unlock(&hw->lock);
+ return -EINVAL;
+ }
+ ret = hw->ops.add_mc_mac_addr(hw, mac_addr);
+ } else {
+ ret = hw->ops.add_uc_mac_addr(hw, mac_addr);
+ }
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to add mac addr(%s), ret = %d", mac_str,
+ ret);
+ }
+
+ return ret;
+}
+
+void
+hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ /* index will be checked by upper level rte interface */
+ struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hw->ops.del_mc_mac_addr(hw, mac_addr);
+ else
+ ret = hw->ops.del_uc_mac_addr(hw, mac_addr);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to remove mac addr(%s), ret = %d", mac_str,
+ ret);
+ }
+}
+
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
new file mode 100644
index 0000000000..094a0bc5ff
--- /dev/null
+++ b/drivers/net/hns3/hns3_common.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#ifndef _HNS3_COMMON_H_
+#define _HNS3_COMMON_H_
+
+#include <sys/time.h>
+
+#include "hns3_ethdev.h"
+
+enum {
+ HNS3_IO_FUNC_HINT_NONE = 0,
+ HNS3_IO_FUNC_HINT_VEC,
+ HNS3_IO_FUNC_HINT_SVE,
+ HNS3_IO_FUNC_HINT_SIMPLE,
+ HNS3_IO_FUNC_HINT_COMMON
+};
+
+#define HNS3_DEVARG_RX_FUNC_HINT "rx_func_hint"
+#define HNS3_DEVARG_TX_FUNC_HINT "tx_func_hint"
+
+#define HNS3_DEVARG_DEV_CAPS_MASK "dev_caps_mask"
+
+#define HNS3_DEVARG_MBX_TIME_LIMIT_MS "mbx_time_limit_ms"
+
+#define MSEC_PER_SEC 1000L
+#define USEC_PER_MSEC 1000L
+
+void hns3_clock_gettime(struct timeval *tv);
+uint64_t hns3_clock_calctime_ms(struct timeval *tv);
+uint64_t hns3_clock_gettime_ms(void);
+
+void hns3_parse_devargs(struct rte_eth_dev *dev);
+
+int hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del);
+int hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del);
+int hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx, __rte_unused uint32_t pool);
+
+void hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx);
+int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr);
+void hns3_ether_format_addr(char *buf, uint16_t size,
+ const struct rte_ether_addr *ether_addr);
+
+#endif /* _HNS3_COMMON_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index ddf85a1705..2ddd29515a 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -6,9 +6,9 @@
#include <rte_bus_pci.h>
#include <ethdev_pci.h>
#include <rte_pci.h>
-#include <rte_kvargs.h>
#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_intr.h"
@@ -105,14 +105,6 @@ static int hns3_do_stop(struct hns3_adapter *hns);
static int hns3_check_port_speed(struct hns3_hw *hw, uint32_t link_speeds);
static int hns3_cfg_mac_mode(struct hns3_hw *hw, bool enable);
-void hns3_ether_format_addr(char *buf, uint16_t size,
- const struct rte_ether_addr *ether_addr)
-{
- snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
- ether_addr->addr_bytes[0],
- ether_addr->addr_bytes[4],
- ether_addr->addr_bytes[5]);
-}
static void
hns3_pf_disable_irq0(struct hns3_hw *hw)
@@ -1609,68 +1601,6 @@ hns3_add_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-static bool
-hns3_find_duplicate_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mc_addr)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct rte_ether_addr *addr;
- int i;
-
- for (i = 0; i < hw->mc_addrs_num; i++) {
- addr = &hw->mc_addrs[i];
- /* Check if there are duplicate addresses in mc_addrs[] */
- if (rte_is_same_ether_addr(addr, mc_addr)) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to add mc mac addr, same addrs"
- "(%s) is added by the set_mc_mac_addr_list "
- "API", mac_str);
- return true;
- }
- }
-
- return false;
-}
-
-int
-hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
- __rte_unused uint32_t idx, __rte_unused uint32_t pool)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- int ret;
-
- rte_spinlock_lock(&hw->lock);
-
- /*
- * In hns3 network engine adding UC and MC mac address with different
- * commands with firmware. We need to determine whether the input
- * address is a UC or a MC address to call different commands.
- * By the way, it is recommended calling the API function named
- * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
- * using the rte_eth_dev_mac_addr_add API function to set MC mac address
- * may affect the specifications of UC mac addresses.
- */
- if (rte_is_multicast_ether_addr(mac_addr)) {
- if (hns3_find_duplicate_mc_addr(hw, mac_addr)) {
- rte_spinlock_unlock(&hw->lock);
- return -EINVAL;
- }
- ret = hw->ops.add_mc_mac_addr(hw, mac_addr);
- } else {
- ret = hw->ops.add_uc_mac_addr(hw, mac_addr);
- }
- rte_spinlock_unlock(&hw->lock);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- mac_addr);
- hns3_err(hw, "failed to add mac addr(%s), ret = %d", mac_str,
- ret);
- }
-
- return ret;
-}
-
static int
hns3_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
{
@@ -1699,30 +1629,6 @@ hns3_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-void
-hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- /* index will be checked by upper level rte interface */
- struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- int ret;
-
- rte_spinlock_lock(&hw->lock);
-
- if (rte_is_multicast_ether_addr(mac_addr))
- ret = hw->ops.del_mc_mac_addr(hw, mac_addr);
- else
- ret = hw->ops.del_uc_mac_addr(hw, mac_addr);
- rte_spinlock_unlock(&hw->lock);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- mac_addr);
- hns3_err(hw, "failed to remove mac addr(%s), ret = %d", mac_str,
- ret);
- }
-}
-
static int
hns3_set_default_mac_addr(struct rte_eth_dev *dev,
struct rte_ether_addr *mac_addr)
@@ -1787,41 +1693,6 @@ hns3_set_default_mac_addr(struct rte_eth_dev *dev,
return ret;
}
-int
-hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct hns3_hw *hw = &hns->hw;
- struct hns3_hw_ops *ops = &hw->ops;
- struct rte_ether_addr *addr;
- uint16_t mac_addrs_capa;
- int ret = 0;
- int i;
-
- mac_addrs_capa =
- hns->is_vf ? HNS3_VF_UC_MACADDR_NUM : HNS3_UC_MACADDR_NUM;
- for (i = 0; i < mac_addrs_capa; i++) {
- addr = &hw->data->mac_addrs[i];
- if (rte_is_zero_ether_addr(addr))
- continue;
- if (rte_is_multicast_ether_addr(addr))
- ret = del ? ops->del_mc_mac_addr(hw, addr) :
- ops->add_mc_mac_addr(hw, addr);
- else
- ret = del ? ops->del_uc_mac_addr(hw, addr) :
- ops->add_uc_mac_addr(hw, addr);
-
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to %s mac addr(%s) index:%d ret = %d.",
- del ? "remove" : "restore", mac_str, i, ret);
- }
- }
-
- return ret;
-}
-
static void
hns3_update_desc_vfid(struct hns3_cmd_desc *desc, uint8_t vfid, bool clr)
{
@@ -1947,150 +1818,6 @@ hns3_remove_mc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-static int
-hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr)
-{
- struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct rte_ether_addr *addr;
- uint16_t mac_addrs_capa;
- uint32_t i;
- uint32_t j;
-
- if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
- hns3_err(hw, "failed to set mc mac addr, nb_mc_addr(%u) "
- "invalid. valid range: 0~%d",
- nb_mc_addr, HNS3_MC_MACADDR_NUM);
- return -EINVAL;
- }
-
- /* Check if input mac addresses are valid */
- for (i = 0; i < nb_mc_addr; i++) {
- addr = &mc_addr_set[i];
- if (!rte_is_multicast_ether_addr(addr)) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw,
- "failed to set mc mac addr, addr(%s) invalid.",
- mac_str);
- return -EINVAL;
- }
-
- /* Check if there are duplicate addresses */
- for (j = i + 1; j < nb_mc_addr; j++) {
- if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
- hns3_ether_format_addr(mac_str,
- RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to set mc mac addr, "
- "addrs invalid. two same addrs(%s).",
- mac_str);
- return -EINVAL;
- }
- }
-
- /*
- * Check if there are duplicate addresses between mac_addrs
- * and mc_addr_set
- */
- mac_addrs_capa = hns->is_vf ? HNS3_VF_UC_MACADDR_NUM :
- HNS3_UC_MACADDR_NUM;
- for (j = 0; j < mac_addrs_capa; j++) {
- if (rte_is_same_ether_addr(addr,
- &hw->data->mac_addrs[j])) {
- hns3_ether_format_addr(mac_str,
- RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to set mc mac addr, "
- "addrs invalid. addrs(%s) has already "
- "configured in mac_addr add API",
- mac_str);
- return -EINVAL;
- }
- }
- }
-
- return 0;
-}
-
-int
-hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_ether_addr *addr;
- int cur_addr_num;
- int set_addr_num;
- int num;
- int ret;
- int i;
-
- /* Check if input parameters are valid */
- ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
- if (ret)
- return ret;
-
- rte_spinlock_lock(&hw->lock);
- cur_addr_num = hw->mc_addrs_num;
- for (i = 0; i < cur_addr_num; i++) {
- num = cur_addr_num - i - 1;
- addr = &hw->mc_addrs[num];
- ret = hw->ops.del_mc_mac_addr(hw, addr);
- if (ret) {
- rte_spinlock_unlock(&hw->lock);
- return ret;
- }
-
- hw->mc_addrs_num--;
- }
-
- set_addr_num = (int)nb_mc_addr;
- for (i = 0; i < set_addr_num; i++) {
- addr = &mc_addr_set[i];
- ret = hw->ops.add_mc_mac_addr(hw, addr);
- if (ret) {
- rte_spinlock_unlock(&hw->lock);
- return ret;
- }
-
- rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
- hw->mc_addrs_num++;
- }
- rte_spinlock_unlock(&hw->lock);
-
- return 0;
-}
-
-int
-hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct hns3_hw *hw = &hns->hw;
- struct rte_ether_addr *addr;
- int ret = 0;
- int i;
-
- for (i = 0; i < hw->mc_addrs_num; i++) {
- addr = &hw->mc_addrs[i];
- if (!rte_is_multicast_ether_addr(addr))
- continue;
- if (del)
- ret = hw->ops.del_mc_mac_addr(hw, addr);
- else
- ret = hw->ops.add_mc_mac_addr(hw, addr);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_dbg(hw, "failed to %s mc mac addr: %s ret = %d",
- del ? "Remove" : "Restore", mac_str, ret);
- }
- }
- return ret;
-}
-
static int
hns3_check_mq_mode(struct rte_eth_dev *dev)
{
@@ -7111,161 +6838,6 @@ hns3_get_module_info(struct rte_eth_dev *dev,
return 0;
}
-void
-hns3_clock_gettime(struct timeval *tv)
-{
-#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
-#define CLOCK_TYPE CLOCK_MONOTONIC_RAW
-#else
-#define CLOCK_TYPE CLOCK_MONOTONIC
-#endif
-#define NSEC_TO_USEC_DIV 1000
-
- struct timespec spec;
- (void)clock_gettime(CLOCK_TYPE, &spec);
-
- tv->tv_sec = spec.tv_sec;
- tv->tv_usec = spec.tv_nsec / NSEC_TO_USEC_DIV;
-}
-
-uint64_t
-hns3_clock_calctime_ms(struct timeval *tv)
-{
- return (uint64_t)tv->tv_sec * MSEC_PER_SEC +
- tv->tv_usec / USEC_PER_MSEC;
-}
-
-uint64_t
-hns3_clock_gettime_ms(void)
-{
- struct timeval tv;
-
- hns3_clock_gettime(&tv);
- return hns3_clock_calctime_ms(&tv);
-}
-
-static int
-hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
-{
- uint32_t hint = HNS3_IO_FUNC_HINT_NONE;
-
- RTE_SET_USED(key);
-
- if (strcmp(value, "vec") == 0)
- hint = HNS3_IO_FUNC_HINT_VEC;
- else if (strcmp(value, "sve") == 0)
- hint = HNS3_IO_FUNC_HINT_SVE;
- else if (strcmp(value, "simple") == 0)
- hint = HNS3_IO_FUNC_HINT_SIMPLE;
- else if (strcmp(value, "common") == 0)
- hint = HNS3_IO_FUNC_HINT_COMMON;
-
- /* If the hint is valid then update output parameters */
- if (hint != HNS3_IO_FUNC_HINT_NONE)
- *(uint32_t *)extra_args = hint;
-
- return 0;
-}
-
-static const char *
-hns3_get_io_hint_func_name(uint32_t hint)
-{
- switch (hint) {
- case HNS3_IO_FUNC_HINT_VEC:
- return "vec";
- case HNS3_IO_FUNC_HINT_SVE:
- return "sve";
- case HNS3_IO_FUNC_HINT_SIMPLE:
- return "simple";
- case HNS3_IO_FUNC_HINT_COMMON:
- return "common";
- default:
- return "none";
- }
-}
-
-static int
-hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
-{
- uint64_t val;
-
- RTE_SET_USED(key);
-
- val = strtoull(value, NULL, 16);
- *(uint64_t *)extra_args = val;
-
- return 0;
-}
-
-static int
-hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
-{
- uint32_t val;
-
- RTE_SET_USED(key);
-
- val = strtoul(value, NULL, 10);
-
- /*
- * 500ms is empirical value in process of mailbox communication. If
- * the delay value is set to one lower thanthe empirical value, mailbox
- * communication may fail.
- */
- if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
- *(uint16_t *)extra_args = val;
-
- return 0;
-}
-
-void
-hns3_parse_devargs(struct rte_eth_dev *dev)
-{
- uint16_t mbx_time_limit_ms = HNS3_MBX_DEF_TIME_LIMIT_MS;
- struct hns3_adapter *hns = dev->data->dev_private;
- uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE;
- uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE;
- struct hns3_hw *hw = &hns->hw;
- uint64_t dev_caps_mask = 0;
- struct rte_kvargs *kvlist;
-
- if (dev->device->devargs == NULL)
- return;
-
- kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL);
- if (!kvlist)
- return;
-
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT,
- &hns3_parse_io_hint_func, &rx_func_hint);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
- &hns3_parse_io_hint_func, &tx_func_hint);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
- &hns3_parse_dev_caps_mask, &dev_caps_mask);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
- &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
-
- rte_kvargs_free(kvlist);
-
- if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE)
- hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT,
- hns3_get_io_hint_func_name(rx_func_hint));
- hns->rx_func_hint = rx_func_hint;
- if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE)
- hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT,
- hns3_get_io_hint_func_name(tx_func_hint));
- hns->tx_func_hint = tx_func_hint;
-
- if (dev_caps_mask != 0)
- hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
- HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
- hns->dev_caps_mask = dev_caps_mask;
-
- if (mbx_time_limit_ms != HNS3_MBX_DEF_TIME_LIMIT_MS)
- hns3_warn(hw, "parsed %s = %u.", HNS3_DEVARG_MBX_TIME_LIMIT_MS,
- mbx_time_limit_ms);
- hns->mbx_time_limit_ms = mbx_time_limit_ms;
-}
-
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_configure = hns3_dev_configure,
.dev_start = hns3_dev_start,
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index f3cc88f43e..634018c847 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -6,7 +6,6 @@
#define _HNS3_ETHDEV_H_
#include <pthread.h>
-#include <sys/time.h>
#include <ethdev_driver.h>
#include <rte_byteorder.h>
#include <rte_io.h>
@@ -869,14 +868,6 @@ struct hns3_adapter {
struct hns3_ptype_table ptype_tbl __rte_cache_aligned;
};
-enum {
- HNS3_IO_FUNC_HINT_NONE = 0,
- HNS3_IO_FUNC_HINT_VEC,
- HNS3_IO_FUNC_HINT_SVE,
- HNS3_IO_FUNC_HINT_SIMPLE,
- HNS3_IO_FUNC_HINT_COMMON
-};
-
#define HNS3_DEVARG_RX_FUNC_HINT "rx_func_hint"
#define HNS3_DEVARG_TX_FUNC_HINT "tx_func_hint"
@@ -1011,13 +1002,6 @@ static inline uint32_t hns3_read_reg(void *base, uint32_t reg)
} \
} while (0)
-#define MSEC_PER_SEC 1000L
-#define USEC_PER_MSEC 1000L
-
-void hns3_clock_gettime(struct timeval *tv);
-uint64_t hns3_clock_calctime_ms(struct timeval *tv);
-uint64_t hns3_clock_gettime_ms(void);
-
static inline uint64_t
hns3_atomic_test_bit(unsigned int nr, volatile uint64_t *addr)
{
@@ -1047,28 +1031,20 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
return __atomic_fetch_and(addr, ~mask, __ATOMIC_RELAXED) & mask;
}
+uint32_t hns3_get_speed_capa(struct hns3_hw *hw);
+
int hns3_buffer_alloc(struct hns3_hw *hw);
int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
const struct rte_flow_ops **ops);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
-void hns3_ether_format_addr(char *buf, uint16_t size,
- const struct rte_ether_addr *ether_addr);
int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
struct rte_eth_dev_info *info);
void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
uint32_t link_speed, uint8_t link_duplex);
-void hns3_parse_devargs(struct rte_eth_dev *dev);
void hns3vf_update_push_lsc_cap(struct hns3_hw *hw, bool supported);
-int hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del);
-int hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del);
-int hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
- __rte_unused uint32_t idx, __rte_unused uint32_t pool);
-void hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx);
-int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr);
+
int hns3_restore_ptp(struct hns3_adapter *hns);
int hns3_mbuf_dyn_rx_timestamp_register(struct rte_eth_dev *dev,
struct rte_eth_conf *conf);
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 242ccf7f9f..1df8966cea 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -10,6 +10,7 @@
#include <rte_vfio.h>
#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
diff --git a/drivers/net/hns3/hns3_intr.c b/drivers/net/hns3/hns3_intr.c
index 3484c76d23..66dc509086 100644
--- a/drivers/net/hns3/hns3_intr.c
+++ b/drivers/net/hns3/hns3_intr.c
@@ -8,7 +8,7 @@
#include <rte_io.h>
#include <rte_malloc.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_intr.h"
#include "hns3_regs.h"
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index 245652e2ed..b3563d4694 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -5,7 +5,7 @@
#include <ethdev_driver.h>
#include <rte_io.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
#include "hns3_intr.h"
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 7e55b24cb8..d26e262335 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -16,7 +16,7 @@
#include <rte_vect.h>
#endif
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index a99e0dbb74..8a4c7cc100 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -29,6 +29,7 @@ sources = files(
'hns3_mp.c',
'hns3_tm.c',
'hns3_ptp.c',
+ 'hns3_common.c',
)
deps += ['hash']
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [dpdk-dev] [PATCH v2 5/9] net/hns3: extract a common file
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 5/9] net/hns3: extract a common file Min Hu (Connor)
@ 2021-11-05 17:11 ` Ferruh Yigit
0 siblings, 0 replies; 38+ messages in thread
From: Ferruh Yigit @ 2021-11-05 17:11 UTC (permalink / raw)
To: Min Hu (Connor), dev; +Cc: andrew.rybchenko
On 11/5/2021 2:46 AM, Min Hu (Connor) wrote:
> @@ -1047,28 +1031,20 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
> return __atomic_fetch_and(addr, ~mask, __ATOMIC_RELAXED) & mask;
> }
>
> +uint32_t hns3_get_speed_capa(struct hns3_hw *hw);
> +
This looks git rebase error, above function is unrelated with the moved
functions, also it cause a build error in the middle of the set because
that function is static in this patch.
Above change is required in last patch, 9/9, where this function made
non-static.
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 6/9] net/hns3: add hns3 flow header file
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (4 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 5/9] net/hns3: extract a common file Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 7/9] net/hns3: remove magic numbers Min Hu (Connor)
` (2 subsequent siblings)
8 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
This patch adds a hns3_flow.h to make the code easier to maintain.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 1 +
drivers/net/hns3/hns3_ethdev.h | 3 +--
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_fdir.h | 31 ----------------------
drivers/net/hns3/hns3_flow.c | 1 +
drivers/net/hns3/hns3_flow.h | 44 +++++++++++++++++++++++++++++++
6 files changed, 48 insertions(+), 33 deletions(-)
create mode 100644 drivers/net/hns3/hns3_flow.h
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 2ddd29515a..181694bf8c 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -15,6 +15,7 @@
#include "hns3_regs.h"
#include "hns3_dcb.h"
#include "hns3_mp.h"
+#include "hns3_flow.h"
#define HNS3_SERVICE_INTERVAL 1000000 /* us */
#define HNS3_SERVICE_QUICK_INTERVAL 10
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 634018c847..a28c7c262b 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -17,6 +17,7 @@
#include "hns3_fdir.h"
#include "hns3_stats.h"
#include "hns3_tm.h"
+#include "hns3_flow.h"
/* Vendor ID */
#define PCI_VENDOR_ID_HUAWEI 0x19e5
@@ -1034,8 +1035,6 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
uint32_t hns3_get_speed_capa(struct hns3_hw *hw);
int hns3_buffer_alloc(struct hns3_hw *hw);
-int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
- const struct rte_flow_ops **ops);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 1df8966cea..8632c8f19b 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -17,6 +17,7 @@
#include "hns3_intr.h"
#include "hns3_dcb.h"
#include "hns3_mp.h"
+#include "hns3_flow.h"
#define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */
#define HNS3VF_SERVICE_INTERVAL 1000000 /* us */
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index 3f610f7b11..f9efff3b52 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -5,8 +5,6 @@
#ifndef _HNS3_FDIR_H_
#define _HNS3_FDIR_H_
-#include <rte_flow.h>
-
struct hns3_fd_key_cfg {
uint8_t key_sel;
uint8_t inner_sipv6_word_en;
@@ -124,14 +122,6 @@ struct hns3_fd_ad_data {
uint16_t rule_id;
};
-struct hns3_flow_counter {
- LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
- uint32_t shared:1; /* Share counter ID with other flow rules. */
- uint32_t ref_cnt:31; /* Reference counter. */
- uint16_t id; /* Counter ID. */
- uint64_t hits; /* Number of packets matched by the rule. */
-};
-
#define HNS3_RULE_FLAG_FDID 0x1
#define HNS3_RULE_FLAG_VF_ID 0x2
#define HNS3_RULE_FLAG_COUNTER 0x4
@@ -173,21 +163,7 @@ struct hns3_fdir_rule_ele {
struct hns3_fdir_rule fdir_conf;
};
-/* rss filter list structure */
-struct hns3_rss_conf_ele {
- TAILQ_ENTRY(hns3_rss_conf_ele) entries;
- struct hns3_rss_conf filter_info;
-};
-
-/* hns3_flow memory list structure */
-struct hns3_flow_mem {
- TAILQ_ENTRY(hns3_flow_mem) entries;
- struct rte_flow *flow;
-};
-
TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
-TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
-TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
/*
* A structure used to define fields of a FDIR related info.
@@ -199,11 +175,6 @@ struct hns3_fdir_info {
struct hns3_fd_cfg fd_cfg;
};
-struct rte_flow {
- enum rte_filter_type filter_type;
- void *rule;
- uint32_t counter_id;
-};
struct hns3_adapter;
int hns3_init_fd_config(struct hns3_adapter *hns);
@@ -213,8 +184,6 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
struct hns3_fdir_rule *rule, bool del);
int hns3_clear_all_fdir_filter(struct hns3_adapter *hns);
int hns3_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value);
-void hns3_flow_init(struct rte_eth_dev *dev);
-void hns3_flow_uninit(struct rte_eth_dev *dev);
int hns3_restore_all_fdir_filter(struct hns3_adapter *hns);
#endif /* _HNS3_FDIR_H_ */
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index da6918fddd..9f2f9cb6cd 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -8,6 +8,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
+#include "hns3_flow.h"
/* Default default keys */
static uint8_t hns3_hash_key[] = {
diff --git a/drivers/net/hns3/hns3_flow.h b/drivers/net/hns3/hns3_flow.h
new file mode 100644
index 0000000000..2eb451b720
--- /dev/null
+++ b/drivers/net/hns3/hns3_flow.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#ifndef _HNS3_FLOW_H_
+#define _HNS3_FLOW_H_
+
+#include <rte_flow.h>
+
+struct hns3_flow_counter {
+ LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
+ uint32_t shared:1; /* Share counter ID with other flow rules. */
+ uint32_t ref_cnt:31; /* Reference counter. */
+ uint16_t id; /* Counter ID. */
+ uint64_t hits; /* Number of packets matched by the rule. */
+};
+
+struct rte_flow {
+ enum rte_filter_type filter_type;
+ void *rule;
+ uint32_t counter_id;
+};
+
+/* rss filter list structure */
+struct hns3_rss_conf_ele {
+ TAILQ_ENTRY(hns3_rss_conf_ele) entries;
+ struct hns3_rss_conf filter_info;
+};
+
+/* hns3_flow memory list structure */
+struct hns3_flow_mem {
+ TAILQ_ENTRY(hns3_flow_mem) entries;
+ struct rte_flow *flow;
+};
+
+TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
+TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
+
+int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
+ const struct rte_flow_ops **ops);
+void hns3_flow_init(struct rte_eth_dev *dev);
+void hns3_flow_uninit(struct rte_eth_dev *dev);
+
+#endif /* _HNS3_FLOW_H_ */
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 7/9] net/hns3: remove magic numbers
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (5 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 6/9] net/hns3: add hns3 flow header file Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 8/9] net/hns3: fix the return value of the function Min Hu (Connor)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
8 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
Removing magic numbers with macros.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 4 ++--
drivers/net/hns3/hns3_common.h | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 5fe0ff5ce7..290999f594 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -54,7 +54,7 @@ hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
- val = strtoull(value, NULL, 16);
+ val = strtoull(value, NULL, HNS3_CONVERT_TO_HEXADECIMAL);
*(uint64_t *)extra_args = val;
return 0;
@@ -67,7 +67,7 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
- val = strtoul(value, NULL, 10);
+ val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
*(uint16_t *)extra_args = val;
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 094a0bc5ff..68f9b1b96a 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -9,6 +9,9 @@
#include "hns3_ethdev.h"
+#define HNS3_CONVERT_TO_DECIMAL 10
+#define HNS3_CONVERT_TO_HEXADECIMAL 16
+
enum {
HNS3_IO_FUNC_HINT_NONE = 0,
HNS3_IO_FUNC_HINT_VEC,
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 8/9] net/hns3: fix the return value of the function
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (6 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 7/9] net/hns3: remove magic numbers Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 17:04 ` Ferruh Yigit
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
8 siblings, 1 reply; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
Fixing the return value of the function to clear static warning.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 290999f594..974219f9bf 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -154,10 +154,10 @@ hns3_clock_gettime_ms(void)
void hns3_ether_format_addr(char *buf, uint16_t size,
const struct rte_ether_addr *ether_addr)
{
- snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
- ether_addr->addr_bytes[0],
- ether_addr->addr_bytes[4],
- ether_addr->addr_bytes[5]);
+ (void)snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
+ ether_addr->addr_bytes[0],
+ ether_addr->addr_bytes[4],
+ ether_addr->addr_bytes[5]);
}
static int
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v2 9/9] net/hns3: remove PF/VF duplicate code
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (7 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 8/9] net/hns3: fix the return value of the function Min Hu (Connor)
@ 2021-11-05 2:46 ` Min Hu (Connor)
2021-11-05 17:02 ` Ferruh Yigit
8 siblings, 1 reply; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-05 2:46 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Chengwen Feng <fengchengwen@huawei.com>
This patch remove PF/VF duplicate code of:
1. get firmware version.
2. get device info.
3. rx interrupt related functions.
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3.tar.gz | Bin 0 -> 203522 bytes
drivers/net/hns3/hns3_common.c | 338 +++++++++++++++++++++++++++++-
drivers/net/hns3/hns3_common.h | 10 +
drivers/net/hns3/hns3_ethdev.c | 314 +--------------------------
drivers/net/hns3/hns3_ethdev.h | 14 +-
drivers/net/hns3/hns3_ethdev_vf.c | 326 +---------------------------
drivers/net/hns3/hns3_tm.c | 2 +-
7 files changed, 362 insertions(+), 642 deletions(-)
create mode 100644 drivers/net/hns3.tar.gz
diff --git a/drivers/net/hns3.tar.gz b/drivers/net/hns3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..af70a374b11a9054947c9c09210f25dd39b54fe2
GIT binary patch
literal 203522
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
M1MeQ^;{X5;03GMPod5s;
literal 0
HcmV?d00001
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 974219f9bf..e6ba15f77c 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -3,9 +3,154 @@
*/
#include <rte_kvargs.h>
+#include <rte_bus_pci.h>
+#include <ethdev_pci.h>
+#include <rte_pci.h>
-#include "hns3_logs.h"
#include "hns3_common.h"
+#include "hns3_logs.h"
+#include "hns3_regs.h"
+#include "hns3_rxtx.h"
+
+int
+hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t version = hw->fw_version;
+ int ret;
+
+ ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+ if (ret < 0)
+ return -EINVAL;
+
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (size_t)ret)
+ return ret;
+ else
+ return 0;
+}
+
+int
+hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t queue_num = hw->tqps_num;
+
+ /*
+ * In interrupt mode, 'max_rx_queues' is set based on the number of
+ * MSI-X interrupt resources of the hardware.
+ */
+ if (hw->data->dev_conf.intr_conf.rxq == 1)
+ queue_num = hw->intr_tqps_num;
+
+ info->max_rx_queues = queue_num;
+ info->max_tx_queues = hw->tqps_num;
+ info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
+ info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
+ info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
+ info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
+ info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_SCATTER |
+ RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
+ RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
+ RTE_ETH_RX_OFFLOAD_RSS_HASH |
+ RTE_ETH_RX_OFFLOAD_TCP_LRO);
+ info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
+ RTE_ETH_TX_OFFLOAD_TCP_TSO |
+ RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
+ RTE_ETH_TX_OFFLOAD_VLAN_INSERT);
+
+ if (!hw->port_base_vlan_cfg.state)
+ info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_QINQ_INSERT;
+
+ if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
+ info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
+ if (hns3_dev_get_support(hw, INDEP_TXRX))
+ info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
+ RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
+ info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
+
+ if (hns3_dev_get_support(hw, PTP))
+ info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
+
+ info->rx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
+ info->tx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
+ .nb_mtu_seg_max = hw->max_non_tso_bd_num,
+ };
+
+ info->default_rxconf = (struct rte_eth_rxconf) {
+ .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
+ /*
+ * If there are no available Rx buffer descriptors, incoming
+ * packets are always dropped by hardware based on hns3 network
+ * engine.
+ */
+ .rx_drop_en = 1,
+ .offloads = 0,
+ };
+ info->default_txconf = (struct rte_eth_txconf) {
+ .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
+ .offloads = 0,
+ };
+
+ info->reta_size = hw->rss_ind_tbl_size;
+ info->hash_key_size = HNS3_RSS_KEY_SIZE;
+ info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+
+ info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+ info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+
+ /*
+ * Next is the PF/VF difference section.
+ */
+ if (!hns->is_vf) {
+ info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
+ info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_KEEP_CRC;
+ info->speed_capa = hns3_get_speed_capa(hw);
+ } else {
+ info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
+ }
+
+ return 0;
+}
static int
hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
@@ -68,6 +213,12 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
+
+ /*
+ * 500ms is empirical value in process of mailbox communication. If
+ * the delay value is set to one lower thanthe empirical value, mailbox
+ * communication may fail.
+ */
if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
*(uint16_t *)extra_args = val;
@@ -116,6 +267,11 @@ hns3_parse_devargs(struct rte_eth_dev *dev)
hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
hns->dev_caps_mask = dev_caps_mask;
+
+ if (mbx_time_limit_ms != HNS3_MBX_DEF_TIME_LIMIT_MS)
+ hns3_warn(hw, "parsed %s = %u.", HNS3_DEVARG_MBX_TIME_LIMIT_MS,
+ mbx_time_limit_ms);
+ hns->mbx_time_limit_ms = mbx_time_limit_ms;
}
void
@@ -425,3 +581,183 @@ hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
}
}
+int
+hns3_init_ring_with_vector(struct hns3_hw *hw)
+{
+ uint16_t vec;
+ int ret;
+ int i;
+
+ /*
+ * In hns3 network engine, vector 0 is always the misc interrupt of this
+ * function, vector 1~N can be used respectively for the queues of the
+ * function. Tx and Rx queues with the same number share the interrupt
+ * vector. In the initialization clearing the all hardware mapping
+ * relationship configurations between queues and interrupt vectors is
+ * needed, so some error caused by the residual configurations, such as
+ * the unexpected Tx interrupt, can be avoid.
+ */
+ vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
+ if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
+ vec = vec - 1; /* the last interrupt is reserved */
+ hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
+ for (i = 0; i < hw->intr_tqps_num; i++) {
+ /*
+ * Set gap limiter/rate limiter/quanity limiter algorithm
+ * configuration for interrupt coalesce of queue's interrupt.
+ */
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
+ /*
+ * QL(quantity limiter) is not used currently, just set 0 to
+ * close it.
+ */
+ hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
+
+ ret = hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_TX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to unbind TX ring(%d) with "
+ "vector: %u, ret=%d", i, vec, ret);
+ return ret;
+ }
+
+ ret = hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to unbind RX ring(%d) with "
+ "vector: %u, ret=%d", i, vec, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_map_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint32_t intr_vector;
+ uint16_t q_id;
+ int ret;
+
+ /*
+ * hns3 needs a separate interrupt to be used as event interrupt which
+ * could not be shared with task queue pair, so KERNEL drivers need
+ * support multiple interrupt vectors.
+ */
+ if (dev->data->dev_conf.intr_conf.rxq == 0 ||
+ !rte_intr_cap_multiple(intr_handle))
+ return 0;
+
+ rte_intr_disable(intr_handle);
+ intr_vector = hw->used_rx_queues;
+ /* creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+
+ /* Allocate vector list */
+ if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
+ hw->used_rx_queues)) {
+ hns3_err(hw, "failed to allocate %u rx_queues intr_vec",
+ hw->used_rx_queues);
+ ret = -ENOMEM;
+ goto alloc_intr_vec_error;
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hw->ops.bind_ring_with_vector(hw, vec, true,
+ HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ goto bind_vector_error;
+
+ if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
+ goto bind_vector_error;
+ /*
+ * If there are not enough efds (e.g. not enough interrupt),
+ * remaining queues will be bond to the last interrupt.
+ */
+ if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
+ vec++;
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+bind_vector_error:
+ rte_intr_vec_list_free(intr_handle);
+alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+void
+hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ (void)hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ rte_intr_vec_list_free(intr_handle);
+}
+
+int
+hns3_restore_rx_interrupt(struct hns3_hw *hw)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hw->ops.bind_ring_with_vector(hw,
+ rte_intr_vec_list_index_get(intr_handle,
+ q_id),
+ true, HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 68f9b1b96a..0dbb1c0413 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -30,6 +30,11 @@ enum {
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
+int hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size);
+int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
+ struct rte_eth_dev_info *info);
+
void hns3_clock_gettime(struct timeval *tv);
uint64_t hns3_clock_calctime_ms(struct timeval *tv);
uint64_t hns3_clock_gettime_ms(void);
@@ -48,4 +53,9 @@ int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
void hns3_ether_format_addr(char *buf, uint16_t size,
const struct rte_ether_addr *ether_addr);
+int hns3_init_ring_with_vector(struct hns3_hw *hw);
+int hns3_map_rx_interrupt(struct rte_eth_dev *dev);
+void hns3_unmap_rx_interrupt(struct rte_eth_dev *dev);
+int hns3_restore_rx_interrupt(struct hns3_hw *hw);
+
#endif /* _HNS3_COMMON_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 181694bf8c..847e660f44 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -1929,62 +1929,6 @@ hns3_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id, bool en,
return 0;
}
-static int
-hns3_init_ring_with_vector(struct hns3_hw *hw)
-{
- uint16_t vec;
- int ret;
- int i;
-
- /*
- * In hns3 network engine, vector 0 is always the misc interrupt of this
- * function, vector 1~N can be used respectively for the queues of the
- * function. Tx and Rx queues with the same number share the interrupt
- * vector. In the initialization clearing the all hardware mapping
- * relationship configurations between queues and interrupt vectors is
- * needed, so some error caused by the residual configurations, such as
- * the unexpected Tx interrupt, can be avoid.
- */
- vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
- if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
- vec = vec - 1; /* the last interrupt is reserved */
- hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
- for (i = 0; i < hw->intr_tqps_num; i++) {
- /*
- * Set gap limiter/rate limiter/quanity limiter algorithm
- * configuration for interrupt coalesce of queue's interrupt.
- */
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
- /*
- * QL(quantity limiter) is not used currently, just set 0 to
- * close it.
- */
- hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
-
- ret = hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_TX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "PF fail to unbind TX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
-
- ret = hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "PF fail to unbind RX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int
hns3_setup_dcb(struct rte_eth_dev *dev)
{
@@ -2255,7 +2199,7 @@ hns3_get_firber_port_speed_capa(uint32_t supported_speed)
return speed_capa;
}
-static uint32_t
+uint32_t
hns3_get_speed_capa(struct hns3_hw *hw)
{
struct hns3_mac *mac = &hw->mac;
@@ -2274,135 +2218,6 @@ hns3_get_speed_capa(struct hns3_hw *hw)
return speed_capa;
}
-int
-hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint16_t queue_num = hw->tqps_num;
-
- /*
- * In interrupt mode, 'max_rx_queues' is set based on the number of
- * MSI-X interrupt resources of the hardware.
- */
- if (hw->data->dev_conf.intr_conf.rxq == 1)
- queue_num = hw->intr_tqps_num;
-
- info->max_rx_queues = queue_num;
- info->max_tx_queues = hw->tqps_num;
- info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
- info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
- info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
- info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
- info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
- info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_KEEP_CRC |
- RTE_ETH_RX_OFFLOAD_SCATTER |
- RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
- RTE_ETH_RX_OFFLOAD_RSS_HASH |
- RTE_ETH_RX_OFFLOAD_TCP_LRO);
- info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
- RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
- hns3_txvlan_cap_get(hw));
-
- if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
- info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
-
- if (hns3_dev_get_support(hw, INDEP_TXRX))
- info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
- RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
- info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
-
- if (hns3_dev_get_support(hw, PTP))
- info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
-
- info->rx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- };
-
- info->tx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
- .nb_mtu_seg_max = hw->max_non_tso_bd_num,
- };
-
- info->speed_capa = hns3_get_speed_capa(hw);
- info->default_rxconf = (struct rte_eth_rxconf) {
- .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
- /*
- * If there are no available Rx buffer descriptors, incoming
- * packets are always dropped by hardware based on hns3 network
- * engine.
- */
- .rx_drop_en = 1,
- .offloads = 0,
- };
- info->default_txconf = (struct rte_eth_txconf) {
- .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
- .offloads = 0,
- };
-
- info->reta_size = hw->rss_ind_tbl_size;
- info->hash_key_size = HNS3_RSS_KEY_SIZE;
- info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
-
- info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
- info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
-
- return 0;
-}
-
-static int
-hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
- size_t fw_size)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint32_t version = hw->fw_version;
- int ret;
-
- ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
- hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
- HNS3_FW_VERSION_BYTE3_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
- HNS3_FW_VERSION_BYTE2_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
- HNS3_FW_VERSION_BYTE1_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
- HNS3_FW_VERSION_BYTE0_S));
- if (ret < 0)
- return -EINVAL;
-
- ret += 1; /* add the size of '\0' */
- if (fw_size < (size_t)ret)
- return ret;
- else
- return 0;
-}
-
static int
hns3_update_port_link_info(struct rte_eth_dev *eth_dev)
{
@@ -5281,98 +5096,6 @@ hns3_do_start(struct hns3_adapter *hns, bool reset_queue)
return ret;
}
-static int
-hns3_map_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint16_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint32_t intr_vector;
- uint16_t q_id;
- int ret;
-
- /*
- * hns3 needs a separate interrupt to be used as event interrupt which
- * could not be shared with task queue pair, so KERNEL drivers need
- * support multiple interrupt vectors.
- */
- if (dev->data->dev_conf.intr_conf.rxq == 0 ||
- !rte_intr_cap_multiple(intr_handle))
- return 0;
-
- rte_intr_disable(intr_handle);
- intr_vector = hw->used_rx_queues;
- /* creates event fd for each intr vector when MSIX is used */
- if (rte_intr_efd_enable(intr_handle, intr_vector))
- return -EINVAL;
-
- /* Allocate vector list */
- if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
- hw->used_rx_queues)) {
- hns3_err(hw, "failed to allocate %u rx_queues intr_vec",
- hw->used_rx_queues);
- ret = -ENOMEM;
- goto alloc_intr_vec_error;
- }
-
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
-
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3_bind_ring_with_vector(hw, vec, true,
- HNS3_RING_TYPE_RX, q_id);
- if (ret)
- goto bind_vector_error;
-
- if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
- goto bind_vector_error;
- /*
- * If there are not enough efds (e.g. not enough interrupt),
- * remaining queues will be bond to the last interrupt.
- */
- if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
- vec++;
- }
- rte_intr_enable(intr_handle);
- return 0;
-
-bind_vector_error:
- rte_intr_vec_list_free(intr_handle);
-alloc_intr_vec_error:
- rte_intr_efd_disable(intr_handle);
- return ret;
-}
-
-static int
-hns3_restore_rx_interrupt(struct hns3_hw *hw)
-{
- struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint16_t q_id;
- int ret;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return 0;
-
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3_bind_ring_with_vector(hw,
- rte_intr_vec_list_index_get(intr_handle,
- q_id),
- true, HNS3_RING_TYPE_RX, q_id);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static void
hns3_restore_filter(struct rte_eth_dev *dev)
{
@@ -5503,40 +5226,6 @@ hns3_do_stop(struct hns3_adapter *hns)
return 0;
}
-static void
-hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_adapter *hns = dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t q_id;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return;
-
- /* unmap the ring with vector */
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- (void)hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX,
- q_id);
- if (vec < base + rte_intr_nb_efd_get(intr_handle)
- - 1)
- vec++;
- }
- }
- /* Clean datapath event and queue/vec mapping */
- rte_intr_efd_disable(intr_handle);
- rte_intr_vec_list_free(intr_handle);
-}
-
static int
hns3_dev_stop(struct rte_eth_dev *dev)
{
@@ -6927,6 +6616,7 @@ hns3_init_hw_ops(struct hns3_hw *hw)
hw->ops.del_mc_mac_addr = hns3_remove_mc_mac_addr;
hw->ops.add_uc_mac_addr = hns3_add_uc_mac_addr;
hw->ops.del_uc_mac_addr = hns3_remove_uc_mac_addr;
+ hw->ops.bind_ring_with_vector = hns3_bind_ring_with_vector;
}
static int
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index a28c7c262b..55518a913d 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -437,6 +437,9 @@ struct hns3_hw_ops {
struct rte_ether_addr *mac_addr);
int (*del_uc_mac_addr)(struct hns3_hw *hw,
struct rte_ether_addr *mac_addr);
+ int (*bind_ring_with_vector)(struct hns3_hw *hw, uint16_t vector_id,
+ bool en, enum hns3_ring_type queue_type,
+ uint16_t queue_id);
};
#define HNS3_INTR_MAPPING_VEC_RSV_ONE 0
@@ -1038,8 +1041,6 @@ int hns3_buffer_alloc(struct hns3_hw *hw);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
-int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
- struct rte_eth_dev_info *info);
void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
uint32_t link_speed, uint8_t link_duplex);
void hns3vf_update_push_lsc_cap(struct hns3_hw *hw, bool supported);
@@ -1071,13 +1072,4 @@ is_reset_pending(struct hns3_adapter *hns)
return ret;
}
-static inline uint64_t
-hns3_txvlan_cap_get(struct hns3_hw *hw)
-{
- if (hw->port_base_vlan_cfg.state)
- return RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
- else
- return RTE_ETH_TX_OFFLOAD_VLAN_INSERT | RTE_ETH_TX_OFFLOAD_QINQ_INSERT;
-}
-
#endif /* _HNS3_ETHDEV_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 8632c8f19b..d8a99693e0 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -422,7 +422,7 @@ hns3vf_restore_promisc(struct hns3_adapter *hns)
}
static int
-hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
+hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id,
bool mmap, enum hns3_ring_type queue_type,
uint16_t queue_id)
{
@@ -434,7 +434,7 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
memset(&bind_msg, 0, sizeof(bind_msg));
code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR :
HNS3_MBX_UNMAP_RING_TO_VECTOR;
- bind_msg.vector_id = vector_id;
+ bind_msg.vector_id = (uint8_t)vector_id;
if (queue_type == HNS3_RING_TYPE_RX)
bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX;
@@ -454,62 +454,6 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
return ret;
}
-static int
-hns3vf_init_ring_with_vector(struct hns3_hw *hw)
-{
- uint16_t vec;
- int ret;
- int i;
-
- /*
- * In hns3 network engine, vector 0 is always the misc interrupt of this
- * function, vector 1~N can be used respectively for the queues of the
- * function. Tx and Rx queues with the same number share the interrupt
- * vector. In the initialization clearing the all hardware mapping
- * relationship configurations between queues and interrupt vectors is
- * needed, so some error caused by the residual configurations, such as
- * the unexpected Tx interrupt, can be avoid.
- */
- vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
- if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
- vec = vec - 1; /* the last interrupt is reserved */
- hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
- for (i = 0; i < hw->intr_tqps_num; i++) {
- /*
- * Set gap limiter/rate limiter/quanity limiter algorithm
- * configuration for interrupt coalesce of queue's interrupt.
- */
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
- /*
- * QL(quantity limiter) is not used currently, just set 0 to
- * close it.
- */
- hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
-
- ret = hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_TX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "VF fail to unbind TX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
-
- ret = hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "VF fail to unbind RX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int
hns3vf_dev_configure(struct rte_eth_dev *dev)
{
@@ -649,103 +593,6 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
return 0;
}
-static int
-hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint16_t q_num = hw->tqps_num;
-
- /*
- * In interrupt mode, 'max_rx_queues' is set based on the number of
- * MSI-X interrupt resources of the hardware.
- */
- if (hw->data->dev_conf.intr_conf.rxq == 1)
- q_num = hw->intr_tqps_num;
-
- info->max_rx_queues = q_num;
- info->max_tx_queues = hw->tqps_num;
- info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
- info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
- info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
- info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
- info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
-
- info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCATTER |
- RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
- RTE_ETH_RX_OFFLOAD_RSS_HASH |
- RTE_ETH_RX_OFFLOAD_TCP_LRO);
- info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
- RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
- hns3_txvlan_cap_get(hw));
-
- if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
- info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
-
- if (hns3_dev_get_support(hw, INDEP_TXRX))
- info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
- RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
- info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
-
- info->rx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- };
-
- info->tx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
- .nb_mtu_seg_max = hw->max_non_tso_bd_num,
- };
-
- info->default_rxconf = (struct rte_eth_rxconf) {
- .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
- /*
- * If there are no available Rx buffer descriptors, incoming
- * packets are always dropped by hardware based on hns3 network
- * engine.
- */
- .rx_drop_en = 1,
- .offloads = 0,
- };
- info->default_txconf = (struct rte_eth_txconf) {
- .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
- .offloads = 0,
- };
-
- info->reta_size = hw->rss_ind_tbl_size;
- info->hash_key_size = HNS3_RSS_KEY_SIZE;
- info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
-
- info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
- info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
-
- return 0;
-}
-
static void
hns3vf_clear_event_cause(struct hns3_hw *hw, uint32_t regclr)
{
@@ -1634,7 +1481,7 @@ hns3vf_init_hardware(struct hns3_adapter *hns)
* some error caused by the residual configurations, such as the
* unexpected interrupt, can be avoid.
*/
- ret = hns3vf_init_ring_with_vector(hw);
+ ret = hns3_init_ring_with_vector(hw);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init ring intr vector: %d", ret);
goto err_init_hardware;
@@ -1821,41 +1668,6 @@ hns3vf_do_stop(struct hns3_adapter *hns)
return 0;
}
-static void
-hns3vf_unmap_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t q_id;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return;
-
- /* unmap the ring with vector */
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- (void)hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX,
- q_id);
- if (vec < base + rte_intr_nb_efd_get(intr_handle)
- - 1)
- vec++;
- }
- }
- /* Clean datapath event and queue/vec mapping */
- rte_intr_efd_disable(intr_handle);
-
- /* Cleanup vector list */
- rte_intr_vec_list_free(intr_handle);
-}
-
static int
hns3vf_dev_stop(struct rte_eth_dev *dev)
{
@@ -1877,7 +1689,7 @@ hns3vf_dev_stop(struct rte_eth_dev *dev)
if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED) == 0) {
hns3_stop_tqps(hw);
hns3vf_do_stop(hns);
- hns3vf_unmap_rx_interrupt(dev);
+ hns3_unmap_rx_interrupt(dev);
hw->adapter_state = HNS3_NIC_CONFIGURED;
}
hns3_rx_scattered_reset(dev);
@@ -1918,34 +1730,6 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
return ret;
}
-static int
-hns3vf_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
- size_t fw_size)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint32_t version = hw->fw_version;
- int ret;
-
- ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
- hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
- HNS3_FW_VERSION_BYTE3_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
- HNS3_FW_VERSION_BYTE2_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
- HNS3_FW_VERSION_BYTE1_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
- HNS3_FW_VERSION_BYTE0_S));
- if (ret < 0)
- return -EINVAL;
-
- ret += 1; /* add the size of '\0' */
- if (fw_size < (size_t)ret)
- return ret;
- else
- return 0;
-}
-
static int
hns3vf_dev_link_update(struct rte_eth_dev *eth_dev,
__rte_unused int wait_to_complete)
@@ -2007,99 +1791,6 @@ hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue)
return ret;
}
-static int
-hns3vf_map_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint32_t intr_vector;
- uint16_t q_id;
- int ret;
-
- /*
- * hns3 needs a separate interrupt to be used as event interrupt which
- * could not be shared with task queue pair, so KERNEL drivers need
- * support multiple interrupt vectors.
- */
- if (dev->data->dev_conf.intr_conf.rxq == 0 ||
- !rte_intr_cap_multiple(intr_handle))
- return 0;
-
- rte_intr_disable(intr_handle);
- intr_vector = hw->used_rx_queues;
- /* It creates event fd for each intr vector when MSIX is used */
- if (rte_intr_efd_enable(intr_handle, intr_vector))
- return -EINVAL;
-
- /* Allocate vector list */
- if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
- hw->used_rx_queues)) {
- hns3_err(hw, "Failed to allocate %u rx_queues"
- " intr_vec", hw->used_rx_queues);
- ret = -ENOMEM;
- goto vf_alloc_intr_vec_error;
- }
-
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
-
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3vf_bind_ring_with_vector(hw, vec, true,
- HNS3_RING_TYPE_RX, q_id);
- if (ret)
- goto vf_bind_vector_error;
-
- if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
- goto vf_bind_vector_error;
-
- /*
- * If there are not enough efds (e.g. not enough interrupt),
- * remaining queues will be bond to the last interrupt.
- */
- if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
- vec++;
- }
- rte_intr_enable(intr_handle);
- return 0;
-
-vf_bind_vector_error:
- rte_intr_vec_list_free(intr_handle);
-vf_alloc_intr_vec_error:
- rte_intr_efd_disable(intr_handle);
- return ret;
-}
-
-static int
-hns3vf_restore_rx_interrupt(struct hns3_hw *hw)
-{
- struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint16_t q_id;
- int ret;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return 0;
-
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3vf_bind_ring_with_vector(hw,
- rte_intr_vec_list_index_get(intr_handle,
- q_id),
- true, HNS3_RING_TYPE_RX, q_id);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static void
hns3vf_restore_filter(struct rte_eth_dev *dev)
{
@@ -2125,7 +1816,7 @@ hns3vf_dev_start(struct rte_eth_dev *dev)
rte_spinlock_unlock(&hw->lock);
return ret;
}
- ret = hns3vf_map_rx_interrupt(dev);
+ ret = hns3_map_rx_interrupt(dev);
if (ret)
goto map_rx_inter_err;
@@ -2442,7 +2133,7 @@ hns3vf_restore_conf(struct hns3_adapter *hns)
if (ret)
goto err_vlan_table;
- ret = hns3vf_restore_rx_interrupt(hw);
+ ret = hns3_restore_rx_interrupt(hw);
if (ret)
goto err_vlan_table;
@@ -2616,8 +2307,8 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.xstats_reset = hns3_dev_xstats_reset,
.xstats_get_by_id = hns3_dev_xstats_get_by_id,
.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
- .dev_infos_get = hns3vf_dev_infos_get,
- .fw_version_get = hns3vf_fw_version_get,
+ .dev_infos_get = hns3_dev_infos_get,
+ .fw_version_get = hns3_fw_version_get,
.rx_queue_setup = hns3_rx_queue_setup,
.tx_queue_setup = hns3_tx_queue_setup,
.rx_queue_release = hns3_dev_rx_queue_release,
@@ -2666,6 +2357,7 @@ hns3vf_init_hw_ops(struct hns3_hw *hw)
hw->ops.del_mc_mac_addr = hns3vf_remove_mc_mac_addr;
hw->ops.add_uc_mac_addr = hns3vf_add_uc_mac_addr;
hw->ops.del_uc_mac_addr = hns3vf_remove_uc_mac_addr;
+ hw->ops.bind_ring_with_vector = hns3vf_bind_ring_with_vector;
}
static int
diff --git a/drivers/net/hns3/hns3_tm.c b/drivers/net/hns3/hns3_tm.c
index 44b607af7a..e1089b6bd0 100644
--- a/drivers/net/hns3/hns3_tm.c
+++ b/drivers/net/hns3/hns3_tm.c
@@ -4,7 +4,7 @@
#include <rte_malloc.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_dcb.h"
#include "hns3_logs.h"
#include "hns3_tm.h"
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [dpdk-dev] [PATCH v2 9/9] net/hns3: remove PF/VF duplicate code
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
@ 2021-11-05 17:02 ` Ferruh Yigit
0 siblings, 0 replies; 38+ messages in thread
From: Ferruh Yigit @ 2021-11-05 17:02 UTC (permalink / raw)
To: Min Hu (Connor); +Cc: andrew.rybchenko, dev
On 11/5/2021 2:46 AM, Min Hu (Connor) wrote:
> From: Chengwen Feng<fengchengwen@huawei.com>
>
> This patch remove PF/VF duplicate code of:
> 1. get firmware version.
> 2. get device info.
> 3. rx interrupt related functions.
>
> Signed-off-by: Chengwen Feng<fengchengwen@huawei.com>
> Signed-off-by: Min Hu (Connor)<humin29@huawei.com>
> ---
> drivers/net/hns3.tar.gz | Bin 0 -> 203522 bytes
I expect this to be blocked by mail list, but somehow it seems passed.
Can you please send a new version without it?
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD
2021-11-02 3:17 [dpdk-dev] [PATCH 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (9 preceding siblings ...)
2021-11-05 2:46 ` [dpdk-dev] [PATCH v2 0/9] code optimization for hns3 PMD Min Hu (Connor)
@ 2021-11-06 1:42 ` Min Hu (Connor)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
` (9 more replies)
10 siblings, 10 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:42 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
This patch set contains refactor patches and code check patches.
Chengwen Feng (1):
net/hns3: remove PF/VF duplicate code
Huisong Li (7):
net/hns3: fix the shift of DMA address in Rx/Tx queue
net/hns3: remove a redundant function declaration
net/hns3: modifying code alignment
net/hns3: use unsigned integer for bitwise operations
net/hns3: extract a common file
net/hns3: remove magic numbers
net/hns3: fix the return value of the function
Min Hu (Connor) (1):
net/hns3: add hns3 flow header file
---
v3:
* fixed build error and some other adjustment.
v2:
* rebase patch on top of latest next-net.
drivers/net/hns3/hns3_cmd.c | 2 +-
drivers/net/hns3/hns3_common.c | 763 ++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_common.h | 61 +++
drivers/net/hns3/hns3_ethdev.c | 749 +----------------------------
drivers/net/hns3/hns3_ethdev.h | 47 +-
drivers/net/hns3/hns3_ethdev_vf.c | 328 +------------
drivers/net/hns3/hns3_fdir.h | 31 --
drivers/net/hns3/hns3_flow.c | 1 +
drivers/net/hns3/hns3_flow.h | 44 ++
drivers/net/hns3/hns3_intr.c | 2 +-
drivers/net/hns3/hns3_mbx.c | 2 +-
drivers/net/hns3/hns3_rxtx.c | 8 +-
drivers/net/hns3/hns3_rxtx.h | 1 -
drivers/net/hns3/hns3_tm.c | 2 +-
drivers/net/hns3/meson.build | 1 +
15 files changed, 902 insertions(+), 1140 deletions(-)
create mode 100644 drivers/net/hns3/hns3_common.c
create mode 100644 drivers/net/hns3/hns3_common.h
create mode 100644 drivers/net/hns3/hns3_flow.h
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
@ 2021-11-06 1:42 ` Min Hu (Connor)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 2/9] net/hns3: remove a redundant function declaration Min Hu (Connor)
` (8 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:42 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
The patch obtains the upper 32 bits of the Rx/Tx queue DMA address in one
step instead of two steps.
Fixes: bba636698316 ("net/hns3: support Rx/Tx and related operations")
Cc: stable@dpdk.org
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index ceb98025f8..00af73c850 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -322,7 +322,7 @@ hns3_init_rx_queue_hw(struct hns3_rx_queue *rxq)
hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_L_REG, (uint32_t)dma_addr);
hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_H_REG,
- (uint32_t)((dma_addr >> 31) >> 1));
+ (uint32_t)(dma_addr >> 32));
hns3_write_dev(rxq, HNS3_RING_RX_BD_LEN_REG,
hns3_buf_size2type(rx_buf_len));
@@ -337,7 +337,7 @@ hns3_init_tx_queue_hw(struct hns3_tx_queue *txq)
hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_L_REG, (uint32_t)dma_addr);
hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_H_REG,
- (uint32_t)((dma_addr >> 31) >> 1));
+ (uint32_t)(dma_addr >> 32));
hns3_write_dev(txq, HNS3_RING_TX_BD_NUM_REG,
HNS3_CFG_DESC_NUM(txq->nb_tx_desc));
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 2/9] net/hns3: remove a redundant function declaration
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
@ 2021-11-06 1:42 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 3/9] net/hns3: modifying code alignment Min Hu (Connor)
` (7 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:42 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
This patch removes a redundant function declaration for
hns3_rx_check_vec_support().
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/hns3/hns3_rxtx.h b/drivers/net/hns3/hns3_rxtx.h
index 33ee8c61a0..63bafc68b6 100644
--- a/drivers/net/hns3/hns3_rxtx.h
+++ b/drivers/net/hns3/hns3_rxtx.h
@@ -711,7 +711,6 @@ uint16_t hns3_recv_pkts_vec_sve(void *rx_queue, struct rte_mbuf **rx_pkts,
int hns3_rx_burst_mode_get(struct rte_eth_dev *dev,
__rte_unused uint16_t queue_id,
struct rte_eth_burst_mode *mode);
-int hns3_rx_check_vec_support(struct rte_eth_dev *dev);
uint16_t hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
uint16_t hns3_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 3/9] net/hns3: modifying code alignment
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 1/9] net/hns3: fix the shift of DMA address in Rx/Tx queue Min Hu (Connor)
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 2/9] net/hns3: remove a redundant function declaration Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 4/9] net/hns3: use unsigned integer for bitwise operations Min Hu (Connor)
` (6 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
This patch modifies some code alignment issues to make the code style more
consistent.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_rxtx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 00af73c850..7e55b24cb8 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -1907,7 +1907,7 @@ hns3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
*/
if (hns->is_vf || hw->vlan_mode == HNS3_SW_SHIFT_AND_DISCARD_MODE)
rxq->pvid_sw_discard_en = hw->port_base_vlan_cfg.state ==
- HNS3_PORT_BASE_VLAN_ENABLE;
+ HNS3_PORT_BASE_VLAN_ENABLE;
else
rxq->pvid_sw_discard_en = false;
rxq->ptype_en = hns3_dev_get_support(hw, RXD_ADV_LAYOUT) ? true : false;
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 4/9] net/hns3: use unsigned integer for bitwise operations
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (2 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 3/9] net/hns3: modifying code alignment Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 5/9] net/hns3: extract a common file Min Hu (Connor)
` (5 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
Bitwise operations should be used only with unsigned integer. This patch
modifies some code that does not meet this rule.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index c5543c48ef..ddf85a1705 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -2104,7 +2104,7 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
int max_tc = 0;
int i;
- if ((rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
+ if (((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
(tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_DCB ||
tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_ONLY)) {
hns3_err(hw, "VMDQ is not supported, rx_mq_mode = %d, tx_mq_mode = %d.",
@@ -2114,7 +2114,7 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
- if (rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
+ if ((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
if (dcb_rx_conf->nb_tcs > pf->tc_max) {
hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
dcb_rx_conf->nb_tcs, pf->tc_max);
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 5/9] net/hns3: extract a common file
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (3 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 4/9] net/hns3: use unsigned integer for bitwise operations Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 6/9] net/hns3: add hns3 flow header file Min Hu (Connor)
` (4 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
This patch extracts a common file to store the common code for PF and VF
driver.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_cmd.c | 2 +-
drivers/net/hns3/hns3_common.c | 426 +++++++++++++++++++++++++++++
drivers/net/hns3/hns3_common.h | 48 ++++
drivers/net/hns3/hns3_ethdev.c | 430 +-----------------------------
drivers/net/hns3/hns3_ethdev.h | 28 +-
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_intr.c | 2 +-
drivers/net/hns3/hns3_mbx.c | 2 +-
drivers/net/hns3/hns3_rxtx.c | 2 +-
drivers/net/hns3/meson.build | 1 +
10 files changed, 482 insertions(+), 460 deletions(-)
create mode 100644 drivers/net/hns3/hns3_common.c
create mode 100644 drivers/net/hns3/hns3_common.h
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 50769c6226..2ce59d8de6 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -5,7 +5,7 @@
#include <ethdev_pci.h>
#include <rte_io.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_regs.h"
#include "hns3_intr.h"
#include "hns3_logs.h"
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
new file mode 100644
index 0000000000..85316d3425
--- /dev/null
+++ b/drivers/net/hns3/hns3_common.c
@@ -0,0 +1,426 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#include <rte_kvargs.h>
+
+#include "hns3_logs.h"
+#include "hns3_common.h"
+
+static int
+hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
+{
+ uint32_t hint = HNS3_IO_FUNC_HINT_NONE;
+
+ RTE_SET_USED(key);
+
+ if (strcmp(value, "vec") == 0)
+ hint = HNS3_IO_FUNC_HINT_VEC;
+ else if (strcmp(value, "sve") == 0)
+ hint = HNS3_IO_FUNC_HINT_SVE;
+ else if (strcmp(value, "simple") == 0)
+ hint = HNS3_IO_FUNC_HINT_SIMPLE;
+ else if (strcmp(value, "common") == 0)
+ hint = HNS3_IO_FUNC_HINT_COMMON;
+
+ /* If the hint is valid then update output parameters */
+ if (hint != HNS3_IO_FUNC_HINT_NONE)
+ *(uint32_t *)extra_args = hint;
+
+ return 0;
+}
+
+static const char *
+hns3_get_io_hint_func_name(uint32_t hint)
+{
+ switch (hint) {
+ case HNS3_IO_FUNC_HINT_VEC:
+ return "vec";
+ case HNS3_IO_FUNC_HINT_SVE:
+ return "sve";
+ case HNS3_IO_FUNC_HINT_SIMPLE:
+ return "simple";
+ case HNS3_IO_FUNC_HINT_COMMON:
+ return "common";
+ default:
+ return "none";
+ }
+}
+
+static int
+hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
+{
+ uint64_t val;
+
+ RTE_SET_USED(key);
+
+ val = strtoull(value, NULL, 16);
+ *(uint64_t *)extra_args = val;
+
+ return 0;
+}
+
+static int
+hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
+{
+ uint32_t val;
+
+ RTE_SET_USED(key);
+
+ val = strtoul(value, NULL, 10);
+ if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
+ *(uint16_t *)extra_args = val;
+
+ return 0;
+}
+
+void
+hns3_parse_devargs(struct rte_eth_dev *dev)
+{
+ uint16_t mbx_time_limit_ms = HNS3_MBX_DEF_TIME_LIMIT_MS;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE;
+ uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t dev_caps_mask = 0;
+ struct rte_kvargs *kvlist;
+
+ if (dev->device->devargs == NULL)
+ return;
+
+ kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL);
+ if (!kvlist)
+ return;
+
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT,
+ &hns3_parse_io_hint_func, &rx_func_hint);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
+ &hns3_parse_io_hint_func, &tx_func_hint);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
+ &hns3_parse_dev_caps_mask, &dev_caps_mask);
+ (void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
+ &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
+
+ rte_kvargs_free(kvlist);
+
+ if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE)
+ hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT,
+ hns3_get_io_hint_func_name(rx_func_hint));
+ hns->rx_func_hint = rx_func_hint;
+ if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE)
+ hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT,
+ hns3_get_io_hint_func_name(tx_func_hint));
+ hns->tx_func_hint = tx_func_hint;
+
+ if (dev_caps_mask != 0)
+ hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
+ HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
+ hns->dev_caps_mask = dev_caps_mask;
+}
+
+void
+hns3_clock_gettime(struct timeval *tv)
+{
+#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
+#define CLOCK_TYPE CLOCK_MONOTONIC_RAW
+#else
+#define CLOCK_TYPE CLOCK_MONOTONIC
+#endif
+#define NSEC_TO_USEC_DIV 1000
+
+ struct timespec spec;
+ (void)clock_gettime(CLOCK_TYPE, &spec);
+
+ tv->tv_sec = spec.tv_sec;
+ tv->tv_usec = spec.tv_nsec / NSEC_TO_USEC_DIV;
+}
+
+uint64_t
+hns3_clock_calctime_ms(struct timeval *tv)
+{
+ return (uint64_t)tv->tv_sec * MSEC_PER_SEC +
+ tv->tv_usec / USEC_PER_MSEC;
+}
+
+uint64_t
+hns3_clock_gettime_ms(void)
+{
+ struct timeval tv;
+
+ hns3_clock_gettime(&tv);
+ return hns3_clock_calctime_ms(&tv);
+}
+
+void hns3_ether_format_addr(char *buf, uint16_t size,
+ const struct rte_ether_addr *ether_addr)
+{
+ snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
+ ether_addr->addr_bytes[0],
+ ether_addr->addr_bytes[4],
+ ether_addr->addr_bytes[5]);
+}
+
+static int
+hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ uint16_t mac_addrs_capa;
+ uint32_t i;
+ uint32_t j;
+
+ if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
+ hns3_err(hw, "failed to set mc mac addr, nb_mc_addr(%u) "
+ "invalid. valid range: 0~%d",
+ nb_mc_addr, HNS3_MC_MACADDR_NUM);
+ return -EINVAL;
+ }
+
+ /* Check if input mac addresses are valid */
+ for (i = 0; i < nb_mc_addr; i++) {
+ addr = &mc_addr_set[i];
+ if (!rte_is_multicast_ether_addr(addr)) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw,
+ "failed to set mc mac addr, addr(%s) invalid.",
+ mac_str);
+ return -EINVAL;
+ }
+
+ /* Check if there are duplicate addresses */
+ for (j = i + 1; j < nb_mc_addr; j++) {
+ if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
+ hns3_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. two same addrs(%s).",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Check if there are duplicate addresses between mac_addrs
+ * and mc_addr_set
+ */
+ mac_addrs_capa = hns->is_vf ? HNS3_VF_UC_MACADDR_NUM :
+ HNS3_UC_MACADDR_NUM;
+ for (j = 0; j < mac_addrs_capa; j++) {
+ if (rte_is_same_ether_addr(addr,
+ &hw->data->mac_addrs[j])) {
+ hns3_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. addrs(%s) has already "
+ "configured in mac_addr add API",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *addr;
+ int cur_addr_num;
+ int set_addr_num;
+ int num;
+ int ret;
+ int i;
+
+ /* Check if input parameters are valid */
+ ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
+ if (ret)
+ return ret;
+
+ rte_spinlock_lock(&hw->lock);
+ cur_addr_num = hw->mc_addrs_num;
+ for (i = 0; i < cur_addr_num; i++) {
+ num = cur_addr_num - i - 1;
+ addr = &hw->mc_addrs[num];
+ ret = hw->ops.del_mc_mac_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ hw->mc_addrs_num--;
+ }
+
+ set_addr_num = (int)nb_mc_addr;
+ for (i = 0; i < set_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ ret = hw->ops.add_mc_mac_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
+ hw->mc_addrs_num++;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+int
+hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ if (!rte_is_multicast_ether_addr(addr))
+ continue;
+ if (del)
+ ret = hw->ops.del_mc_mac_addr(hw, addr);
+ else
+ ret = hw->ops.add_mc_mac_addr(hw, addr);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_dbg(hw, "failed to %s mc mac addr: %s ret = %d",
+ del ? "Remove" : "Restore", mac_str, ret);
+ }
+ }
+ return ret;
+}
+
+int
+hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_hw_ops *ops = &hw->ops;
+ struct rte_ether_addr *addr;
+ uint16_t mac_addrs_capa;
+ int ret = 0;
+ int i;
+
+ mac_addrs_capa =
+ hns->is_vf ? HNS3_VF_UC_MACADDR_NUM : HNS3_UC_MACADDR_NUM;
+ for (i = 0; i < mac_addrs_capa; i++) {
+ addr = &hw->data->mac_addrs[i];
+ if (rte_is_zero_ether_addr(addr))
+ continue;
+ if (rte_is_multicast_ether_addr(addr))
+ ret = del ? ops->del_mc_mac_addr(hw, addr) :
+ ops->add_mc_mac_addr(hw, addr);
+ else
+ ret = del ? ops->del_uc_mac_addr(hw, addr) :
+ ops->add_uc_mac_addr(hw, addr);
+
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to %s mac addr(%s) index:%d ret = %d.",
+ del ? "remove" : "restore", mac_str, i, ret);
+ }
+ }
+
+ return ret;
+}
+
+static bool
+hns3_find_duplicate_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mc_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ /* Check if there are duplicate addresses in mc_addrs[] */
+ if (rte_is_same_ether_addr(addr, mc_addr)) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to add mc mac addr, same addrs"
+ "(%s) is added by the set_mc_mac_addr_list "
+ "API", mac_str);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int
+hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx, __rte_unused uint32_t pool)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ /*
+ * In hns3 network engine adding UC and MC mac address with different
+ * commands with firmware. We need to determine whether the input
+ * address is a UC or a MC address to call different commands.
+ * By the way, it is recommended calling the API function named
+ * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
+ * using the rte_eth_dev_mac_addr_add API function to set MC mac address
+ * may affect the specifications of UC mac addresses.
+ */
+ if (rte_is_multicast_ether_addr(mac_addr)) {
+ if (hns3_find_duplicate_mc_addr(hw, mac_addr)) {
+ rte_spinlock_unlock(&hw->lock);
+ return -EINVAL;
+ }
+ ret = hw->ops.add_mc_mac_addr(hw, mac_addr);
+ } else {
+ ret = hw->ops.add_uc_mac_addr(hw, mac_addr);
+ }
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to add mac addr(%s), ret = %d", mac_str,
+ ret);
+ }
+
+ return ret;
+}
+
+void
+hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ /* index will be checked by upper level rte interface */
+ struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hw->ops.del_mc_mac_addr(hw, mac_addr);
+ else
+ ret = hw->ops.del_uc_mac_addr(hw, mac_addr);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to remove mac addr(%s), ret = %d", mac_str,
+ ret);
+ }
+}
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
new file mode 100644
index 0000000000..094a0bc5ff
--- /dev/null
+++ b/drivers/net/hns3/hns3_common.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#ifndef _HNS3_COMMON_H_
+#define _HNS3_COMMON_H_
+
+#include <sys/time.h>
+
+#include "hns3_ethdev.h"
+
+enum {
+ HNS3_IO_FUNC_HINT_NONE = 0,
+ HNS3_IO_FUNC_HINT_VEC,
+ HNS3_IO_FUNC_HINT_SVE,
+ HNS3_IO_FUNC_HINT_SIMPLE,
+ HNS3_IO_FUNC_HINT_COMMON
+};
+
+#define HNS3_DEVARG_RX_FUNC_HINT "rx_func_hint"
+#define HNS3_DEVARG_TX_FUNC_HINT "tx_func_hint"
+
+#define HNS3_DEVARG_DEV_CAPS_MASK "dev_caps_mask"
+
+#define HNS3_DEVARG_MBX_TIME_LIMIT_MS "mbx_time_limit_ms"
+
+#define MSEC_PER_SEC 1000L
+#define USEC_PER_MSEC 1000L
+
+void hns3_clock_gettime(struct timeval *tv);
+uint64_t hns3_clock_calctime_ms(struct timeval *tv);
+uint64_t hns3_clock_gettime_ms(void);
+
+void hns3_parse_devargs(struct rte_eth_dev *dev);
+
+int hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del);
+int hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del);
+int hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx, __rte_unused uint32_t pool);
+
+void hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx);
+int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr);
+void hns3_ether_format_addr(char *buf, uint16_t size,
+ const struct rte_ether_addr *ether_addr);
+
+#endif /* _HNS3_COMMON_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index ddf85a1705..2ddd29515a 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -6,9 +6,9 @@
#include <rte_bus_pci.h>
#include <ethdev_pci.h>
#include <rte_pci.h>
-#include <rte_kvargs.h>
#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_intr.h"
@@ -105,14 +105,6 @@ static int hns3_do_stop(struct hns3_adapter *hns);
static int hns3_check_port_speed(struct hns3_hw *hw, uint32_t link_speeds);
static int hns3_cfg_mac_mode(struct hns3_hw *hw, bool enable);
-void hns3_ether_format_addr(char *buf, uint16_t size,
- const struct rte_ether_addr *ether_addr)
-{
- snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
- ether_addr->addr_bytes[0],
- ether_addr->addr_bytes[4],
- ether_addr->addr_bytes[5]);
-}
static void
hns3_pf_disable_irq0(struct hns3_hw *hw)
@@ -1609,68 +1601,6 @@ hns3_add_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-static bool
-hns3_find_duplicate_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mc_addr)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct rte_ether_addr *addr;
- int i;
-
- for (i = 0; i < hw->mc_addrs_num; i++) {
- addr = &hw->mc_addrs[i];
- /* Check if there are duplicate addresses in mc_addrs[] */
- if (rte_is_same_ether_addr(addr, mc_addr)) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to add mc mac addr, same addrs"
- "(%s) is added by the set_mc_mac_addr_list "
- "API", mac_str);
- return true;
- }
- }
-
- return false;
-}
-
-int
-hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
- __rte_unused uint32_t idx, __rte_unused uint32_t pool)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- int ret;
-
- rte_spinlock_lock(&hw->lock);
-
- /*
- * In hns3 network engine adding UC and MC mac address with different
- * commands with firmware. We need to determine whether the input
- * address is a UC or a MC address to call different commands.
- * By the way, it is recommended calling the API function named
- * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
- * using the rte_eth_dev_mac_addr_add API function to set MC mac address
- * may affect the specifications of UC mac addresses.
- */
- if (rte_is_multicast_ether_addr(mac_addr)) {
- if (hns3_find_duplicate_mc_addr(hw, mac_addr)) {
- rte_spinlock_unlock(&hw->lock);
- return -EINVAL;
- }
- ret = hw->ops.add_mc_mac_addr(hw, mac_addr);
- } else {
- ret = hw->ops.add_uc_mac_addr(hw, mac_addr);
- }
- rte_spinlock_unlock(&hw->lock);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- mac_addr);
- hns3_err(hw, "failed to add mac addr(%s), ret = %d", mac_str,
- ret);
- }
-
- return ret;
-}
-
static int
hns3_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
{
@@ -1699,30 +1629,6 @@ hns3_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-void
-hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- /* index will be checked by upper level rte interface */
- struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- int ret;
-
- rte_spinlock_lock(&hw->lock);
-
- if (rte_is_multicast_ether_addr(mac_addr))
- ret = hw->ops.del_mc_mac_addr(hw, mac_addr);
- else
- ret = hw->ops.del_uc_mac_addr(hw, mac_addr);
- rte_spinlock_unlock(&hw->lock);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- mac_addr);
- hns3_err(hw, "failed to remove mac addr(%s), ret = %d", mac_str,
- ret);
- }
-}
-
static int
hns3_set_default_mac_addr(struct rte_eth_dev *dev,
struct rte_ether_addr *mac_addr)
@@ -1787,41 +1693,6 @@ hns3_set_default_mac_addr(struct rte_eth_dev *dev,
return ret;
}
-int
-hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct hns3_hw *hw = &hns->hw;
- struct hns3_hw_ops *ops = &hw->ops;
- struct rte_ether_addr *addr;
- uint16_t mac_addrs_capa;
- int ret = 0;
- int i;
-
- mac_addrs_capa =
- hns->is_vf ? HNS3_VF_UC_MACADDR_NUM : HNS3_UC_MACADDR_NUM;
- for (i = 0; i < mac_addrs_capa; i++) {
- addr = &hw->data->mac_addrs[i];
- if (rte_is_zero_ether_addr(addr))
- continue;
- if (rte_is_multicast_ether_addr(addr))
- ret = del ? ops->del_mc_mac_addr(hw, addr) :
- ops->add_mc_mac_addr(hw, addr);
- else
- ret = del ? ops->del_uc_mac_addr(hw, addr) :
- ops->add_uc_mac_addr(hw, addr);
-
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to %s mac addr(%s) index:%d ret = %d.",
- del ? "remove" : "restore", mac_str, i, ret);
- }
- }
-
- return ret;
-}
-
static void
hns3_update_desc_vfid(struct hns3_cmd_desc *desc, uint8_t vfid, bool clr)
{
@@ -1947,150 +1818,6 @@ hns3_remove_mc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
return ret;
}
-static int
-hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr)
-{
- struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct rte_ether_addr *addr;
- uint16_t mac_addrs_capa;
- uint32_t i;
- uint32_t j;
-
- if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
- hns3_err(hw, "failed to set mc mac addr, nb_mc_addr(%u) "
- "invalid. valid range: 0~%d",
- nb_mc_addr, HNS3_MC_MACADDR_NUM);
- return -EINVAL;
- }
-
- /* Check if input mac addresses are valid */
- for (i = 0; i < nb_mc_addr; i++) {
- addr = &mc_addr_set[i];
- if (!rte_is_multicast_ether_addr(addr)) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw,
- "failed to set mc mac addr, addr(%s) invalid.",
- mac_str);
- return -EINVAL;
- }
-
- /* Check if there are duplicate addresses */
- for (j = i + 1; j < nb_mc_addr; j++) {
- if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
- hns3_ether_format_addr(mac_str,
- RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to set mc mac addr, "
- "addrs invalid. two same addrs(%s).",
- mac_str);
- return -EINVAL;
- }
- }
-
- /*
- * Check if there are duplicate addresses between mac_addrs
- * and mc_addr_set
- */
- mac_addrs_capa = hns->is_vf ? HNS3_VF_UC_MACADDR_NUM :
- HNS3_UC_MACADDR_NUM;
- for (j = 0; j < mac_addrs_capa; j++) {
- if (rte_is_same_ether_addr(addr,
- &hw->data->mac_addrs[j])) {
- hns3_ether_format_addr(mac_str,
- RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_err(hw, "failed to set mc mac addr, "
- "addrs invalid. addrs(%s) has already "
- "configured in mac_addr add API",
- mac_str);
- return -EINVAL;
- }
- }
- }
-
- return 0;
-}
-
-int
-hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_ether_addr *addr;
- int cur_addr_num;
- int set_addr_num;
- int num;
- int ret;
- int i;
-
- /* Check if input parameters are valid */
- ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
- if (ret)
- return ret;
-
- rte_spinlock_lock(&hw->lock);
- cur_addr_num = hw->mc_addrs_num;
- for (i = 0; i < cur_addr_num; i++) {
- num = cur_addr_num - i - 1;
- addr = &hw->mc_addrs[num];
- ret = hw->ops.del_mc_mac_addr(hw, addr);
- if (ret) {
- rte_spinlock_unlock(&hw->lock);
- return ret;
- }
-
- hw->mc_addrs_num--;
- }
-
- set_addr_num = (int)nb_mc_addr;
- for (i = 0; i < set_addr_num; i++) {
- addr = &mc_addr_set[i];
- ret = hw->ops.add_mc_mac_addr(hw, addr);
- if (ret) {
- rte_spinlock_unlock(&hw->lock);
- return ret;
- }
-
- rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
- hw->mc_addrs_num++;
- }
- rte_spinlock_unlock(&hw->lock);
-
- return 0;
-}
-
-int
-hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
-{
- char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
- struct hns3_hw *hw = &hns->hw;
- struct rte_ether_addr *addr;
- int ret = 0;
- int i;
-
- for (i = 0; i < hw->mc_addrs_num; i++) {
- addr = &hw->mc_addrs[i];
- if (!rte_is_multicast_ether_addr(addr))
- continue;
- if (del)
- ret = hw->ops.del_mc_mac_addr(hw, addr);
- else
- ret = hw->ops.add_mc_mac_addr(hw, addr);
- if (ret) {
- hns3_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
- addr);
- hns3_dbg(hw, "failed to %s mc mac addr: %s ret = %d",
- del ? "Remove" : "Restore", mac_str, ret);
- }
- }
- return ret;
-}
-
static int
hns3_check_mq_mode(struct rte_eth_dev *dev)
{
@@ -7111,161 +6838,6 @@ hns3_get_module_info(struct rte_eth_dev *dev,
return 0;
}
-void
-hns3_clock_gettime(struct timeval *tv)
-{
-#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
-#define CLOCK_TYPE CLOCK_MONOTONIC_RAW
-#else
-#define CLOCK_TYPE CLOCK_MONOTONIC
-#endif
-#define NSEC_TO_USEC_DIV 1000
-
- struct timespec spec;
- (void)clock_gettime(CLOCK_TYPE, &spec);
-
- tv->tv_sec = spec.tv_sec;
- tv->tv_usec = spec.tv_nsec / NSEC_TO_USEC_DIV;
-}
-
-uint64_t
-hns3_clock_calctime_ms(struct timeval *tv)
-{
- return (uint64_t)tv->tv_sec * MSEC_PER_SEC +
- tv->tv_usec / USEC_PER_MSEC;
-}
-
-uint64_t
-hns3_clock_gettime_ms(void)
-{
- struct timeval tv;
-
- hns3_clock_gettime(&tv);
- return hns3_clock_calctime_ms(&tv);
-}
-
-static int
-hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
-{
- uint32_t hint = HNS3_IO_FUNC_HINT_NONE;
-
- RTE_SET_USED(key);
-
- if (strcmp(value, "vec") == 0)
- hint = HNS3_IO_FUNC_HINT_VEC;
- else if (strcmp(value, "sve") == 0)
- hint = HNS3_IO_FUNC_HINT_SVE;
- else if (strcmp(value, "simple") == 0)
- hint = HNS3_IO_FUNC_HINT_SIMPLE;
- else if (strcmp(value, "common") == 0)
- hint = HNS3_IO_FUNC_HINT_COMMON;
-
- /* If the hint is valid then update output parameters */
- if (hint != HNS3_IO_FUNC_HINT_NONE)
- *(uint32_t *)extra_args = hint;
-
- return 0;
-}
-
-static const char *
-hns3_get_io_hint_func_name(uint32_t hint)
-{
- switch (hint) {
- case HNS3_IO_FUNC_HINT_VEC:
- return "vec";
- case HNS3_IO_FUNC_HINT_SVE:
- return "sve";
- case HNS3_IO_FUNC_HINT_SIMPLE:
- return "simple";
- case HNS3_IO_FUNC_HINT_COMMON:
- return "common";
- default:
- return "none";
- }
-}
-
-static int
-hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
-{
- uint64_t val;
-
- RTE_SET_USED(key);
-
- val = strtoull(value, NULL, 16);
- *(uint64_t *)extra_args = val;
-
- return 0;
-}
-
-static int
-hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
-{
- uint32_t val;
-
- RTE_SET_USED(key);
-
- val = strtoul(value, NULL, 10);
-
- /*
- * 500ms is empirical value in process of mailbox communication. If
- * the delay value is set to one lower thanthe empirical value, mailbox
- * communication may fail.
- */
- if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
- *(uint16_t *)extra_args = val;
-
- return 0;
-}
-
-void
-hns3_parse_devargs(struct rte_eth_dev *dev)
-{
- uint16_t mbx_time_limit_ms = HNS3_MBX_DEF_TIME_LIMIT_MS;
- struct hns3_adapter *hns = dev->data->dev_private;
- uint32_t rx_func_hint = HNS3_IO_FUNC_HINT_NONE;
- uint32_t tx_func_hint = HNS3_IO_FUNC_HINT_NONE;
- struct hns3_hw *hw = &hns->hw;
- uint64_t dev_caps_mask = 0;
- struct rte_kvargs *kvlist;
-
- if (dev->device->devargs == NULL)
- return;
-
- kvlist = rte_kvargs_parse(dev->device->devargs->args, NULL);
- if (!kvlist)
- return;
-
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_RX_FUNC_HINT,
- &hns3_parse_io_hint_func, &rx_func_hint);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_TX_FUNC_HINT,
- &hns3_parse_io_hint_func, &tx_func_hint);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_DEV_CAPS_MASK,
- &hns3_parse_dev_caps_mask, &dev_caps_mask);
- (void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
- &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
-
- rte_kvargs_free(kvlist);
-
- if (rx_func_hint != HNS3_IO_FUNC_HINT_NONE)
- hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_RX_FUNC_HINT,
- hns3_get_io_hint_func_name(rx_func_hint));
- hns->rx_func_hint = rx_func_hint;
- if (tx_func_hint != HNS3_IO_FUNC_HINT_NONE)
- hns3_warn(hw, "parsed %s = %s.", HNS3_DEVARG_TX_FUNC_HINT,
- hns3_get_io_hint_func_name(tx_func_hint));
- hns->tx_func_hint = tx_func_hint;
-
- if (dev_caps_mask != 0)
- hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
- HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
- hns->dev_caps_mask = dev_caps_mask;
-
- if (mbx_time_limit_ms != HNS3_MBX_DEF_TIME_LIMIT_MS)
- hns3_warn(hw, "parsed %s = %u.", HNS3_DEVARG_MBX_TIME_LIMIT_MS,
- mbx_time_limit_ms);
- hns->mbx_time_limit_ms = mbx_time_limit_ms;
-}
-
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_configure = hns3_dev_configure,
.dev_start = hns3_dev_start,
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index f3cc88f43e..7438a8a2a8 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -6,7 +6,6 @@
#define _HNS3_ETHDEV_H_
#include <pthread.h>
-#include <sys/time.h>
#include <ethdev_driver.h>
#include <rte_byteorder.h>
#include <rte_io.h>
@@ -869,14 +868,6 @@ struct hns3_adapter {
struct hns3_ptype_table ptype_tbl __rte_cache_aligned;
};
-enum {
- HNS3_IO_FUNC_HINT_NONE = 0,
- HNS3_IO_FUNC_HINT_VEC,
- HNS3_IO_FUNC_HINT_SVE,
- HNS3_IO_FUNC_HINT_SIMPLE,
- HNS3_IO_FUNC_HINT_COMMON
-};
-
#define HNS3_DEVARG_RX_FUNC_HINT "rx_func_hint"
#define HNS3_DEVARG_TX_FUNC_HINT "tx_func_hint"
@@ -1011,13 +1002,6 @@ static inline uint32_t hns3_read_reg(void *base, uint32_t reg)
} \
} while (0)
-#define MSEC_PER_SEC 1000L
-#define USEC_PER_MSEC 1000L
-
-void hns3_clock_gettime(struct timeval *tv);
-uint64_t hns3_clock_calctime_ms(struct timeval *tv);
-uint64_t hns3_clock_gettime_ms(void);
-
static inline uint64_t
hns3_atomic_test_bit(unsigned int nr, volatile uint64_t *addr)
{
@@ -1053,22 +1037,12 @@ int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
-void hns3_ether_format_addr(char *buf, uint16_t size,
- const struct rte_ether_addr *ether_addr);
int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
struct rte_eth_dev_info *info);
void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
uint32_t link_speed, uint8_t link_duplex);
-void hns3_parse_devargs(struct rte_eth_dev *dev);
void hns3vf_update_push_lsc_cap(struct hns3_hw *hw, bool supported);
-int hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del);
-int hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del);
-int hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
- __rte_unused uint32_t idx, __rte_unused uint32_t pool);
-void hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx);
-int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
- struct rte_ether_addr *mc_addr_set,
- uint32_t nb_mc_addr);
+
int hns3_restore_ptp(struct hns3_adapter *hns);
int hns3_mbuf_dyn_rx_timestamp_register(struct rte_eth_dev *dev,
struct rte_eth_conf *conf);
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 242ccf7f9f..1df8966cea 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -10,6 +10,7 @@
#include <rte_vfio.h>
#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
diff --git a/drivers/net/hns3/hns3_intr.c b/drivers/net/hns3/hns3_intr.c
index 3484c76d23..66dc509086 100644
--- a/drivers/net/hns3/hns3_intr.c
+++ b/drivers/net/hns3/hns3_intr.c
@@ -8,7 +8,7 @@
#include <rte_io.h>
#include <rte_malloc.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_logs.h"
#include "hns3_intr.h"
#include "hns3_regs.h"
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index 245652e2ed..b3563d4694 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -5,7 +5,7 @@
#include <ethdev_driver.h>
#include <rte_io.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
#include "hns3_intr.h"
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 7e55b24cb8..d26e262335 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -16,7 +16,7 @@
#include <rte_vect.h>
#endif
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index a99e0dbb74..8a4c7cc100 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -29,6 +29,7 @@ sources = files(
'hns3_mp.c',
'hns3_tm.c',
'hns3_ptp.c',
+ 'hns3_common.c',
)
deps += ['hash']
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 6/9] net/hns3: add hns3 flow header file
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (4 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 5/9] net/hns3: extract a common file Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 7/9] net/hns3: remove magic numbers Min Hu (Connor)
` (3 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
This patch adds a hns3_flow.h to make the code easier to maintain.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 1 +
drivers/net/hns3/hns3_ethdev.h | 3 +--
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_fdir.h | 31 ----------------------
drivers/net/hns3/hns3_flow.c | 1 +
drivers/net/hns3/hns3_flow.h | 44 +++++++++++++++++++++++++++++++
6 files changed, 48 insertions(+), 33 deletions(-)
create mode 100644 drivers/net/hns3/hns3_flow.h
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 2ddd29515a..181694bf8c 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -15,6 +15,7 @@
#include "hns3_regs.h"
#include "hns3_dcb.h"
#include "hns3_mp.h"
+#include "hns3_flow.h"
#define HNS3_SERVICE_INTERVAL 1000000 /* us */
#define HNS3_SERVICE_QUICK_INTERVAL 10
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 7438a8a2a8..67e506f6df 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -17,6 +17,7 @@
#include "hns3_fdir.h"
#include "hns3_stats.h"
#include "hns3_tm.h"
+#include "hns3_flow.h"
/* Vendor ID */
#define PCI_VENDOR_ID_HUAWEI 0x19e5
@@ -1032,8 +1033,6 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
}
int hns3_buffer_alloc(struct hns3_hw *hw);
-int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
- const struct rte_flow_ops **ops);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 1df8966cea..8632c8f19b 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -17,6 +17,7 @@
#include "hns3_intr.h"
#include "hns3_dcb.h"
#include "hns3_mp.h"
+#include "hns3_flow.h"
#define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */
#define HNS3VF_SERVICE_INTERVAL 1000000 /* us */
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index 3f610f7b11..f9efff3b52 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -5,8 +5,6 @@
#ifndef _HNS3_FDIR_H_
#define _HNS3_FDIR_H_
-#include <rte_flow.h>
-
struct hns3_fd_key_cfg {
uint8_t key_sel;
uint8_t inner_sipv6_word_en;
@@ -124,14 +122,6 @@ struct hns3_fd_ad_data {
uint16_t rule_id;
};
-struct hns3_flow_counter {
- LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
- uint32_t shared:1; /* Share counter ID with other flow rules. */
- uint32_t ref_cnt:31; /* Reference counter. */
- uint16_t id; /* Counter ID. */
- uint64_t hits; /* Number of packets matched by the rule. */
-};
-
#define HNS3_RULE_FLAG_FDID 0x1
#define HNS3_RULE_FLAG_VF_ID 0x2
#define HNS3_RULE_FLAG_COUNTER 0x4
@@ -173,21 +163,7 @@ struct hns3_fdir_rule_ele {
struct hns3_fdir_rule fdir_conf;
};
-/* rss filter list structure */
-struct hns3_rss_conf_ele {
- TAILQ_ENTRY(hns3_rss_conf_ele) entries;
- struct hns3_rss_conf filter_info;
-};
-
-/* hns3_flow memory list structure */
-struct hns3_flow_mem {
- TAILQ_ENTRY(hns3_flow_mem) entries;
- struct rte_flow *flow;
-};
-
TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
-TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
-TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
/*
* A structure used to define fields of a FDIR related info.
@@ -199,11 +175,6 @@ struct hns3_fdir_info {
struct hns3_fd_cfg fd_cfg;
};
-struct rte_flow {
- enum rte_filter_type filter_type;
- void *rule;
- uint32_t counter_id;
-};
struct hns3_adapter;
int hns3_init_fd_config(struct hns3_adapter *hns);
@@ -213,8 +184,6 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
struct hns3_fdir_rule *rule, bool del);
int hns3_clear_all_fdir_filter(struct hns3_adapter *hns);
int hns3_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value);
-void hns3_flow_init(struct rte_eth_dev *dev);
-void hns3_flow_uninit(struct rte_eth_dev *dev);
int hns3_restore_all_fdir_filter(struct hns3_adapter *hns);
#endif /* _HNS3_FDIR_H_ */
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index da6918fddd..9f2f9cb6cd 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -8,6 +8,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
+#include "hns3_flow.h"
/* Default default keys */
static uint8_t hns3_hash_key[] = {
diff --git a/drivers/net/hns3/hns3_flow.h b/drivers/net/hns3/hns3_flow.h
new file mode 100644
index 0000000000..2eb451b720
--- /dev/null
+++ b/drivers/net/hns3/hns3_flow.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 HiSilicon Limited
+ */
+
+#ifndef _HNS3_FLOW_H_
+#define _HNS3_FLOW_H_
+
+#include <rte_flow.h>
+
+struct hns3_flow_counter {
+ LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
+ uint32_t shared:1; /* Share counter ID with other flow rules. */
+ uint32_t ref_cnt:31; /* Reference counter. */
+ uint16_t id; /* Counter ID. */
+ uint64_t hits; /* Number of packets matched by the rule. */
+};
+
+struct rte_flow {
+ enum rte_filter_type filter_type;
+ void *rule;
+ uint32_t counter_id;
+};
+
+/* rss filter list structure */
+struct hns3_rss_conf_ele {
+ TAILQ_ENTRY(hns3_rss_conf_ele) entries;
+ struct hns3_rss_conf filter_info;
+};
+
+/* hns3_flow memory list structure */
+struct hns3_flow_mem {
+ TAILQ_ENTRY(hns3_flow_mem) entries;
+ struct rte_flow *flow;
+};
+
+TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
+TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
+
+int hns3_dev_flow_ops_get(struct rte_eth_dev *dev,
+ const struct rte_flow_ops **ops);
+void hns3_flow_init(struct rte_eth_dev *dev);
+void hns3_flow_uninit(struct rte_eth_dev *dev);
+
+#endif /* _HNS3_FLOW_H_ */
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 7/9] net/hns3: remove magic numbers
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (5 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 6/9] net/hns3: add hns3 flow header file Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 8/9] net/hns3: fix the return value of the function Min Hu (Connor)
` (2 subsequent siblings)
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
Removing magic numbers with macros.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 4 ++--
drivers/net/hns3/hns3_common.h | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 85316d3425..c306e0b0ed 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -54,7 +54,7 @@ hns3_parse_dev_caps_mask(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
- val = strtoull(value, NULL, 16);
+ val = strtoull(value, NULL, HNS3_CONVERT_TO_HEXADECIMAL);
*(uint64_t *)extra_args = val;
return 0;
@@ -67,7 +67,7 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
- val = strtoul(value, NULL, 10);
+ val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
*(uint16_t *)extra_args = val;
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 094a0bc5ff..68f9b1b96a 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -9,6 +9,9 @@
#include "hns3_ethdev.h"
+#define HNS3_CONVERT_TO_DECIMAL 10
+#define HNS3_CONVERT_TO_HEXADECIMAL 16
+
enum {
HNS3_IO_FUNC_HINT_NONE = 0,
HNS3_IO_FUNC_HINT_VEC,
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 8/9] net/hns3: fix the return value of the function
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (6 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 7/9] net/hns3: remove magic numbers Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
2021-11-08 15:13 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Ferruh Yigit
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Huisong Li <lihuisong@huawei.com>
Fixing the return value of the function to clear static warning.
Fixes: 1181500b2fc5 ("net/hns3: adjust MAC address logging")
Cc: stable@dpdk.org
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index c306e0b0ed..9a47fbfbde 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -154,10 +154,10 @@ hns3_clock_gettime_ms(void)
void hns3_ether_format_addr(char *buf, uint16_t size,
const struct rte_ether_addr *ether_addr)
{
- snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
- ether_addr->addr_bytes[0],
- ether_addr->addr_bytes[4],
- ether_addr->addr_bytes[5]);
+ (void)snprintf(buf, size, "%02X:**:**:**:%02X:%02X",
+ ether_addr->addr_bytes[0],
+ ether_addr->addr_bytes[4],
+ ether_addr->addr_bytes[5]);
}
static int
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [dpdk-dev] [PATCH v3 9/9] net/hns3: remove PF/VF duplicate code
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (7 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 8/9] net/hns3: fix the return value of the function Min Hu (Connor)
@ 2021-11-06 1:43 ` Min Hu (Connor)
2021-11-08 15:13 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Ferruh Yigit
9 siblings, 0 replies; 38+ messages in thread
From: Min Hu (Connor) @ 2021-11-06 1:43 UTC (permalink / raw)
To: dev; +Cc: ferruh.yigit, andrew.rybchenko
From: Chengwen Feng <fengchengwen@huawei.com>
This patch remove PF/VF duplicate code of:
1. get firmware version.
2. get device info.
3. rx interrupt related functions.
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
drivers/net/hns3/hns3_common.c | 339 +++++++++++++++++++++++++++++-
drivers/net/hns3/hns3_common.h | 10 +
drivers/net/hns3/hns3_ethdev.c | 314 +--------------------------
drivers/net/hns3/hns3_ethdev.h | 16 +-
drivers/net/hns3/hns3_ethdev_vf.c | 326 +---------------------------
drivers/net/hns3/hns3_tm.c | 2 +-
6 files changed, 365 insertions(+), 642 deletions(-)
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 9a47fbfbde..e6ba15f77c 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -3,9 +3,154 @@
*/
#include <rte_kvargs.h>
+#include <rte_bus_pci.h>
+#include <ethdev_pci.h>
+#include <rte_pci.h>
-#include "hns3_logs.h"
#include "hns3_common.h"
+#include "hns3_logs.h"
+#include "hns3_regs.h"
+#include "hns3_rxtx.h"
+
+int
+hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t version = hw->fw_version;
+ int ret;
+
+ ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+ if (ret < 0)
+ return -EINVAL;
+
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (size_t)ret)
+ return ret;
+ else
+ return 0;
+}
+
+int
+hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t queue_num = hw->tqps_num;
+
+ /*
+ * In interrupt mode, 'max_rx_queues' is set based on the number of
+ * MSI-X interrupt resources of the hardware.
+ */
+ if (hw->data->dev_conf.intr_conf.rxq == 1)
+ queue_num = hw->intr_tqps_num;
+
+ info->max_rx_queues = queue_num;
+ info->max_tx_queues = hw->tqps_num;
+ info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
+ info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
+ info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
+ info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
+ info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_SCATTER |
+ RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
+ RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
+ RTE_ETH_RX_OFFLOAD_RSS_HASH |
+ RTE_ETH_RX_OFFLOAD_TCP_LRO);
+ info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
+ RTE_ETH_TX_OFFLOAD_TCP_TSO |
+ RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
+ RTE_ETH_TX_OFFLOAD_VLAN_INSERT);
+
+ if (!hw->port_base_vlan_cfg.state)
+ info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_QINQ_INSERT;
+
+ if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
+ info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
+ if (hns3_dev_get_support(hw, INDEP_TXRX))
+ info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
+ RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
+ info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
+
+ if (hns3_dev_get_support(hw, PTP))
+ info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
+
+ info->rx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
+ info->tx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
+ .nb_mtu_seg_max = hw->max_non_tso_bd_num,
+ };
+
+ info->default_rxconf = (struct rte_eth_rxconf) {
+ .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
+ /*
+ * If there are no available Rx buffer descriptors, incoming
+ * packets are always dropped by hardware based on hns3 network
+ * engine.
+ */
+ .rx_drop_en = 1,
+ .offloads = 0,
+ };
+ info->default_txconf = (struct rte_eth_txconf) {
+ .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
+ .offloads = 0,
+ };
+
+ info->reta_size = hw->rss_ind_tbl_size;
+ info->hash_key_size = HNS3_RSS_KEY_SIZE;
+ info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+
+ info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+ info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+
+ /*
+ * Next is the PF/VF difference section.
+ */
+ if (!hns->is_vf) {
+ info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
+ info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_KEEP_CRC;
+ info->speed_capa = hns3_get_speed_capa(hw);
+ } else {
+ info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
+ }
+
+ return 0;
+}
static int
hns3_parse_io_hint_func(const char *key, const char *value, void *extra_args)
@@ -68,6 +213,12 @@ hns3_parse_mbx_time_limit(const char *key, const char *value, void *extra_args)
RTE_SET_USED(key);
val = strtoul(value, NULL, HNS3_CONVERT_TO_DECIMAL);
+
+ /*
+ * 500ms is empirical value in process of mailbox communication. If
+ * the delay value is set to one lower thanthe empirical value, mailbox
+ * communication may fail.
+ */
if (val > HNS3_MBX_DEF_TIME_LIMIT_MS && val <= UINT16_MAX)
*(uint16_t *)extra_args = val;
@@ -116,6 +267,11 @@ hns3_parse_devargs(struct rte_eth_dev *dev)
hns3_warn(hw, "parsed %s = 0x%" PRIx64 ".",
HNS3_DEVARG_DEV_CAPS_MASK, dev_caps_mask);
hns->dev_caps_mask = dev_caps_mask;
+
+ if (mbx_time_limit_ms != HNS3_MBX_DEF_TIME_LIMIT_MS)
+ hns3_warn(hw, "parsed %s = %u.", HNS3_DEVARG_MBX_TIME_LIMIT_MS,
+ mbx_time_limit_ms);
+ hns->mbx_time_limit_ms = mbx_time_limit_ms;
}
void
@@ -424,3 +580,184 @@ hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
ret);
}
}
+
+int
+hns3_init_ring_with_vector(struct hns3_hw *hw)
+{
+ uint16_t vec;
+ int ret;
+ int i;
+
+ /*
+ * In hns3 network engine, vector 0 is always the misc interrupt of this
+ * function, vector 1~N can be used respectively for the queues of the
+ * function. Tx and Rx queues with the same number share the interrupt
+ * vector. In the initialization clearing the all hardware mapping
+ * relationship configurations between queues and interrupt vectors is
+ * needed, so some error caused by the residual configurations, such as
+ * the unexpected Tx interrupt, can be avoid.
+ */
+ vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
+ if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
+ vec = vec - 1; /* the last interrupt is reserved */
+ hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
+ for (i = 0; i < hw->intr_tqps_num; i++) {
+ /*
+ * Set gap limiter/rate limiter/quanity limiter algorithm
+ * configuration for interrupt coalesce of queue's interrupt.
+ */
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
+ /*
+ * QL(quantity limiter) is not used currently, just set 0 to
+ * close it.
+ */
+ hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
+
+ ret = hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_TX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to unbind TX ring(%d) with "
+ "vector: %u, ret=%d", i, vec, ret);
+ return ret;
+ }
+
+ ret = hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to unbind RX ring(%d) with "
+ "vector: %u, ret=%d", i, vec, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_map_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint32_t intr_vector;
+ uint16_t q_id;
+ int ret;
+
+ /*
+ * hns3 needs a separate interrupt to be used as event interrupt which
+ * could not be shared with task queue pair, so KERNEL drivers need
+ * support multiple interrupt vectors.
+ */
+ if (dev->data->dev_conf.intr_conf.rxq == 0 ||
+ !rte_intr_cap_multiple(intr_handle))
+ return 0;
+
+ rte_intr_disable(intr_handle);
+ intr_vector = hw->used_rx_queues;
+ /* creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+
+ /* Allocate vector list */
+ if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
+ hw->used_rx_queues)) {
+ hns3_err(hw, "failed to allocate %u rx_queues intr_vec",
+ hw->used_rx_queues);
+ ret = -ENOMEM;
+ goto alloc_intr_vec_error;
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hw->ops.bind_ring_with_vector(hw, vec, true,
+ HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ goto bind_vector_error;
+
+ if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
+ goto bind_vector_error;
+ /*
+ * If there are not enough efds (e.g. not enough interrupt),
+ * remaining queues will be bond to the last interrupt.
+ */
+ if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
+ vec++;
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+bind_vector_error:
+ rte_intr_vec_list_free(intr_handle);
+alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+void
+hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ (void)hw->ops.bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ rte_intr_vec_list_free(intr_handle);
+}
+
+int
+hns3_restore_rx_interrupt(struct hns3_hw *hw)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hw->ops.bind_ring_with_vector(hw,
+ rte_intr_vec_list_index_get(intr_handle,
+ q_id),
+ true, HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 68f9b1b96a..0dbb1c0413 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -30,6 +30,11 @@ enum {
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
+int hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size);
+int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
+ struct rte_eth_dev_info *info);
+
void hns3_clock_gettime(struct timeval *tv);
uint64_t hns3_clock_calctime_ms(struct timeval *tv);
uint64_t hns3_clock_gettime_ms(void);
@@ -48,4 +53,9 @@ int hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
void hns3_ether_format_addr(char *buf, uint16_t size,
const struct rte_ether_addr *ether_addr);
+int hns3_init_ring_with_vector(struct hns3_hw *hw);
+int hns3_map_rx_interrupt(struct rte_eth_dev *dev);
+void hns3_unmap_rx_interrupt(struct rte_eth_dev *dev);
+int hns3_restore_rx_interrupt(struct hns3_hw *hw);
+
#endif /* _HNS3_COMMON_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 181694bf8c..847e660f44 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -1929,62 +1929,6 @@ hns3_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id, bool en,
return 0;
}
-static int
-hns3_init_ring_with_vector(struct hns3_hw *hw)
-{
- uint16_t vec;
- int ret;
- int i;
-
- /*
- * In hns3 network engine, vector 0 is always the misc interrupt of this
- * function, vector 1~N can be used respectively for the queues of the
- * function. Tx and Rx queues with the same number share the interrupt
- * vector. In the initialization clearing the all hardware mapping
- * relationship configurations between queues and interrupt vectors is
- * needed, so some error caused by the residual configurations, such as
- * the unexpected Tx interrupt, can be avoid.
- */
- vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
- if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
- vec = vec - 1; /* the last interrupt is reserved */
- hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
- for (i = 0; i < hw->intr_tqps_num; i++) {
- /*
- * Set gap limiter/rate limiter/quanity limiter algorithm
- * configuration for interrupt coalesce of queue's interrupt.
- */
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
- /*
- * QL(quantity limiter) is not used currently, just set 0 to
- * close it.
- */
- hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
-
- ret = hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_TX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "PF fail to unbind TX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
-
- ret = hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "PF fail to unbind RX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int
hns3_setup_dcb(struct rte_eth_dev *dev)
{
@@ -2255,7 +2199,7 @@ hns3_get_firber_port_speed_capa(uint32_t supported_speed)
return speed_capa;
}
-static uint32_t
+uint32_t
hns3_get_speed_capa(struct hns3_hw *hw)
{
struct hns3_mac *mac = &hw->mac;
@@ -2274,135 +2218,6 @@ hns3_get_speed_capa(struct hns3_hw *hw)
return speed_capa;
}
-int
-hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint16_t queue_num = hw->tqps_num;
-
- /*
- * In interrupt mode, 'max_rx_queues' is set based on the number of
- * MSI-X interrupt resources of the hardware.
- */
- if (hw->data->dev_conf.intr_conf.rxq == 1)
- queue_num = hw->intr_tqps_num;
-
- info->max_rx_queues = queue_num;
- info->max_tx_queues = hw->tqps_num;
- info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
- info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
- info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
- info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
- info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
- info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_KEEP_CRC |
- RTE_ETH_RX_OFFLOAD_SCATTER |
- RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
- RTE_ETH_RX_OFFLOAD_RSS_HASH |
- RTE_ETH_RX_OFFLOAD_TCP_LRO);
- info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
- RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
- hns3_txvlan_cap_get(hw));
-
- if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
- info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
-
- if (hns3_dev_get_support(hw, INDEP_TXRX))
- info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
- RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
- info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
-
- if (hns3_dev_get_support(hw, PTP))
- info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
-
- info->rx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- };
-
- info->tx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
- .nb_mtu_seg_max = hw->max_non_tso_bd_num,
- };
-
- info->speed_capa = hns3_get_speed_capa(hw);
- info->default_rxconf = (struct rte_eth_rxconf) {
- .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
- /*
- * If there are no available Rx buffer descriptors, incoming
- * packets are always dropped by hardware based on hns3 network
- * engine.
- */
- .rx_drop_en = 1,
- .offloads = 0,
- };
- info->default_txconf = (struct rte_eth_txconf) {
- .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
- .offloads = 0,
- };
-
- info->reta_size = hw->rss_ind_tbl_size;
- info->hash_key_size = HNS3_RSS_KEY_SIZE;
- info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
-
- info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
- info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
-
- return 0;
-}
-
-static int
-hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
- size_t fw_size)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint32_t version = hw->fw_version;
- int ret;
-
- ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
- hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
- HNS3_FW_VERSION_BYTE3_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
- HNS3_FW_VERSION_BYTE2_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
- HNS3_FW_VERSION_BYTE1_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
- HNS3_FW_VERSION_BYTE0_S));
- if (ret < 0)
- return -EINVAL;
-
- ret += 1; /* add the size of '\0' */
- if (fw_size < (size_t)ret)
- return ret;
- else
- return 0;
-}
-
static int
hns3_update_port_link_info(struct rte_eth_dev *eth_dev)
{
@@ -5281,98 +5096,6 @@ hns3_do_start(struct hns3_adapter *hns, bool reset_queue)
return ret;
}
-static int
-hns3_map_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint16_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint32_t intr_vector;
- uint16_t q_id;
- int ret;
-
- /*
- * hns3 needs a separate interrupt to be used as event interrupt which
- * could not be shared with task queue pair, so KERNEL drivers need
- * support multiple interrupt vectors.
- */
- if (dev->data->dev_conf.intr_conf.rxq == 0 ||
- !rte_intr_cap_multiple(intr_handle))
- return 0;
-
- rte_intr_disable(intr_handle);
- intr_vector = hw->used_rx_queues;
- /* creates event fd for each intr vector when MSIX is used */
- if (rte_intr_efd_enable(intr_handle, intr_vector))
- return -EINVAL;
-
- /* Allocate vector list */
- if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
- hw->used_rx_queues)) {
- hns3_err(hw, "failed to allocate %u rx_queues intr_vec",
- hw->used_rx_queues);
- ret = -ENOMEM;
- goto alloc_intr_vec_error;
- }
-
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
-
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3_bind_ring_with_vector(hw, vec, true,
- HNS3_RING_TYPE_RX, q_id);
- if (ret)
- goto bind_vector_error;
-
- if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
- goto bind_vector_error;
- /*
- * If there are not enough efds (e.g. not enough interrupt),
- * remaining queues will be bond to the last interrupt.
- */
- if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
- vec++;
- }
- rte_intr_enable(intr_handle);
- return 0;
-
-bind_vector_error:
- rte_intr_vec_list_free(intr_handle);
-alloc_intr_vec_error:
- rte_intr_efd_disable(intr_handle);
- return ret;
-}
-
-static int
-hns3_restore_rx_interrupt(struct hns3_hw *hw)
-{
- struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint16_t q_id;
- int ret;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return 0;
-
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3_bind_ring_with_vector(hw,
- rte_intr_vec_list_index_get(intr_handle,
- q_id),
- true, HNS3_RING_TYPE_RX, q_id);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static void
hns3_restore_filter(struct rte_eth_dev *dev)
{
@@ -5503,40 +5226,6 @@ hns3_do_stop(struct hns3_adapter *hns)
return 0;
}
-static void
-hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_adapter *hns = dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t q_id;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return;
-
- /* unmap the ring with vector */
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- (void)hns3_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX,
- q_id);
- if (vec < base + rte_intr_nb_efd_get(intr_handle)
- - 1)
- vec++;
- }
- }
- /* Clean datapath event and queue/vec mapping */
- rte_intr_efd_disable(intr_handle);
- rte_intr_vec_list_free(intr_handle);
-}
-
static int
hns3_dev_stop(struct rte_eth_dev *dev)
{
@@ -6927,6 +6616,7 @@ hns3_init_hw_ops(struct hns3_hw *hw)
hw->ops.del_mc_mac_addr = hns3_remove_mc_mac_addr;
hw->ops.add_uc_mac_addr = hns3_add_uc_mac_addr;
hw->ops.del_uc_mac_addr = hns3_remove_uc_mac_addr;
+ hw->ops.bind_ring_with_vector = hns3_bind_ring_with_vector;
}
static int
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 67e506f6df..55518a913d 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -437,6 +437,9 @@ struct hns3_hw_ops {
struct rte_ether_addr *mac_addr);
int (*del_uc_mac_addr)(struct hns3_hw *hw,
struct rte_ether_addr *mac_addr);
+ int (*bind_ring_with_vector)(struct hns3_hw *hw, uint16_t vector_id,
+ bool en, enum hns3_ring_type queue_type,
+ uint16_t queue_id);
};
#define HNS3_INTR_MAPPING_VEC_RSV_ONE 0
@@ -1032,12 +1035,12 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
return __atomic_fetch_and(addr, ~mask, __ATOMIC_RELAXED) & mask;
}
+uint32_t hns3_get_speed_capa(struct hns3_hw *hw);
+
int hns3_buffer_alloc(struct hns3_hw *hw);
bool hns3_is_reset_pending(struct hns3_adapter *hns);
bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
void hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query);
-int hns3_dev_infos_get(struct rte_eth_dev *eth_dev,
- struct rte_eth_dev_info *info);
void hns3vf_update_link_status(struct hns3_hw *hw, uint8_t link_status,
uint32_t link_speed, uint8_t link_duplex);
void hns3vf_update_push_lsc_cap(struct hns3_hw *hw, bool supported);
@@ -1069,13 +1072,4 @@ is_reset_pending(struct hns3_adapter *hns)
return ret;
}
-static inline uint64_t
-hns3_txvlan_cap_get(struct hns3_hw *hw)
-{
- if (hw->port_base_vlan_cfg.state)
- return RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
- else
- return RTE_ETH_TX_OFFLOAD_VLAN_INSERT | RTE_ETH_TX_OFFLOAD_QINQ_INSERT;
-}
-
#endif /* _HNS3_ETHDEV_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 8632c8f19b..d8a99693e0 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -422,7 +422,7 @@ hns3vf_restore_promisc(struct hns3_adapter *hns)
}
static int
-hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
+hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id,
bool mmap, enum hns3_ring_type queue_type,
uint16_t queue_id)
{
@@ -434,7 +434,7 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
memset(&bind_msg, 0, sizeof(bind_msg));
code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR :
HNS3_MBX_UNMAP_RING_TO_VECTOR;
- bind_msg.vector_id = vector_id;
+ bind_msg.vector_id = (uint8_t)vector_id;
if (queue_type == HNS3_RING_TYPE_RX)
bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX;
@@ -454,62 +454,6 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
return ret;
}
-static int
-hns3vf_init_ring_with_vector(struct hns3_hw *hw)
-{
- uint16_t vec;
- int ret;
- int i;
-
- /*
- * In hns3 network engine, vector 0 is always the misc interrupt of this
- * function, vector 1~N can be used respectively for the queues of the
- * function. Tx and Rx queues with the same number share the interrupt
- * vector. In the initialization clearing the all hardware mapping
- * relationship configurations between queues and interrupt vectors is
- * needed, so some error caused by the residual configurations, such as
- * the unexpected Tx interrupt, can be avoid.
- */
- vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
- if (hw->intr.mapping_mode == HNS3_INTR_MAPPING_VEC_RSV_ONE)
- vec = vec - 1; /* the last interrupt is reserved */
- hw->intr_tqps_num = RTE_MIN(vec, hw->tqps_num);
- for (i = 0; i < hw->intr_tqps_num; i++) {
- /*
- * Set gap limiter/rate limiter/quanity limiter algorithm
- * configuration for interrupt coalesce of queue's interrupt.
- */
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
- HNS3_TQP_INTR_GL_DEFAULT);
- hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
- /*
- * QL(quantity limiter) is not used currently, just set 0 to
- * close it.
- */
- hns3_set_queue_intr_ql(hw, i, HNS3_TQP_INTR_QL_DEFAULT);
-
- ret = hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_TX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "VF fail to unbind TX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
-
- ret = hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX, i);
- if (ret) {
- PMD_INIT_LOG(ERR, "VF fail to unbind RX ring(%d) with "
- "vector: %u, ret=%d", i, vec, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int
hns3vf_dev_configure(struct rte_eth_dev *dev)
{
@@ -649,103 +593,6 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
return 0;
}
-static int
-hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint16_t q_num = hw->tqps_num;
-
- /*
- * In interrupt mode, 'max_rx_queues' is set based on the number of
- * MSI-X interrupt resources of the hardware.
- */
- if (hw->data->dev_conf.intr_conf.rxq == 1)
- q_num = hw->intr_tqps_num;
-
- info->max_rx_queues = q_num;
- info->max_tx_queues = hw->tqps_num;
- info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
- info->min_rx_bufsize = HNS3_MIN_BD_BUF_SIZE;
- info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
- info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
- info->max_lro_pkt_size = HNS3_MAX_LRO_SIZE;
-
- info->rx_offload_capa = (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
- RTE_ETH_RX_OFFLOAD_SCATTER |
- RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
- RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
- RTE_ETH_RX_OFFLOAD_RSS_HASH |
- RTE_ETH_RX_OFFLOAD_TCP_LRO);
- info->tx_offload_capa = (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
- RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
- RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
- RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
- RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
- RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
- RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
- hns3_txvlan_cap_get(hw));
-
- if (hns3_dev_get_support(hw, OUTER_UDP_CKSUM))
- info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
-
- if (hns3_dev_get_support(hw, INDEP_TXRX))
- info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
- RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
- info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
-
- info->rx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- };
-
- info->tx_desc_lim = (struct rte_eth_desc_lim) {
- .nb_max = HNS3_MAX_RING_DESC,
- .nb_min = HNS3_MIN_RING_DESC,
- .nb_align = HNS3_ALIGN_RING_DESC,
- .nb_seg_max = HNS3_MAX_TSO_BD_PER_PKT,
- .nb_mtu_seg_max = hw->max_non_tso_bd_num,
- };
-
- info->default_rxconf = (struct rte_eth_rxconf) {
- .rx_free_thresh = HNS3_DEFAULT_RX_FREE_THRESH,
- /*
- * If there are no available Rx buffer descriptors, incoming
- * packets are always dropped by hardware based on hns3 network
- * engine.
- */
- .rx_drop_en = 1,
- .offloads = 0,
- };
- info->default_txconf = (struct rte_eth_txconf) {
- .tx_rs_thresh = HNS3_DEFAULT_TX_RS_THRESH,
- .offloads = 0,
- };
-
- info->reta_size = hw->rss_ind_tbl_size;
- info->hash_key_size = HNS3_RSS_KEY_SIZE;
- info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
-
- info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
- info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
- info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
- info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
-
- return 0;
-}
-
static void
hns3vf_clear_event_cause(struct hns3_hw *hw, uint32_t regclr)
{
@@ -1634,7 +1481,7 @@ hns3vf_init_hardware(struct hns3_adapter *hns)
* some error caused by the residual configurations, such as the
* unexpected interrupt, can be avoid.
*/
- ret = hns3vf_init_ring_with_vector(hw);
+ ret = hns3_init_ring_with_vector(hw);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init ring intr vector: %d", ret);
goto err_init_hardware;
@@ -1821,41 +1668,6 @@ hns3vf_do_stop(struct hns3_adapter *hns)
return 0;
}
-static void
-hns3vf_unmap_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint16_t q_id;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return;
-
- /* unmap the ring with vector */
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- (void)hns3vf_bind_ring_with_vector(hw, vec, false,
- HNS3_RING_TYPE_RX,
- q_id);
- if (vec < base + rte_intr_nb_efd_get(intr_handle)
- - 1)
- vec++;
- }
- }
- /* Clean datapath event and queue/vec mapping */
- rte_intr_efd_disable(intr_handle);
-
- /* Cleanup vector list */
- rte_intr_vec_list_free(intr_handle);
-}
-
static int
hns3vf_dev_stop(struct rte_eth_dev *dev)
{
@@ -1877,7 +1689,7 @@ hns3vf_dev_stop(struct rte_eth_dev *dev)
if (__atomic_load_n(&hw->reset.resetting, __ATOMIC_RELAXED) == 0) {
hns3_stop_tqps(hw);
hns3vf_do_stop(hns);
- hns3vf_unmap_rx_interrupt(dev);
+ hns3_unmap_rx_interrupt(dev);
hw->adapter_state = HNS3_NIC_CONFIGURED;
}
hns3_rx_scattered_reset(dev);
@@ -1918,34 +1730,6 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
return ret;
}
-static int
-hns3vf_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
- size_t fw_size)
-{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- uint32_t version = hw->fw_version;
- int ret;
-
- ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
- hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
- HNS3_FW_VERSION_BYTE3_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
- HNS3_FW_VERSION_BYTE2_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
- HNS3_FW_VERSION_BYTE1_S),
- hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
- HNS3_FW_VERSION_BYTE0_S));
- if (ret < 0)
- return -EINVAL;
-
- ret += 1; /* add the size of '\0' */
- if (fw_size < (size_t)ret)
- return ret;
- else
- return 0;
-}
-
static int
hns3vf_dev_link_update(struct rte_eth_dev *eth_dev,
__rte_unused int wait_to_complete)
@@ -2007,99 +1791,6 @@ hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue)
return ret;
}
-static int
-hns3vf_map_rx_interrupt(struct rte_eth_dev *dev)
-{
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
- uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
- uint32_t intr_vector;
- uint16_t q_id;
- int ret;
-
- /*
- * hns3 needs a separate interrupt to be used as event interrupt which
- * could not be shared with task queue pair, so KERNEL drivers need
- * support multiple interrupt vectors.
- */
- if (dev->data->dev_conf.intr_conf.rxq == 0 ||
- !rte_intr_cap_multiple(intr_handle))
- return 0;
-
- rte_intr_disable(intr_handle);
- intr_vector = hw->used_rx_queues;
- /* It creates event fd for each intr vector when MSIX is used */
- if (rte_intr_efd_enable(intr_handle, intr_vector))
- return -EINVAL;
-
- /* Allocate vector list */
- if (rte_intr_vec_list_alloc(intr_handle, "intr_vec",
- hw->used_rx_queues)) {
- hns3_err(hw, "Failed to allocate %u rx_queues"
- " intr_vec", hw->used_rx_queues);
- ret = -ENOMEM;
- goto vf_alloc_intr_vec_error;
- }
-
- if (rte_intr_allow_others(intr_handle)) {
- vec = RTE_INTR_VEC_RXTX_OFFSET;
- base = RTE_INTR_VEC_RXTX_OFFSET;
- }
-
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3vf_bind_ring_with_vector(hw, vec, true,
- HNS3_RING_TYPE_RX, q_id);
- if (ret)
- goto vf_bind_vector_error;
-
- if (rte_intr_vec_list_index_set(intr_handle, q_id, vec))
- goto vf_bind_vector_error;
-
- /*
- * If there are not enough efds (e.g. not enough interrupt),
- * remaining queues will be bond to the last interrupt.
- */
- if (vec < base + rte_intr_nb_efd_get(intr_handle) - 1)
- vec++;
- }
- rte_intr_enable(intr_handle);
- return 0;
-
-vf_bind_vector_error:
- rte_intr_vec_list_free(intr_handle);
-vf_alloc_intr_vec_error:
- rte_intr_efd_disable(intr_handle);
- return ret;
-}
-
-static int
-hns3vf_restore_rx_interrupt(struct hns3_hw *hw)
-{
- struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
- uint16_t q_id;
- int ret;
-
- if (dev->data->dev_conf.intr_conf.rxq == 0)
- return 0;
-
- if (rte_intr_dp_is_en(intr_handle)) {
- for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
- ret = hns3vf_bind_ring_with_vector(hw,
- rte_intr_vec_list_index_get(intr_handle,
- q_id),
- true, HNS3_RING_TYPE_RX, q_id);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static void
hns3vf_restore_filter(struct rte_eth_dev *dev)
{
@@ -2125,7 +1816,7 @@ hns3vf_dev_start(struct rte_eth_dev *dev)
rte_spinlock_unlock(&hw->lock);
return ret;
}
- ret = hns3vf_map_rx_interrupt(dev);
+ ret = hns3_map_rx_interrupt(dev);
if (ret)
goto map_rx_inter_err;
@@ -2442,7 +2133,7 @@ hns3vf_restore_conf(struct hns3_adapter *hns)
if (ret)
goto err_vlan_table;
- ret = hns3vf_restore_rx_interrupt(hw);
+ ret = hns3_restore_rx_interrupt(hw);
if (ret)
goto err_vlan_table;
@@ -2616,8 +2307,8 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.xstats_reset = hns3_dev_xstats_reset,
.xstats_get_by_id = hns3_dev_xstats_get_by_id,
.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
- .dev_infos_get = hns3vf_dev_infos_get,
- .fw_version_get = hns3vf_fw_version_get,
+ .dev_infos_get = hns3_dev_infos_get,
+ .fw_version_get = hns3_fw_version_get,
.rx_queue_setup = hns3_rx_queue_setup,
.tx_queue_setup = hns3_tx_queue_setup,
.rx_queue_release = hns3_dev_rx_queue_release,
@@ -2666,6 +2357,7 @@ hns3vf_init_hw_ops(struct hns3_hw *hw)
hw->ops.del_mc_mac_addr = hns3vf_remove_mc_mac_addr;
hw->ops.add_uc_mac_addr = hns3vf_add_uc_mac_addr;
hw->ops.del_uc_mac_addr = hns3vf_remove_uc_mac_addr;
+ hw->ops.bind_ring_with_vector = hns3vf_bind_ring_with_vector;
}
static int
diff --git a/drivers/net/hns3/hns3_tm.c b/drivers/net/hns3/hns3_tm.c
index 44b607af7a..e1089b6bd0 100644
--- a/drivers/net/hns3/hns3_tm.c
+++ b/drivers/net/hns3/hns3_tm.c
@@ -4,7 +4,7 @@
#include <rte_malloc.h>
-#include "hns3_ethdev.h"
+#include "hns3_common.h"
#include "hns3_dcb.h"
#include "hns3_logs.h"
#include "hns3_tm.h"
--
2.33.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD
2021-11-06 1:42 ` [dpdk-dev] [PATCH v3 0/9] code optimization for hns3 PMD Min Hu (Connor)
` (8 preceding siblings ...)
2021-11-06 1:43 ` [dpdk-dev] [PATCH v3 9/9] net/hns3: remove PF/VF duplicate code Min Hu (Connor)
@ 2021-11-08 15:13 ` Ferruh Yigit
9 siblings, 0 replies; 38+ messages in thread
From: Ferruh Yigit @ 2021-11-08 15:13 UTC (permalink / raw)
To: Min Hu (Connor), dev; +Cc: andrew.rybchenko
On 11/6/2021 1:42 AM, Min Hu (Connor) wrote:
> This patch set contains refactor patches and code check patches.
>
> Chengwen Feng (1):
> net/hns3: remove PF/VF duplicate code
>
> Huisong Li (7):
> net/hns3: fix the shift of DMA address in Rx/Tx queue
> net/hns3: remove a redundant function declaration
> net/hns3: modifying code alignment
> net/hns3: use unsigned integer for bitwise operations
> net/hns3: extract a common file
> net/hns3: remove magic numbers
> net/hns3: fix the return value of the function
>
> Min Hu (Connor) (1):
> net/hns3: add hns3 flow header file
> ---
> v3:
> * fixed build error and some other adjustment.
>
> v2:
> * rebase patch on top of latest next-net.
>
Series applied to dpdk-next-net/main, thanks.
^ permalink raw reply [flat|nested] 38+ messages in thread