Thread (32 messages) 32 messages, 2 authors, 2021-12-29
STALE1669d
Revisions (5)
  1. v1 [diff vs current]
  2. v2 [diff vs current]
  3. v3 current
  4. v4 [diff vs current]
  5. v6 [diff vs current]

[PATCH v3 10/25] net/spnic: add function info initialization

From: Yanling Song <hidden>
Date: 2021-12-24 08:34:19
Subsystem: networking drivers, the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

This patch mainly implements function info initialization
including mtu, link state, port state, port info and cos
as well as the definition of the corresponding data structure.

Signed-off-by: Yanling Song <redacted>
---
 drivers/net/spnic/base/spnic_hw_cfg.c  |  43 +++
 drivers/net/spnic/base/spnic_hw_cfg.h  |   6 +
 drivers/net/spnic/base/spnic_nic_cfg.c | 221 ++++++++++++++
 drivers/net/spnic/base/spnic_nic_cfg.h | 213 ++++++++++++++
 drivers/net/spnic/spnic_ethdev.c       | 382 ++++++++++++++++++++++++-
 drivers/net/spnic/spnic_ethdev.h       |  22 +-
 6 files changed, 876 insertions(+), 11 deletions(-)
diff --git a/drivers/net/spnic/base/spnic_hw_cfg.c b/drivers/net/spnic/base/spnic_hw_cfg.c
index 6505f48273..49e16ee89c 100644
--- a/drivers/net/spnic/base/spnic_hw_cfg.c
+++ b/drivers/net/spnic/base/spnic_hw_cfg.c
@@ -156,6 +156,49 @@ void spnic_free_capability(void *dev)
 	rte_free(((struct spnic_hwdev *)dev)->cfg_mgmt);
 }
 
+/* *
+ * @brief spnic_support_nic - function support nic
+ * @param hwdev: device pointer to hwdev
+ * @retval true: function support nic
+ * @retval false: function not support nic
+ */
+bool spnic_support_nic(void *hwdev)
+{
+	struct spnic_hwdev *dev = (struct spnic_hwdev *)hwdev;
+
+	if (!hwdev)
+		return false;
+
+	if (!IS_NIC_TYPE(dev))
+		return false;
+
+	return true;
+}
+
+u16 spnic_func_max_sqs(void *hwdev)
+{
+	struct spnic_hwdev *dev = hwdev;
+
+	if (!dev) {
+		PMD_DRV_LOG(INFO, "Hwdev is NULL for getting max_sqs");
+		return 0;
+	}
+
+	return dev->cfg_mgmt->svc_cap.nic_cap.max_sqs;
+}
+
+u16 spnic_func_max_rqs(void *hwdev)
+{
+	struct spnic_hwdev *dev = hwdev;
+
+	if (!dev) {
+		PMD_DRV_LOG(INFO, "Hwdev is NULL for getting max_rqs");
+		return 0;
+	}
+
+	return dev->cfg_mgmt->svc_cap.nic_cap.max_rqs;
+}
+
 u8 spnic_physical_port_id(void *hwdev)
 {
 	struct spnic_hwdev *dev = hwdev;
diff --git a/drivers/net/spnic/base/spnic_hw_cfg.h b/drivers/net/spnic/base/spnic_hw_cfg.h
index 9ab51f2875..5019f38ec2 100644
--- a/drivers/net/spnic/base/spnic_hw_cfg.h
+++ b/drivers/net/spnic/base/spnic_hw_cfg.h
@@ -112,8 +112,14 @@ struct spnic_cfg_cmd_dev_cap {
 int spnic_init_capability(void *dev);
 void spnic_free_capability(void *dev);
 
+u16 spnic_func_max_sqs(void *hwdev);
+u16 spnic_func_max_rqs(void *hwdev);
+
 u8 spnic_physical_port_id(void *hwdev);
 
 int cfg_mbx_vf_proc_msg(void *hwdev, void *pri_handle, u16 cmd, void *buf_in,
 			u16 in_size, void *buf_out, u16 *out_size);
+
+bool spnic_support_nic(void *hwdev);
+
 #endif /* _SPNIC_HW_CFG_H_ */
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c b/drivers/net/spnic/base/spnic_nic_cfg.c
index c47bc330a3..886aaea384 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.c
+++ b/drivers/net/spnic/base/spnic_nic_cfg.c
@@ -265,6 +265,227 @@ int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info)
 	return 0;
 }
 
