18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* QLogic qed NIC Driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/stddef.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 188c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 198c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 208c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 218c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 228c2ecf20Sopenharmony_ci#include <linux/crc32.h> 238c2ecf20Sopenharmony_ci#include <linux/qed/qed_if.h> 248c2ecf20Sopenharmony_ci#include <linux/qed/qed_ll2_if.h> 258c2ecf20Sopenharmony_ci#include <net/devlink.h> 268c2ecf20Sopenharmony_ci#include <linux/aer.h> 278c2ecf20Sopenharmony_ci#include <linux/phylink.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "qed.h" 308c2ecf20Sopenharmony_ci#include "qed_sriov.h" 318c2ecf20Sopenharmony_ci#include "qed_sp.h" 328c2ecf20Sopenharmony_ci#include "qed_dev_api.h" 338c2ecf20Sopenharmony_ci#include "qed_ll2.h" 348c2ecf20Sopenharmony_ci#include "qed_fcoe.h" 358c2ecf20Sopenharmony_ci#include "qed_iscsi.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "qed_mcp.h" 388c2ecf20Sopenharmony_ci#include "qed_reg_addr.h" 398c2ecf20Sopenharmony_ci#include "qed_hw.h" 408c2ecf20Sopenharmony_ci#include "qed_selftest.h" 418c2ecf20Sopenharmony_ci#include "qed_debug.h" 428c2ecf20Sopenharmony_ci#include "qed_devlink.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define QED_ROCE_QPS (8192) 458c2ecf20Sopenharmony_ci#define QED_ROCE_DPIS (8) 468c2ecf20Sopenharmony_ci#define QED_RDMA_SRQS QED_ROCE_QPS 478c2ecf20Sopenharmony_ci#define QED_NVM_CFG_GET_FLAGS 0xA 488c2ecf20Sopenharmony_ci#define QED_NVM_CFG_GET_PF_FLAGS 0x1A 498c2ecf20Sopenharmony_ci#define QED_NVM_CFG_MAX_ATTRS 50 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic char version[] = 528c2ecf20Sopenharmony_ci "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module"); 558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 568c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define FW_FILE_VERSION \ 598c2ecf20Sopenharmony_ci __stringify(FW_MAJOR_VERSION) "." \ 608c2ecf20Sopenharmony_ci __stringify(FW_MINOR_VERSION) "." \ 618c2ecf20Sopenharmony_ci __stringify(FW_REVISION_VERSION) "." \ 628c2ecf20Sopenharmony_ci __stringify(FW_ENGINEERING_VERSION) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define QED_FW_FILE_NAME \ 658c2ecf20Sopenharmony_ci "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QED_FW_FILE_NAME); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* MFW speed capabilities maps */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct qed_mfw_speed_map { 728c2ecf20Sopenharmony_ci u32 mfw_val; 738c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(caps); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci const u32 *cap_arr; 768c2ecf20Sopenharmony_ci u32 arr_size; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define QED_MFW_SPEED_MAP(type, arr) \ 808c2ecf20Sopenharmony_ci{ \ 818c2ecf20Sopenharmony_ci .mfw_val = (type), \ 828c2ecf20Sopenharmony_ci .cap_arr = (arr), \ 838c2ecf20Sopenharmony_ci .arr_size = ARRAY_SIZE(arr), \ 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_1g[] __initconst = { 878c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 888c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 898c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_10g[] __initconst = { 938c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 948c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 958c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 968c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 978c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 988c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 998c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 1008c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_20g[] __initconst = { 1048c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_25g[] __initconst = { 1088c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1098c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1108c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_40g[] __initconst = { 1148c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 1158c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1168c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1178c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_50g_base_r[] __initconst = { 1218c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 1228c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 1238c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 1248c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 1258c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_50g_base_r2[] __initconst = { 1298c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 1308c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 1318c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_100g_base_r2[] __initconst = { 1358c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 1368c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 1378c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 1388c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 1398c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic const u32 qed_mfw_ext_100g_base_r4[] __initconst = { 1438c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 1448c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 1458c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 1468c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic struct qed_mfw_speed_map qed_mfw_ext_maps[] __ro_after_init = { 1508c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_1G, qed_mfw_ext_1g), 1518c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_10G, qed_mfw_ext_10g), 1528c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_20G, qed_mfw_ext_20g), 1538c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_25G, qed_mfw_ext_25g), 1548c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_40G, qed_mfw_ext_40g), 1558c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R, 1568c2ecf20Sopenharmony_ci qed_mfw_ext_50g_base_r), 1578c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R2, 1588c2ecf20Sopenharmony_ci qed_mfw_ext_50g_base_r2), 1598c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R2, 1608c2ecf20Sopenharmony_ci qed_mfw_ext_100g_base_r2), 1618c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R4, 1628c2ecf20Sopenharmony_ci qed_mfw_ext_100g_base_r4), 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_1g[] __initconst = { 1668c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 1678c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 1688c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_10g[] __initconst = { 1728c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 1738c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 1748c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 1758c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 1768c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 1778c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 1788c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 1798c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_20g[] __initconst = { 1838c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_25g[] __initconst = { 1878c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1888c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1898c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_40g[] __initconst = { 1938c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 1948c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1958c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1968c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_50g[] __initconst = { 2008c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 2018c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 2028c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic const u32 qed_mfw_legacy_bb_100g[] __initconst = { 2068c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 2078c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 2088c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 2098c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic struct qed_mfw_speed_map qed_mfw_legacy_maps[] __ro_after_init = { 2138c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G, 2148c2ecf20Sopenharmony_ci qed_mfw_legacy_1g), 2158c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G, 2168c2ecf20Sopenharmony_ci qed_mfw_legacy_10g), 2178c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G, 2188c2ecf20Sopenharmony_ci qed_mfw_legacy_20g), 2198c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G, 2208c2ecf20Sopenharmony_ci qed_mfw_legacy_25g), 2218c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G, 2228c2ecf20Sopenharmony_ci qed_mfw_legacy_40g), 2238c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G, 2248c2ecf20Sopenharmony_ci qed_mfw_legacy_50g), 2258c2ecf20Sopenharmony_ci QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G, 2268c2ecf20Sopenharmony_ci qed_mfw_legacy_bb_100g), 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void __init qed_mfw_speed_map_populate(struct qed_mfw_speed_map *map) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci map->cap_arr = NULL; 2348c2ecf20Sopenharmony_ci map->arr_size = 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void __init qed_mfw_speed_maps_init(void) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u32 i; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) 2428c2ecf20Sopenharmony_ci qed_mfw_speed_map_populate(qed_mfw_ext_maps + i); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) 2458c2ecf20Sopenharmony_ci qed_mfw_speed_map_populate(qed_mfw_legacy_maps + i); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int __init qed_init(void) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci pr_info("%s", version); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci qed_mfw_speed_maps_init(); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_cimodule_init(qed_init); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void __exit qed_exit(void) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci /* To prevent marking this module as "permanent" */ 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_cimodule_exit(qed_exit); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* Check if the DMA controller on the machine can properly handle the DMA 2658c2ecf20Sopenharmony_ci * addressing required by the device. 2668c2ecf20Sopenharmony_ci*/ 2678c2ecf20Sopenharmony_cistatic int qed_set_coherency_mask(struct qed_dev *cdev) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct device *dev = &cdev->pdev->dev; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { 2728c2ecf20Sopenharmony_ci if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { 2738c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 2748c2ecf20Sopenharmony_ci "Can't request 64-bit consistent allocations\n"); 2758c2ecf20Sopenharmony_ci return -EIO; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { 2788c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); 2798c2ecf20Sopenharmony_ci return -EIO; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void qed_free_pci(struct qed_dev *cdev) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct pci_dev *pdev = cdev->pdev; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (cdev->doorbells && cdev->db_size) 2928c2ecf20Sopenharmony_ci iounmap(cdev->doorbells); 2938c2ecf20Sopenharmony_ci if (cdev->regview) 2948c2ecf20Sopenharmony_ci iounmap(cdev->regview); 2958c2ecf20Sopenharmony_ci if (atomic_read(&pdev->enable_cnt) == 1) 2968c2ecf20Sopenharmony_ci pci_release_regions(pdev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci pci_disable_device(pdev); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci#define PCI_REVISION_ID_ERROR_VAL 0xff 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* Performs PCI initializations as well as initializing PCI-related parameters 3048c2ecf20Sopenharmony_ci * in the device structrue. Returns 0 in case of success. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistatic int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci u8 rev_id; 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci cdev->pdev = pdev; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 3148c2ecf20Sopenharmony_ci if (rc) { 3158c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Cannot enable PCI device\n"); 3168c2ecf20Sopenharmony_ci goto err0; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 3208c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "No memory region found in bar #0\n"); 3218c2ecf20Sopenharmony_ci rc = -EIO; 3228c2ecf20Sopenharmony_ci goto err1; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 3268c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "No memory region found in bar #2\n"); 3278c2ecf20Sopenharmony_ci rc = -EIO; 3288c2ecf20Sopenharmony_ci goto err1; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (atomic_read(&pdev->enable_cnt) == 1) { 3328c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, "qed"); 3338c2ecf20Sopenharmony_ci if (rc) { 3348c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 3358c2ecf20Sopenharmony_ci "Failed to request PCI memory resources\n"); 3368c2ecf20Sopenharmony_ci goto err1; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci pci_set_master(pdev); 3398c2ecf20Sopenharmony_ci pci_save_state(pdev); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 3438c2ecf20Sopenharmony_ci if (rev_id == PCI_REVISION_ID_ERROR_VAL) { 3448c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 3458c2ecf20Sopenharmony_ci "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", 3468c2ecf20Sopenharmony_ci rev_id); 3478c2ecf20Sopenharmony_ci rc = -ENODEV; 3488c2ecf20Sopenharmony_ci goto err2; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if (!pci_is_pcie(pdev)) { 3518c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "The bus is not PCI Express\n"); 3528c2ecf20Sopenharmony_ci rc = -EIO; 3538c2ecf20Sopenharmony_ci goto err2; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); 3578c2ecf20Sopenharmony_ci if (IS_PF(cdev) && !cdev->pci_params.pm_cap) 3588c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Cannot find power management capability\n"); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci rc = qed_set_coherency_mask(cdev); 3618c2ecf20Sopenharmony_ci if (rc) 3628c2ecf20Sopenharmony_ci goto err2; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci cdev->pci_params.mem_start = pci_resource_start(pdev, 0); 3658c2ecf20Sopenharmony_ci cdev->pci_params.mem_end = pci_resource_end(pdev, 0); 3668c2ecf20Sopenharmony_ci cdev->pci_params.irq = pdev->irq; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci cdev->regview = pci_ioremap_bar(pdev, 0); 3698c2ecf20Sopenharmony_ci if (!cdev->regview) { 3708c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Cannot map register space, aborting\n"); 3718c2ecf20Sopenharmony_ci rc = -ENOMEM; 3728c2ecf20Sopenharmony_ci goto err2; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); 3768c2ecf20Sopenharmony_ci cdev->db_size = pci_resource_len(cdev->pdev, 2); 3778c2ecf20Sopenharmony_ci if (!cdev->db_size) { 3788c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 3798c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "No Doorbell bar available\n"); 3808c2ecf20Sopenharmony_ci return -EINVAL; 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (!cdev->doorbells) { 3898c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Cannot map doorbell space\n"); 3908c2ecf20Sopenharmony_ci return -ENOMEM; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* AER (Advanced Error reporting) configuration */ 3948c2ecf20Sopenharmony_ci rc = pci_enable_pcie_error_reporting(pdev); 3958c2ecf20Sopenharmony_ci if (rc) 3968c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 3978c2ecf20Sopenharmony_ci "Failed to configure PCIe AER [%d]\n", rc); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cierr2: 4028c2ecf20Sopenharmony_ci pci_release_regions(pdev); 4038c2ecf20Sopenharmony_cierr1: 4048c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4058c2ecf20Sopenharmony_cierr0: 4068c2ecf20Sopenharmony_ci return rc; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciint qed_fill_dev_info(struct qed_dev *cdev, 4108c2ecf20Sopenharmony_ci struct qed_dev_info *dev_info) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 4138c2ecf20Sopenharmony_ci struct qed_hw_info *hw_info = &p_hwfn->hw_info; 4148c2ecf20Sopenharmony_ci struct qed_tunnel_info *tun = &cdev->tunnel; 4158c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci memset(dev_info, 0, sizeof(struct qed_dev_info)); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 4208c2ecf20Sopenharmony_ci tun->vxlan.b_mode_enabled) 4218c2ecf20Sopenharmony_ci dev_info->vxlan_enable = true; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && 4248c2ecf20Sopenharmony_ci tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 4258c2ecf20Sopenharmony_ci tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 4268c2ecf20Sopenharmony_ci dev_info->gre_enable = true; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && 4298c2ecf20Sopenharmony_ci tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 4308c2ecf20Sopenharmony_ci tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 4318c2ecf20Sopenharmony_ci dev_info->geneve_enable = true; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci dev_info->num_hwfns = cdev->num_hwfns; 4348c2ecf20Sopenharmony_ci dev_info->pci_mem_start = cdev->pci_params.mem_start; 4358c2ecf20Sopenharmony_ci dev_info->pci_mem_end = cdev->pci_params.mem_end; 4368c2ecf20Sopenharmony_ci dev_info->pci_irq = cdev->pci_params.irq; 4378c2ecf20Sopenharmony_ci dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn); 4388c2ecf20Sopenharmony_ci dev_info->dev_type = cdev->type; 4398c2ecf20Sopenharmony_ci ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 4428c2ecf20Sopenharmony_ci dev_info->fw_major = FW_MAJOR_VERSION; 4438c2ecf20Sopenharmony_ci dev_info->fw_minor = FW_MINOR_VERSION; 4448c2ecf20Sopenharmony_ci dev_info->fw_rev = FW_REVISION_VERSION; 4458c2ecf20Sopenharmony_ci dev_info->fw_eng = FW_ENGINEERING_VERSION; 4468c2ecf20Sopenharmony_ci dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH, 4478c2ecf20Sopenharmony_ci &cdev->mf_bits); 4488c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits)) 4498c2ecf20Sopenharmony_ci dev_info->b_arfs_capable = true; 4508c2ecf20Sopenharmony_ci dev_info->tx_switching = true; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME) 4538c2ecf20Sopenharmony_ci dev_info->wol_support = true; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; 4588c2ecf20Sopenharmony_ci } else { 4598c2ecf20Sopenharmony_ci qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, 4608c2ecf20Sopenharmony_ci &dev_info->fw_minor, &dev_info->fw_rev, 4618c2ecf20Sopenharmony_ci &dev_info->fw_eng); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 4658c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 4668c2ecf20Sopenharmony_ci if (ptt) { 4678c2ecf20Sopenharmony_ci qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, 4688c2ecf20Sopenharmony_ci &dev_info->mfw_rev, NULL); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, 4718c2ecf20Sopenharmony_ci &dev_info->mbi_version); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, 4748c2ecf20Sopenharmony_ci &dev_info->flash_size); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci } else { 4798c2ecf20Sopenharmony_ci qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, 4808c2ecf20Sopenharmony_ci &dev_info->mfw_rev, NULL); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci dev_info->mtu = hw_info->mtu; 4848c2ecf20Sopenharmony_ci cdev->common_dev_info = *dev_info; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic void qed_free_cdev(struct qed_dev *cdev) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci kfree((void *)cdev); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct qed_dev *cdev; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 4998c2ecf20Sopenharmony_ci if (!cdev) 5008c2ecf20Sopenharmony_ci return cdev; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci qed_init_struct(cdev); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return cdev; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* Sets the requested power state */ 5088c2ecf20Sopenharmony_cistatic int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci if (!cdev) 5118c2ecf20Sopenharmony_ci return -ENODEV; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* probing */ 5188c2ecf20Sopenharmony_cistatic struct qed_dev *qed_probe(struct pci_dev *pdev, 5198c2ecf20Sopenharmony_ci struct qed_probe_params *params) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct qed_dev *cdev; 5228c2ecf20Sopenharmony_ci int rc; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci cdev = qed_alloc_cdev(pdev); 5258c2ecf20Sopenharmony_ci if (!cdev) 5268c2ecf20Sopenharmony_ci goto err0; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; 5298c2ecf20Sopenharmony_ci cdev->protocol = params->protocol; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (params->is_vf) 5328c2ecf20Sopenharmony_ci cdev->b_is_vf = true; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci qed_init_dp(cdev, params->dp_module, params->dp_level); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci cdev->recov_in_prog = params->recov_in_prog; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci rc = qed_init_pci(cdev, pdev); 5398c2ecf20Sopenharmony_ci if (rc) { 5408c2ecf20Sopenharmony_ci DP_ERR(cdev, "init pci failed\n"); 5418c2ecf20Sopenharmony_ci goto err1; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci DP_INFO(cdev, "PCI init completed successfully\n"); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); 5468c2ecf20Sopenharmony_ci if (rc) { 5478c2ecf20Sopenharmony_ci DP_ERR(cdev, "hw prepare failed\n"); 5488c2ecf20Sopenharmony_ci goto err2; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci DP_INFO(cdev, "qed_probe completed successfully\n"); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return cdev; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cierr2: 5568c2ecf20Sopenharmony_ci qed_free_pci(cdev); 5578c2ecf20Sopenharmony_cierr1: 5588c2ecf20Sopenharmony_ci qed_free_cdev(cdev); 5598c2ecf20Sopenharmony_cierr0: 5608c2ecf20Sopenharmony_ci return NULL; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic void qed_remove(struct qed_dev *cdev) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci if (!cdev) 5668c2ecf20Sopenharmony_ci return; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci qed_hw_remove(cdev); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci qed_free_pci(cdev); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci qed_set_power_state(cdev, PCI_D3hot); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci qed_free_cdev(cdev); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic void qed_disable_msix(struct qed_dev *cdev) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 5808c2ecf20Sopenharmony_ci pci_disable_msix(cdev->pdev); 5818c2ecf20Sopenharmony_ci kfree(cdev->int_params.msix_table); 5828c2ecf20Sopenharmony_ci } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { 5838c2ecf20Sopenharmony_ci pci_disable_msi(cdev->pdev); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int qed_enable_msix(struct qed_dev *cdev, 5908c2ecf20Sopenharmony_ci struct qed_int_params *int_params) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci int i, rc, cnt; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci cnt = int_params->in.num_vectors; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) 5978c2ecf20Sopenharmony_ci int_params->msix_table[i].entry = i; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, 6008c2ecf20Sopenharmony_ci int_params->in.min_msix_cnt, cnt); 6018c2ecf20Sopenharmony_ci if (rc < cnt && rc >= int_params->in.min_msix_cnt && 6028c2ecf20Sopenharmony_ci (rc % cdev->num_hwfns)) { 6038c2ecf20Sopenharmony_ci pci_disable_msix(cdev->pdev); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* If fastpath is initialized, we need at least one interrupt 6068c2ecf20Sopenharmony_ci * per hwfn [and the slow path interrupts]. New requested number 6078c2ecf20Sopenharmony_ci * should be a multiple of the number of hwfns. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; 6108c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 6118c2ecf20Sopenharmony_ci "Trying to enable MSI-X with less vectors (%d out of %d)\n", 6128c2ecf20Sopenharmony_ci cnt, int_params->in.num_vectors); 6138c2ecf20Sopenharmony_ci rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, 6148c2ecf20Sopenharmony_ci cnt); 6158c2ecf20Sopenharmony_ci if (!rc) 6168c2ecf20Sopenharmony_ci rc = cnt; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* For VFs, we should return with an error in case we didn't get the 6208c2ecf20Sopenharmony_ci * exact number of msix vectors as we requested. 6218c2ecf20Sopenharmony_ci * Not doing that will lead to a crash when starting queues for 6228c2ecf20Sopenharmony_ci * this VF. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_ci if ((IS_PF(cdev) && rc > 0) || (IS_VF(cdev) && rc == cnt)) { 6258c2ecf20Sopenharmony_ci /* MSI-x configuration was achieved */ 6268c2ecf20Sopenharmony_ci int_params->out.int_mode = QED_INT_MODE_MSIX; 6278c2ecf20Sopenharmony_ci int_params->out.num_vectors = rc; 6288c2ecf20Sopenharmony_ci rc = 0; 6298c2ecf20Sopenharmony_ci } else { 6308c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 6318c2ecf20Sopenharmony_ci "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", 6328c2ecf20Sopenharmony_ci cnt, rc); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return rc; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci/* This function outputs the int mode and the number of enabled msix vector */ 6398c2ecf20Sopenharmony_cistatic int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct qed_int_params *int_params = &cdev->int_params; 6428c2ecf20Sopenharmony_ci struct msix_entry *tbl; 6438c2ecf20Sopenharmony_ci int rc = 0, cnt; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci switch (int_params->in.int_mode) { 6468c2ecf20Sopenharmony_ci case QED_INT_MODE_MSIX: 6478c2ecf20Sopenharmony_ci /* Allocate MSIX table */ 6488c2ecf20Sopenharmony_ci cnt = int_params->in.num_vectors; 6498c2ecf20Sopenharmony_ci int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); 6508c2ecf20Sopenharmony_ci if (!int_params->msix_table) { 6518c2ecf20Sopenharmony_ci rc = -ENOMEM; 6528c2ecf20Sopenharmony_ci goto out; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* Enable MSIX */ 6568c2ecf20Sopenharmony_ci rc = qed_enable_msix(cdev, int_params); 6578c2ecf20Sopenharmony_ci if (!rc) 6588c2ecf20Sopenharmony_ci goto out; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to enable MSI-X\n"); 6618c2ecf20Sopenharmony_ci kfree(int_params->msix_table); 6628c2ecf20Sopenharmony_ci if (force_mode) 6638c2ecf20Sopenharmony_ci goto out; 6648c2ecf20Sopenharmony_ci fallthrough; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci case QED_INT_MODE_MSI: 6678c2ecf20Sopenharmony_ci if (cdev->num_hwfns == 1) { 6688c2ecf20Sopenharmony_ci rc = pci_enable_msi(cdev->pdev); 6698c2ecf20Sopenharmony_ci if (!rc) { 6708c2ecf20Sopenharmony_ci int_params->out.int_mode = QED_INT_MODE_MSI; 6718c2ecf20Sopenharmony_ci goto out; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to enable MSI\n"); 6758c2ecf20Sopenharmony_ci if (force_mode) 6768c2ecf20Sopenharmony_ci goto out; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci fallthrough; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci case QED_INT_MODE_INTA: 6818c2ecf20Sopenharmony_ci int_params->out.int_mode = QED_INT_MODE_INTA; 6828c2ecf20Sopenharmony_ci rc = 0; 6838c2ecf20Sopenharmony_ci goto out; 6848c2ecf20Sopenharmony_ci default: 6858c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Unknown int_mode value %d\n", 6868c2ecf20Sopenharmony_ci int_params->in.int_mode); 6878c2ecf20Sopenharmony_ci rc = -EINVAL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ciout: 6918c2ecf20Sopenharmony_ci if (!rc) 6928c2ecf20Sopenharmony_ci DP_INFO(cdev, "Using %s interrupts\n", 6938c2ecf20Sopenharmony_ci int_params->out.int_mode == QED_INT_MODE_INTA ? 6948c2ecf20Sopenharmony_ci "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? 6958c2ecf20Sopenharmony_ci "MSI" : "MSIX"); 6968c2ecf20Sopenharmony_ci cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return rc; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic void qed_simd_handler_config(struct qed_dev *cdev, void *token, 7028c2ecf20Sopenharmony_ci int index, void(*handler)(void *)) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 7058c2ecf20Sopenharmony_ci int relative_idx = index / cdev->num_hwfns; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci hwfn->simd_proto_handler[relative_idx].func = handler; 7088c2ecf20Sopenharmony_ci hwfn->simd_proto_handler[relative_idx].token = token; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic void qed_simd_handler_clean(struct qed_dev *cdev, int index) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 7148c2ecf20Sopenharmony_ci int relative_idx = index / cdev->num_hwfns; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci memset(&hwfn->simd_proto_handler[relative_idx], 0, 7178c2ecf20Sopenharmony_ci sizeof(struct qed_simd_fp_handler)); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic irqreturn_t qed_msix_sp_int(int irq, void *tasklet) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci tasklet_schedule((struct tasklet_struct *)tasklet); 7238c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic irqreturn_t qed_single_int(int irq, void *dev_instance) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct qed_dev *cdev = (struct qed_dev *)dev_instance; 7298c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 7308c2ecf20Sopenharmony_ci irqreturn_t rc = IRQ_NONE; 7318c2ecf20Sopenharmony_ci u64 status; 7328c2ecf20Sopenharmony_ci int i, j; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci for (i = 0; i < cdev->num_hwfns; i++) { 7358c2ecf20Sopenharmony_ci status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (!status) 7388c2ecf20Sopenharmony_ci continue; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci hwfn = &cdev->hwfns[i]; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Slowpath interrupt */ 7438c2ecf20Sopenharmony_ci if (unlikely(status & 0x1)) { 7448c2ecf20Sopenharmony_ci tasklet_schedule(&hwfn->sp_dpc); 7458c2ecf20Sopenharmony_ci status &= ~0x1; 7468c2ecf20Sopenharmony_ci rc = IRQ_HANDLED; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Fastpath interrupts */ 7508c2ecf20Sopenharmony_ci for (j = 0; j < 64; j++) { 7518c2ecf20Sopenharmony_ci if ((0x2ULL << j) & status) { 7528c2ecf20Sopenharmony_ci struct qed_simd_fp_handler *p_handler = 7538c2ecf20Sopenharmony_ci &hwfn->simd_proto_handler[j]; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (p_handler->func) 7568c2ecf20Sopenharmony_ci p_handler->func(p_handler->token); 7578c2ecf20Sopenharmony_ci else 7588c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, 7598c2ecf20Sopenharmony_ci "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n", 7608c2ecf20Sopenharmony_ci j, status); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci status &= ~(0x2ULL << j); 7638c2ecf20Sopenharmony_ci rc = IRQ_HANDLED; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (unlikely(status)) 7688c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, NETIF_MSG_INTR, 7698c2ecf20Sopenharmony_ci "got an unknown interrupt status 0x%llx\n", 7708c2ecf20Sopenharmony_ci status); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return rc; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ciint qed_slowpath_irq_req(struct qed_hwfn *hwfn) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct qed_dev *cdev = hwfn->cdev; 7798c2ecf20Sopenharmony_ci u32 int_mode; 7808c2ecf20Sopenharmony_ci int rc = 0; 7818c2ecf20Sopenharmony_ci u8 id; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci int_mode = cdev->int_params.out.int_mode; 7848c2ecf20Sopenharmony_ci if (int_mode == QED_INT_MODE_MSIX) { 7858c2ecf20Sopenharmony_ci id = hwfn->my_id; 7868c2ecf20Sopenharmony_ci snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", 7878c2ecf20Sopenharmony_ci id, cdev->pdev->bus->number, 7888c2ecf20Sopenharmony_ci PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 7898c2ecf20Sopenharmony_ci rc = request_irq(cdev->int_params.msix_table[id].vector, 7908c2ecf20Sopenharmony_ci qed_msix_sp_int, 0, hwfn->name, &hwfn->sp_dpc); 7918c2ecf20Sopenharmony_ci } else { 7928c2ecf20Sopenharmony_ci unsigned long flags = 0; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", 7958c2ecf20Sopenharmony_ci cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), 7968c2ecf20Sopenharmony_ci PCI_FUNC(cdev->pdev->devfn)); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) 7998c2ecf20Sopenharmony_ci flags |= IRQF_SHARED; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci rc = request_irq(cdev->pdev->irq, qed_single_int, 8028c2ecf20Sopenharmony_ci flags, cdev->name, cdev); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (rc) 8068c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); 8078c2ecf20Sopenharmony_ci else 8088c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), 8098c2ecf20Sopenharmony_ci "Requested slowpath %s\n", 8108c2ecf20Sopenharmony_ci (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return rc; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci /* Calling the disable function will make sure that any 8188c2ecf20Sopenharmony_ci * currently-running function is completed. The following call to the 8198c2ecf20Sopenharmony_ci * enable function makes this sequence a flush-like operation. 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci if (p_hwfn->b_sp_dpc_enabled) { 8228c2ecf20Sopenharmony_ci tasklet_disable(&p_hwfn->sp_dpc); 8238c2ecf20Sopenharmony_ci tasklet_enable(&p_hwfn->sp_dpc); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_civoid qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 8308c2ecf20Sopenharmony_ci u8 id = p_hwfn->my_id; 8318c2ecf20Sopenharmony_ci u32 int_mode; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci int_mode = cdev->int_params.out.int_mode; 8348c2ecf20Sopenharmony_ci if (int_mode == QED_INT_MODE_MSIX) 8358c2ecf20Sopenharmony_ci synchronize_irq(cdev->int_params.msix_table[id].vector); 8368c2ecf20Sopenharmony_ci else 8378c2ecf20Sopenharmony_ci synchronize_irq(cdev->pdev->irq); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci qed_slowpath_tasklet_flush(p_hwfn); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic void qed_slowpath_irq_free(struct qed_dev *cdev) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci int i; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 8478c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 8488c2ecf20Sopenharmony_ci if (!cdev->hwfns[i].b_int_requested) 8498c2ecf20Sopenharmony_ci break; 8508c2ecf20Sopenharmony_ci synchronize_irq(cdev->int_params.msix_table[i].vector); 8518c2ecf20Sopenharmony_ci free_irq(cdev->int_params.msix_table[i].vector, 8528c2ecf20Sopenharmony_ci &cdev->hwfns[i].sp_dpc); 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci } else { 8558c2ecf20Sopenharmony_ci if (QED_LEADING_HWFN(cdev)->b_int_requested) 8568c2ecf20Sopenharmony_ci free_irq(cdev->pdev->irq, cdev); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci qed_int_disable_post_isr_release(cdev); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic int qed_nic_stop(struct qed_dev *cdev) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci int i, rc; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci rc = qed_hw_stop(cdev); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci for (i = 0; i < cdev->num_hwfns; i++) { 8688c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (p_hwfn->b_sp_dpc_enabled) { 8718c2ecf20Sopenharmony_ci tasklet_disable(&p_hwfn->sp_dpc); 8728c2ecf20Sopenharmony_ci p_hwfn->b_sp_dpc_enabled = false; 8738c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, 8748c2ecf20Sopenharmony_ci "Disabled sp tasklet [hwfn %d] at %p\n", 8758c2ecf20Sopenharmony_ci i, &p_hwfn->sp_dpc); 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci qed_dbg_pf_exit(cdev); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return rc; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int qed_nic_setup(struct qed_dev *cdev) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci int rc, i; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Determine if interface is going to require LL2 */ 8898c2ecf20Sopenharmony_ci if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) { 8908c2ecf20Sopenharmony_ci for (i = 0; i < cdev->num_hwfns; i++) { 8918c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci p_hwfn->using_ll2 = true; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci rc = qed_resc_alloc(cdev); 8988c2ecf20Sopenharmony_ci if (rc) 8998c2ecf20Sopenharmony_ci return rc; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci DP_INFO(cdev, "Allocated qed resources\n"); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci qed_resc_setup(cdev); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return rc; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci int limit = 0; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Mark the fastpath as free/used */ 9138c2ecf20Sopenharmony_ci cdev->int_params.fp_initialized = cnt ? true : false; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) 9168c2ecf20Sopenharmony_ci limit = cdev->num_hwfns * 63; 9178c2ecf20Sopenharmony_ci else if (cdev->int_params.fp_msix_cnt) 9188c2ecf20Sopenharmony_ci limit = cdev->int_params.fp_msix_cnt; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (!limit) 9218c2ecf20Sopenharmony_ci return -ENOMEM; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return min_t(int, cnt, limit); 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci memset(info, 0, sizeof(struct qed_int_info)); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (!cdev->int_params.fp_initialized) { 9318c2ecf20Sopenharmony_ci DP_INFO(cdev, 9328c2ecf20Sopenharmony_ci "Protocol driver requested interrupt information, but its support is not yet configured\n"); 9338c2ecf20Sopenharmony_ci return -EINVAL; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* Need to expose only MSI-X information; Single IRQ is handled solely 9378c2ecf20Sopenharmony_ci * by qed. 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_ci if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 9408c2ecf20Sopenharmony_ci int msix_base = cdev->int_params.fp_msix_base; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci info->msix_cnt = cdev->int_params.fp_msix_cnt; 9438c2ecf20Sopenharmony_ci info->msix = &cdev->int_params.msix_table[msix_base]; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int qed_slowpath_setup_int(struct qed_dev *cdev, 9508c2ecf20Sopenharmony_ci enum qed_int_mode int_mode) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct qed_sb_cnt_info sb_cnt_info; 9538c2ecf20Sopenharmony_ci int num_l2_queues = 0; 9548c2ecf20Sopenharmony_ci int rc; 9558c2ecf20Sopenharmony_ci int i; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { 9588c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 9638c2ecf20Sopenharmony_ci cdev->int_params.in.int_mode = int_mode; 9648c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 9658c2ecf20Sopenharmony_ci memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); 9668c2ecf20Sopenharmony_ci qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); 9678c2ecf20Sopenharmony_ci cdev->int_params.in.num_vectors += sb_cnt_info.cnt; 9688c2ecf20Sopenharmony_ci cdev->int_params.in.num_vectors++; /* slowpath */ 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci /* We want a minimum of one slowpath and one fastpath vector per hwfn */ 9728c2ecf20Sopenharmony_ci cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (is_kdump_kernel()) { 9758c2ecf20Sopenharmony_ci DP_INFO(cdev, 9768c2ecf20Sopenharmony_ci "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", 9778c2ecf20Sopenharmony_ci cdev->int_params.in.min_msix_cnt); 9788c2ecf20Sopenharmony_ci cdev->int_params.in.num_vectors = 9798c2ecf20Sopenharmony_ci cdev->int_params.in.min_msix_cnt; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci rc = qed_set_int_mode(cdev, false); 9838c2ecf20Sopenharmony_ci if (rc) { 9848c2ecf20Sopenharmony_ci DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); 9858c2ecf20Sopenharmony_ci return rc; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_base = cdev->num_hwfns; 9898c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - 9908c2ecf20Sopenharmony_ci cdev->num_hwfns; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_QED_RDMA) || 9938c2ecf20Sopenharmony_ci !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 9978c2ecf20Sopenharmony_ci num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_RDMA, 10008c2ecf20Sopenharmony_ci "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n", 10018c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_cnt, num_l2_queues); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (cdev->int_params.fp_msix_cnt > num_l2_queues) { 10048c2ecf20Sopenharmony_ci cdev->int_params.rdma_msix_cnt = 10058c2ecf20Sopenharmony_ci (cdev->int_params.fp_msix_cnt - num_l2_queues) 10068c2ecf20Sopenharmony_ci / cdev->num_hwfns; 10078c2ecf20Sopenharmony_ci cdev->int_params.rdma_msix_base = 10088c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_base + num_l2_queues; 10098c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_cnt = num_l2_queues; 10108c2ecf20Sopenharmony_ci } else { 10118c2ecf20Sopenharmony_ci cdev->int_params.rdma_msix_cnt = 0; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", 10158c2ecf20Sopenharmony_ci cdev->int_params.rdma_msix_cnt, 10168c2ecf20Sopenharmony_ci cdev->int_params.rdma_msix_base); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return 0; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic int qed_slowpath_vf_setup_int(struct qed_dev *cdev) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci int rc; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 10268c2ecf20Sopenharmony_ci cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), 10298c2ecf20Sopenharmony_ci &cdev->int_params.in.num_vectors); 10308c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1) { 10318c2ecf20Sopenharmony_ci u8 vectors = 0; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); 10348c2ecf20Sopenharmony_ci cdev->int_params.in.num_vectors += vectors; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* We want a minimum of one fastpath vector per vf hwfn */ 10388c2ecf20Sopenharmony_ci cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci rc = qed_set_int_mode(cdev, true); 10418c2ecf20Sopenharmony_ci if (rc) 10428c2ecf20Sopenharmony_ci return rc; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_base = 0; 10458c2ecf20Sopenharmony_ci cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ciu32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, 10518c2ecf20Sopenharmony_ci u8 *input_buf, u32 max_size, u8 *unzip_buf) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci int rc; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci p_hwfn->stream->next_in = input_buf; 10568c2ecf20Sopenharmony_ci p_hwfn->stream->avail_in = input_len; 10578c2ecf20Sopenharmony_ci p_hwfn->stream->next_out = unzip_buf; 10588c2ecf20Sopenharmony_ci p_hwfn->stream->avail_out = max_size; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (rc != Z_OK) { 10638c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", 10648c2ecf20Sopenharmony_ci rc); 10658c2ecf20Sopenharmony_ci return 0; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci rc = zlib_inflate(p_hwfn->stream, Z_FINISH); 10698c2ecf20Sopenharmony_ci zlib_inflateEnd(p_hwfn->stream); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (rc != Z_OK && rc != Z_STREAM_END) { 10728c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", 10738c2ecf20Sopenharmony_ci p_hwfn->stream->msg, rc); 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return p_hwfn->stream->total_out / 4; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic int qed_alloc_stream_mem(struct qed_dev *cdev) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci int i; 10838c2ecf20Sopenharmony_ci void *workspace; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 10868c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); 10898c2ecf20Sopenharmony_ci if (!p_hwfn->stream) 10908c2ecf20Sopenharmony_ci return -ENOMEM; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci workspace = vzalloc(zlib_inflate_workspacesize()); 10938c2ecf20Sopenharmony_ci if (!workspace) 10948c2ecf20Sopenharmony_ci return -ENOMEM; 10958c2ecf20Sopenharmony_ci p_hwfn->stream->workspace = workspace; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return 0; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic void qed_free_stream_mem(struct qed_dev *cdev) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci int i; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 11068c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (!p_hwfn->stream) 11098c2ecf20Sopenharmony_ci return; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci vfree(p_hwfn->stream->workspace); 11128c2ecf20Sopenharmony_ci kfree(p_hwfn->stream); 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic void qed_update_pf_params(struct qed_dev *cdev, 11178c2ecf20Sopenharmony_ci struct qed_pf_params *params) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci int i; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_RDMA)) { 11228c2ecf20Sopenharmony_ci params->rdma_pf_params.num_qps = QED_ROCE_QPS; 11238c2ecf20Sopenharmony_ci params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; 11248c2ecf20Sopenharmony_ci params->rdma_pf_params.num_srqs = QED_RDMA_SRQS; 11258c2ecf20Sopenharmony_ci /* divide by 3 the MRs to avoid MF ILT overflow */ 11268c2ecf20Sopenharmony_ci params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1 || IS_VF(cdev)) 11308c2ecf20Sopenharmony_ci params->eth_pf_params.num_arfs_filters = 0; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* In case we might support RDMA, don't allow qede to be greedy 11338c2ecf20Sopenharmony_ci * with the L2 contexts. Allow for 64 queues [rx, tx cos, xdp] 11348c2ecf20Sopenharmony_ci * per hwfn. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_ci if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) { 11378c2ecf20Sopenharmony_ci u16 *num_cons; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci num_cons = ¶ms->eth_pf_params.num_cons; 11408c2ecf20Sopenharmony_ci *num_cons = min_t(u16, *num_cons, QED_MAX_L2_CONS); 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci for (i = 0; i < cdev->num_hwfns; i++) { 11448c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci p_hwfn->pf_params = *params; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci#define QED_PERIODIC_DB_REC_COUNT 10 11518c2ecf20Sopenharmony_ci#define QED_PERIODIC_DB_REC_INTERVAL_MS 100 11528c2ecf20Sopenharmony_ci#define QED_PERIODIC_DB_REC_INTERVAL \ 11538c2ecf20Sopenharmony_ci msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS) 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic int qed_slowpath_delayed_work(struct qed_hwfn *hwfn, 11568c2ecf20Sopenharmony_ci enum qed_slowpath_wq_flag wq_flag, 11578c2ecf20Sopenharmony_ci unsigned long delay) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci if (!hwfn->slowpath_wq_active) 11608c2ecf20Sopenharmony_ci return -EINVAL; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* Memory barrier for setting atomic bit */ 11638c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 11648c2ecf20Sopenharmony_ci set_bit(wq_flag, &hwfn->slowpath_task_flags); 11658c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 11668c2ecf20Sopenharmony_ci queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci return 0; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_civoid qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci /* Reset periodic Doorbell Recovery counter */ 11748c2ecf20Sopenharmony_ci p_hwfn->periodic_db_rec_count = QED_PERIODIC_DB_REC_COUNT; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* Don't schedule periodic Doorbell Recovery if already scheduled */ 11778c2ecf20Sopenharmony_ci if (test_bit(QED_SLOWPATH_PERIODIC_DB_REC, 11788c2ecf20Sopenharmony_ci &p_hwfn->slowpath_task_flags)) 11798c2ecf20Sopenharmony_ci return; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci qed_slowpath_delayed_work(p_hwfn, QED_SLOWPATH_PERIODIC_DB_REC, 11828c2ecf20Sopenharmony_ci QED_PERIODIC_DB_REC_INTERVAL); 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic void qed_slowpath_wq_stop(struct qed_dev *cdev) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci int i; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 11908c2ecf20Sopenharmony_ci return; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 11938c2ecf20Sopenharmony_ci if (!cdev->hwfns[i].slowpath_wq) 11948c2ecf20Sopenharmony_ci continue; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Stop queuing new delayed works */ 11978c2ecf20Sopenharmony_ci cdev->hwfns[i].slowpath_wq_active = false; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci cancel_delayed_work(&cdev->hwfns[i].slowpath_task); 12008c2ecf20Sopenharmony_ci destroy_workqueue(cdev->hwfns[i].slowpath_wq); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic void qed_slowpath_task(struct work_struct *work) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 12078c2ecf20Sopenharmony_ci slowpath_task.work); 12088c2ecf20Sopenharmony_ci struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!ptt) { 12118c2ecf20Sopenharmony_ci if (hwfn->slowpath_wq_active) 12128c2ecf20Sopenharmony_ci queue_delayed_work(hwfn->slowpath_wq, 12138c2ecf20Sopenharmony_ci &hwfn->slowpath_task, 0); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci return; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ, 12198c2ecf20Sopenharmony_ci &hwfn->slowpath_task_flags)) 12208c2ecf20Sopenharmony_ci qed_mfw_process_tlv_req(hwfn, ptt); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC, 12238c2ecf20Sopenharmony_ci &hwfn->slowpath_task_flags)) { 12248c2ecf20Sopenharmony_ci qed_db_rec_handler(hwfn, ptt); 12258c2ecf20Sopenharmony_ci if (hwfn->periodic_db_rec_count--) 12268c2ecf20Sopenharmony_ci qed_slowpath_delayed_work(hwfn, 12278c2ecf20Sopenharmony_ci QED_SLOWPATH_PERIODIC_DB_REC, 12288c2ecf20Sopenharmony_ci QED_PERIODIC_DB_REC_INTERVAL); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic int qed_slowpath_wq_start(struct qed_dev *cdev) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 12378c2ecf20Sopenharmony_ci char name[NAME_SIZE]; 12388c2ecf20Sopenharmony_ci int i; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 12448c2ecf20Sopenharmony_ci hwfn = &cdev->hwfns[i]; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", 12478c2ecf20Sopenharmony_ci cdev->pdev->bus->number, 12488c2ecf20Sopenharmony_ci PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); 12518c2ecf20Sopenharmony_ci if (!hwfn->slowpath_wq) { 12528c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); 12538c2ecf20Sopenharmony_ci return -ENOMEM; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task); 12578c2ecf20Sopenharmony_ci hwfn->slowpath_wq_active = true; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci return 0; 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic int qed_slowpath_start(struct qed_dev *cdev, 12648c2ecf20Sopenharmony_ci struct qed_slowpath_params *params) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci struct qed_drv_load_params drv_load_params; 12678c2ecf20Sopenharmony_ci struct qed_hw_init_params hw_init_params; 12688c2ecf20Sopenharmony_ci struct qed_mcp_drv_version drv_version; 12698c2ecf20Sopenharmony_ci struct qed_tunnel_info tunn_info; 12708c2ecf20Sopenharmony_ci const u8 *data = NULL; 12718c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 12728c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 12738c2ecf20Sopenharmony_ci int rc = -EINVAL; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (qed_iov_wq_start(cdev)) 12768c2ecf20Sopenharmony_ci goto err; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (qed_slowpath_wq_start(cdev)) 12798c2ecf20Sopenharmony_ci goto err; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 12828c2ecf20Sopenharmony_ci rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, 12838c2ecf20Sopenharmony_ci &cdev->pdev->dev); 12848c2ecf20Sopenharmony_ci if (rc) { 12858c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 12868c2ecf20Sopenharmony_ci "Failed to find fw file - /lib/firmware/%s\n", 12878c2ecf20Sopenharmony_ci QED_FW_FILE_NAME); 12888c2ecf20Sopenharmony_ci goto err; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (cdev->num_hwfns == 1) { 12928c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 12938c2ecf20Sopenharmony_ci if (p_ptt) { 12948c2ecf20Sopenharmony_ci QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; 12958c2ecf20Sopenharmony_ci } else { 12968c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 12978c2ecf20Sopenharmony_ci "Failed to acquire PTT for aRFS\n"); 12988c2ecf20Sopenharmony_ci rc = -EINVAL; 12998c2ecf20Sopenharmony_ci goto err; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 13058c2ecf20Sopenharmony_ci rc = qed_nic_setup(cdev); 13068c2ecf20Sopenharmony_ci if (rc) 13078c2ecf20Sopenharmony_ci goto err; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 13108c2ecf20Sopenharmony_ci rc = qed_slowpath_setup_int(cdev, params->int_mode); 13118c2ecf20Sopenharmony_ci else 13128c2ecf20Sopenharmony_ci rc = qed_slowpath_vf_setup_int(cdev); 13138c2ecf20Sopenharmony_ci if (rc) 13148c2ecf20Sopenharmony_ci goto err1; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 13178c2ecf20Sopenharmony_ci /* Allocate stream for unzipping */ 13188c2ecf20Sopenharmony_ci rc = qed_alloc_stream_mem(cdev); 13198c2ecf20Sopenharmony_ci if (rc) 13208c2ecf20Sopenharmony_ci goto err2; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci /* First Dword used to differentiate between various sources */ 13238c2ecf20Sopenharmony_ci data = cdev->firmware->data + sizeof(u32); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci qed_dbg_pf_init(cdev); 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* Start the slowpath */ 13298c2ecf20Sopenharmony_ci memset(&hw_init_params, 0, sizeof(hw_init_params)); 13308c2ecf20Sopenharmony_ci memset(&tunn_info, 0, sizeof(tunn_info)); 13318c2ecf20Sopenharmony_ci tunn_info.vxlan.b_mode_enabled = true; 13328c2ecf20Sopenharmony_ci tunn_info.l2_gre.b_mode_enabled = true; 13338c2ecf20Sopenharmony_ci tunn_info.ip_gre.b_mode_enabled = true; 13348c2ecf20Sopenharmony_ci tunn_info.l2_geneve.b_mode_enabled = true; 13358c2ecf20Sopenharmony_ci tunn_info.ip_geneve.b_mode_enabled = true; 13368c2ecf20Sopenharmony_ci tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 13378c2ecf20Sopenharmony_ci tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 13388c2ecf20Sopenharmony_ci tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 13398c2ecf20Sopenharmony_ci tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 13408c2ecf20Sopenharmony_ci tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 13418c2ecf20Sopenharmony_ci hw_init_params.p_tunn = &tunn_info; 13428c2ecf20Sopenharmony_ci hw_init_params.b_hw_start = true; 13438c2ecf20Sopenharmony_ci hw_init_params.int_mode = cdev->int_params.out.int_mode; 13448c2ecf20Sopenharmony_ci hw_init_params.allow_npar_tx_switch = true; 13458c2ecf20Sopenharmony_ci hw_init_params.bin_fw_data = data; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci memset(&drv_load_params, 0, sizeof(drv_load_params)); 13488c2ecf20Sopenharmony_ci drv_load_params.is_crash_kernel = is_kdump_kernel(); 13498c2ecf20Sopenharmony_ci drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; 13508c2ecf20Sopenharmony_ci drv_load_params.avoid_eng_reset = false; 13518c2ecf20Sopenharmony_ci drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; 13528c2ecf20Sopenharmony_ci hw_init_params.p_drv_load_params = &drv_load_params; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci rc = qed_hw_init(cdev, &hw_init_params); 13558c2ecf20Sopenharmony_ci if (rc) 13568c2ecf20Sopenharmony_ci goto err2; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci DP_INFO(cdev, 13598c2ecf20Sopenharmony_ci "HW initialization and function start completed successfully\n"); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 13628c2ecf20Sopenharmony_ci cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | 13638c2ecf20Sopenharmony_ci BIT(QED_MODE_L2GENEVE_TUNN) | 13648c2ecf20Sopenharmony_ci BIT(QED_MODE_IPGENEVE_TUNN) | 13658c2ecf20Sopenharmony_ci BIT(QED_MODE_L2GRE_TUNN) | 13668c2ecf20Sopenharmony_ci BIT(QED_MODE_IPGRE_TUNN)); 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* Allocate LL2 interface if needed */ 13708c2ecf20Sopenharmony_ci if (QED_LEADING_HWFN(cdev)->using_ll2) { 13718c2ecf20Sopenharmony_ci rc = qed_ll2_alloc_if(cdev); 13728c2ecf20Sopenharmony_ci if (rc) 13738c2ecf20Sopenharmony_ci goto err3; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 13768c2ecf20Sopenharmony_ci hwfn = QED_LEADING_HWFN(cdev); 13778c2ecf20Sopenharmony_ci drv_version.version = (params->drv_major << 24) | 13788c2ecf20Sopenharmony_ci (params->drv_minor << 16) | 13798c2ecf20Sopenharmony_ci (params->drv_rev << 8) | 13808c2ecf20Sopenharmony_ci (params->drv_eng); 13818c2ecf20Sopenharmony_ci strlcpy(drv_version.name, params->name, 13828c2ecf20Sopenharmony_ci MCP_DRV_VER_STR_SIZE - 4); 13838c2ecf20Sopenharmony_ci rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, 13848c2ecf20Sopenharmony_ci &drv_version); 13858c2ecf20Sopenharmony_ci if (rc) { 13868c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed sending drv version command\n"); 13878c2ecf20Sopenharmony_ci goto err4; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci qed_reset_vport_stats(cdev); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci return 0; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_cierr4: 13968c2ecf20Sopenharmony_ci qed_ll2_dealloc_if(cdev); 13978c2ecf20Sopenharmony_cierr3: 13988c2ecf20Sopenharmony_ci qed_hw_stop(cdev); 13998c2ecf20Sopenharmony_cierr2: 14008c2ecf20Sopenharmony_ci qed_hw_timers_stop_all(cdev); 14018c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 14028c2ecf20Sopenharmony_ci qed_slowpath_irq_free(cdev); 14038c2ecf20Sopenharmony_ci qed_free_stream_mem(cdev); 14048c2ecf20Sopenharmony_ci qed_disable_msix(cdev); 14058c2ecf20Sopenharmony_cierr1: 14068c2ecf20Sopenharmony_ci qed_resc_free(cdev); 14078c2ecf20Sopenharmony_cierr: 14088c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 14098c2ecf20Sopenharmony_ci release_firmware(cdev->firmware); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (IS_PF(cdev) && (cdev->num_hwfns == 1) && 14128c2ecf20Sopenharmony_ci QED_LEADING_HWFN(cdev)->p_arfs_ptt) 14138c2ecf20Sopenharmony_ci qed_ptt_release(QED_LEADING_HWFN(cdev), 14148c2ecf20Sopenharmony_ci QED_LEADING_HWFN(cdev)->p_arfs_ptt); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci qed_iov_wq_stop(cdev, false); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci qed_slowpath_wq_stop(cdev); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci return rc; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_cistatic int qed_slowpath_stop(struct qed_dev *cdev) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci if (!cdev) 14268c2ecf20Sopenharmony_ci return -ENODEV; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci qed_slowpath_wq_stop(cdev); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci qed_ll2_dealloc_if(cdev); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 14338c2ecf20Sopenharmony_ci if (cdev->num_hwfns == 1) 14348c2ecf20Sopenharmony_ci qed_ptt_release(QED_LEADING_HWFN(cdev), 14358c2ecf20Sopenharmony_ci QED_LEADING_HWFN(cdev)->p_arfs_ptt); 14368c2ecf20Sopenharmony_ci qed_free_stream_mem(cdev); 14378c2ecf20Sopenharmony_ci if (IS_QED_ETH_IF(cdev)) 14388c2ecf20Sopenharmony_ci qed_sriov_disable(cdev, true); 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci qed_nic_stop(cdev); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 14448c2ecf20Sopenharmony_ci qed_slowpath_irq_free(cdev); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci qed_disable_msix(cdev); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci qed_resc_free(cdev); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci qed_iov_wq_stop(cdev, true); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 14538c2ecf20Sopenharmony_ci release_firmware(cdev->firmware); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci return 0; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci int i; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci memcpy(cdev->name, name, NAME_SIZE); 14638c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 14648c2ecf20Sopenharmony_ci snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic u32 qed_sb_init(struct qed_dev *cdev, 14688c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info, 14698c2ecf20Sopenharmony_ci void *sb_virt_addr, 14708c2ecf20Sopenharmony_ci dma_addr_t sb_phy_addr, u16 sb_id, 14718c2ecf20Sopenharmony_ci enum qed_sb_type type) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 14748c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 14758c2ecf20Sopenharmony_ci u16 rel_sb_id; 14768c2ecf20Sopenharmony_ci u32 rc; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 14798c2ecf20Sopenharmony_ci if (type == QED_SB_TYPE_L2_QUEUE) { 14808c2ecf20Sopenharmony_ci p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 14818c2ecf20Sopenharmony_ci rel_sb_id = sb_id / cdev->num_hwfns; 14828c2ecf20Sopenharmony_ci } else { 14838c2ecf20Sopenharmony_ci p_hwfn = QED_AFFIN_HWFN(cdev); 14848c2ecf20Sopenharmony_ci rel_sb_id = sb_id; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_INTR, 14888c2ecf20Sopenharmony_ci "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 14898c2ecf20Sopenharmony_ci IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (IS_PF(p_hwfn->cdev)) { 14928c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 14938c2ecf20Sopenharmony_ci if (!p_ptt) 14948c2ecf20Sopenharmony_ci return -EBUSY; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, 14978c2ecf20Sopenharmony_ci sb_phy_addr, rel_sb_id); 14988c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 14998c2ecf20Sopenharmony_ci } else { 15008c2ecf20Sopenharmony_ci rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, 15018c2ecf20Sopenharmony_ci sb_phy_addr, rel_sb_id); 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return rc; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic u32 qed_sb_release(struct qed_dev *cdev, 15088c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info, 15098c2ecf20Sopenharmony_ci u16 sb_id, 15108c2ecf20Sopenharmony_ci enum qed_sb_type type) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 15138c2ecf20Sopenharmony_ci u16 rel_sb_id; 15148c2ecf20Sopenharmony_ci u32 rc; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 15178c2ecf20Sopenharmony_ci if (type == QED_SB_TYPE_L2_QUEUE) { 15188c2ecf20Sopenharmony_ci p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 15198c2ecf20Sopenharmony_ci rel_sb_id = sb_id / cdev->num_hwfns; 15208c2ecf20Sopenharmony_ci } else { 15218c2ecf20Sopenharmony_ci p_hwfn = QED_AFFIN_HWFN(cdev); 15228c2ecf20Sopenharmony_ci rel_sb_id = sb_id; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_INTR, 15268c2ecf20Sopenharmony_ci "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 15278c2ecf20Sopenharmony_ci IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci return rc; 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cistatic bool qed_can_link_change(struct qed_dev *cdev) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci return true; 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_cistatic void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params, 15408c2ecf20Sopenharmony_ci const struct qed_link_params *params) 15418c2ecf20Sopenharmony_ci{ 15428c2ecf20Sopenharmony_ci struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed; 15438c2ecf20Sopenharmony_ci const struct qed_mfw_speed_map *map; 15448c2ecf20Sopenharmony_ci u32 i; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 15478c2ecf20Sopenharmony_ci ext_speed->autoneg = !!params->autoneg; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 15508c2ecf20Sopenharmony_ci ext_speed->advertised_speeds = 0; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) { 15538c2ecf20Sopenharmony_ci map = qed_mfw_ext_maps + i; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (linkmode_intersects(params->adv_speeds, map->caps)) 15568c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= map->mfw_val; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) { 15618c2ecf20Sopenharmony_ci switch (params->forced_speed) { 15628c2ecf20Sopenharmony_ci case SPEED_1000: 15638c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_1G; 15648c2ecf20Sopenharmony_ci break; 15658c2ecf20Sopenharmony_ci case SPEED_10000: 15668c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_10G; 15678c2ecf20Sopenharmony_ci break; 15688c2ecf20Sopenharmony_ci case SPEED_20000: 15698c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_20G; 15708c2ecf20Sopenharmony_ci break; 15718c2ecf20Sopenharmony_ci case SPEED_25000: 15728c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_25G; 15738c2ecf20Sopenharmony_ci break; 15748c2ecf20Sopenharmony_ci case SPEED_40000: 15758c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_40G; 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci case SPEED_50000: 15788c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_50G_R | 15798c2ecf20Sopenharmony_ci QED_EXT_SPEED_50G_R2; 15808c2ecf20Sopenharmony_ci break; 15818c2ecf20Sopenharmony_ci case SPEED_100000: 15828c2ecf20Sopenharmony_ci ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 | 15838c2ecf20Sopenharmony_ci QED_EXT_SPEED_100G_R4 | 15848c2ecf20Sopenharmony_ci QED_EXT_SPEED_100G_P4; 15858c2ecf20Sopenharmony_ci break; 15868c2ecf20Sopenharmony_ci default: 15878c2ecf20Sopenharmony_ci break; 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)) 15928c2ecf20Sopenharmony_ci return; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci switch (params->forced_speed) { 15958c2ecf20Sopenharmony_ci case SPEED_25000: 15968c2ecf20Sopenharmony_ci switch (params->fec) { 15978c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_NONE: 15988c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE; 15998c2ecf20Sopenharmony_ci break; 16008c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_FIRECODE: 16018c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R; 16028c2ecf20Sopenharmony_ci break; 16038c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_RS: 16048c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528; 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_AUTO: 16078c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 | 16088c2ecf20Sopenharmony_ci ETH_EXT_FEC_25G_BASE_R | 16098c2ecf20Sopenharmony_ci ETH_EXT_FEC_25G_NONE; 16108c2ecf20Sopenharmony_ci break; 16118c2ecf20Sopenharmony_ci default: 16128c2ecf20Sopenharmony_ci break; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci break; 16168c2ecf20Sopenharmony_ci case SPEED_40000: 16178c2ecf20Sopenharmony_ci switch (params->fec) { 16188c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_NONE: 16198c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE; 16208c2ecf20Sopenharmony_ci break; 16218c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_FIRECODE: 16228c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R; 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_AUTO: 16258c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R | 16268c2ecf20Sopenharmony_ci ETH_EXT_FEC_40G_NONE; 16278c2ecf20Sopenharmony_ci break; 16288c2ecf20Sopenharmony_ci default: 16298c2ecf20Sopenharmony_ci break; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci break; 16338c2ecf20Sopenharmony_ci case SPEED_50000: 16348c2ecf20Sopenharmony_ci switch (params->fec) { 16358c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_NONE: 16368c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE; 16378c2ecf20Sopenharmony_ci break; 16388c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_FIRECODE: 16398c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R; 16408c2ecf20Sopenharmony_ci break; 16418c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_RS: 16428c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528; 16438c2ecf20Sopenharmony_ci break; 16448c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_AUTO: 16458c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 | 16468c2ecf20Sopenharmony_ci ETH_EXT_FEC_50G_BASE_R | 16478c2ecf20Sopenharmony_ci ETH_EXT_FEC_50G_NONE; 16488c2ecf20Sopenharmony_ci break; 16498c2ecf20Sopenharmony_ci default: 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci break; 16548c2ecf20Sopenharmony_ci case SPEED_100000: 16558c2ecf20Sopenharmony_ci switch (params->fec) { 16568c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_NONE: 16578c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE; 16588c2ecf20Sopenharmony_ci break; 16598c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_FIRECODE: 16608c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R; 16618c2ecf20Sopenharmony_ci break; 16628c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_RS: 16638c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528; 16648c2ecf20Sopenharmony_ci break; 16658c2ecf20Sopenharmony_ci case FEC_FORCE_MODE_AUTO: 16668c2ecf20Sopenharmony_ci link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 | 16678c2ecf20Sopenharmony_ci ETH_EXT_FEC_100G_BASE_R | 16688c2ecf20Sopenharmony_ci ETH_EXT_FEC_100G_NONE; 16698c2ecf20Sopenharmony_ci break; 16708c2ecf20Sopenharmony_ci default: 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci break; 16758c2ecf20Sopenharmony_ci default: 16768c2ecf20Sopenharmony_ci break; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci} 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_cistatic int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci struct qed_mcp_link_params *link_params; 16838c2ecf20Sopenharmony_ci struct qed_mcp_link_speed_params *speed; 16848c2ecf20Sopenharmony_ci const struct qed_mfw_speed_map *map; 16858c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 16868c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 16878c2ecf20Sopenharmony_ci int rc; 16888c2ecf20Sopenharmony_ci u32 i; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (!cdev) 16918c2ecf20Sopenharmony_ci return -ENODEV; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* The link should be set only once per PF */ 16948c2ecf20Sopenharmony_ci hwfn = &cdev->hwfns[0]; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci /* When VF wants to set link, force it to read the bulletin instead. 16978c2ecf20Sopenharmony_ci * This mimics the PF behavior, where a noitification [both immediate 16988c2ecf20Sopenharmony_ci * and possible later] would be generated when changing properties. 16998c2ecf20Sopenharmony_ci */ 17008c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 17018c2ecf20Sopenharmony_ci qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); 17028c2ecf20Sopenharmony_ci return 0; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 17068c2ecf20Sopenharmony_ci if (!ptt) 17078c2ecf20Sopenharmony_ci return -EBUSY; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci link_params = qed_mcp_get_link_params(hwfn); 17108c2ecf20Sopenharmony_ci if (!link_params) 17118c2ecf20Sopenharmony_ci return -ENODATA; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci speed = &link_params->speed; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 17168c2ecf20Sopenharmony_ci speed->autoneg = !!params->autoneg; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 17198c2ecf20Sopenharmony_ci speed->advertised_speeds = 0; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) { 17228c2ecf20Sopenharmony_ci map = qed_mfw_legacy_maps + i; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (linkmode_intersects(params->adv_speeds, map->caps)) 17258c2ecf20Sopenharmony_ci speed->advertised_speeds |= map->mfw_val; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) 17308c2ecf20Sopenharmony_ci speed->forced_speed = params->forced_speed; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci if (qed_mcp_is_ext_speed_supported(hwfn)) 17338c2ecf20Sopenharmony_ci qed_set_ext_speed_params(link_params, params); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { 17368c2ecf20Sopenharmony_ci if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 17378c2ecf20Sopenharmony_ci link_params->pause.autoneg = true; 17388c2ecf20Sopenharmony_ci else 17398c2ecf20Sopenharmony_ci link_params->pause.autoneg = false; 17408c2ecf20Sopenharmony_ci if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) 17418c2ecf20Sopenharmony_ci link_params->pause.forced_rx = true; 17428c2ecf20Sopenharmony_ci else 17438c2ecf20Sopenharmony_ci link_params->pause.forced_rx = false; 17448c2ecf20Sopenharmony_ci if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) 17458c2ecf20Sopenharmony_ci link_params->pause.forced_tx = true; 17468c2ecf20Sopenharmony_ci else 17478c2ecf20Sopenharmony_ci link_params->pause.forced_tx = false; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { 17518c2ecf20Sopenharmony_ci switch (params->loopback_mode) { 17528c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_INT_PHY: 17538c2ecf20Sopenharmony_ci link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; 17548c2ecf20Sopenharmony_ci break; 17558c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_EXT_PHY: 17568c2ecf20Sopenharmony_ci link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; 17578c2ecf20Sopenharmony_ci break; 17588c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_EXT: 17598c2ecf20Sopenharmony_ci link_params->loopback_mode = ETH_LOOPBACK_EXT; 17608c2ecf20Sopenharmony_ci break; 17618c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_MAC: 17628c2ecf20Sopenharmony_ci link_params->loopback_mode = ETH_LOOPBACK_MAC; 17638c2ecf20Sopenharmony_ci break; 17648c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123: 17658c2ecf20Sopenharmony_ci link_params->loopback_mode = 17668c2ecf20Sopenharmony_ci ETH_LOOPBACK_CNIG_AH_ONLY_0123; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301: 17698c2ecf20Sopenharmony_ci link_params->loopback_mode = 17708c2ecf20Sopenharmony_ci ETH_LOOPBACK_CNIG_AH_ONLY_2301; 17718c2ecf20Sopenharmony_ci break; 17728c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_PCS_AH_ONLY: 17738c2ecf20Sopenharmony_ci link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY; 17748c2ecf20Sopenharmony_ci break; 17758c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY: 17768c2ecf20Sopenharmony_ci link_params->loopback_mode = 17778c2ecf20Sopenharmony_ci ETH_LOOPBACK_REVERSE_MAC_AH_ONLY; 17788c2ecf20Sopenharmony_ci break; 17798c2ecf20Sopenharmony_ci case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY: 17808c2ecf20Sopenharmony_ci link_params->loopback_mode = 17818c2ecf20Sopenharmony_ci ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY; 17828c2ecf20Sopenharmony_ci break; 17838c2ecf20Sopenharmony_ci default: 17848c2ecf20Sopenharmony_ci link_params->loopback_mode = ETH_LOOPBACK_NONE; 17858c2ecf20Sopenharmony_ci break; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) 17908c2ecf20Sopenharmony_ci memcpy(&link_params->eee, ¶ms->eee, 17918c2ecf20Sopenharmony_ci sizeof(link_params->eee)); 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG) 17948c2ecf20Sopenharmony_ci link_params->fec = params->fec; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci rc = qed_mcp_set_link(hwfn, ptt, params->link_up); 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci return rc; 18018c2ecf20Sopenharmony_ci} 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_cistatic int qed_get_port_type(u32 media_type) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci int port_type; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci switch (media_type) { 18088c2ecf20Sopenharmony_ci case MEDIA_SFPP_10G_FIBER: 18098c2ecf20Sopenharmony_ci case MEDIA_SFP_1G_FIBER: 18108c2ecf20Sopenharmony_ci case MEDIA_XFP_FIBER: 18118c2ecf20Sopenharmony_ci case MEDIA_MODULE_FIBER: 18128c2ecf20Sopenharmony_ci port_type = PORT_FIBRE; 18138c2ecf20Sopenharmony_ci break; 18148c2ecf20Sopenharmony_ci case MEDIA_DA_TWINAX: 18158c2ecf20Sopenharmony_ci port_type = PORT_DA; 18168c2ecf20Sopenharmony_ci break; 18178c2ecf20Sopenharmony_ci case MEDIA_BASE_T: 18188c2ecf20Sopenharmony_ci port_type = PORT_TP; 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci case MEDIA_KR: 18218c2ecf20Sopenharmony_ci case MEDIA_NOT_PRESENT: 18228c2ecf20Sopenharmony_ci port_type = PORT_NONE; 18238c2ecf20Sopenharmony_ci break; 18248c2ecf20Sopenharmony_ci case MEDIA_UNSPECIFIED: 18258c2ecf20Sopenharmony_ci default: 18268c2ecf20Sopenharmony_ci port_type = PORT_OTHER; 18278c2ecf20Sopenharmony_ci break; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci return port_type; 18308c2ecf20Sopenharmony_ci} 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_cistatic int qed_get_link_data(struct qed_hwfn *hwfn, 18338c2ecf20Sopenharmony_ci struct qed_mcp_link_params *params, 18348c2ecf20Sopenharmony_ci struct qed_mcp_link_state *link, 18358c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities *link_caps) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci void *p; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (!IS_PF(hwfn->cdev)) { 18408c2ecf20Sopenharmony_ci qed_vf_get_link_params(hwfn, params); 18418c2ecf20Sopenharmony_ci qed_vf_get_link_state(hwfn, link); 18428c2ecf20Sopenharmony_ci qed_vf_get_link_caps(hwfn, link_caps); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci return 0; 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci p = qed_mcp_get_link_params(hwfn); 18488c2ecf20Sopenharmony_ci if (!p) 18498c2ecf20Sopenharmony_ci return -ENXIO; 18508c2ecf20Sopenharmony_ci memcpy(params, p, sizeof(*params)); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci p = qed_mcp_get_link_state(hwfn); 18538c2ecf20Sopenharmony_ci if (!p) 18548c2ecf20Sopenharmony_ci return -ENXIO; 18558c2ecf20Sopenharmony_ci memcpy(link, p, sizeof(*link)); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci p = qed_mcp_get_link_capabilities(hwfn); 18588c2ecf20Sopenharmony_ci if (!p) 18598c2ecf20Sopenharmony_ci return -ENXIO; 18608c2ecf20Sopenharmony_ci memcpy(link_caps, p, sizeof(*link_caps)); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci return 0; 18638c2ecf20Sopenharmony_ci} 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_cistatic void qed_fill_link_capability(struct qed_hwfn *hwfn, 18668c2ecf20Sopenharmony_ci struct qed_ptt *ptt, u32 capability, 18678c2ecf20Sopenharmony_ci unsigned long *if_caps) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci u32 media_type, tcvr_state, tcvr_type; 18708c2ecf20Sopenharmony_ci u32 speed_mask, board_cfg; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) 18738c2ecf20Sopenharmony_ci media_type = MEDIA_UNSPECIFIED; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) 18768c2ecf20Sopenharmony_ci tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) 18798c2ecf20Sopenharmony_ci speed_mask = 0xFFFFFFFF; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) 18828c2ecf20Sopenharmony_ci board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 18858c2ecf20Sopenharmony_ci "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", 18868c2ecf20Sopenharmony_ci media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci switch (media_type) { 18898c2ecf20Sopenharmony_ci case MEDIA_DA_TWINAX: 18908c2ecf20Sopenharmony_ci phylink_set(if_caps, FIBRE); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 18938c2ecf20Sopenharmony_ci phylink_set(if_caps, 20000baseKR2_Full); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* For DAC media multiple speed capabilities are supported */ 18968c2ecf20Sopenharmony_ci capability |= speed_mask; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 18998c2ecf20Sopenharmony_ci phylink_set(if_caps, 1000baseKX_Full); 19008c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19018c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseCR_Full); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 19048c2ecf20Sopenharmony_ci switch (tcvr_type) { 19058c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_40G_CR4: 19068c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 19078c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 19088c2ecf20Sopenharmony_ci phylink_set(if_caps, 40000baseCR4_Full); 19098c2ecf20Sopenharmony_ci break; 19108c2ecf20Sopenharmony_ci default: 19118c2ecf20Sopenharmony_ci break; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 19158c2ecf20Sopenharmony_ci phylink_set(if_caps, 25000baseCR_Full); 19168c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 19178c2ecf20Sopenharmony_ci phylink_set(if_caps, 50000baseCR2_Full); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (capability & 19208c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 19218c2ecf20Sopenharmony_ci switch (tcvr_type) { 19228c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_CR4: 19238c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 19248c2ecf20Sopenharmony_ci phylink_set(if_caps, 100000baseCR4_Full); 19258c2ecf20Sopenharmony_ci break; 19268c2ecf20Sopenharmony_ci default: 19278c2ecf20Sopenharmony_ci break; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci case MEDIA_BASE_T: 19328c2ecf20Sopenharmony_ci phylink_set(if_caps, TP); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { 19358c2ecf20Sopenharmony_ci if (capability & 19368c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 19378c2ecf20Sopenharmony_ci phylink_set(if_caps, 1000baseT_Full); 19388c2ecf20Sopenharmony_ci if (capability & 19398c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19408c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseT_Full); 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { 19448c2ecf20Sopenharmony_ci phylink_set(if_caps, FIBRE); 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci switch (tcvr_type) { 19478c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1000BASET: 19488c2ecf20Sopenharmony_ci phylink_set(if_caps, 1000baseT_Full); 19498c2ecf20Sopenharmony_ci break; 19508c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_BASET: 19518c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseT_Full); 19528c2ecf20Sopenharmony_ci break; 19538c2ecf20Sopenharmony_ci default: 19548c2ecf20Sopenharmony_ci break; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci break; 19598c2ecf20Sopenharmony_ci case MEDIA_SFP_1G_FIBER: 19608c2ecf20Sopenharmony_ci case MEDIA_SFPP_10G_FIBER: 19618c2ecf20Sopenharmony_ci case MEDIA_XFP_FIBER: 19628c2ecf20Sopenharmony_ci case MEDIA_MODULE_FIBER: 19638c2ecf20Sopenharmony_ci phylink_set(if_caps, FIBRE); 19648c2ecf20Sopenharmony_ci capability |= speed_mask; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 19678c2ecf20Sopenharmony_ci switch (tcvr_type) { 19688c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1G_LX: 19698c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1G_SX: 19708c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 19718c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 19728c2ecf20Sopenharmony_ci phylink_set(if_caps, 1000baseKX_Full); 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci default: 19758c2ecf20Sopenharmony_ci break; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19798c2ecf20Sopenharmony_ci switch (tcvr_type) { 19808c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_SR: 19818c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 19828c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 19838c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 19848c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseSR_Full); 19858c2ecf20Sopenharmony_ci break; 19868c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_LR: 19878c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 19888c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 19898c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 19908c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseLR_Full); 19918c2ecf20Sopenharmony_ci break; 19928c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_LRM: 19938c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseLRM_Full); 19948c2ecf20Sopenharmony_ci break; 19958c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_ER: 19968c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseR_FEC); 19978c2ecf20Sopenharmony_ci break; 19988c2ecf20Sopenharmony_ci default: 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 20038c2ecf20Sopenharmony_ci phylink_set(if_caps, 20000baseKR2_Full); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 20068c2ecf20Sopenharmony_ci switch (tcvr_type) { 20078c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_SR: 20088c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 20098c2ecf20Sopenharmony_ci phylink_set(if_caps, 25000baseSR_Full); 20108c2ecf20Sopenharmony_ci break; 20118c2ecf20Sopenharmony_ci default: 20128c2ecf20Sopenharmony_ci break; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 20168c2ecf20Sopenharmony_ci switch (tcvr_type) { 20178c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_40G_LR4: 20188c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 20198c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 20208c2ecf20Sopenharmony_ci phylink_set(if_caps, 40000baseLR4_Full); 20218c2ecf20Sopenharmony_ci break; 20228c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_40G_SR4: 20238c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 20248c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 20258c2ecf20Sopenharmony_ci phylink_set(if_caps, 40000baseSR4_Full); 20268c2ecf20Sopenharmony_ci break; 20278c2ecf20Sopenharmony_ci default: 20288c2ecf20Sopenharmony_ci break; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 20328c2ecf20Sopenharmony_ci phylink_set(if_caps, 50000baseKR2_Full); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci if (capability & 20358c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 20368c2ecf20Sopenharmony_ci switch (tcvr_type) { 20378c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_SR4: 20388c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 20398c2ecf20Sopenharmony_ci phylink_set(if_caps, 100000baseSR4_Full); 20408c2ecf20Sopenharmony_ci break; 20418c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 20428c2ecf20Sopenharmony_ci phylink_set(if_caps, 100000baseLR4_ER4_Full); 20438c2ecf20Sopenharmony_ci break; 20448c2ecf20Sopenharmony_ci default: 20458c2ecf20Sopenharmony_ci break; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci break; 20498c2ecf20Sopenharmony_ci case MEDIA_KR: 20508c2ecf20Sopenharmony_ci phylink_set(if_caps, Backplane); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 20538c2ecf20Sopenharmony_ci phylink_set(if_caps, 20000baseKR2_Full); 20548c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 20558c2ecf20Sopenharmony_ci phylink_set(if_caps, 1000baseKX_Full); 20568c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 20578c2ecf20Sopenharmony_ci phylink_set(if_caps, 10000baseKR_Full); 20588c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 20598c2ecf20Sopenharmony_ci phylink_set(if_caps, 25000baseKR_Full); 20608c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 20618c2ecf20Sopenharmony_ci phylink_set(if_caps, 40000baseKR4_Full); 20628c2ecf20Sopenharmony_ci if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 20638c2ecf20Sopenharmony_ci phylink_set(if_caps, 50000baseKR2_Full); 20648c2ecf20Sopenharmony_ci if (capability & 20658c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 20668c2ecf20Sopenharmony_ci phylink_set(if_caps, 100000baseKR4_Full); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci break; 20698c2ecf20Sopenharmony_ci case MEDIA_UNSPECIFIED: 20708c2ecf20Sopenharmony_ci case MEDIA_NOT_PRESENT: 20718c2ecf20Sopenharmony_ci default: 20728c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, 20738c2ecf20Sopenharmony_ci "Unknown media and transceiver type;\n"); 20748c2ecf20Sopenharmony_ci break; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_cistatic void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask) 20798c2ecf20Sopenharmony_ci{ 20808c2ecf20Sopenharmony_ci *speed_mask = 0; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (caps & 20838c2ecf20Sopenharmony_ci (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD)) 20848c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 20858c2ecf20Sopenharmony_ci if (caps & QED_LINK_PARTNER_SPEED_10G) 20868c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 20878c2ecf20Sopenharmony_ci if (caps & QED_LINK_PARTNER_SPEED_20G) 20888c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; 20898c2ecf20Sopenharmony_ci if (caps & QED_LINK_PARTNER_SPEED_25G) 20908c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 20918c2ecf20Sopenharmony_ci if (caps & QED_LINK_PARTNER_SPEED_40G) 20928c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 20938c2ecf20Sopenharmony_ci if (caps & QED_LINK_PARTNER_SPEED_50G) 20948c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; 20958c2ecf20Sopenharmony_ci if (caps & QED_LINK_PARTNER_SPEED_100G) 20968c2ecf20Sopenharmony_ci *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; 20978c2ecf20Sopenharmony_ci} 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cistatic void qed_fill_link(struct qed_hwfn *hwfn, 21008c2ecf20Sopenharmony_ci struct qed_ptt *ptt, 21018c2ecf20Sopenharmony_ci struct qed_link_output *if_link) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities link_caps; 21048c2ecf20Sopenharmony_ci struct qed_mcp_link_params params; 21058c2ecf20Sopenharmony_ci struct qed_mcp_link_state link; 21068c2ecf20Sopenharmony_ci u32 media_type, speed_mask; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci memset(if_link, 0, sizeof(*if_link)); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci /* Prepare source inputs */ 21118c2ecf20Sopenharmony_ci if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { 21128c2ecf20Sopenharmony_ci dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); 21138c2ecf20Sopenharmony_ci return; 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci /* Set the link parameters to pass to protocol driver */ 21178c2ecf20Sopenharmony_ci if (link.link_up) 21188c2ecf20Sopenharmony_ci if_link->link_up = true; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) { 21218c2ecf20Sopenharmony_ci if (link_caps.default_ext_autoneg) 21228c2ecf20Sopenharmony_ci phylink_set(if_link->supported_caps, Autoneg); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (params.ext_speed.autoneg) 21278c2ecf20Sopenharmony_ci phylink_set(if_link->advertised_caps, Autoneg); 21288c2ecf20Sopenharmony_ci else 21298c2ecf20Sopenharmony_ci phylink_clear(if_link->advertised_caps, Autoneg); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci qed_fill_link_capability(hwfn, ptt, 21328c2ecf20Sopenharmony_ci params.ext_speed.advertised_speeds, 21338c2ecf20Sopenharmony_ci if_link->advertised_caps); 21348c2ecf20Sopenharmony_ci } else { 21358c2ecf20Sopenharmony_ci if (link_caps.default_speed_autoneg) 21368c2ecf20Sopenharmony_ci phylink_set(if_link->supported_caps, Autoneg); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (params.speed.autoneg) 21418c2ecf20Sopenharmony_ci phylink_set(if_link->advertised_caps, Autoneg); 21428c2ecf20Sopenharmony_ci else 21438c2ecf20Sopenharmony_ci phylink_clear(if_link->advertised_caps, Autoneg); 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci if (params.pause.autoneg || 21478c2ecf20Sopenharmony_ci (params.pause.forced_rx && params.pause.forced_tx)) 21488c2ecf20Sopenharmony_ci phylink_set(if_link->supported_caps, Asym_Pause); 21498c2ecf20Sopenharmony_ci if (params.pause.autoneg || params.pause.forced_rx || 21508c2ecf20Sopenharmony_ci params.pause.forced_tx) 21518c2ecf20Sopenharmony_ci phylink_set(if_link->supported_caps, Pause); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci if_link->sup_fec = link_caps.fec_default; 21548c2ecf20Sopenharmony_ci if_link->active_fec = params.fec; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci /* Fill link advertised capability */ 21578c2ecf20Sopenharmony_ci qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, 21588c2ecf20Sopenharmony_ci if_link->advertised_caps); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* Fill link supported capability */ 21618c2ecf20Sopenharmony_ci qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, 21628c2ecf20Sopenharmony_ci if_link->supported_caps); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci /* Fill partner advertised capability */ 21658c2ecf20Sopenharmony_ci qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask); 21668c2ecf20Sopenharmony_ci qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci if (link.link_up) 21698c2ecf20Sopenharmony_ci if_link->speed = link.speed; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci /* TODO - fill duplex properly */ 21728c2ecf20Sopenharmony_ci if_link->duplex = DUPLEX_FULL; 21738c2ecf20Sopenharmony_ci qed_mcp_get_media_type(hwfn, ptt, &media_type); 21748c2ecf20Sopenharmony_ci if_link->port = qed_get_port_type(media_type); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci if_link->autoneg = params.speed.autoneg; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci if (params.pause.autoneg) 21798c2ecf20Sopenharmony_ci if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 21808c2ecf20Sopenharmony_ci if (params.pause.forced_rx) 21818c2ecf20Sopenharmony_ci if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; 21828c2ecf20Sopenharmony_ci if (params.pause.forced_tx) 21838c2ecf20Sopenharmony_ci if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci if (link.an_complete) 21868c2ecf20Sopenharmony_ci phylink_set(if_link->lp_caps, Autoneg); 21878c2ecf20Sopenharmony_ci if (link.partner_adv_pause) 21888c2ecf20Sopenharmony_ci phylink_set(if_link->lp_caps, Pause); 21898c2ecf20Sopenharmony_ci if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || 21908c2ecf20Sopenharmony_ci link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) 21918c2ecf20Sopenharmony_ci phylink_set(if_link->lp_caps, Asym_Pause); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) { 21948c2ecf20Sopenharmony_ci if_link->eee_supported = false; 21958c2ecf20Sopenharmony_ci } else { 21968c2ecf20Sopenharmony_ci if_link->eee_supported = true; 21978c2ecf20Sopenharmony_ci if_link->eee_active = link.eee_active; 21988c2ecf20Sopenharmony_ci if_link->sup_caps = link_caps.eee_speed_caps; 21998c2ecf20Sopenharmony_ci /* MFW clears adv_caps on eee disable; use configured value */ 22008c2ecf20Sopenharmony_ci if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : 22018c2ecf20Sopenharmony_ci params.eee.adv_caps; 22028c2ecf20Sopenharmony_ci if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; 22038c2ecf20Sopenharmony_ci if_link->eee.enable = params.eee.enable; 22048c2ecf20Sopenharmony_ci if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; 22058c2ecf20Sopenharmony_ci if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_cistatic void qed_get_current_link(struct qed_dev *cdev, 22108c2ecf20Sopenharmony_ci struct qed_link_output *if_link) 22118c2ecf20Sopenharmony_ci{ 22128c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 22138c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 22148c2ecf20Sopenharmony_ci int i; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci hwfn = &cdev->hwfns[0]; 22178c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 22188c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 22198c2ecf20Sopenharmony_ci if (ptt) { 22208c2ecf20Sopenharmony_ci qed_fill_link(hwfn, ptt, if_link); 22218c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 22228c2ecf20Sopenharmony_ci } else { 22238c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci } else { 22268c2ecf20Sopenharmony_ci qed_fill_link(hwfn, NULL, if_link); 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 22308c2ecf20Sopenharmony_ci qed_inform_vf_link_state(&cdev->hwfns[i]); 22318c2ecf20Sopenharmony_ci} 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_civoid qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci void *cookie = hwfn->cdev->ops_cookie; 22368c2ecf20Sopenharmony_ci struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 22378c2ecf20Sopenharmony_ci struct qed_link_output if_link; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci qed_fill_link(hwfn, ptt, &if_link); 22408c2ecf20Sopenharmony_ci qed_inform_vf_link_state(hwfn); 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(hwfn) && cookie) 22438c2ecf20Sopenharmony_ci op->link_update(cookie, &if_link); 22448c2ecf20Sopenharmony_ci} 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_civoid qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 22478c2ecf20Sopenharmony_ci{ 22488c2ecf20Sopenharmony_ci void *cookie = hwfn->cdev->ops_cookie; 22498c2ecf20Sopenharmony_ci struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update) 22528c2ecf20Sopenharmony_ci op->bw_update(cookie); 22538c2ecf20Sopenharmony_ci} 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_cistatic int qed_drain(struct qed_dev *cdev) 22568c2ecf20Sopenharmony_ci{ 22578c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn; 22588c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 22598c2ecf20Sopenharmony_ci int i, rc; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 22628c2ecf20Sopenharmony_ci return 0; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 22658c2ecf20Sopenharmony_ci hwfn = &cdev->hwfns[i]; 22668c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 22678c2ecf20Sopenharmony_ci if (!ptt) { 22688c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); 22698c2ecf20Sopenharmony_ci return -EBUSY; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci rc = qed_mcp_drain(hwfn, ptt); 22728c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 22738c2ecf20Sopenharmony_ci if (rc) 22748c2ecf20Sopenharmony_ci return rc; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci return 0; 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_cistatic u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev, 22818c2ecf20Sopenharmony_ci struct qed_nvm_image_att *nvm_image, 22828c2ecf20Sopenharmony_ci u32 *crc) 22838c2ecf20Sopenharmony_ci{ 22848c2ecf20Sopenharmony_ci u8 *buf = NULL; 22858c2ecf20Sopenharmony_ci int rc; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci /* Allocate a buffer for holding the nvram image */ 22888c2ecf20Sopenharmony_ci buf = kzalloc(nvm_image->length, GFP_KERNEL); 22898c2ecf20Sopenharmony_ci if (!buf) 22908c2ecf20Sopenharmony_ci return -ENOMEM; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci /* Read image into buffer */ 22938c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr, 22948c2ecf20Sopenharmony_ci buf, nvm_image->length); 22958c2ecf20Sopenharmony_ci if (rc) { 22968c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed reading image from nvm\n"); 22978c2ecf20Sopenharmony_ci goto out; 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci /* Convert the buffer into big-endian format (excluding the 23018c2ecf20Sopenharmony_ci * closing 4 bytes of CRC). 23028c2ecf20Sopenharmony_ci */ 23038c2ecf20Sopenharmony_ci cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf, 23048c2ecf20Sopenharmony_ci DIV_ROUND_UP(nvm_image->length - 4, 4)); 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci /* Calc CRC for the "actual" image buffer, i.e. not including 23078c2ecf20Sopenharmony_ci * the last 4 CRC bytes. 23088c2ecf20Sopenharmony_ci */ 23098c2ecf20Sopenharmony_ci *crc = ~crc32(~0U, buf, nvm_image->length - 4); 23108c2ecf20Sopenharmony_ci *crc = (__force u32)cpu_to_be32p(crc); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ciout: 23138c2ecf20Sopenharmony_ci kfree(buf); 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci return rc; 23168c2ecf20Sopenharmony_ci} 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci/* Binary file format - 23198c2ecf20Sopenharmony_ci * /----------------------------------------------------------------------\ 23208c2ecf20Sopenharmony_ci * 0B | 0x4 [command index] | 23218c2ecf20Sopenharmony_ci * 4B | image_type | Options | Number of register settings | 23228c2ecf20Sopenharmony_ci * 8B | Value | 23238c2ecf20Sopenharmony_ci * 12B | Mask | 23248c2ecf20Sopenharmony_ci * 16B | Offset | 23258c2ecf20Sopenharmony_ci * \----------------------------------------------------------------------/ 23268c2ecf20Sopenharmony_ci * There can be several Value-Mask-Offset sets as specified by 'Number of...'. 23278c2ecf20Sopenharmony_ci * Options - 0'b - Calculate & Update CRC for image 23288c2ecf20Sopenharmony_ci */ 23298c2ecf20Sopenharmony_cistatic int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data, 23308c2ecf20Sopenharmony_ci bool *check_resp) 23318c2ecf20Sopenharmony_ci{ 23328c2ecf20Sopenharmony_ci struct qed_nvm_image_att nvm_image; 23338c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 23348c2ecf20Sopenharmony_ci bool is_crc = false; 23358c2ecf20Sopenharmony_ci u32 image_type; 23368c2ecf20Sopenharmony_ci int rc = 0, i; 23378c2ecf20Sopenharmony_ci u16 len; 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci *data += 4; 23408c2ecf20Sopenharmony_ci image_type = **data; 23418c2ecf20Sopenharmony_ci p_hwfn = QED_LEADING_HWFN(cdev); 23428c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 23438c2ecf20Sopenharmony_ci if (image_type == p_hwfn->nvm_info.image_att[i].image_type) 23448c2ecf20Sopenharmony_ci break; 23458c2ecf20Sopenharmony_ci if (i == p_hwfn->nvm_info.num_images) { 23468c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed to find nvram image of type %08x\n", 23478c2ecf20Sopenharmony_ci image_type); 23488c2ecf20Sopenharmony_ci return -ENOENT; 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 23528c2ecf20Sopenharmony_ci nvm_image.length = p_hwfn->nvm_info.image_att[i].len; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 23558c2ecf20Sopenharmony_ci "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n", 23568c2ecf20Sopenharmony_ci **data, image_type, nvm_image.start_addr, 23578c2ecf20Sopenharmony_ci nvm_image.start_addr + nvm_image.length - 1); 23588c2ecf20Sopenharmony_ci (*data)++; 23598c2ecf20Sopenharmony_ci is_crc = !!(**data & BIT(0)); 23608c2ecf20Sopenharmony_ci (*data)++; 23618c2ecf20Sopenharmony_ci len = *((u16 *)*data); 23628c2ecf20Sopenharmony_ci *data += 2; 23638c2ecf20Sopenharmony_ci if (is_crc) { 23648c2ecf20Sopenharmony_ci u32 crc = 0; 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc); 23678c2ecf20Sopenharmony_ci if (rc) { 23688c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc); 23698c2ecf20Sopenharmony_ci goto exit; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 23738c2ecf20Sopenharmony_ci (nvm_image.start_addr + 23748c2ecf20Sopenharmony_ci nvm_image.length - 4), (u8 *)&crc, 4); 23758c2ecf20Sopenharmony_ci if (rc) 23768c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed writing to %08x, rc = %d\n", 23778c2ecf20Sopenharmony_ci nvm_image.start_addr + nvm_image.length - 4, rc); 23788c2ecf20Sopenharmony_ci goto exit; 23798c2ecf20Sopenharmony_ci } 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci /* Iterate over the values for setting */ 23828c2ecf20Sopenharmony_ci while (len) { 23838c2ecf20Sopenharmony_ci u32 offset, mask, value, cur_value; 23848c2ecf20Sopenharmony_ci u8 buf[4]; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci value = *((u32 *)*data); 23878c2ecf20Sopenharmony_ci *data += 4; 23888c2ecf20Sopenharmony_ci mask = *((u32 *)*data); 23898c2ecf20Sopenharmony_ci *data += 4; 23908c2ecf20Sopenharmony_ci offset = *((u32 *)*data); 23918c2ecf20Sopenharmony_ci *data += 4; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf, 23948c2ecf20Sopenharmony_ci 4); 23958c2ecf20Sopenharmony_ci if (rc) { 23968c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed reading from %08x\n", 23978c2ecf20Sopenharmony_ci nvm_image.start_addr + offset); 23988c2ecf20Sopenharmony_ci goto exit; 23998c2ecf20Sopenharmony_ci } 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci cur_value = le32_to_cpu(*((__le32 *)buf)); 24028c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 24038c2ecf20Sopenharmony_ci "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n", 24048c2ecf20Sopenharmony_ci nvm_image.start_addr + offset, cur_value, 24058c2ecf20Sopenharmony_ci (cur_value & ~mask) | (value & mask), value, mask); 24068c2ecf20Sopenharmony_ci value = (value & mask) | (cur_value & ~mask); 24078c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 24088c2ecf20Sopenharmony_ci nvm_image.start_addr + offset, 24098c2ecf20Sopenharmony_ci (u8 *)&value, 4); 24108c2ecf20Sopenharmony_ci if (rc) { 24118c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed writing to %08x\n", 24128c2ecf20Sopenharmony_ci nvm_image.start_addr + offset); 24138c2ecf20Sopenharmony_ci goto exit; 24148c2ecf20Sopenharmony_ci } 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci len--; 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ciexit: 24198c2ecf20Sopenharmony_ci return rc; 24208c2ecf20Sopenharmony_ci} 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci/* Binary file format - 24238c2ecf20Sopenharmony_ci * /----------------------------------------------------------------------\ 24248c2ecf20Sopenharmony_ci * 0B | 0x3 [command index] | 24258c2ecf20Sopenharmony_ci * 4B | b'0: check_response? | b'1-31 reserved | 24268c2ecf20Sopenharmony_ci * 8B | File-type | reserved | 24278c2ecf20Sopenharmony_ci * 12B | Image length in bytes | 24288c2ecf20Sopenharmony_ci * \----------------------------------------------------------------------/ 24298c2ecf20Sopenharmony_ci * Start a new file of the provided type 24308c2ecf20Sopenharmony_ci */ 24318c2ecf20Sopenharmony_cistatic int qed_nvm_flash_image_file_start(struct qed_dev *cdev, 24328c2ecf20Sopenharmony_ci const u8 **data, bool *check_resp) 24338c2ecf20Sopenharmony_ci{ 24348c2ecf20Sopenharmony_ci u32 file_type, file_size = 0; 24358c2ecf20Sopenharmony_ci int rc; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci *data += 4; 24388c2ecf20Sopenharmony_ci *check_resp = !!(**data & BIT(0)); 24398c2ecf20Sopenharmony_ci *data += 4; 24408c2ecf20Sopenharmony_ci file_type = **data; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 24438c2ecf20Sopenharmony_ci "About to start a new file of type %02x\n", file_type); 24448c2ecf20Sopenharmony_ci if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) { 24458c2ecf20Sopenharmony_ci *data += 4; 24468c2ecf20Sopenharmony_ci file_size = *((u32 *)(*data)); 24478c2ecf20Sopenharmony_ci } 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type, 24508c2ecf20Sopenharmony_ci (u8 *)(&file_size), 4); 24518c2ecf20Sopenharmony_ci *data += 4; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci return rc; 24548c2ecf20Sopenharmony_ci} 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci/* Binary file format - 24578c2ecf20Sopenharmony_ci * /----------------------------------------------------------------------\ 24588c2ecf20Sopenharmony_ci * 0B | 0x2 [command index] | 24598c2ecf20Sopenharmony_ci * 4B | Length in bytes | 24608c2ecf20Sopenharmony_ci * 8B | b'0: check_response? | b'1-31 reserved | 24618c2ecf20Sopenharmony_ci * 12B | Offset in bytes | 24628c2ecf20Sopenharmony_ci * 16B | Data ... | 24638c2ecf20Sopenharmony_ci * \----------------------------------------------------------------------/ 24648c2ecf20Sopenharmony_ci * Write data as part of a file that was previously started. Data should be 24658c2ecf20Sopenharmony_ci * of length equal to that provided in the message 24668c2ecf20Sopenharmony_ci */ 24678c2ecf20Sopenharmony_cistatic int qed_nvm_flash_image_file_data(struct qed_dev *cdev, 24688c2ecf20Sopenharmony_ci const u8 **data, bool *check_resp) 24698c2ecf20Sopenharmony_ci{ 24708c2ecf20Sopenharmony_ci u32 offset, len; 24718c2ecf20Sopenharmony_ci int rc; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci *data += 4; 24748c2ecf20Sopenharmony_ci len = *((u32 *)(*data)); 24758c2ecf20Sopenharmony_ci *data += 4; 24768c2ecf20Sopenharmony_ci *check_resp = !!(**data & BIT(0)); 24778c2ecf20Sopenharmony_ci *data += 4; 24788c2ecf20Sopenharmony_ci offset = *((u32 *)(*data)); 24798c2ecf20Sopenharmony_ci *data += 4; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 24828c2ecf20Sopenharmony_ci "About to write File-data: %08x bytes to offset %08x\n", 24838c2ecf20Sopenharmony_ci len, offset); 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset, 24868c2ecf20Sopenharmony_ci (char *)(*data), len); 24878c2ecf20Sopenharmony_ci *data += len; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci return rc; 24908c2ecf20Sopenharmony_ci} 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci/* Binary file format [General header] - 24938c2ecf20Sopenharmony_ci * /----------------------------------------------------------------------\ 24948c2ecf20Sopenharmony_ci * 0B | QED_NVM_SIGNATURE | 24958c2ecf20Sopenharmony_ci * 4B | Length in bytes | 24968c2ecf20Sopenharmony_ci * 8B | Highest command in this batchfile | Reserved | 24978c2ecf20Sopenharmony_ci * \----------------------------------------------------------------------/ 24988c2ecf20Sopenharmony_ci */ 24998c2ecf20Sopenharmony_cistatic int qed_nvm_flash_image_validate(struct qed_dev *cdev, 25008c2ecf20Sopenharmony_ci const struct firmware *image, 25018c2ecf20Sopenharmony_ci const u8 **data) 25028c2ecf20Sopenharmony_ci{ 25038c2ecf20Sopenharmony_ci u32 signature, len; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci /* Check minimum size */ 25068c2ecf20Sopenharmony_ci if (image->size < 12) { 25078c2ecf20Sopenharmony_ci DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size); 25088c2ecf20Sopenharmony_ci return -EINVAL; 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci /* Check signature */ 25128c2ecf20Sopenharmony_ci signature = *((u32 *)(*data)); 25138c2ecf20Sopenharmony_ci if (signature != QED_NVM_SIGNATURE) { 25148c2ecf20Sopenharmony_ci DP_ERR(cdev, "Wrong signature '%08x'\n", signature); 25158c2ecf20Sopenharmony_ci return -EINVAL; 25168c2ecf20Sopenharmony_ci } 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci *data += 4; 25198c2ecf20Sopenharmony_ci /* Validate internal size equals the image-size */ 25208c2ecf20Sopenharmony_ci len = *((u32 *)(*data)); 25218c2ecf20Sopenharmony_ci if (len != image->size) { 25228c2ecf20Sopenharmony_ci DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n", 25238c2ecf20Sopenharmony_ci len, (u32)image->size); 25248c2ecf20Sopenharmony_ci return -EINVAL; 25258c2ecf20Sopenharmony_ci } 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci *data += 4; 25288c2ecf20Sopenharmony_ci /* Make sure driver familiar with all commands necessary for this */ 25298c2ecf20Sopenharmony_ci if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) { 25308c2ecf20Sopenharmony_ci DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n", 25318c2ecf20Sopenharmony_ci *((u16 *)(*data))); 25328c2ecf20Sopenharmony_ci return -EINVAL; 25338c2ecf20Sopenharmony_ci } 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci *data += 4; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci return 0; 25388c2ecf20Sopenharmony_ci} 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci/* Binary file format - 25418c2ecf20Sopenharmony_ci * /----------------------------------------------------------------------\ 25428c2ecf20Sopenharmony_ci * 0B | 0x5 [command index] | 25438c2ecf20Sopenharmony_ci * 4B | Number of config attributes | Reserved | 25448c2ecf20Sopenharmony_ci * 4B | Config ID | Entity ID | Length | 25458c2ecf20Sopenharmony_ci * 4B | Value | 25468c2ecf20Sopenharmony_ci * | | 25478c2ecf20Sopenharmony_ci * \----------------------------------------------------------------------/ 25488c2ecf20Sopenharmony_ci * There can be several cfg_id-entity_id-Length-Value sets as specified by 25498c2ecf20Sopenharmony_ci * 'Number of config attributes'. 25508c2ecf20Sopenharmony_ci * 25518c2ecf20Sopenharmony_ci * The API parses config attributes from the user provided buffer and flashes 25528c2ecf20Sopenharmony_ci * them to the respective NVM path using Management FW inerface. 25538c2ecf20Sopenharmony_ci */ 25548c2ecf20Sopenharmony_cistatic int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data) 25558c2ecf20Sopenharmony_ci{ 25568c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 25578c2ecf20Sopenharmony_ci u8 entity_id, len, buf[32]; 25588c2ecf20Sopenharmony_ci bool need_nvm_init = true; 25598c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 25608c2ecf20Sopenharmony_ci u16 cfg_id, count; 25618c2ecf20Sopenharmony_ci int rc = 0, i; 25628c2ecf20Sopenharmony_ci u32 flags; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 25658c2ecf20Sopenharmony_ci if (!ptt) 25668c2ecf20Sopenharmony_ci return -EAGAIN; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci /* NVM CFG ID attribute header */ 25698c2ecf20Sopenharmony_ci *data += 4; 25708c2ecf20Sopenharmony_ci count = *((u16 *)*data); 25718c2ecf20Sopenharmony_ci *data += 4; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 25748c2ecf20Sopenharmony_ci "Read config ids: num_attrs = %0d\n", count); 25758c2ecf20Sopenharmony_ci /* NVM CFG ID attributes. Start loop index from 1 to avoid additional 25768c2ecf20Sopenharmony_ci * arithmetic operations in the implementation. 25778c2ecf20Sopenharmony_ci */ 25788c2ecf20Sopenharmony_ci for (i = 1; i <= count; i++) { 25798c2ecf20Sopenharmony_ci cfg_id = *((u16 *)*data); 25808c2ecf20Sopenharmony_ci *data += 2; 25818c2ecf20Sopenharmony_ci entity_id = **data; 25828c2ecf20Sopenharmony_ci (*data)++; 25838c2ecf20Sopenharmony_ci len = **data; 25848c2ecf20Sopenharmony_ci (*data)++; 25858c2ecf20Sopenharmony_ci memcpy(buf, *data, len); 25868c2ecf20Sopenharmony_ci *data += len; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci flags = 0; 25898c2ecf20Sopenharmony_ci if (need_nvm_init) { 25908c2ecf20Sopenharmony_ci flags |= QED_NVM_CFG_OPTION_INIT; 25918c2ecf20Sopenharmony_ci need_nvm_init = false; 25928c2ecf20Sopenharmony_ci } 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci /* Commit to flash and free the resources */ 25958c2ecf20Sopenharmony_ci if (!(i % QED_NVM_CFG_MAX_ATTRS) || i == count) { 25968c2ecf20Sopenharmony_ci flags |= QED_NVM_CFG_OPTION_COMMIT | 25978c2ecf20Sopenharmony_ci QED_NVM_CFG_OPTION_FREE; 25988c2ecf20Sopenharmony_ci need_nvm_init = true; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci if (entity_id) 26028c2ecf20Sopenharmony_ci flags |= QED_NVM_CFG_OPTION_ENTITY_SEL; 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 26058c2ecf20Sopenharmony_ci "cfg_id = %d entity = %d len = %d\n", cfg_id, 26068c2ecf20Sopenharmony_ci entity_id, len); 26078c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags, 26088c2ecf20Sopenharmony_ci buf, len); 26098c2ecf20Sopenharmony_ci if (rc) { 26108c2ecf20Sopenharmony_ci DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id); 26118c2ecf20Sopenharmony_ci break; 26128c2ecf20Sopenharmony_ci } 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci return rc; 26188c2ecf20Sopenharmony_ci} 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci#define QED_MAX_NVM_BUF_LEN 32 26218c2ecf20Sopenharmony_cistatic int qed_nvm_flash_cfg_len(struct qed_dev *cdev, u32 cmd) 26228c2ecf20Sopenharmony_ci{ 26238c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26248c2ecf20Sopenharmony_ci u8 buf[QED_MAX_NVM_BUF_LEN]; 26258c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 26268c2ecf20Sopenharmony_ci u32 len; 26278c2ecf20Sopenharmony_ci int rc; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 26308c2ecf20Sopenharmony_ci if (!ptt) 26318c2ecf20Sopenharmony_ci return QED_MAX_NVM_BUF_LEN; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, 0, QED_NVM_CFG_GET_FLAGS, buf, 26348c2ecf20Sopenharmony_ci &len); 26358c2ecf20Sopenharmony_ci if (rc || !len) { 26368c2ecf20Sopenharmony_ci DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26378c2ecf20Sopenharmony_ci len = QED_MAX_NVM_BUF_LEN; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci return len; 26438c2ecf20Sopenharmony_ci} 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_cistatic int qed_nvm_flash_cfg_read(struct qed_dev *cdev, u8 **data, 26468c2ecf20Sopenharmony_ci u32 cmd, u32 entity_id) 26478c2ecf20Sopenharmony_ci{ 26488c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26498c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 26508c2ecf20Sopenharmony_ci u32 flags, len; 26518c2ecf20Sopenharmony_ci int rc = 0; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 26548c2ecf20Sopenharmony_ci if (!ptt) 26558c2ecf20Sopenharmony_ci return -EAGAIN; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 26588c2ecf20Sopenharmony_ci "Read config cmd = %d entity id %d\n", cmd, entity_id); 26598c2ecf20Sopenharmony_ci flags = entity_id ? QED_NVM_CFG_GET_PF_FLAGS : QED_NVM_CFG_GET_FLAGS; 26608c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, entity_id, flags, *data, &len); 26618c2ecf20Sopenharmony_ci if (rc) 26628c2ecf20Sopenharmony_ci DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci return rc; 26678c2ecf20Sopenharmony_ci} 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_cistatic int qed_nvm_flash(struct qed_dev *cdev, const char *name) 26708c2ecf20Sopenharmony_ci{ 26718c2ecf20Sopenharmony_ci const struct firmware *image; 26728c2ecf20Sopenharmony_ci const u8 *data, *data_end; 26738c2ecf20Sopenharmony_ci u32 cmd_type; 26748c2ecf20Sopenharmony_ci int rc; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci rc = request_firmware(&image, name, &cdev->pdev->dev); 26778c2ecf20Sopenharmony_ci if (rc) { 26788c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed to find '%s'\n", name); 26798c2ecf20Sopenharmony_ci return rc; 26808c2ecf20Sopenharmony_ci } 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, NETIF_MSG_DRV, 26838c2ecf20Sopenharmony_ci "Flashing '%s' - firmware's data at %p, size is %08x\n", 26848c2ecf20Sopenharmony_ci name, image->data, (u32)image->size); 26858c2ecf20Sopenharmony_ci data = image->data; 26868c2ecf20Sopenharmony_ci data_end = data + image->size; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci rc = qed_nvm_flash_image_validate(cdev, image, &data); 26898c2ecf20Sopenharmony_ci if (rc) 26908c2ecf20Sopenharmony_ci goto exit; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci while (data < data_end) { 26938c2ecf20Sopenharmony_ci bool check_resp = false; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci /* Parse the actual command */ 26968c2ecf20Sopenharmony_ci cmd_type = *((u32 *)data); 26978c2ecf20Sopenharmony_ci switch (cmd_type) { 26988c2ecf20Sopenharmony_ci case QED_NVM_FLASH_CMD_FILE_DATA: 26998c2ecf20Sopenharmony_ci rc = qed_nvm_flash_image_file_data(cdev, &data, 27008c2ecf20Sopenharmony_ci &check_resp); 27018c2ecf20Sopenharmony_ci break; 27028c2ecf20Sopenharmony_ci case QED_NVM_FLASH_CMD_FILE_START: 27038c2ecf20Sopenharmony_ci rc = qed_nvm_flash_image_file_start(cdev, &data, 27048c2ecf20Sopenharmony_ci &check_resp); 27058c2ecf20Sopenharmony_ci break; 27068c2ecf20Sopenharmony_ci case QED_NVM_FLASH_CMD_NVM_CHANGE: 27078c2ecf20Sopenharmony_ci rc = qed_nvm_flash_image_access(cdev, &data, 27088c2ecf20Sopenharmony_ci &check_resp); 27098c2ecf20Sopenharmony_ci break; 27108c2ecf20Sopenharmony_ci case QED_NVM_FLASH_CMD_NVM_CFG_ID: 27118c2ecf20Sopenharmony_ci rc = qed_nvm_flash_cfg_write(cdev, &data); 27128c2ecf20Sopenharmony_ci break; 27138c2ecf20Sopenharmony_ci default: 27148c2ecf20Sopenharmony_ci DP_ERR(cdev, "Unknown command %08x\n", cmd_type); 27158c2ecf20Sopenharmony_ci rc = -EINVAL; 27168c2ecf20Sopenharmony_ci goto exit; 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci if (rc) { 27208c2ecf20Sopenharmony_ci DP_ERR(cdev, "Command %08x failed\n", cmd_type); 27218c2ecf20Sopenharmony_ci goto exit; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci /* Check response if needed */ 27258c2ecf20Sopenharmony_ci if (check_resp) { 27268c2ecf20Sopenharmony_ci u32 mcp_response = 0; 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) { 27298c2ecf20Sopenharmony_ci DP_ERR(cdev, "Failed getting MCP response\n"); 27308c2ecf20Sopenharmony_ci rc = -EINVAL; 27318c2ecf20Sopenharmony_ci goto exit; 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci switch (mcp_response & FW_MSG_CODE_MASK) { 27358c2ecf20Sopenharmony_ci case FW_MSG_CODE_OK: 27368c2ecf20Sopenharmony_ci case FW_MSG_CODE_NVM_OK: 27378c2ecf20Sopenharmony_ci case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK: 27388c2ecf20Sopenharmony_ci case FW_MSG_CODE_PHY_OK: 27398c2ecf20Sopenharmony_ci break; 27408c2ecf20Sopenharmony_ci default: 27418c2ecf20Sopenharmony_ci DP_ERR(cdev, "MFW returns error: %08x\n", 27428c2ecf20Sopenharmony_ci mcp_response); 27438c2ecf20Sopenharmony_ci rc = -EINVAL; 27448c2ecf20Sopenharmony_ci goto exit; 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci } 27478c2ecf20Sopenharmony_ci } 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ciexit: 27508c2ecf20Sopenharmony_ci release_firmware(image); 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci return rc; 27538c2ecf20Sopenharmony_ci} 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_cistatic int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, 27568c2ecf20Sopenharmony_ci u8 *buf, u16 len) 27578c2ecf20Sopenharmony_ci{ 27588c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci return qed_mcp_get_nvm_image(hwfn, type, buf, len); 27618c2ecf20Sopenharmony_ci} 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_civoid qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 27668c2ecf20Sopenharmony_ci void *cookie = p_hwfn->cdev->ops_cookie; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci if (ops && ops->schedule_recovery_handler) 27698c2ecf20Sopenharmony_ci ops->schedule_recovery_handler(cookie); 27708c2ecf20Sopenharmony_ci} 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_cistatic const char * const qed_hw_err_type_descr[] = { 27738c2ecf20Sopenharmony_ci [QED_HW_ERR_FAN_FAIL] = "Fan Failure", 27748c2ecf20Sopenharmony_ci [QED_HW_ERR_MFW_RESP_FAIL] = "MFW Response Failure", 27758c2ecf20Sopenharmony_ci [QED_HW_ERR_HW_ATTN] = "HW Attention", 27768c2ecf20Sopenharmony_ci [QED_HW_ERR_DMAE_FAIL] = "DMAE Failure", 27778c2ecf20Sopenharmony_ci [QED_HW_ERR_RAMROD_FAIL] = "Ramrod Failure", 27788c2ecf20Sopenharmony_ci [QED_HW_ERR_FW_ASSERT] = "FW Assertion", 27798c2ecf20Sopenharmony_ci [QED_HW_ERR_LAST] = "Unknown", 27808c2ecf20Sopenharmony_ci}; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_civoid qed_hw_error_occurred(struct qed_hwfn *p_hwfn, 27838c2ecf20Sopenharmony_ci enum qed_hw_err_type err_type) 27848c2ecf20Sopenharmony_ci{ 27858c2ecf20Sopenharmony_ci struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 27868c2ecf20Sopenharmony_ci void *cookie = p_hwfn->cdev->ops_cookie; 27878c2ecf20Sopenharmony_ci const char *err_str; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci if (err_type > QED_HW_ERR_LAST) 27908c2ecf20Sopenharmony_ci err_type = QED_HW_ERR_LAST; 27918c2ecf20Sopenharmony_ci err_str = qed_hw_err_type_descr[err_type]; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str); 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci /* Call the HW error handler of the protocol driver. 27968c2ecf20Sopenharmony_ci * If it is not available - perform a minimal handling of preventing 27978c2ecf20Sopenharmony_ci * HW attentions from being reasserted. 27988c2ecf20Sopenharmony_ci */ 27998c2ecf20Sopenharmony_ci if (ops && ops->schedule_hw_err_handler) 28008c2ecf20Sopenharmony_ci ops->schedule_hw_err_handler(cookie, err_type); 28018c2ecf20Sopenharmony_ci else 28028c2ecf20Sopenharmony_ci qed_int_attn_clr_enable(p_hwfn->cdev, true); 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_cistatic int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, 28068c2ecf20Sopenharmony_ci void *handle) 28078c2ecf20Sopenharmony_ci{ 28088c2ecf20Sopenharmony_ci return qed_set_queue_coalesce(rx_coal, tx_coal, handle); 28098c2ecf20Sopenharmony_ci} 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_cistatic int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) 28128c2ecf20Sopenharmony_ci{ 28138c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28148c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 28158c2ecf20Sopenharmony_ci int status = 0; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 28188c2ecf20Sopenharmony_ci if (!ptt) 28198c2ecf20Sopenharmony_ci return -EAGAIN; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci status = qed_mcp_set_led(hwfn, ptt, mode); 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci return status; 28268c2ecf20Sopenharmony_ci} 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ciint qed_recovery_process(struct qed_dev *cdev) 28298c2ecf20Sopenharmony_ci{ 28308c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 28318c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 28328c2ecf20Sopenharmony_ci int rc = 0; 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 28358c2ecf20Sopenharmony_ci if (!p_ptt) 28368c2ecf20Sopenharmony_ci return -EAGAIN; 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci rc = qed_start_recovery_process(p_hwfn, p_ptt); 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci return rc; 28438c2ecf20Sopenharmony_ci} 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_cistatic int qed_update_wol(struct qed_dev *cdev, bool enabled) 28468c2ecf20Sopenharmony_ci{ 28478c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28488c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 28498c2ecf20Sopenharmony_ci int rc = 0; 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 28528c2ecf20Sopenharmony_ci return 0; 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 28558c2ecf20Sopenharmony_ci if (!ptt) 28568c2ecf20Sopenharmony_ci return -EAGAIN; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED 28598c2ecf20Sopenharmony_ci : QED_OV_WOL_DISABLED); 28608c2ecf20Sopenharmony_ci if (rc) 28618c2ecf20Sopenharmony_ci goto out; 28628c2ecf20Sopenharmony_ci rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ciout: 28658c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 28668c2ecf20Sopenharmony_ci return rc; 28678c2ecf20Sopenharmony_ci} 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_cistatic int qed_update_drv_state(struct qed_dev *cdev, bool active) 28708c2ecf20Sopenharmony_ci{ 28718c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28728c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 28738c2ecf20Sopenharmony_ci int status = 0; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 28768c2ecf20Sopenharmony_ci return 0; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 28798c2ecf20Sopenharmony_ci if (!ptt) 28808c2ecf20Sopenharmony_ci return -EAGAIN; 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? 28838c2ecf20Sopenharmony_ci QED_OV_DRIVER_STATE_ACTIVE : 28848c2ecf20Sopenharmony_ci QED_OV_DRIVER_STATE_DISABLED); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci return status; 28898c2ecf20Sopenharmony_ci} 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_cistatic int qed_update_mac(struct qed_dev *cdev, u8 *mac) 28928c2ecf20Sopenharmony_ci{ 28938c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28948c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 28958c2ecf20Sopenharmony_ci int status = 0; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 28988c2ecf20Sopenharmony_ci return 0; 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 29018c2ecf20Sopenharmony_ci if (!ptt) 29028c2ecf20Sopenharmony_ci return -EAGAIN; 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci status = qed_mcp_ov_update_mac(hwfn, ptt, mac); 29058c2ecf20Sopenharmony_ci if (status) 29068c2ecf20Sopenharmony_ci goto out; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ciout: 29118c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 29128c2ecf20Sopenharmony_ci return status; 29138c2ecf20Sopenharmony_ci} 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_cistatic int qed_update_mtu(struct qed_dev *cdev, u16 mtu) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29188c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 29198c2ecf20Sopenharmony_ci int status = 0; 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 29228c2ecf20Sopenharmony_ci return 0; 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 29258c2ecf20Sopenharmony_ci if (!ptt) 29268c2ecf20Sopenharmony_ci return -EAGAIN; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); 29298c2ecf20Sopenharmony_ci if (status) 29308c2ecf20Sopenharmony_ci goto out; 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ciout: 29358c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 29368c2ecf20Sopenharmony_ci return status; 29378c2ecf20Sopenharmony_ci} 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_cistatic int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 29408c2ecf20Sopenharmony_ci u8 dev_addr, u32 offset, u32 len) 29418c2ecf20Sopenharmony_ci{ 29428c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29438c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 29448c2ecf20Sopenharmony_ci int rc = 0; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 29478c2ecf20Sopenharmony_ci return 0; 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 29508c2ecf20Sopenharmony_ci if (!ptt) 29518c2ecf20Sopenharmony_ci return -EAGAIN; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr, 29548c2ecf20Sopenharmony_ci offset, len, buf); 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci return rc; 29598c2ecf20Sopenharmony_ci} 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_cistatic int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val) 29628c2ecf20Sopenharmony_ci{ 29638c2ecf20Sopenharmony_ci struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29648c2ecf20Sopenharmony_ci struct qed_ptt *ptt; 29658c2ecf20Sopenharmony_ci int rc = 0; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci if (IS_VF(cdev)) 29688c2ecf20Sopenharmony_ci return 0; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci ptt = qed_ptt_acquire(hwfn); 29718c2ecf20Sopenharmony_ci if (!ptt) 29728c2ecf20Sopenharmony_ci return -EAGAIN; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci rc = qed_dbg_grc_config(hwfn, cfg_id, val); 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci qed_ptt_release(hwfn, ptt); 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci return rc; 29798c2ecf20Sopenharmony_ci} 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_cistatic u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev) 29828c2ecf20Sopenharmony_ci{ 29838c2ecf20Sopenharmony_ci return QED_AFFIN_HWFN_IDX(cdev); 29848c2ecf20Sopenharmony_ci} 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_cistatic struct qed_selftest_ops qed_selftest_ops_pass = { 29878c2ecf20Sopenharmony_ci .selftest_memory = &qed_selftest_memory, 29888c2ecf20Sopenharmony_ci .selftest_interrupt = &qed_selftest_interrupt, 29898c2ecf20Sopenharmony_ci .selftest_register = &qed_selftest_register, 29908c2ecf20Sopenharmony_ci .selftest_clock = &qed_selftest_clock, 29918c2ecf20Sopenharmony_ci .selftest_nvram = &qed_selftest_nvram, 29928c2ecf20Sopenharmony_ci}; 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ciconst struct qed_common_ops qed_common_ops_pass = { 29958c2ecf20Sopenharmony_ci .selftest = &qed_selftest_ops_pass, 29968c2ecf20Sopenharmony_ci .probe = &qed_probe, 29978c2ecf20Sopenharmony_ci .remove = &qed_remove, 29988c2ecf20Sopenharmony_ci .set_power_state = &qed_set_power_state, 29998c2ecf20Sopenharmony_ci .set_name = &qed_set_name, 30008c2ecf20Sopenharmony_ci .update_pf_params = &qed_update_pf_params, 30018c2ecf20Sopenharmony_ci .slowpath_start = &qed_slowpath_start, 30028c2ecf20Sopenharmony_ci .slowpath_stop = &qed_slowpath_stop, 30038c2ecf20Sopenharmony_ci .set_fp_int = &qed_set_int_fp, 30048c2ecf20Sopenharmony_ci .get_fp_int = &qed_get_int_fp, 30058c2ecf20Sopenharmony_ci .sb_init = &qed_sb_init, 30068c2ecf20Sopenharmony_ci .sb_release = &qed_sb_release, 30078c2ecf20Sopenharmony_ci .simd_handler_config = &qed_simd_handler_config, 30088c2ecf20Sopenharmony_ci .simd_handler_clean = &qed_simd_handler_clean, 30098c2ecf20Sopenharmony_ci .dbg_grc = &qed_dbg_grc, 30108c2ecf20Sopenharmony_ci .dbg_grc_size = &qed_dbg_grc_size, 30118c2ecf20Sopenharmony_ci .can_link_change = &qed_can_link_change, 30128c2ecf20Sopenharmony_ci .set_link = &qed_set_link, 30138c2ecf20Sopenharmony_ci .get_link = &qed_get_current_link, 30148c2ecf20Sopenharmony_ci .drain = &qed_drain, 30158c2ecf20Sopenharmony_ci .update_msglvl = &qed_init_dp, 30168c2ecf20Sopenharmony_ci .devlink_register = qed_devlink_register, 30178c2ecf20Sopenharmony_ci .devlink_unregister = qed_devlink_unregister, 30188c2ecf20Sopenharmony_ci .report_fatal_error = qed_report_fatal_error, 30198c2ecf20Sopenharmony_ci .dbg_all_data = &qed_dbg_all_data, 30208c2ecf20Sopenharmony_ci .dbg_all_data_size = &qed_dbg_all_data_size, 30218c2ecf20Sopenharmony_ci .chain_alloc = &qed_chain_alloc, 30228c2ecf20Sopenharmony_ci .chain_free = &qed_chain_free, 30238c2ecf20Sopenharmony_ci .nvm_flash = &qed_nvm_flash, 30248c2ecf20Sopenharmony_ci .nvm_get_image = &qed_nvm_get_image, 30258c2ecf20Sopenharmony_ci .set_coalesce = &qed_set_coalesce, 30268c2ecf20Sopenharmony_ci .set_led = &qed_set_led, 30278c2ecf20Sopenharmony_ci .recovery_process = &qed_recovery_process, 30288c2ecf20Sopenharmony_ci .recovery_prolog = &qed_recovery_prolog, 30298c2ecf20Sopenharmony_ci .attn_clr_enable = &qed_int_attn_clr_enable, 30308c2ecf20Sopenharmony_ci .update_drv_state = &qed_update_drv_state, 30318c2ecf20Sopenharmony_ci .update_mac = &qed_update_mac, 30328c2ecf20Sopenharmony_ci .update_mtu = &qed_update_mtu, 30338c2ecf20Sopenharmony_ci .update_wol = &qed_update_wol, 30348c2ecf20Sopenharmony_ci .db_recovery_add = &qed_db_recovery_add, 30358c2ecf20Sopenharmony_ci .db_recovery_del = &qed_db_recovery_del, 30368c2ecf20Sopenharmony_ci .read_module_eeprom = &qed_read_module_eeprom, 30378c2ecf20Sopenharmony_ci .get_affin_hwfn_idx = &qed_get_affin_hwfn_idx, 30388c2ecf20Sopenharmony_ci .read_nvm_cfg = &qed_nvm_flash_cfg_read, 30398c2ecf20Sopenharmony_ci .read_nvm_cfg_len = &qed_nvm_flash_cfg_len, 30408c2ecf20Sopenharmony_ci .set_grc_config = &qed_set_grc_config, 30418c2ecf20Sopenharmony_ci}; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_civoid qed_get_protocol_stats(struct qed_dev *cdev, 30448c2ecf20Sopenharmony_ci enum qed_mcp_protocol_type type, 30458c2ecf20Sopenharmony_ci union qed_mcp_protocol_stats *stats) 30468c2ecf20Sopenharmony_ci{ 30478c2ecf20Sopenharmony_ci struct qed_eth_stats eth_stats; 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci switch (type) { 30528c2ecf20Sopenharmony_ci case QED_MCP_LAN_STATS: 30538c2ecf20Sopenharmony_ci qed_get_vport_stats(cdev, ð_stats); 30548c2ecf20Sopenharmony_ci stats->lan_stats.ucast_rx_pkts = 30558c2ecf20Sopenharmony_ci eth_stats.common.rx_ucast_pkts; 30568c2ecf20Sopenharmony_ci stats->lan_stats.ucast_tx_pkts = 30578c2ecf20Sopenharmony_ci eth_stats.common.tx_ucast_pkts; 30588c2ecf20Sopenharmony_ci stats->lan_stats.fcs_err = -1; 30598c2ecf20Sopenharmony_ci break; 30608c2ecf20Sopenharmony_ci case QED_MCP_FCOE_STATS: 30618c2ecf20Sopenharmony_ci qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); 30628c2ecf20Sopenharmony_ci break; 30638c2ecf20Sopenharmony_ci case QED_MCP_ISCSI_STATS: 30648c2ecf20Sopenharmony_ci qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); 30658c2ecf20Sopenharmony_ci break; 30668c2ecf20Sopenharmony_ci default: 30678c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_SP, 30688c2ecf20Sopenharmony_ci "Invalid protocol type = %d\n", type); 30698c2ecf20Sopenharmony_ci return; 30708c2ecf20Sopenharmony_ci } 30718c2ecf20Sopenharmony_ci} 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ciint qed_mfw_tlv_req(struct qed_hwfn *hwfn) 30748c2ecf20Sopenharmony_ci{ 30758c2ecf20Sopenharmony_ci DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 30768c2ecf20Sopenharmony_ci "Scheduling slowpath task [Flag: %d]\n", 30778c2ecf20Sopenharmony_ci QED_SLOWPATH_MFW_TLV_REQ); 30788c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 30798c2ecf20Sopenharmony_ci set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags); 30808c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 30818c2ecf20Sopenharmony_ci queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci return 0; 30848c2ecf20Sopenharmony_ci} 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_cistatic void 30878c2ecf20Sopenharmony_ciqed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv) 30888c2ecf20Sopenharmony_ci{ 30898c2ecf20Sopenharmony_ci struct qed_common_cb_ops *op = cdev->protocol_ops.common; 30908c2ecf20Sopenharmony_ci struct qed_eth_stats_common *p_common; 30918c2ecf20Sopenharmony_ci struct qed_generic_tlvs gen_tlvs; 30928c2ecf20Sopenharmony_ci struct qed_eth_stats stats; 30938c2ecf20Sopenharmony_ci int i; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci memset(&gen_tlvs, 0, sizeof(gen_tlvs)); 30968c2ecf20Sopenharmony_ci op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs); 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM) 30998c2ecf20Sopenharmony_ci tlv->flags.ipv4_csum_offload = true; 31008c2ecf20Sopenharmony_ci if (gen_tlvs.feat_flags & QED_TLV_LSO) 31018c2ecf20Sopenharmony_ci tlv->flags.lso_supported = true; 31028c2ecf20Sopenharmony_ci tlv->flags.b_set = true; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci for (i = 0; i < QED_TLV_MAC_COUNT; i++) { 31058c2ecf20Sopenharmony_ci if (is_valid_ether_addr(gen_tlvs.mac[i])) { 31068c2ecf20Sopenharmony_ci ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]); 31078c2ecf20Sopenharmony_ci tlv->mac_set[i] = true; 31088c2ecf20Sopenharmony_ci } 31098c2ecf20Sopenharmony_ci } 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci qed_get_vport_stats(cdev, &stats); 31128c2ecf20Sopenharmony_ci p_common = &stats.common; 31138c2ecf20Sopenharmony_ci tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 31148c2ecf20Sopenharmony_ci p_common->rx_bcast_pkts; 31158c2ecf20Sopenharmony_ci tlv->rx_frames_set = true; 31168c2ecf20Sopenharmony_ci tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 31178c2ecf20Sopenharmony_ci p_common->rx_bcast_bytes; 31188c2ecf20Sopenharmony_ci tlv->rx_bytes_set = true; 31198c2ecf20Sopenharmony_ci tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 31208c2ecf20Sopenharmony_ci p_common->tx_bcast_pkts; 31218c2ecf20Sopenharmony_ci tlv->tx_frames_set = true; 31228c2ecf20Sopenharmony_ci tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 31238c2ecf20Sopenharmony_ci p_common->tx_bcast_bytes; 31248c2ecf20Sopenharmony_ci tlv->rx_bytes_set = true; 31258c2ecf20Sopenharmony_ci} 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ciint qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type, 31288c2ecf20Sopenharmony_ci union qed_mfw_tlv_data *tlv_buf) 31298c2ecf20Sopenharmony_ci{ 31308c2ecf20Sopenharmony_ci struct qed_dev *cdev = hwfn->cdev; 31318c2ecf20Sopenharmony_ci struct qed_common_cb_ops *ops; 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci ops = cdev->protocol_ops.common; 31348c2ecf20Sopenharmony_ci if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) { 31358c2ecf20Sopenharmony_ci DP_NOTICE(hwfn, "Can't collect TLV management info\n"); 31368c2ecf20Sopenharmony_ci return -EINVAL; 31378c2ecf20Sopenharmony_ci } 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci switch (type) { 31408c2ecf20Sopenharmony_ci case QED_MFW_TLV_GENERIC: 31418c2ecf20Sopenharmony_ci qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic); 31428c2ecf20Sopenharmony_ci break; 31438c2ecf20Sopenharmony_ci case QED_MFW_TLV_ETH: 31448c2ecf20Sopenharmony_ci ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth); 31458c2ecf20Sopenharmony_ci break; 31468c2ecf20Sopenharmony_ci case QED_MFW_TLV_FCOE: 31478c2ecf20Sopenharmony_ci ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe); 31488c2ecf20Sopenharmony_ci break; 31498c2ecf20Sopenharmony_ci case QED_MFW_TLV_ISCSI: 31508c2ecf20Sopenharmony_ci ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi); 31518c2ecf20Sopenharmony_ci break; 31528c2ecf20Sopenharmony_ci default: 31538c2ecf20Sopenharmony_ci break; 31548c2ecf20Sopenharmony_ci } 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci return 0; 31578c2ecf20Sopenharmony_ci} 3158