From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from dpdk.org (dpdk.org [92.243.14.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 60135A3160
	for <public@inbox.dpdk.org>; Thu, 10 Oct 2019 16:38:19 +0200 (CEST)
Received: from [92.243.14.124] (localhost [127.0.0.1])
	by dpdk.org (Postfix) with ESMTP id 75E0F1E9FA;
	Thu, 10 Oct 2019 16:38:12 +0200 (CEST)
Received: from huawei.com (szxga05-in.huawei.com [45.249.212.191])
 by dpdk.org (Postfix) with ESMTP id 5F93B1E9D1
 for <dev@dpdk.org>; Thu, 10 Oct 2019 16:38:11 +0200 (CEST)
Received: from DGGEMS411-HUB.china.huawei.com (unknown [172.30.72.58])
 by Forcepoint Email with ESMTP id 81C96DA4AC3335335229
 for <dev@dpdk.org>; Thu, 10 Oct 2019 22:38:10 +0800 (CST)
Received: from tester.localdomain (10.175.119.39) by
 DGGEMS411-HUB.china.huawei.com (10.3.19.211) with Microsoft SMTP Server id
 14.3.439.0; Thu, 10 Oct 2019 22:38:04 +0800
From: Xiaoyun wang <cloud.wangxiaoyun@huawei.com>
To: <ferruh.yigit@intel.com>
CC: <dev@dpdk.org>, <xuanziyang2@huawei.com>, <shahar.belkar@huawei.com>,
 <luoxianjun@huawei.com>, <tanya.brokhman@huawei.com>,
 <zhouguoyang@huawei.com>, Xiaoyun wang <cloud.wangxiaoyun@huawei.com>
Date: Thu, 10 Oct 2019 22:51:50 +0800
Message-ID: <0005fc973df0adfc6f2d1e16c646abbfca077a62.1570718029.git.cloud.wangxiaoyun@huawei.com>
X-Mailer: git-send-email 1.8.3.1
In-Reply-To: <cover.1570718029.git.cloud.wangxiaoyun@huawei.com>
References: <cover.1570718029.git.cloud.wangxiaoyun@huawei.com>
MIME-Version: 1.0
Content-Type: text/plain
X-Originating-IP: [10.175.119.39]
X-CFilter-Loop: Reflected
Subject: [dpdk-dev] [PATCH v4 06/19] net/hinic: add unicast and multicast
	MAC set
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org
Sender: "dev" <dev-bounces@dpdk.org>

This patch adds unicast and multicast set interfaces.
Application can add or remove unicast MAC address, also can set
multicast MAC address, tha maximum multicast list size is 2048.

Signed-off-by: Xiaoyun wang <cloud.wangxiaoyun@huawei.com>
---
 doc/guides/nics/hinic.rst                 |   2 +
 drivers/net/hinic/base/hinic_pmd_niccfg.c |  55 +++++++
 drivers/net/hinic/hinic_pmd_ethdev.c      | 260 +++++++++++++++++++++++++++---
 drivers/net/hinic/hinic_pmd_ethdev.h      |   2 +
 4 files changed, 298 insertions(+), 21 deletions(-)

diff --git a/doc/guides/nics/hinic.rst b/doc/guides/nics/hinic.rst
index 681519c..4df5f16 100644
--- a/doc/guides/nics/hinic.rst
+++ b/doc/guides/nics/hinic.rst
@@ -28,6 +28,8 @@ Features
 - VLAN filter and VLAN offload
 - Allmulticast mode
 - MTU update
+- Unicast MAC filter
+- Multicast MAC filter
 
 Prerequisites
 -------------
diff --git a/drivers/net/hinic/base/hinic_pmd_niccfg.c b/drivers/net/hinic/base/hinic_pmd_niccfg.c
index 8bd7ed6..054925c 100644
--- a/drivers/net/hinic/base/hinic_pmd_niccfg.c
+++ b/drivers/net/hinic/base/hinic_pmd_niccfg.c
@@ -250,6 +250,61 @@ int hinic_get_default_mac(void *hwdev, u8 *mac_addr)
 }
 
 /**
+*  hinic_update_mac - Update mac address to hardware.
+*
+* @param hwdev
+*   The hardware interface of a nic device.
+* @param old_mac
+*   Old mac address.
+* @param new_mac
+*   New mac address.
+* @param vlan_id
+*   Set 0 for mac_vlan table initialization.
+* @param func_id
+*   Global function id of NIC.
+*
+* @return
+*   0 on success.
+*   negative error value otherwise.
+*/
+int hinic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,
+		     u16 func_id)
+{
+	struct hinic_port_mac_update mac_info;
+	u16 out_size = sizeof(mac_info);
+	int err;
+
+	if (!hwdev || !old_mac || !new_mac) {
+		PMD_DRV_LOG(ERR, "Hwdev, old_mac or new_mac is NULL\n");
+		return -EINVAL;
+	}
+
+	memset(&mac_info, 0, sizeof(mac_info));
+	mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+	mac_info.func_id = func_id;
+	mac_info.vlan_id = vlan_id;
+	memcpy(mac_info.old_mac, old_mac, ETH_ALEN);
+	memcpy(mac_info.new_mac, new_mac, ETH_ALEN);
+
+	err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UPDATE_MAC,
+				     &mac_info, sizeof(mac_info),
+				     &mac_info, &out_size);
+	if (err || !out_size ||
+	    (mac_info.mgmt_msg_head.status &&
+	     mac_info.mgmt_msg_head.status != HINIC_PF_SET_VF_ALREADY)) {
+		PMD_DRV_LOG(ERR, "Failed to update MAC, err: %d, status: 0x%x, out size: 0x%x\n",
+			    err, mac_info.mgmt_msg_head.status, out_size);
+		return -EINVAL;
+	}
+	if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
+		PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore update operation.\n");
+		return HINIC_PF_SET_VF_ALREADY;
+	}
+
+	return 0;
+}
+
+/**
  * hinic_set_port_mtu -  Set MTU to port.
  *
  * @param hwdev
diff --git a/drivers/net/hinic/hinic_pmd_ethdev.c b/drivers/net/hinic/hinic_pmd_ethdev.c
index 96967a3..91b4f98 100644
--- a/drivers/net/hinic/hinic_pmd_ethdev.c
+++ b/drivers/net/hinic/hinic_pmd_ethdev.c
@@ -51,8 +51,8 @@
 #define NR_MAX_COS			8
 
 #define HINIC_MIN_RX_BUF_SIZE		1024
-#define HINIC_MAX_MAC_ADDRS		1
-
+#define HINIC_MAX_UC_MAC_ADDRS		128
+#define HINIC_MAX_MC_MAC_ADDRS		2048
 /*
  * vlan_id is a 12 bit number.
  * The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -716,7 +716,7 @@ static void hinic_get_speed_capa(struct rte_eth_dev *dev, uint32_t *speed_capa)
 	info->max_tx_queues  = nic_dev->nic_cap.max_sqs;
 	info->min_rx_bufsize = HINIC_MIN_RX_BUF_SIZE;
 	info->max_rx_pktlen  = HINIC_MAX_JUMBO_FRAME_SIZE;
-	info->max_mac_addrs  = HINIC_MAX_MAC_ADDRS;
+	info->max_mac_addrs  = HINIC_MAX_UC_MAC_ADDRS;
 	info->min_mtu = HINIC_MIN_MTU_SIZE;
 	info->max_mtu = HINIC_MAX_MTU_SIZE;
 
@@ -1342,21 +1342,41 @@ static int hinic_init_mac_addr(struct rte_eth_dev *eth_dev)
 	if (rc)
 		return rc;
 
-	memmove(eth_dev->data->mac_addrs->addr_bytes,
-		addr_bytes, RTE_ETHER_ADDR_LEN);
-
-	if (rte_is_zero_ether_addr(eth_dev->data->mac_addrs))
-		hinic_gen_random_mac_addr(eth_dev->data->mac_addrs);
+	rte_ether_addr_copy((struct rte_ether_addr *)addr_bytes,
+		&eth_dev->data->mac_addrs[0]);
+	if (rte_is_zero_ether_addr(&eth_dev->data->mac_addrs[0]))
+		hinic_gen_random_mac_addr(&eth_dev->data->mac_addrs[0]);
 
 	func_id = hinic_global_func_id(nic_dev->hwdev);
-	rc = hinic_set_mac(nic_dev->hwdev, eth_dev->data->mac_addrs->addr_bytes,
-			   0, func_id);
+	rc = hinic_set_mac(nic_dev->hwdev,
+			eth_dev->data->mac_addrs[0].addr_bytes,
+			0, func_id);
 	if (rc && rc != HINIC_PF_SET_VF_ALREADY)
 		return rc;
 
+	rte_ether_addr_copy(&eth_dev->data->mac_addrs[0],
+			&nic_dev->default_addr);
+
 	return 0;
 }
 
+static void hinic_delete_mc_addr_list(struct hinic_nic_dev *nic_dev)
+{
+	u16 func_id;
+	u32 i;
+
+	func_id = hinic_global_func_id(nic_dev->hwdev);
+
+	for (i = 0; i < HINIC_MAX_MC_MAC_ADDRS; i++) {
+		if (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))
+			break;
+
+		hinic_del_mac(nic_dev->hwdev, nic_dev->mc_list[i].addr_bytes,
+			      0, func_id);
+		memset(&nic_dev->mc_list[i], 0, sizeof(struct rte_ether_addr));
+	}
+}
+
 /**
  * Deinit mac_vlan table in NIC.
  *
@@ -1371,19 +1391,29 @@ static void hinic_deinit_mac_addr(struct rte_eth_dev *eth_dev)
 {
 	struct hinic_nic_dev *nic_dev =
 				HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
-	int rc;
 	u16 func_id = 0;
-
-	if (rte_is_zero_ether_addr(eth_dev->data->mac_addrs))
-		return;
+	int rc;
+	int i;
 
 	func_id = hinic_global_func_id(nic_dev->hwdev);
-	rc = hinic_del_mac(nic_dev->hwdev,
-			   eth_dev->data->mac_addrs->addr_bytes,
-			   0, func_id);
-	if (rc && rc != HINIC_PF_SET_VF_ALREADY)
-		PMD_DRV_LOG(ERR, "Delete mac table failed, dev_name: %s",
-			    eth_dev->data->name);
+
+	for (i = 0; i < HINIC_MAX_UC_MAC_ADDRS; i++) {
+		if (rte_is_zero_ether_addr(&eth_dev->data->mac_addrs[i]))
+			continue;
+
+		rc = hinic_del_mac(nic_dev->hwdev,
+				   eth_dev->data->mac_addrs[i].addr_bytes,
+				   0, func_id);
+		if (rc && rc != HINIC_PF_SET_VF_ALREADY)
+			PMD_DRV_LOG(ERR, "Delete mac table failed, dev_name: %s",
+				    eth_dev->data->name);
+
+		memset(&eth_dev->data->mac_addrs[i], 0,
+		       sizeof(struct rte_ether_addr));
+	}
+
+	/* delete multicast mac addrs */
+	hinic_delete_mc_addr_list(nic_dev);
 }
 
 static int hinic_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