+
+int spnic_get_link_state(void *hwdev, u8 *link_state)
+{
+	struct spnic_cmd_link_state get_link;
+	u16 out_size = sizeof(get_link);
+	int err;
+
+	if (!hwdev || !link_state)
+		return -EINVAL;
+
+	memset(&get_link, 0, sizeof(get_link));
+	get_link.port_id = spnic_physical_port_id(hwdev);
+	err = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_GET_LINK_STATUS, &get_link,
+				   sizeof(get_link), &get_link, &out_size);
+	if (err || !out_size || get_link.msg_head.status) {
+		PMD_DRV_LOG(ERR, "Get link state failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, get_link.msg_head.status, out_size);
+		return -EIO;
+	}
+
+	*link_state = get_link.state;
+
+	return 0;
+}
+
+int spnic_set_vport_enable(void *hwdev, bool enable)
+{
+	struct spnic_vport_state en_state;
+	u16 out_size = sizeof(en_state);
+	int err;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	memset(&en_state, 0, sizeof(en_state));
+	en_state.func_id = spnic_global_func_id(hwdev);
+	en_state.state = enable ? 1 : 0;
+
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_VPORT_ENABLE, &en_state,
+				     sizeof(en_state), &en_state, &out_size);
+	if (err || !out_size || en_state.msg_head.status) {
+		PMD_DRV_LOG(ERR, "Set vport state failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, en_state.msg_head.status, out_size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int spnic_set_port_enable(void *hwdev, bool enable)
+{
+	struct mag_cmd_set_port_enable en_state;
+	u16 out_size = sizeof(en_state);
+	int err;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	if (spnic_func_type(hwdev) == TYPE_VF)
+		return 0;
+
+	memset(&en_state, 0, sizeof(en_state));
+	en_state.function_id = spnic_global_func_id(hwdev);
+	en_state.state = enable ? MAG_CMD_TX_ENABLE | MAG_CMD_RX_ENABLE :
+				MAG_CMD_PORT_DISABLE;
+
+	err = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_SET_PORT_ENABLE, &en_state,
+				     sizeof(en_state), &en_state, &out_size);
+	if (err || !out_size || en_state.head.status) {
+		PMD_DRV_LOG(ERR, "Set port state failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, en_state.head.status, out_size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int spnic_set_function_table(void *hwdev, u32 cfg_bitmap,
+				     struct spnic_func_tbl_cfg *cfg)
+{
+	struct spnic_cmd_set_func_tbl cmd_func_tbl;
+	u16 out_size = sizeof(cmd_func_tbl);
+	int err;
+
+	memset(&cmd_func_tbl, 0, sizeof(cmd_func_tbl));
+	cmd_func_tbl.func_id = spnic_global_func_id(hwdev);
+	cmd_func_tbl.cfg_bitmap = cfg_bitmap;
+	cmd_func_tbl.tbl_cfg = *cfg;
+
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_FUNC_TBL,
+				     &cmd_func_tbl, sizeof(cmd_func_tbl),
+				     &cmd_func_tbl, &out_size);
+	if (err || cmd_func_tbl.msg_head.status || !out_size) {
+		PMD_DRV_LOG(ERR, "Set func table failed, bitmap: 0x%x, err: %d, "
+			    "status: 0x%x, out size: 0x%x\n", cfg_bitmap, err,
+			    cmd_func_tbl.msg_head.status, out_size);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int spnic_init_function_table(void *hwdev, u16 rx_buff_len)
+{
+	struct spnic_func_tbl_cfg func_tbl_cfg;
+	u32 cfg_bitmap = BIT(FUNC_CFG_INIT) | BIT(FUNC_CFG_MTU) |
+			 BIT(FUNC_CFG_RX_BUF_SIZE);
+
+	memset(&func_tbl_cfg, 0, sizeof(func_tbl_cfg));
+	func_tbl_cfg.mtu = 0x3FFF; /* Default, max mtu */
+	func_tbl_cfg.rx_wqe_buf_size = rx_buff_len;
+
+	return spnic_set_function_table(hwdev, cfg_bitmap, &func_tbl_cfg);
+}
+
+int spnic_set_port_mtu(void *hwdev, u16 new_mtu)
+{
+	struct spnic_func_tbl_cfg func_tbl_cfg;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	if (new_mtu < SPNIC_MIN_MTU_SIZE) {
+		PMD_DRV_LOG(ERR, "Invalid mtu size: %ubytes, mtu size < %ubytes",
+			    new_mtu, SPNIC_MIN_MTU_SIZE);
+		return -EINVAL;
+	}
+
+	if (new_mtu > SPNIC_MAX_JUMBO_FRAME_SIZE) {
+		PMD_DRV_LOG(ERR, "Invalid mtu size: %ubytes, mtu size > %ubytes",
+			    new_mtu, SPNIC_MAX_JUMBO_FRAME_SIZE);
+		return -EINVAL;
+	}
+
+	memset(&func_tbl_cfg, 0, sizeof(func_tbl_cfg));
+	func_tbl_cfg.mtu = new_mtu;
+
+	return spnic_set_function_table(hwdev, BIT(FUNC_CFG_MTU),
+					&func_tbl_cfg);
+}
+
+static int spnic_vf_func_init(void *hwdev)
+{
+	struct spnic_cmd_register_vf register_info;
+	u16 out_size = sizeof(register_info);
+	int err;
+
+	if (spnic_func_type(hwdev) != TYPE_VF)
+		return 0;
+
+	memset(&register_info, 0, sizeof(register_info));
+	register_info.op_register = 1;
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER,
+				     &register_info, sizeof(register_info),
+				     &register_info, &out_size);
+	if (err || register_info.msg_head.status || !out_size) {
+		PMD_DRV_LOG(ERR, "Register VF failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, register_info.msg_head.status, out_size);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int spnic_vf_func_free(void *hwdev)
+{
+	struct spnic_cmd_register_vf unregister;
+	u16 out_size = sizeof(unregister);
+	int err;
+
+	if (spnic_func_type(hwdev) != TYPE_VF)
+		return 0;
+
+	memset(&unregister, 0, sizeof(unregister));
+	unregister.op_register = 0;
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER,
+				     &unregister, sizeof(unregister),
+				     &unregister, &out_size);
+	if (err || unregister.msg_head.status || !out_size) {
+		PMD_DRV_LOG(ERR, "Unregister VF failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, unregister.msg_head.status, out_size);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int spnic_init_nic_hwdev(void *hwdev)
+{
+	return spnic_vf_func_init(hwdev);
+}
+
+void spnic_free_nic_hwdev(void *hwdev)
+{
+	if (!hwdev)
+		return;
+
+	spnic_vf_func_free(hwdev);
+}
+
+int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id)
+{
+	struct spnic_cmd_vf_dcb_state vf_dcb;
+	u16 out_size = sizeof(vf_dcb);
+	int err;
+
+	memset(&vf_dcb, 0, sizeof(vf_dcb));
+
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_COS, &vf_dcb,
+				     sizeof(vf_dcb), &vf_dcb, &out_size);
+	if (err || !out_size || vf_dcb.msg_head.status) {
+		PMD_DRV_LOG(ERR, "Get VF default cos failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, vf_dcb.msg_head.status, out_size);
+		return -EIO;
+	}
+
+	*cos_id = vf_dcb.state.default_cos;
+
+	return 0;
+}
+
 static int _mag_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in,
 				 u16 in_size, void *buf_out, u16 *out_size)
 {
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h
index a10a310530..0af4588c1a 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.h
+++ b/drivers/net/spnic/base/spnic_nic_cfg.h
@@ -12,6 +12,26 @@
 #define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1)
 #define HW_VF_ID_TO_OS(hw_vf_id) ((hw_vf_id) - 1)
 
+#define SPNIC_DCB_UP_MAX		0x8
+
+#define SPNIC_MAX_NUM_RQ		256
+
+#define SPNIC_MAX_MTU_SIZE		9600
+#define SPNIC_MIN_MTU_SIZE		384
+
+#define SPNIC_COS_NUM_MAX		8
+
+#define SPNIC_VLAN_TAG_SIZE		4
+#define SPNIC_ETH_OVERHEAD \
+	(RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + SPNIC_VLAN_TAG_SIZE * 2)
+
+#define SPNIC_MIN_FRAME_SIZE (SPNIC_MIN_MTU_SIZE + SPNIC_ETH_OVERHEAD)
+#define SPNIC_MAX_JUMBO_FRAME_SIZE (SPNIC_MAX_MTU_SIZE + SPNIC_ETH_OVERHEAD)
+
+#define SPNIC_MTU_TO_PKTLEN(mtu)	((mtu) + SPNIC_ETH_OVERHEAD)
+
+#define SPNIC_PKTLEN_TO_MTU(pktlen)	((pktlen) - SPNIC_ETH_OVERHEAD)
+
 #define SPNIC_PF_SET_VF_ALREADY		0x4
 #define SPNIC_MGMT_STATUS_EXIST		0x6
 #define CHECK_IPSU_15BIT		0x8000
@@ -92,6 +112,114 @@ struct spnic_cmd_link_state {
 	u16 rsvd1;
 };
 
+struct nic_pause_config {
+	u8 auto_neg;
+	u8 rx_pause;
+	u8 tx_pause;
+};
+
+struct spnic_cmd_pause_config {
+	struct mgmt_msg_head msg_head;
+
+	u8 port_id;
+	u8 opcode;
+	u16 rsvd1;
+	u8 auto_neg;
+	u8 rx_pause;
+	u8 tx_pause;
+	u8 rsvd2[5];
+};
+
+struct spnic_vport_state {
+	struct mgmt_msg_head msg_head;
+
+	u16 func_id;
+	u16 rsvd1;
+	u8 state;  /* 0--disable, 1--enable */
+	u8 rsvd2[3];
+};
+
+#define MAG_CMD_PORT_DISABLE  0x0
+#define MAG_CMD_TX_ENABLE     0x1
+#define MAG_CMD_RX_ENABLE     0x2
+/* the physical port is disable only when all pf of the port are set to down,
+ * if any pf is enable, the port is enable
+ */
+struct mag_cmd_set_port_enable {
+	struct mgmt_msg_head head;
+
+	u16 function_id;
+	u16 rsvd0;
+
+	u8 state;  /* bitmap bit0:tx_en bit1:rx_en */
+	u8 rsvd1[3];
+};
+
+struct mag_cmd_get_port_enable {
+	struct mgmt_msg_head head;
+
+	u8 port;
+	u8 state; /* bitmap bit0:tx_en bit1:rx_en */
+	u8 rsvd0[2];
+};
+
+struct spnic_cmd_clear_qp_resource {
+	struct mgmt_msg_head msg_head;
+
+	u16 func_id;
+	u16 rsvd1;
+};
+
+
+enum spnic_func_tbl_cfg_bitmap {
+	FUNC_CFG_INIT,
+	FUNC_CFG_RX_BUF_SIZE,
+	FUNC_CFG_MTU,
+};
+
+struct spnic_func_tbl_cfg {
+	u16 rx_wqe_buf_size;
+	u16 mtu;
+	u32 rsvd[9];
+};
+
+struct spnic_cmd_set_func_tbl {
+	struct mgmt_msg_head msg_head;
+
+	u16 func_id;
+	u16 rsvd;
+
+	u32 cfg_bitmap;
+	struct spnic_func_tbl_cfg tbl_cfg;
+};
+
+enum {
+	SPNIC_IFLA_VF_LINK_STATE_AUTO,	/* Link state of the uplink */
+	SPNIC_IFLA_VF_LINK_STATE_ENABLE, /* Link always up */
+	SPNIC_IFLA_VF_LINK_STATE_DISABLE, /* Link always down */
+};
+
+struct spnic_dcb_state {
+	u8 dcb_on;
+	u8 default_cos;
+	u16 rsvd1;
+	u8 up_cos[SPNIC_DCB_UP_MAX];
+	u32 rsvd2[7];
+};
+
+struct spnic_cmd_vf_dcb_state {
+	struct mgmt_msg_head msg_head;
+
+	struct spnic_dcb_state state;
+};
+
+struct spnic_cmd_register_vf {
+	struct mgmt_msg_head msg_head;
+
+	u8 op_register; /* 0 - unregister, 1 - register */
+	u8 rsvd[39];
+};
+
 int l2nic_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size,
 			   void *buf_out, u16 *out_size);
 
@@ -164,6 +292,77 @@ int spnic_set_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);
  */
 int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);
 
+/**
+ * Set function mtu
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] new_mtu
+ *   MTU value
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_port_mtu(void *hwdev, u16 new_mtu);
+
+/**
+ * Set function valid status
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] enable
+ *   0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_vport_enable(void *hwdev, bool enable);
+
+/**
+ * Set port status
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] enable
+ *   0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_port_enable(void *hwdev, bool enable);
+
+/**
+ * Get link state
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] link_state
+ *   Link state, 0-link down, 1-link up
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_get_link_state(void *hwdev, u8 *link_state);
+
+/**
+ * Init nic hwdev
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_init_nic_hwdev(void *hwdev);
+
+/**
+ * Free nic hwdev
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ */
+void spnic_free_nic_hwdev(void *hwdev);
+
 /**
  * Get port info
  *
@@ -177,4 +376,18 @@ int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);
  */
 int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info);
 
+int spnic_init_function_table(void *hwdev, u16 rx_buff_len);
+
+/**
+ * Get VF function default cos
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] cos_id
+ *   Cos id
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id);
 #endif /* _SPNIC_NIC_CFG_H_ */
diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c
index 8f71280fa7..7f73e70df1 100644
--- a/drivers/net/spnic/spnic_ethdev.c
+++ b/drivers/net/spnic/spnic_ethdev.c
@@ -30,23 +30,106 @@ int spnic_logtype;
 #define SPNIC_MAX_UC_MAC_ADDRS		128
 #define SPNIC_MAX_MC_MAC_ADDRS		128
 
-static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev)
+/**
+ * Deinit mac_vlan table in hardware.
+ *
+ * @param[in] eth_dev
+ *   Pointer to ethernet device structure.
+ */
+
+/**
+ * Set ethernet device link state up.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure.
+ */
+static int spnic_dev_set_link_up(struct rte_eth_dev *dev)
 {
-	u16 func_id;
-	u32 i;
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	int err;
 
-	func_id = spnic_global_func_id(nic_dev->hwdev);
+	/* Link status follow phy port status, mpu will open pma */
+	err = spnic_set_port_enable(nic_dev->hwdev, true);
+	if (err)
+		PMD_DRV_LOG(ERR, "Set MAC link up failed, dev_name: %s, port_id: %d",
+			    nic_dev->dev_name, dev->data->port_id);
 
-	for (i = 0; i < SPNIC_MAX_MC_MAC_ADDRS; i++) {
-		if (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))
+	return err;
+}
+
+/**
+ * Set ethernet device link state down.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure.
+ */
+static int spnic_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	int err;
+
+	/* Link status follow phy port status, mpu will close pma */
+	err = spnic_set_port_enable(nic_dev->hwdev, false);
+	if (err)
+		PMD_DRV_LOG(ERR, "Set MAC link down failed, dev_name: %s, port_id: %d",
+			    nic_dev->dev_name, dev->data->port_id);
+
+	return err;
+}
+
+/**
+ * Get device physical link information.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ * @param[in] wait_to_complete
+ *   Wait for request completion.
+ *
+ * @retval 0 : Link status changed
+ * @retval -1 : Link status not changed.
+ */
+static int spnic_link_update(struct rte_eth_dev *dev, int wait_to_complete)
+{
+#define CHECK_INTERVAL 10  /* 10ms */
+#define MAX_REPEAT_TIME 100  /* 1s (100 * 10ms) in total */
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_link link;
+	u8 link_state;
+	unsigned int rep_cnt = MAX_REPEAT_TIME;
+	int ret;
+
+	memset(&link, 0, sizeof(link));
+	do {
+		/* Get link status information from hardware */
+		ret = spnic_get_link_state(nic_dev->hwdev, &link_state);
+		if (ret) {
+			link.link_status = ETH_LINK_DOWN;
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			link.link_duplex = ETH_LINK_HALF_DUPLEX;
+			link.link_autoneg = ETH_LINK_FIXED;
+			goto out;
+		}
+
+		get_port_info(nic_dev->hwdev, link_state, &link);
+
+		if (!wait_to_complete || link.link_status)
 			break;
 
-		spnic_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));
-	}
+		rte_delay_ms(CHECK_INTERVAL);
+	} while (rep_cnt--);
+
+out:
+	return rte_eth_linkstatus_set(dev, &link);
 }
 
