X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fqede%2Fqede_main.c;h=8a108f99ce42eab4524420f8ae37c4873840830b;hb=35b2d13fd6fdcbd191f2a30d74648faeb1186c65;hp=b09fb85761ef63ba682cc441cf8909b84f1fc9d2;hpb=2ea6f76aff402be2c7a19cd244e83b46641bced5;p=dpdk.git diff --git a/drivers/net/qede/qede_main.c b/drivers/net/qede/qede_main.c index b09fb85761..8a108f99ce 100644 --- a/drivers/net/qede/qede_main.c +++ b/drivers/net/qede/qede_main.c @@ -1,27 +1,24 @@ -/* - * Copyright (c) 2016 QLogic Corporation. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2016 - 2018 Cavium Inc. * All rights reserved. - * www.qlogic.com - * - * See LICENSE.qede_pmd for copyright and licensing details. + * www.cavium.com */ -#include -#include -#include -#include #include +#include +#include +#include #include "qede_ethdev.h" -static uint8_t npar_tx_switching = 1; +/* Alarm timeout. */ +#define QEDE_ALARM_TIMEOUT_US 100000 -#define CONFIG_QED_BINARY_FW /* Global variable to hold absolute path of fw file */ -char fw_file[PATH_MAX]; +char qede_fw_file[PATH_MAX]; -const char *QEDE_DEFAULT_FIRMWARE = - "/lib/firmware/qed/qed_init_values_zipped-8.7.7.0.bin"; +static const char * const QEDE_DEFAULT_FIRMWARE = + "/lib/firmware/qed/qed_init_values-8.37.7.0.bin"; static void qed_update_pf_params(struct ecore_dev *edev, struct ecore_pf_params *params) @@ -38,25 +35,35 @@ static void qed_init_pci(struct ecore_dev *edev, struct rte_pci_device *pci_dev) { edev->regview = pci_dev->mem_resource[0].addr; edev->doorbells = pci_dev->mem_resource[2].addr; + edev->db_size = pci_dev->mem_resource[2].len; } static int qed_probe(struct ecore_dev *edev, struct rte_pci_device *pci_dev, - enum qed_protocol protocol, uint32_t dp_module, - uint8_t dp_level, bool is_vf) + uint32_t dp_module, uint8_t dp_level, bool is_vf) { - struct qede_dev *qdev = (struct qede_dev *)edev; + struct ecore_hw_prepare_params hw_prepare_params; int rc; ecore_init_struct(edev); - qdev->protocol = protocol; - if (is_vf) { + edev->drv_type = DRV_ID_DRV_TYPE_LINUX; + /* Protocol type is always fixed to PROTOCOL_ETH */ + + if (is_vf) edev->b_is_vf = true; - edev->sriov_info.b_hw_channel = true; - } + ecore_init_dp(edev, dp_module, dp_level, NULL); qed_init_pci(edev, pci_dev); - rc = ecore_hw_prepare(edev, ECORE_PCI_DEFAULT); + + memset(&hw_prepare_params, 0, sizeof(hw_prepare_params)); + hw_prepare_params.personality = ECORE_PCI_ETH; + hw_prepare_params.drv_resc_alloc = false; + hw_prepare_params.chk_reg_fifo = false; + hw_prepare_params.initiate_pf_flr = true; + hw_prepare_params.allow_mdump = false; + hw_prepare_params.b_en_pacing = false; + hw_prepare_params.epoch = (u32)time(NULL); + rc = ecore_hw_prepare(edev, &hw_prepare_params); if (rc) { DP_ERR(edev, "hw prepare failed\n"); return rc; @@ -67,7 +74,7 @@ qed_probe(struct ecore_dev *edev, struct rte_pci_device *pci_dev, static int qed_nic_setup(struct ecore_dev *edev) { - int rc, i; + int rc; rc = ecore_resc_alloc(edev); if (rc) @@ -79,6 +86,7 @@ static int qed_nic_setup(struct ecore_dev *edev) return rc; } +#ifdef CONFIG_ECORE_ZIPPED_FW static int qed_alloc_stream_mem(struct ecore_dev *edev) { int i; @@ -108,7 +116,9 @@ static void qed_free_stream_mem(struct ecore_dev *edev) OSAL_FREE(p_hwfn->p_dev, p_hwfn->stream); } } +#endif +#ifdef CONFIG_ECORE_BINARY_FW static int qed_load_firmware_data(struct ecore_dev *edev) { int fd; @@ -116,66 +126,131 @@ static int qed_load_firmware_data(struct ecore_dev *edev) const char *fw = RTE_LIBRTE_QEDE_FW; if (strcmp(fw, "") == 0) - strcpy(fw_file, QEDE_DEFAULT_FIRMWARE); + strcpy(qede_fw_file, QEDE_DEFAULT_FIRMWARE); else - strcpy(fw_file, fw); + strcpy(qede_fw_file, fw); - fd = open(fw_file, O_RDONLY); + fd = open(qede_fw_file, O_RDONLY); if (fd < 0) { - DP_NOTICE(edev, false, "Can't open firmware file\n"); + DP_ERR(edev, "Can't open firmware file\n"); return -ENOENT; } if (fstat(fd, &st) < 0) { - DP_NOTICE(edev, false, "Can't stat firmware file\n"); + DP_ERR(edev, "Can't stat firmware file\n"); + close(fd); return -1; } edev->firmware = rte_zmalloc("qede_fw", st.st_size, RTE_CACHE_LINE_SIZE); if (!edev->firmware) { - DP_NOTICE(edev, false, "Can't allocate memory for firmware\n"); + DP_ERR(edev, "Can't allocate memory for firmware\n"); close(fd); return -ENOMEM; } if (read(fd, edev->firmware, st.st_size) != st.st_size) { - DP_NOTICE(edev, false, "Can't read firmware data\n"); + DP_ERR(edev, "Can't read firmware data\n"); close(fd); return -1; } edev->fw_len = st.st_size; if (edev->fw_len < 104) { - DP_NOTICE(edev, false, "Invalid fw size: %" PRIu64 "\n", + DP_ERR(edev, "Invalid fw size: %" PRIu64 "\n", edev->fw_len); + close(fd); return -EINVAL; } + close(fd); return 0; } +#endif + +static void qed_handle_bulletin_change(struct ecore_hwfn *hwfn) +{ + uint8_t mac[ETH_ALEN], is_mac_exist, is_mac_forced; + + is_mac_exist = ecore_vf_bulletin_get_forced_mac(hwfn, mac, + &is_mac_forced); + if (is_mac_exist && is_mac_forced) + rte_memcpy(hwfn->hw_info.hw_mac_addr, mac, ETH_ALEN); + + /* Always update link configuration according to bulletin */ + qed_link_update(hwfn); +} + +static void qede_vf_task(void *arg) +{ + struct ecore_hwfn *p_hwfn = arg; + uint8_t change = 0; + + /* Read the bulletin board, and re-schedule the task */ + ecore_vf_read_bulletin(p_hwfn, &change); + if (change) + qed_handle_bulletin_change(p_hwfn); + + rte_eal_alarm_set(QEDE_ALARM_TIMEOUT_US, qede_vf_task, p_hwfn); +} + +static void qed_start_iov_task(struct ecore_dev *edev) +{ + struct ecore_hwfn *p_hwfn; + int i; + for_each_hwfn(edev, i) { + p_hwfn = &edev->hwfns[i]; + if (!IS_PF(edev)) + rte_eal_alarm_set(QEDE_ALARM_TIMEOUT_US, qede_vf_task, + p_hwfn); + } +} + +static void qed_stop_iov_task(struct ecore_dev *edev) +{ + struct ecore_hwfn *p_hwfn; + int i; + + for_each_hwfn(edev, i) { + p_hwfn = &edev->hwfns[i]; + if (!IS_PF(edev)) + rte_eal_alarm_cancel(qede_vf_task, p_hwfn); + } +} static int qed_slowpath_start(struct ecore_dev *edev, struct qed_slowpath_params *params) { - bool allow_npar_tx_switching; + struct ecore_drv_load_params drv_load_params; + struct ecore_hw_init_params hw_init_params; + struct ecore_mcp_drv_version drv_version; const uint8_t *data = NULL; struct ecore_hwfn *hwfn; - struct ecore_mcp_drv_version drv_version; - struct qede_dev *qdev = (struct qede_dev *)edev; + struct ecore_ptt *p_ptt; int rc; -#ifdef QED_ENC_SUPPORTED - struct ecore_tunn_start_params tunn_info; -#endif -#ifdef CONFIG_QED_BINARY_FW - rc = qed_load_firmware_data(edev); - if (rc) { - DP_NOTICE(edev, true, - "Failed to find fw file %s\n", fw_file); - goto err; - } + if (IS_PF(edev)) { +#ifdef CONFIG_ECORE_BINARY_FW + rc = qed_load_firmware_data(edev); + if (rc) { + DP_ERR(edev, "Failed to find fw file %s\n", + qede_fw_file); + goto err; + } #endif + hwfn = ECORE_LEADING_HWFN(edev); + if (edev->num_hwfns == 1) { /* skip aRFS for 100G device */ + p_ptt = ecore_ptt_acquire(hwfn); + if (p_ptt) { + ECORE_LEADING_HWFN(edev)->p_arfs_ptt = p_ptt; + } else { + DP_ERR(edev, "Failed to acquire PTT for flowdir\n"); + rc = -ENOMEM; + goto err; + } + } + } rc = qed_nic_setup(edev); if (rc) @@ -184,36 +259,39 @@ static int qed_slowpath_start(struct ecore_dev *edev, /* set int_coalescing_mode */ edev->int_coalescing_mode = ECORE_COAL_MODE_ENABLE; - /* Should go with CONFIG_QED_BINARY_FW */ - /* Allocate stream for unzipping */ - rc = qed_alloc_stream_mem(edev); - if (rc) { - DP_NOTICE(edev, true, - "Failed to allocate stream memory\n"); - goto err2; +#ifdef CONFIG_ECORE_ZIPPED_FW + if (IS_PF(edev)) { + /* Allocate stream for unzipping */ + rc = qed_alloc_stream_mem(edev); + if (rc) { + DP_ERR(edev, "Failed to allocate stream memory\n"); + goto err1; + } } - - /* Start the slowpath */ -#ifdef CONFIG_QED_BINARY_FW - data = edev->firmware; #endif - allow_npar_tx_switching = npar_tx_switching ? true : false; - -#ifdef QED_ENC_SUPPORTED - memset(&tunn_info, 0, sizeof(tunn_info)); - tunn_info.tunn_mode |= 1 << QED_MODE_VXLAN_TUNN | - 1 << QED_MODE_L2GRE_TUNN | - 1 << QED_MODE_IPGRE_TUNN | - 1 << QED_MODE_L2GENEVE_TUNN | 1 << QED_MODE_IPGENEVE_TUNN; - tunn_info.tunn_clss_vxlan = QED_TUNN_CLSS_MAC_VLAN; - tunn_info.tunn_clss_l2gre = QED_TUNN_CLSS_MAC_VLAN; - tunn_info.tunn_clss_ipgre = QED_TUNN_CLSS_MAC_VLAN; - rc = ecore_hw_init(edev, &tunn_info, true, ECORE_INT_MODE_MSIX, - allow_npar_tx_switching, data); -#else - rc = ecore_hw_init(edev, NULL, true, ECORE_INT_MODE_MSIX, - allow_npar_tx_switching, data); + + qed_start_iov_task(edev); + +#ifdef CONFIG_ECORE_BINARY_FW + if (IS_PF(edev)) + data = (const uint8_t *)edev->firmware + sizeof(u32); #endif + + /* Start the slowpath */ + memset(&hw_init_params, 0, sizeof(hw_init_params)); + hw_init_params.b_hw_start = true; + hw_init_params.int_mode = params->int_mode; + hw_init_params.allow_npar_tx_switch = true; + hw_init_params.bin_fw_data = data; + + memset(&drv_load_params, 0, sizeof(drv_load_params)); + drv_load_params.mfw_timeout_val = ECORE_LOAD_REQ_LOCK_TO_DEFAULT; + drv_load_params.avoid_eng_reset = false; + drv_load_params.override_force_load = ECORE_OVERRIDE_FORCE_LOAD_ALWAYS; + hw_init_params.avoid_eng_affin = false; + hw_init_params.p_drv_load_params = &drv_load_params; + + rc = ecore_hw_init(edev, &hw_init_params); if (rc) { DP_ERR(edev, "ecore_hw_init failed\n"); goto err2; @@ -221,68 +299,111 @@ static int qed_slowpath_start(struct ecore_dev *edev, DP_INFO(edev, "HW inited and function started\n"); - hwfn = ECORE_LEADING_HWFN(edev); - drv_version.version = (params->drv_major << 24) | + if (IS_PF(edev)) { + hwfn = ECORE_LEADING_HWFN(edev); + drv_version.version = (params->drv_major << 24) | (params->drv_minor << 16) | (params->drv_rev << 8) | (params->drv_eng); - /* TBD: strlcpy() */ - strncpy((char *)drv_version.name, (const char *)params->name, - MCP_DRV_VER_STR_SIZE - 4); - rc = ecore_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, + strlcpy((char *)drv_version.name, (const char *)params->name, + sizeof(drv_version.name)); + rc = ecore_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, &drv_version); - if (rc) { - DP_NOTICE(edev, true, - "Failed sending drv version command\n"); - return rc; + if (rc) { + DP_ERR(edev, "Failed sending drv version command\n"); + goto err3; + } } + ecore_reset_vport_stats(edev); + return 0; +err3: ecore_hw_stop(edev); err2: + qed_stop_iov_task(edev); +#ifdef CONFIG_ECORE_ZIPPED_FW + qed_free_stream_mem(edev); +err1: +#endif ecore_resc_free(edev); err: -#ifdef CONFIG_QED_BINARY_FW - if (edev->firmware) - rte_free(edev->firmware); - edev->firmware = NULL; +#ifdef CONFIG_ECORE_BINARY_FW + if (IS_PF(edev)) { + if (edev->firmware) + rte_free(edev->firmware); + edev->firmware = NULL; + } #endif + qed_stop_iov_task(edev); + return rc; } static int qed_fill_dev_info(struct ecore_dev *edev, struct qed_dev_info *dev_info) { + struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(edev); struct ecore_ptt *ptt = NULL; + struct ecore_tunnel_info *tun = &edev->tunnel; memset(dev_info, 0, sizeof(struct qed_dev_info)); + + if (tun->vxlan.tun_cls == ECORE_TUNN_CLSS_MAC_VLAN && + tun->vxlan.b_mode_enabled) + dev_info->vxlan_enable = true; + + if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && + tun->l2_gre.tun_cls == ECORE_TUNN_CLSS_MAC_VLAN && + tun->ip_gre.tun_cls == ECORE_TUNN_CLSS_MAC_VLAN) + dev_info->gre_enable = true; + + if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && + tun->l2_geneve.tun_cls == ECORE_TUNN_CLSS_MAC_VLAN && + tun->ip_geneve.tun_cls == ECORE_TUNN_CLSS_MAC_VLAN) + dev_info->geneve_enable = true; + dev_info->num_hwfns = edev->num_hwfns; dev_info->is_mf_default = IS_MF_DEFAULT(&edev->hwfns[0]); + dev_info->mtu = ECORE_LEADING_HWFN(edev)->hw_info.mtu; + dev_info->dev_type = edev->type; + rte_memcpy(&dev_info->hw_mac, &edev->hwfns[0].hw_info.hw_mac_addr, - ETHER_ADDR_LEN); + RTE_ETHER_ADDR_LEN); dev_info->fw_major = FW_MAJOR_VERSION; dev_info->fw_minor = FW_MINOR_VERSION; dev_info->fw_rev = FW_REVISION_VERSION; dev_info->fw_eng = FW_ENGINEERING_VERSION; - dev_info->mf_mode = edev->mf_mode; - dev_info->tx_switching = false; - ptt = ecore_ptt_acquire(ECORE_LEADING_HWFN(edev)); - if (ptt) { - ecore_mcp_get_mfw_ver(edev, ptt, + if (IS_PF(edev)) { + dev_info->b_inter_pf_switch = + OSAL_TEST_BIT(ECORE_MF_INTER_PF_SWITCH, &edev->mf_bits); + if (!OSAL_TEST_BIT(ECORE_MF_DISABLE_ARFS, &edev->mf_bits)) + dev_info->b_arfs_capable = true; + dev_info->tx_switching = false; + + dev_info->smart_an = ecore_mcp_is_smart_an_supported(p_hwfn); + + ptt = ecore_ptt_acquire(ECORE_LEADING_HWFN(edev)); + if (ptt) { + ecore_mcp_get_mfw_ver(ECORE_LEADING_HWFN(edev), ptt, &dev_info->mfw_rev, NULL); - ecore_mcp_get_flash_size(ECORE_LEADING_HWFN(edev), ptt, + ecore_mcp_get_flash_size(ECORE_LEADING_HWFN(edev), ptt, &dev_info->flash_size); - /* Workaround to allow PHY-read commands for - * B0 bringup. - */ - if (ECORE_IS_BB_B0(edev)) - dev_info->flash_size = 0xffffffff; + /* Workaround to allow PHY-read commands for + * B0 bringup. + */ + if (ECORE_IS_BB_B0(edev)) + dev_info->flash_size = 0xffffffff; - ecore_ptt_release(ECORE_LEADING_HWFN(edev), ptt); + ecore_ptt_release(ECORE_LEADING_HWFN(edev), ptt); + } + } else { + ecore_mcp_get_mfw_ver(ECORE_LEADING_HWFN(edev), ptt, + &dev_info->mfw_rev, NULL); } return 0; @@ -291,31 +412,55 @@ qed_fill_dev_info(struct ecore_dev *edev, struct qed_dev_info *dev_info) int qed_fill_eth_dev_info(struct ecore_dev *edev, struct qed_dev_eth_info *info) { - struct qede_dev *qdev = (struct qede_dev *)edev; + uint8_t queues = 0; int i; memset(info, 0, sizeof(*info)); info->num_tc = 1 /* @@@TBD aelior MULTI_COS */; - info->num_queues = 0; - for_each_hwfn(edev, i) - info->num_queues += - FEAT_NUM(&edev->hwfns[i], ECORE_PF_L2_QUE); + if (IS_PF(edev)) { + int max_vf_vlan_filters = 0; + + info->num_queues = 0; + for_each_hwfn(edev, i) + info->num_queues += + FEAT_NUM(&edev->hwfns[i], ECORE_PF_L2_QUE); + + if (IS_ECORE_SRIOV(edev)) + max_vf_vlan_filters = edev->p_iov_info->total_vfs * + ECORE_ETH_VF_NUM_VLAN_FILTERS; + info->num_vlan_filters = RESC_NUM(&edev->hwfns[0], ECORE_VLAN) - + max_vf_vlan_filters; + + rte_memcpy(&info->port_mac, &edev->hwfns[0].hw_info.hw_mac_addr, + RTE_ETHER_ADDR_LEN); + } else { + ecore_vf_get_num_rxqs(ECORE_LEADING_HWFN(edev), + &info->num_queues); + if (ECORE_IS_CMT(edev)) { + ecore_vf_get_num_rxqs(&edev->hwfns[1], &queues); + info->num_queues += queues; + } + + ecore_vf_get_num_vlan_filters(&edev->hwfns[0], + (u8 *)&info->num_vlan_filters); - info->num_vlan_filters = RESC_NUM(&edev->hwfns[0], ECORE_VLAN); + ecore_vf_get_port_mac(&edev->hwfns[0], + (uint8_t *)&info->port_mac); - rte_memcpy(&info->port_mac, &edev->hwfns[0].hw_info.hw_mac_addr, - ETHER_ADDR_LEN); + info->is_legacy = ecore_vf_get_pre_fp_hsi(&edev->hwfns[0]); + } qed_fill_dev_info(edev, &info->common); + if (IS_VF(edev)) + memset(&info->common.hw_mac, 0, RTE_ETHER_ADDR_LEN); + return 0; } -static void -qed_set_id(struct ecore_dev *edev, char name[NAME_SIZE], - const char ver_str[VER_SIZE]) +static void qed_set_name(struct ecore_dev *edev, char name[NAME_SIZE]) { int i; @@ -323,29 +468,18 @@ qed_set_id(struct ecore_dev *edev, char name[NAME_SIZE], for_each_hwfn(edev, i) { snprintf(edev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); } - rte_memcpy(edev->ver_str, ver_str, VER_SIZE); - edev->drv_type = DRV_ID_DRV_TYPE_LINUX; } static uint32_t qed_sb_init(struct ecore_dev *edev, struct ecore_sb_info *sb_info, - void *sb_virt_addr, dma_addr_t sb_phy_addr, - uint16_t sb_id, enum qed_sb_type type) + void *sb_virt_addr, dma_addr_t sb_phy_addr, uint16_t sb_id) { struct ecore_hwfn *p_hwfn; int hwfn_index; uint16_t rel_sb_id; - uint8_t n_hwfns; + uint8_t n_hwfns = edev->num_hwfns; uint32_t rc; - /* RoCE uses single engine and CMT uses two engines. When using both - * we force only a single engine. Storage uses only engine 0 too. - */ - if (type == QED_SB_TYPE_L2_QUEUE) - n_hwfns = edev->num_hwfns; - else - n_hwfns = 1; - hwfn_index = sb_id % n_hwfns; p_hwfn = &edev->hwfns[hwfn_index]; rel_sb_id = sb_id / n_hwfns; @@ -360,22 +494,29 @@ qed_sb_init(struct ecore_dev *edev, struct ecore_sb_info *sb_info, } static void qed_fill_link(struct ecore_hwfn *hwfn, + __rte_unused struct ecore_ptt *ptt, struct qed_link_output *if_link) { struct ecore_mcp_link_params params; struct ecore_mcp_link_state link; struct ecore_mcp_link_capabilities link_caps; - uint32_t media_type; uint8_t change = 0; memset(if_link, 0, sizeof(*if_link)); /* Prepare source inputs */ - rte_memcpy(¶ms, ecore_mcp_get_link_params(hwfn), + if (IS_PF(hwfn->p_dev)) { + rte_memcpy(¶ms, ecore_mcp_get_link_params(hwfn), sizeof(params)); - rte_memcpy(&link, ecore_mcp_get_link_state(hwfn), sizeof(link)); - rte_memcpy(&link_caps, ecore_mcp_get_link_capabilities(hwfn), + rte_memcpy(&link, ecore_mcp_get_link_state(hwfn), sizeof(link)); + rte_memcpy(&link_caps, ecore_mcp_get_link_capabilities(hwfn), sizeof(link_caps)); + } else { + ecore_vf_read_bulletin(hwfn, &change); + ecore_vf_get_link_params(hwfn, ¶ms); + ecore_vf_get_link_state(hwfn, &link); + ecore_vf_get_link_caps(hwfn, &link_caps); + } /* Set the link parameters to pass to protocol driver */ if (link.link_up) @@ -386,6 +527,9 @@ static void qed_fill_link(struct ecore_hwfn *hwfn, if_link->duplex = QEDE_DUPLEX_FULL; + /* Fill up the native advertised speed cap mask */ + if_link->adv_speed = params.speed.advertised_speeds; + if (params.speed.autoneg) if_link->supported_caps |= QEDE_SUPPORTED_AUTONEG; @@ -401,17 +545,42 @@ static void qed_fill_link(struct ecore_hwfn *hwfn, if (params.pause.forced_tx) if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; + + if (link_caps.default_eee == ECORE_MCP_EEE_UNSUPPORTED) { + if_link->eee_supported = false; + } else { + if_link->eee_supported = true; + if_link->eee_active = link.eee_active; + if_link->sup_caps = link_caps.eee_speed_caps; + /* MFW clears adv_caps on eee disable; use configured value */ + if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : + params.eee.adv_caps; + if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; + if_link->eee.enable = params.eee.enable; + if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; + if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; + } } static void qed_get_current_link(struct ecore_dev *edev, struct qed_link_output *if_link) { - qed_fill_link(&edev->hwfns[0], if_link); + struct ecore_hwfn *hwfn; + struct ecore_ptt *ptt; -#ifdef CONFIG_QED_SRIOV - for_each_hwfn(cdev, i) - qed_inform_vf_link_state(&cdev->hwfns[i]); -#endif + hwfn = &edev->hwfns[0]; + if (IS_PF(edev)) { + ptt = ecore_ptt_acquire(hwfn); + if (!ptt) + DP_NOTICE(hwfn, true, "Failed to fill link; No PTT\n"); + + qed_fill_link(hwfn, ptt, if_link); + + if (ptt) + ecore_ptt_release(hwfn, ptt); + } else { + qed_fill_link(hwfn, NULL, if_link); + } } static int qed_set_link(struct ecore_dev *edev, struct qed_link_params *params) @@ -421,6 +590,9 @@ static int qed_set_link(struct ecore_dev *edev, struct qed_link_params *params) struct ecore_mcp_link_params *link_params; int rc; + if (IS_VF(edev)) + return 0; + /* The link should be set only once per PF */ hwfn = &edev->hwfns[0]; @@ -447,6 +619,10 @@ static int qed_set_link(struct ecore_dev *edev, struct qed_link_params *params) link_params->pause.forced_tx = false; } + if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) + memcpy(&link_params->eee, ¶ms->eee, + sizeof(link_params->eee)); + rc = ecore_mcp_set_link(hwfn, ptt, params->link_up); ecore_ptt_release(hwfn, ptt); @@ -454,17 +630,31 @@ static int qed_set_link(struct ecore_dev *edev, struct qed_link_params *params) return rc; } +void qed_link_update(struct ecore_hwfn *hwfn) +{ + struct ecore_dev *edev = hwfn->p_dev; + struct qede_dev *qdev = (struct qede_dev *)edev; + struct rte_eth_dev *dev = (struct rte_eth_dev *)qdev->ethdev; + + if (!qede_link_update(dev, 0)) + _rte_eth_dev_callback_process(dev, + RTE_ETH_EVENT_INTR_LSC, NULL); +} + static int qed_drain(struct ecore_dev *edev) { struct ecore_hwfn *hwfn; struct ecore_ptt *ptt; int i, rc; + if (IS_VF(edev)) + return 0; + for_each_hwfn(edev, i) { hwfn = &edev->hwfns[i]; ptt = ecore_ptt_acquire(hwfn); if (!ptt) { - DP_NOTICE(hwfn, true, "Failed to drain NIG; No PTT\n"); + DP_ERR(hwfn, "Failed to drain NIG; No PTT\n"); return -EBUSY; } rc = ecore_mcp_drain(hwfn, ptt); @@ -490,19 +680,6 @@ static int qed_nic_stop(struct ecore_dev *edev) return rc; } -static int qed_nic_reset(struct ecore_dev *edev) -{ - int rc; - - rc = ecore_hw_reset(edev); - if (rc) - return rc; - - ecore_resc_free(edev); - - return 0; -} - static int qed_slowpath_stop(struct ecore_dev *edev) { #ifdef CONFIG_QED_SRIOV @@ -512,11 +689,21 @@ static int qed_slowpath_stop(struct ecore_dev *edev) if (!edev) return -ENODEV; - qed_free_stream_mem(edev); + if (IS_PF(edev)) { +#ifdef CONFIG_ECORE_ZIPPED_FW + qed_free_stream_mem(edev); +#endif + +#ifdef CONFIG_QED_SRIOV + if (IS_QED_ETH_IF(edev)) + qed_sriov_disable(edev, true); +#endif + } qed_nic_stop(edev); - qed_nic_reset(edev); + ecore_resc_free(edev); + qed_stop_iov_task(edev); return 0; } @@ -529,17 +716,71 @@ static void qed_remove(struct ecore_dev *edev) ecore_hw_remove(edev); } +static int qed_send_drv_state(struct ecore_dev *edev, bool active) +{ + struct ecore_hwfn *hwfn = ECORE_LEADING_HWFN(edev); + struct ecore_ptt *ptt; + int status = 0; + + ptt = ecore_ptt_acquire(hwfn); + if (!ptt) + return -EAGAIN; + + status = ecore_mcp_ov_update_driver_state(hwfn, ptt, active ? + ECORE_OV_DRIVER_STATE_ACTIVE : + ECORE_OV_DRIVER_STATE_DISABLED); + + ecore_ptt_release(hwfn, ptt); + + return status; +} + +static int qed_get_sb_info(struct ecore_dev *edev, struct ecore_sb_info *sb, + u16 qid, struct ecore_sb_info_dbg *sb_dbg) +{ + struct ecore_hwfn *hwfn = &edev->hwfns[qid % edev->num_hwfns]; + struct ecore_ptt *ptt; + int rc; + + if (IS_VF(edev)) + return -EINVAL; + + ptt = ecore_ptt_acquire(hwfn); + if (!ptt) { + DP_ERR(hwfn, "Can't acquire PTT\n"); + return -EAGAIN; + } + + memset(sb_dbg, 0, sizeof(*sb_dbg)); + rc = ecore_int_get_sb_dbg(hwfn, ptt, sb, sb_dbg); + + ecore_ptt_release(hwfn, ptt); + return rc; +} + const struct qed_common_ops qed_common_ops_pass = { INIT_STRUCT_FIELD(probe, &qed_probe), INIT_STRUCT_FIELD(update_pf_params, &qed_update_pf_params), INIT_STRUCT_FIELD(slowpath_start, &qed_slowpath_start), - INIT_STRUCT_FIELD(set_id, &qed_set_id), + INIT_STRUCT_FIELD(set_name, &qed_set_name), INIT_STRUCT_FIELD(chain_alloc, &ecore_chain_alloc), INIT_STRUCT_FIELD(chain_free, &ecore_chain_free), INIT_STRUCT_FIELD(sb_init, &qed_sb_init), + INIT_STRUCT_FIELD(get_sb_info, &qed_get_sb_info), INIT_STRUCT_FIELD(get_link, &qed_get_current_link), INIT_STRUCT_FIELD(set_link, &qed_set_link), INIT_STRUCT_FIELD(drain, &qed_drain), INIT_STRUCT_FIELD(slowpath_stop, &qed_slowpath_stop), INIT_STRUCT_FIELD(remove, &qed_remove), + INIT_STRUCT_FIELD(send_drv_state, &qed_send_drv_state), }; + +const struct qed_eth_ops qed_eth_ops_pass = { + INIT_STRUCT_FIELD(common, &qed_common_ops_pass), + INIT_STRUCT_FIELD(fill_dev_info, &qed_fill_eth_dev_info), +}; + +const struct qed_eth_ops *qed_get_eth_ops(void) +{ + return &qed_eth_ops_pass; +}