@@ -2091,6 +2121,169 @@ static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
 
 	return count;
 }
+/**
+ *  DPDK callback to set mac address
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param addr
+ *   Pointer to mac address
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int hinic_set_mac_addr(struct rte_eth_dev *dev,
+			      struct rte_ether_addr *addr)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	u16 func_id;
+	int err;
+
+	func_id = hinic_global_func_id(nic_dev->hwdev);
+	err = hinic_update_mac(nic_dev->hwdev, nic_dev->default_addr.addr_bytes,
+			       addr->addr_bytes, 0, func_id);
+	if (err)
+		return err;
+
+	rte_ether_addr_copy(addr, &nic_dev->default_addr);
+
+	PMD_DRV_LOG(INFO, "Set new mac address %02x:%02x:%02x:%02x:%02x:%02x\n",
+		    addr->addr_bytes[0], addr->addr_bytes[1],
+		    addr->addr_bytes[2], addr->addr_bytes[3],
+		    addr->addr_bytes[4], addr->addr_bytes[5]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param index
+ *   MAC address index.
+ */
+static void hinic_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	u16 func_id;
+	int ret;
+
+	if (index >= HINIC_MAX_UC_MAC_ADDRS) {
+		PMD_DRV_LOG(INFO, "Remove mac index(%u) is out of range",
+			    index);
+		return;
+	}
+
+	func_id = hinic_global_func_id(nic_dev->hwdev);
+	ret = hinic_del_mac(nic_dev->hwdev,
+			    dev->data->mac_addrs[index].addr_bytes, 0, func_id);
+	if (ret)
+		return;
+
+	memset(&dev->data->mac_addrs[index], 0, sizeof(struct rte_ether_addr));
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ * @param index
+ *   MAC address index.
+ * @param vmdq
+ *   VMDq pool index to associate address with (ignored).
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+
+static int hinic_mac_addr_add(struct rte_eth_dev *dev,
+			      struct rte_ether_addr *mac_addr, uint32_t index,
+			      __rte_unused uint32_t vmdq)
+{
+	struct hinic_nic_dev  *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	unsigned int i;
+	u16 func_id;
+	int ret;
+
+	if (index >= HINIC_MAX_UC_MAC_ADDRS) {
+		PMD_DRV_LOG(INFO, "Add mac index(%u) is out of range,", index);
+		return -EINVAL;
+	}
+
+	/* First, make sure this address isn't already configured. */
+	for (i = 0; (i != HINIC_MAX_UC_MAC_ADDRS); ++i) {
+		/* Skip this index, it's going to be reconfigured. */
+		if (i == index)
+			continue;
+
+		if (memcmp(&dev->data->mac_addrs[i],
+			mac_addr, sizeof(*mac_addr)))
+			continue;
+
+		PMD_DRV_LOG(INFO, "MAC address already configured");
+		return -EADDRINUSE;
+	}
+
+	func_id = hinic_global_func_id(nic_dev->hwdev);
+	ret = hinic_set_mac(nic_dev->hwdev, mac_addr->addr_bytes, 0, func_id);
+	if (ret)
+		return ret;
+
+	dev->data->mac_addrs[index] = *mac_addr;
+	return 0;
+}
+
+/**
+ *  DPDK callback to set multicast mac address
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mc_addr_set
+ *   Pointer to multicast mac address
+ * @param nb_mc_addr
+ *   mc addr count
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int hinic_set_mc_addr_list(struct rte_eth_dev *dev,
+				  struct rte_ether_addr *mc_addr_set,
+				  uint32_t nb_mc_addr)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	u16 func_id;
+	int ret;
+	u32 i;
+
+	func_id = hinic_global_func_id(nic_dev->hwdev);
+
+	/* delete old multi_cast addrs firstly */
+	hinic_delete_mc_addr_list(nic_dev);
+
+	if (nb_mc_addr > HINIC_MAX_MC_MAC_ADDRS)
+		goto allmulti;
+
+	for (i = 0; i < nb_mc_addr; i++) {
+		ret = hinic_set_mac(nic_dev->hwdev, mc_addr_set[i].addr_bytes,
+				    0, func_id);
+		/* if add mc addr failed, set all multi_cast */
+		if (ret) {
+			hinic_delete_mc_addr_list(nic_dev);
+			goto allmulti;
+		}
+
+		rte_ether_addr_copy(&mc_addr_set[i], &nic_dev->mc_list[i]);
+	}
+
+	return 0;
+
+allmulti:
+	hinic_dev_allmulticast_enable(dev);
+
+	return 0;
+}
 
 static int hinic_set_default_pause_feature(struct hinic_nic_dev *nic_dev)
 {
@@ -2539,6 +2732,10 @@ static void hinic_dev_close(struct rte_eth_dev *dev)
 	.xstats_get                    = hinic_dev_xstats_get,
 	.xstats_reset                  = hinic_dev_xstats_reset,
 	.xstats_get_names              = hinic_dev_xstats_get_names,
+	.mac_addr_set                  = hinic_set_mac_addr,
+	.mac_addr_remove               = hinic_mac_addr_remove,
+	.mac_addr_add                  = hinic_mac_addr_add,
+	.set_mc_addr_list              = hinic_set_mc_addr_list,
 };
 
 static const struct eth_dev_ops hinic_pmd_vf_ops = {
@@ -2566,6 +2763,10 @@ static void hinic_dev_close(struct rte_eth_dev *dev)
 	.xstats_get                    = hinic_dev_xstats_get,
 	.xstats_reset                  = hinic_dev_xstats_reset,
 	.xstats_get_names              = hinic_dev_xstats_get_names,
+	.mac_addr_set                  = hinic_set_mac_addr,
+	.mac_addr_remove               = hinic_mac_addr_remove,
+	.mac_addr_add                  = hinic_mac_addr_add,
+	.set_mc_addr_list              = hinic_set_mc_addr_list,
 };
 
 static int hinic_func_init(struct rte_eth_dev *eth_dev)