+static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev);
+
 /**
  * Deinit mac_vlan table in hardware.
  *
@@ -82,6 +165,122 @@ static void spnic_deinit_mac_addr(struct rte_eth_dev *eth_dev)
 	spnic_delete_mc_addr_list(nic_dev);
 }
 
+static int spnic_init_sw_rxtxqs(struct spnic_nic_dev *nic_dev)
+{
+	u32 txq_size;
+	u32 rxq_size;
+
+	/* Allocate software txq array */
+	txq_size = nic_dev->max_sqs * sizeof(*nic_dev->txqs);
+	nic_dev->txqs = rte_zmalloc("spnic_txqs", txq_size,
+				    RTE_CACHE_LINE_SIZE);
+	if (!nic_dev->txqs) {
+		PMD_DRV_LOG(ERR, "Allocate txqs failed");
+		return -ENOMEM;
+	}
+
+	/* Allocate software rxq array */
+	rxq_size = nic_dev->max_rqs * sizeof(*nic_dev->rxqs);
+	nic_dev->rxqs = rte_zmalloc("spnic_rxqs", rxq_size,
+				    RTE_CACHE_LINE_SIZE);
+	if (!nic_dev->rxqs) {
+		/* Free txqs */
+		rte_free(nic_dev->txqs);
+		nic_dev->txqs = NULL;
+
+		PMD_DRV_LOG(ERR, "Allocate rxqs failed");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void spnic_deinit_sw_rxtxqs(struct spnic_nic_dev *nic_dev)
+{
+	rte_free(nic_dev->txqs);
+	nic_dev->txqs = NULL;
+
+	rte_free(nic_dev->rxqs);
+	nic_dev->rxqs = NULL;
+}
+
+/**
+ * Start the device.
+ *
+ * Initialize function table, rxq and txq context, config rx offload, and enable
+ * vport and port to prepare receiving packets.
+ *
+ * @param[in] eth_dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+static int spnic_dev_start(struct rte_eth_dev *eth_dev)
+{
+	struct spnic_nic_dev *nic_dev;
+	int err;
+
+	nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+
+	err = spnic_init_function_table(nic_dev->hwdev, nic_dev->rx_buff_len);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init function table failed, dev_name: %s",
+			    eth_dev->data->name);
+		goto init_func_tbl_fail;
+	}
+
+	/* Set default mtu */
+	err = spnic_set_port_mtu(nic_dev->hwdev, nic_dev->mtu_size);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Set mtu_size[%d] failed, dev_name: %s",
+			    nic_dev->mtu_size, eth_dev->data->name);
+		goto set_mtu_fail;
+	}
+
+
+	/* Update eth_dev link status */
+	if (eth_dev->data->dev_conf.intr_conf.lsc != 0)
+		(void)spnic_link_update(eth_dev, 0);
+
+	rte_bit_relaxed_set32(SPNIC_DEV_START, &nic_dev->dev_status);
+
+	return 0;
+
+set_mtu_fail:
+init_func_tbl_fail:
+
+	return err;
+}
+
+/**
+ * Stop the device.
+ *
+ * Stop phy port and vport, flush pending io request, clean context configure
+ * and free io resourece.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ */
+static int spnic_dev_stop(struct rte_eth_dev *dev)
+{
+	struct spnic_nic_dev *nic_dev;
+	struct rte_eth_link link;
+
+	nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	if (!rte_bit_relaxed_test_and_clear32(SPNIC_DEV_START, &nic_dev->dev_status)) {
+		PMD_DRV_LOG(INFO, "Device %s already stopped",
+			    nic_dev->dev_name);
+		return 0;
+	}
+
+	/* Clear recorded link status */
+	memset(&link, 0, sizeof(link));
+	(void)rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
 /**
  * Close the device.
  *
@@ -99,11 +298,19 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)
 		return 0;
 	}
 
+	spnic_dev_stop(eth_dev);
+
+	spnic_deinit_sw_rxtxqs(nic_dev);
 	spnic_deinit_mac_addr(eth_dev);
 	rte_free(nic_dev->mc_list);
 
 	rte_bit_relaxed_clear32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);
 
+
+	/* Destroy rx mode mutex */
+	spnic_mutex_destroy(&nic_dev->rx_mode_mutex);
+
+	spnic_free_nic_hwdev(nic_dev->hwdev);
 	spnic_free_hwdev(nic_dev->hwdev);
 
 	eth_dev->dev_ops = NULL;
@@ -113,6 +320,34 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)
 
 	return 0;
 }
