From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1A4DCA00C5; Fri, 24 Dec 2021 09:34:19 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E46F2411B8; Fri, 24 Dec 2021 09:33:23 +0100 (CET) Received: from VLXDG1SPAM1.ramaxel.com (email.ramaxel.com [221.4.138.186]) by mails.dpdk.org (Postfix) with ESMTP id 6EF0241190 for ; Fri, 24 Dec 2021 09:33:21 +0100 (CET) Received: from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local [172.26.18.31]) by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BO8Woch043401 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 24 Dec 2021 16:32:51 +0800 (GMT-8) (envelope-from songyl@ramaxel.com) Received: from localhost.localdomain (10.64.9.47) by V12DG1MBS01.ramaxel.local (172.26.18.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2308.14; Fri, 24 Dec 2021 16:32:50 +0800 From: Yanling Song To: CC: , , , , Subject: [PATCH v3 10/25] net/spnic: add function info initialization Date: Fri, 24 Dec 2021 16:32:28 +0800 Message-ID: <7876aa4f83b776734096823ced59757164d7bb69.1640332922.git.songyl@ramaxel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.64.9.47] X-ClientProxiedBy: V12DG1MBS03.ramaxel.local (172.26.18.33) To V12DG1MBS01.ramaxel.local (172.26.18.31) X-DNSRBL: X-MAIL: VLXDG1SPAM1.ramaxel.com 1BO8Woch043401 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org 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 --- 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(®ister_info, 0, sizeof(register_info)); + register_info.op_register = 1; + err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER, + ®ister_info, sizeof(register_info), + ®ister_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