@@ -2573,6 +2774,7 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
 	struct rte_pci_device *pci_dev;
 	struct rte_ether_addr *eth_addr;
 	struct hinic_nic_dev *nic_dev;
+	u32 mac_size;
 	int rc;
 
 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
@@ -2599,7 +2801,8 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
 		 pci_dev->addr.devid, pci_dev->addr.function);
 
 	/* alloc mac_addrs */
-	eth_addr = rte_zmalloc("hinic_mac", sizeof(*eth_addr), 0);
+	mac_size = HINIC_MAX_UC_MAC_ADDRS * sizeof(struct rte_ether_addr);
+	eth_addr = rte_zmalloc("hinic_mac", mac_size, 0);
 	if (!eth_addr) {
 		PMD_DRV_LOG(ERR, "Allocate ethernet addresses' memory failed, dev_name: %s",
 			    eth_dev->data->name);
@@ -2608,6 +2811,15 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
 	}
 	eth_dev->data->mac_addrs = eth_addr;
 
+	mac_size = HINIC_MAX_MC_MAC_ADDRS * sizeof(struct rte_ether_addr);
+	nic_dev->mc_list = rte_zmalloc("hinic_mc", mac_size, 0);
+	if (!nic_dev->mc_list) {
+		PMD_DRV_LOG(ERR, "Allocate mcast address' memory failed, dev_name: %s",
+			    eth_dev->data->name);
+		rc = -ENOMEM;
+		goto mc_addr_fail;
+	}
+
 	/*
 	 * Pass the information to the rte_eth_dev_close() that it should also
 	 * release the private port resources.
@@ -2672,6 +2884,10 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
 	hinic_nic_dev_destroy(eth_dev);
 
 create_nic_dev_fail:
+	rte_free(nic_dev->mc_list);
+	nic_dev->mc_list = NULL;
+
+mc_addr_fail:
 	rte_free(eth_addr);
 	eth_dev->data->mac_addrs = NULL;
 
@@ -2716,6 +2932,8 @@ static int hinic_dev_uninit(struct rte_eth_dev *dev)
 	dev->rx_pkt_burst = NULL;
 	dev->tx_pkt_burst = NULL;
 
+	rte_free(nic_dev->mc_list);
+
 	rte_free(dev->data->mac_addrs);
 	dev->data->mac_addrs = NULL;
 
diff --git a/drivers/net/hinic/hinic_pmd_ethdev.h b/drivers/net/hinic/hinic_pmd_ethdev.h
index f7a1167..b4f93ad 100644
--- a/drivers/net/hinic/hinic_pmd_ethdev.h
+++ b/drivers/net/hinic/hinic_pmd_ethdev.h
@@ -56,6 +56,8 @@ struct hinic_nic_dev {
 
 	u32 vfta[HINIC_VFTA_SIZE];	/* VLAN bitmap */
 
+	struct rte_ether_addr default_addr;
+	struct rte_ether_addr *mc_list;
 	/* info */
 	unsigned int flags;
 	struct nic_service_cap nic_cap;
-- 
1.8.3.1