+
+static int spnic_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	int err = 0;
+
+	PMD_DRV_LOG(INFO, "Set port mtu, port_id: %d, mtu: %d, max_pkt_len: %d",
+		    dev->data->port_id, mtu, SPNIC_MTU_TO_PKTLEN(mtu));
+
+	if (mtu < SPNIC_MIN_MTU_SIZE || mtu > SPNIC_MAX_MTU_SIZE) {
+		PMD_DRV_LOG(ERR, "Invalid mtu: %d, must between %d and %d",
+			    mtu, SPNIC_MIN_MTU_SIZE, SPNIC_MAX_MTU_SIZE);
+		return -EINVAL;
+	}
+
+	err = spnic_set_port_mtu(nic_dev->hwdev, mtu);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Set port mtu failed, err: %d", err);
+		return err;
+	}
+
+	/* Update max frame size */
+	dev->data->dev_conf.rxmode.mtu = SPNIC_MTU_TO_PKTLEN(mtu);
+	nic_dev->mtu_size = mtu;
+
+	return err;
+}
+
 /**
  * Update MAC address
  *
@@ -233,6 +468,23 @@ static int spnic_mac_addr_add(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev)
+{
+	u16 func_id;
+	u32 i;
+
+	func_id = spnic_global_func_id(nic_dev->hwdev);
+
+	for (i = 0; i < SPNIC_MAX_MC_MAC_ADDRS; i++) {
+		if (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))
+			break;
+
+		spnic_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));
+	}
+}
+
 /**
  * Set multicast MAC address
  *
@@ -287,7 +539,15 @@ static int spnic_set_mc_addr_list(struct rte_eth_dev *dev,
 
 	return 0;
 }
+
 static const struct eth_dev_ops spnic_pmd_ops = {
+	.dev_set_link_up               = spnic_dev_set_link_up,
+	.dev_set_link_down             = spnic_dev_set_link_down,
+	.link_update                   = spnic_link_update,
+	.dev_start                     = spnic_dev_start,
+	.dev_stop                      = spnic_dev_stop,
+	.dev_close                     = spnic_dev_close,
+	.mtu_set                       = spnic_dev_set_mtu,
 	.mac_addr_set                  = spnic_set_mac_addr,
 	.mac_addr_remove               = spnic_mac_addr_remove,
 	.mac_addr_add                  = spnic_mac_addr_add,
@@ -295,6 +555,11 @@ static const struct eth_dev_ops spnic_pmd_ops = {
 };
 
 static const struct eth_dev_ops spnic_pmd_vf_ops = {
+	.link_update                   = spnic_link_update,
+	.dev_start                     = spnic_dev_start,
+	.dev_stop                      = spnic_dev_stop,
+	.dev_close                     = spnic_dev_close,
+	.mtu_set                       = spnic_dev_set_mtu,
 	.mac_addr_set                  = spnic_set_mac_addr,
 	.mac_addr_remove               = spnic_mac_addr_remove,
 	.mac_addr_add                  = spnic_mac_addr_add,
@@ -341,6 +606,66 @@ static int spnic_init_mac_table(struct rte_eth_dev *eth_dev)
 	return 0;
 }
 
+static int spnic_pf_get_default_cos(struct spnic_hwdev *hwdev, u8 *cos_id)
+{
+	u8 default_cos = 0;
+	u8 valid_cos_bitmap;
+	u8 i;
+
+	valid_cos_bitmap = hwdev->cfg_mgmt->svc_cap.cos_valid_bitmap;
+	if (!valid_cos_bitmap) {
+		PMD_DRV_LOG(ERR, "PF has none cos to support\n");
+		return -EFAULT;
+	}
+
+	for (i = 0; i < SPNIC_COS_NUM_MAX; i++) {
+		if (valid_cos_bitmap & BIT(i))
+			/* Find max cos id as default cos */
+			default_cos = i;
+	}
+
+	*cos_id = default_cos;
+
+	return 0;
+}
+
+static int spnic_init_default_cos(struct spnic_nic_dev *nic_dev)
+{
+	u8 cos_id = 0;
+	int err;
+
+	if (!SPNIC_IS_VF(nic_dev->hwdev)) {
+		err = spnic_pf_get_default_cos(nic_dev->hwdev, &cos_id);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Get PF default cos failed, err: %d",
+				    err);
+			return err;
+		}
+	} else {
+		err = spnic_vf_get_default_cos(nic_dev->hwdev, &cos_id);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Get VF default cos failed, err: %d",
+				    err);
+			return err;
+		}
+	}
+
+	nic_dev->default_cos = cos_id;
+	PMD_DRV_LOG(INFO, "Default cos %d", nic_dev->default_cos);
+	return 0;
+}
+
+static int spnic_set_default_hw_feature(struct spnic_nic_dev *nic_dev)
+{
+	int err;
+
+	err = spnic_init_default_cos(nic_dev);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static int spnic_func_init(struct rte_eth_dev *eth_dev)
 {
 	struct spnic_nic_dev *nic_dev = NULL;
@@ -411,10 +736,28 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)
 		goto init_hwdev_fail;
 	}
 
