[v2,06/17] net/hinic: add unicast and multicast MAC set

Message ID e34687cd15f9cf991fced6471e074f1033167a28.1569421287.git.cloud.wangxiaoyun@huawei.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series Add advanced features for Huawei hinic pmd |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Wangxiaoyun (Cloud) Sept. 25, 2019, 2:30 p.m. UTC
  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>
---
 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 +
 3 files changed, 296 insertions(+), 21 deletions(-)
  

Patch

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 8eeeaea..16dc1cd 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;
 
 	hinic_get_speed_capa(dev, &info->speed_capa);
 	info->rx_queue_offload_capa = 0;
@@ -1340,21 +1340,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.
  *
@@ -1369,19 +1389,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)
@@ -2089,6 +2119,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)
 {
@@ -2537,6 +2730,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 = {
@@ -2564,6 +2761,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)
@@ -2571,6 +2772,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);
@@ -2597,7 +2799,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);
@@ -2606,6 +2809,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.
@@ -2670,6 +2882,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;
 
@@ -2714,6 +2930,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;