+	nic_dev->max_sqs = spnic_func_max_sqs(nic_dev->hwdev);
+	nic_dev->max_rqs = spnic_func_max_rqs(nic_dev->hwdev);
+
 	if (SPNIC_FUNC_TYPE(nic_dev->hwdev) == TYPE_VF)
 		eth_dev->dev_ops = &spnic_pmd_vf_ops;
 	else
 		eth_dev->dev_ops = &spnic_pmd_ops;
+
+	err = spnic_init_nic_hwdev(nic_dev->hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init nic hwdev failed, dev_name: %s",
+			    eth_dev->data->name);
+		goto init_nic_hwdev_fail;
+	}
+
+	err = spnic_init_sw_rxtxqs(nic_dev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s",
+			    eth_dev->data->name);
+		goto init_sw_rxtxqs_fail;
+	}
+
 	err = spnic_init_mac_table(eth_dev);
 	if (err) {
 		PMD_DRV_LOG(ERR, "Init mac table failed, dev_name: %s",
@@ -422,6 +765,16 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)
 		goto init_mac_table_fail;
 	}
 
+	/* Set hardware feature to default status */
+	err = spnic_set_default_hw_feature(nic_dev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Set hw default features failed, dev_name: %s",
+			    eth_dev->data->name);
+		goto set_default_feature_fail;
+	}
+
+	spnic_mutex_init(&nic_dev->rx_mode_mutex, NULL);
+
 	rte_bit_relaxed_set32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);
 
 	rte_bit_relaxed_set32(SPNIC_DEV_INIT, &nic_dev->dev_status);
@@ -430,7 +783,16 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)
 
 	return 0;
 
+set_default_feature_fail:
+	spnic_deinit_mac_addr(eth_dev);
+
 init_mac_table_fail:
+	spnic_deinit_sw_rxtxqs(nic_dev);
+
+init_sw_rxtxqs_fail:
+	spnic_free_nic_hwdev(nic_dev->hwdev);
+
+init_nic_hwdev_fail:
 	spnic_free_hwdev(nic_dev->hwdev);
 	eth_dev->dev_ops = NULL;
 
diff --git a/drivers/net/spnic/spnic_ethdev.h b/drivers/net/spnic/spnic_ethdev.h
index 654234aaa4..321db389dc 100644
--- a/drivers/net/spnic/spnic_ethdev.h
+++ b/drivers/net/spnic/spnic_ethdev.h
@@ -4,6 +4,7 @@
 
 #ifndef _SPNIC_ETHDEV_H_
 #define _SPNIC_ETHDEV_H_
+#define SPNIC_DEV_NAME_LEN		32
 
 #define SPNIC_UINT32_BIT_SIZE		(CHAR_BIT * sizeof(uint32_t))
 #define SPNIC_VFTA_SIZE			(4096 / SPNIC_UINT32_BIT_SIZE)
@@ -16,7 +17,25 @@ enum spnic_dev_status {
 	SPNIC_DEV_INTR_EN
 };
 
-#define SPNIC_DEV_NAME_LEN		32
+enum nic_feature_cap {
+	NIC_F_CSUM = BIT(0),
+	NIC_F_SCTP_CRC = BIT(1),
+	NIC_F_TSO = BIT(2),
+	NIC_F_LRO = BIT(3),
+	NIC_F_UFO = BIT(4),
+	NIC_F_RSS = BIT(5),
+	NIC_F_RX_VLAN_FILTER = BIT(6),
+	NIC_F_RX_VLAN_STRIP = BIT(7),
+	NIC_F_TX_VLAN_INSERT = BIT(8),
+	NIC_F_VXLAN_OFFLOAD = BIT(9),
+	NIC_F_IPSEC_OFFLOAD = BIT(10),
+	NIC_F_FDIR = BIT(11),
+	NIC_F_PROMISC = BIT(12),
+	NIC_F_ALLMULTI = BIT(13),
+};
+
+#define DEFAULT_DRV_FEATURE		0x3FFF
+
 struct spnic_nic_dev {
 	struct spnic_hwdev *hwdev; /* Hardware device */
 
@@ -53,6 +72,7 @@ struct spnic_nic_dev {
 	struct rte_ether_addr *mc_list;
 
 	char dev_name[SPNIC_DEV_NAME_LEN];
+	u64 feature_cap;
 	u32 vfta[SPNIC_VFTA_SIZE]; /* VLAN bitmap */
 };
 
-- 
2.32.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help