11f4d4ed6SAlexander Lobakin // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2fe56b9e6SYuval Mintz /* QLogic qed NIC Driver 3e8f1cb50SMintz, Yuval * Copyright (c) 2015-2017 QLogic Corporation 4663eacd8SAlexander Lobakin * Copyright (c) 2019-2020 Marvell International Ltd. 5fe56b9e6SYuval Mintz */ 6fe56b9e6SYuval Mintz 7fe56b9e6SYuval Mintz #include <linux/stddef.h> 8fe56b9e6SYuval Mintz #include <linux/pci.h> 9fe56b9e6SYuval Mintz #include <linux/kernel.h> 10fe56b9e6SYuval Mintz #include <linux/slab.h> 11fe56b9e6SYuval Mintz #include <linux/delay.h> 12fe56b9e6SYuval Mintz #include <asm/byteorder.h> 13fe56b9e6SYuval Mintz #include <linux/dma-mapping.h> 14fe56b9e6SYuval Mintz #include <linux/string.h> 15fe56b9e6SYuval Mintz #include <linux/module.h> 16fe56b9e6SYuval Mintz #include <linux/interrupt.h> 17fe56b9e6SYuval Mintz #include <linux/workqueue.h> 18fe56b9e6SYuval Mintz #include <linux/ethtool.h> 19fe56b9e6SYuval Mintz #include <linux/etherdevice.h> 20fe56b9e6SYuval Mintz #include <linux/vmalloc.h> 215d24bcf1STomer Tayar #include <linux/crash_dump.h> 223a69cae8SSudarsana Reddy Kalluru #include <linux/crc32.h> 23fe56b9e6SYuval Mintz #include <linux/qed/qed_if.h> 240a7fb11cSYuval Mintz #include <linux/qed/qed_ll2_if.h> 2524e04879SMichal Kalderon #include <net/devlink.h> 262196d831SSudarsana Reddy Kalluru #include <linux/aer.h> 27bdb5d8ecSAlexander Lobakin #include <linux/phylink.h> 28fe56b9e6SYuval Mintz 29fe56b9e6SYuval Mintz #include "qed.h" 3037bff2b9SYuval Mintz #include "qed_sriov.h" 31fe56b9e6SYuval Mintz #include "qed_sp.h" 32fe56b9e6SYuval Mintz #include "qed_dev_api.h" 330a7fb11cSYuval Mintz #include "qed_ll2.h" 341e128c81SArun Easi #include "qed_fcoe.h" 352f2b2614SMintz, Yuval #include "qed_iscsi.h" 362f2b2614SMintz, Yuval 37fe56b9e6SYuval Mintz #include "qed_mcp.h" 38c56a8be7SRahul Verma #include "qed_reg_addr.h" 39fe56b9e6SYuval Mintz #include "qed_hw.h" 4003dc76caSSudarsana Reddy Kalluru #include "qed_selftest.h" 411e128c81SArun Easi #include "qed_debug.h" 4252306deeSIgor Russkikh #include "qed_devlink.h" 43fe56b9e6SYuval Mintz 4451ff1725SRam Amrani #define QED_ROCE_QPS (8192) 4551ff1725SRam Amrani #define QED_ROCE_DPIS (8) 4639dbc646SYuval Bason #define QED_RDMA_SRQS QED_ROCE_QPS 472d4c8495SSudarsana Reddy Kalluru #define QED_NVM_CFG_GET_FLAGS 0xA 482d4c8495SSudarsana Reddy Kalluru #define QED_NVM_CFG_GET_PF_FLAGS 0x1A 49c63b0968SSudarsana Reddy Kalluru #define QED_NVM_CFG_MAX_ATTRS 50 5051ff1725SRam Amrani 515abd7e92SYuval Mintz static char version[] = 525abd7e92SYuval Mintz "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; 53fe56b9e6SYuval Mintz 545abd7e92SYuval Mintz MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module"); 55fe56b9e6SYuval Mintz MODULE_LICENSE("GPL"); 56fe56b9e6SYuval Mintz MODULE_VERSION(DRV_MODULE_VERSION); 57fe56b9e6SYuval Mintz 58fe56b9e6SYuval Mintz #define FW_FILE_VERSION \ 59fe56b9e6SYuval Mintz __stringify(FW_MAJOR_VERSION) "." \ 60fe56b9e6SYuval Mintz __stringify(FW_MINOR_VERSION) "." \ 61fe56b9e6SYuval Mintz __stringify(FW_REVISION_VERSION) "." \ 62fe56b9e6SYuval Mintz __stringify(FW_ENGINEERING_VERSION) 63fe56b9e6SYuval Mintz 64fe56b9e6SYuval Mintz #define QED_FW_FILE_NAME \ 65fe56b9e6SYuval Mintz "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" 66fe56b9e6SYuval Mintz 67d43d3f0fSYuval Mintz MODULE_FIRMWARE(QED_FW_FILE_NAME); 68d43d3f0fSYuval Mintz 69097818fcSAlexander Lobakin /* MFW speed capabilities maps */ 70097818fcSAlexander Lobakin 71097818fcSAlexander Lobakin struct qed_mfw_speed_map { 72097818fcSAlexander Lobakin u32 mfw_val; 73097818fcSAlexander Lobakin __ETHTOOL_DECLARE_LINK_MODE_MASK(caps); 74097818fcSAlexander Lobakin 75097818fcSAlexander Lobakin const u32 *cap_arr; 76097818fcSAlexander Lobakin u32 arr_size; 77097818fcSAlexander Lobakin }; 78097818fcSAlexander Lobakin 79097818fcSAlexander Lobakin #define QED_MFW_SPEED_MAP(type, arr) \ 80097818fcSAlexander Lobakin { \ 81097818fcSAlexander Lobakin .mfw_val = (type), \ 82097818fcSAlexander Lobakin .cap_arr = (arr), \ 83097818fcSAlexander Lobakin .arr_size = ARRAY_SIZE(arr), \ 84097818fcSAlexander Lobakin } 85097818fcSAlexander Lobakin 8699785a87SAlexander Lobakin static const u32 qed_mfw_ext_1g[] __initconst = { 8799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 8899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 8999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 9099785a87SAlexander Lobakin }; 9199785a87SAlexander Lobakin 9299785a87SAlexander Lobakin static const u32 qed_mfw_ext_10g[] __initconst = { 9399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 9499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 9599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 9699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 9799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 9899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 9999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 10099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 10199785a87SAlexander Lobakin }; 10299785a87SAlexander Lobakin 10399785a87SAlexander Lobakin static const u32 qed_mfw_ext_20g[] __initconst = { 10499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 10599785a87SAlexander Lobakin }; 10699785a87SAlexander Lobakin 10799785a87SAlexander Lobakin static const u32 qed_mfw_ext_25g[] __initconst = { 10899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 10999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 11099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 11199785a87SAlexander Lobakin }; 11299785a87SAlexander Lobakin 11399785a87SAlexander Lobakin static const u32 qed_mfw_ext_40g[] __initconst = { 11499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 11599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 11699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 11799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 11899785a87SAlexander Lobakin }; 11999785a87SAlexander Lobakin 12099785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r[] __initconst = { 12199785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 12299785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 12399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 12499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 12599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 12699785a87SAlexander Lobakin }; 12799785a87SAlexander Lobakin 12899785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r2[] __initconst = { 12999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 13099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 13199785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 13299785a87SAlexander Lobakin }; 13399785a87SAlexander Lobakin 13499785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r2[] __initconst = { 13599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 13699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 13799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 13899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 13999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 14099785a87SAlexander Lobakin }; 14199785a87SAlexander Lobakin 14299785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r4[] __initconst = { 14399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 14499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 14599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 14699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 14799785a87SAlexander Lobakin }; 14899785a87SAlexander Lobakin 14999785a87SAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_ext_maps[] __ro_after_init = { 15099785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_1G, qed_mfw_ext_1g), 15199785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_10G, qed_mfw_ext_10g), 15299785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_20G, qed_mfw_ext_20g), 15399785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_25G, qed_mfw_ext_25g), 15499785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_40G, qed_mfw_ext_40g), 15599785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R, 15699785a87SAlexander Lobakin qed_mfw_ext_50g_base_r), 15799785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R2, 15899785a87SAlexander Lobakin qed_mfw_ext_50g_base_r2), 15999785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R2, 16099785a87SAlexander Lobakin qed_mfw_ext_100g_base_r2), 16199785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R4, 16299785a87SAlexander Lobakin qed_mfw_ext_100g_base_r4), 16399785a87SAlexander Lobakin }; 16499785a87SAlexander Lobakin 165097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_1g[] __initconst = { 166097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 167097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 168097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 169097818fcSAlexander Lobakin }; 170097818fcSAlexander Lobakin 171097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_10g[] __initconst = { 172097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 173097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 174097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 175097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 176097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 177097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 178097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 179097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 180097818fcSAlexander Lobakin }; 181097818fcSAlexander Lobakin 182097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_20g[] __initconst = { 183097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 184097818fcSAlexander Lobakin }; 185097818fcSAlexander Lobakin 186097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_25g[] __initconst = { 187097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 188097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 189097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 190097818fcSAlexander Lobakin }; 191097818fcSAlexander Lobakin 192097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_40g[] __initconst = { 193097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 194097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 195097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 196097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 197097818fcSAlexander Lobakin }; 198097818fcSAlexander Lobakin 199097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_50g[] __initconst = { 200097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 201097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 202097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 203097818fcSAlexander Lobakin }; 204097818fcSAlexander Lobakin 205097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_bb_100g[] __initconst = { 206097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 207097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 208097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 209097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 210097818fcSAlexander Lobakin }; 211097818fcSAlexander Lobakin 212097818fcSAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_legacy_maps[] __ro_after_init = { 213097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G, 214097818fcSAlexander Lobakin qed_mfw_legacy_1g), 215097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G, 216097818fcSAlexander Lobakin qed_mfw_legacy_10g), 217097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G, 218097818fcSAlexander Lobakin qed_mfw_legacy_20g), 219097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G, 220097818fcSAlexander Lobakin qed_mfw_legacy_25g), 221097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G, 222097818fcSAlexander Lobakin qed_mfw_legacy_40g), 223097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G, 224097818fcSAlexander Lobakin qed_mfw_legacy_50g), 225097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G, 226097818fcSAlexander Lobakin qed_mfw_legacy_bb_100g), 227097818fcSAlexander Lobakin }; 228097818fcSAlexander Lobakin 229097818fcSAlexander Lobakin static void __init qed_mfw_speed_map_populate(struct qed_mfw_speed_map *map) 230097818fcSAlexander Lobakin { 231097818fcSAlexander Lobakin linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps); 232097818fcSAlexander Lobakin 233097818fcSAlexander Lobakin map->cap_arr = NULL; 234097818fcSAlexander Lobakin map->arr_size = 0; 235097818fcSAlexander Lobakin } 236097818fcSAlexander Lobakin 237097818fcSAlexander Lobakin static void __init qed_mfw_speed_maps_init(void) 238097818fcSAlexander Lobakin { 239097818fcSAlexander Lobakin u32 i; 240097818fcSAlexander Lobakin 24199785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) 24299785a87SAlexander Lobakin qed_mfw_speed_map_populate(qed_mfw_ext_maps + i); 24399785a87SAlexander Lobakin 244097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) 245097818fcSAlexander Lobakin qed_mfw_speed_map_populate(qed_mfw_legacy_maps + i); 246097818fcSAlexander Lobakin } 247097818fcSAlexander Lobakin 248fe56b9e6SYuval Mintz static int __init qed_init(void) 249fe56b9e6SYuval Mintz { 250fe56b9e6SYuval Mintz pr_info("%s", version); 251fe56b9e6SYuval Mintz 252097818fcSAlexander Lobakin qed_mfw_speed_maps_init(); 253097818fcSAlexander Lobakin 254fe56b9e6SYuval Mintz return 0; 255fe56b9e6SYuval Mintz } 256fe56b9e6SYuval Mintz module_init(qed_init); 257097818fcSAlexander Lobakin 258097818fcSAlexander Lobakin static void __exit qed_exit(void) 259097818fcSAlexander Lobakin { 260097818fcSAlexander Lobakin /* To prevent marking this module as "permanent" */ 261097818fcSAlexander Lobakin } 262097818fcSAlexander Lobakin module_exit(qed_exit); 263fe56b9e6SYuval Mintz 264fe56b9e6SYuval Mintz /* Check if the DMA controller on the machine can properly handle the DMA 265fe56b9e6SYuval Mintz * addressing required by the device. 266fe56b9e6SYuval Mintz */ 267fe56b9e6SYuval Mintz static int qed_set_coherency_mask(struct qed_dev *cdev) 268fe56b9e6SYuval Mintz { 269fe56b9e6SYuval Mintz struct device *dev = &cdev->pdev->dev; 270fe56b9e6SYuval Mintz 271fe56b9e6SYuval Mintz if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { 272fe56b9e6SYuval Mintz if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { 273fe56b9e6SYuval Mintz DP_NOTICE(cdev, 274fe56b9e6SYuval Mintz "Can't request 64-bit consistent allocations\n"); 275fe56b9e6SYuval Mintz return -EIO; 276fe56b9e6SYuval Mintz } 277fe56b9e6SYuval Mintz } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { 278fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); 279fe56b9e6SYuval Mintz return -EIO; 280fe56b9e6SYuval Mintz } 281fe56b9e6SYuval Mintz 282fe56b9e6SYuval Mintz return 0; 283fe56b9e6SYuval Mintz } 284fe56b9e6SYuval Mintz 285fe56b9e6SYuval Mintz static void qed_free_pci(struct qed_dev *cdev) 286fe56b9e6SYuval Mintz { 287fe56b9e6SYuval Mintz struct pci_dev *pdev = cdev->pdev; 288fe56b9e6SYuval Mintz 2892196d831SSudarsana Reddy Kalluru pci_disable_pcie_error_reporting(pdev); 2902196d831SSudarsana Reddy Kalluru 2911a850bfcSMintz, Yuval if (cdev->doorbells && cdev->db_size) 292fe56b9e6SYuval Mintz iounmap(cdev->doorbells); 293fe56b9e6SYuval Mintz if (cdev->regview) 294fe56b9e6SYuval Mintz iounmap(cdev->regview); 295fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) 296fe56b9e6SYuval Mintz pci_release_regions(pdev); 297fe56b9e6SYuval Mintz 298fe56b9e6SYuval Mintz pci_disable_device(pdev); 299fe56b9e6SYuval Mintz } 300fe56b9e6SYuval Mintz 3010dfaba6dSYuval Mintz #define PCI_REVISION_ID_ERROR_VAL 0xff 3020dfaba6dSYuval Mintz 303fe56b9e6SYuval Mintz /* Performs PCI initializations as well as initializing PCI-related parameters 304fe56b9e6SYuval Mintz * in the device structrue. Returns 0 in case of success. 305fe56b9e6SYuval Mintz */ 3061a635e48SYuval Mintz static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) 307fe56b9e6SYuval Mintz { 3080dfaba6dSYuval Mintz u8 rev_id; 309fe56b9e6SYuval Mintz int rc; 310fe56b9e6SYuval Mintz 311fe56b9e6SYuval Mintz cdev->pdev = pdev; 312fe56b9e6SYuval Mintz 313fe56b9e6SYuval Mintz rc = pci_enable_device(pdev); 314fe56b9e6SYuval Mintz if (rc) { 315fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot enable PCI device\n"); 316fe56b9e6SYuval Mintz goto err0; 317fe56b9e6SYuval Mintz } 318fe56b9e6SYuval Mintz 319fe56b9e6SYuval Mintz if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 320fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #0\n"); 321fe56b9e6SYuval Mintz rc = -EIO; 322fe56b9e6SYuval Mintz goto err1; 323fe56b9e6SYuval Mintz } 324fe56b9e6SYuval Mintz 3251408cc1fSYuval Mintz if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 326fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #2\n"); 327fe56b9e6SYuval Mintz rc = -EIO; 328fe56b9e6SYuval Mintz goto err1; 329fe56b9e6SYuval Mintz } 330fe56b9e6SYuval Mintz 331fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) { 332fe56b9e6SYuval Mintz rc = pci_request_regions(pdev, "qed"); 333fe56b9e6SYuval Mintz if (rc) { 334fe56b9e6SYuval Mintz DP_NOTICE(cdev, 335fe56b9e6SYuval Mintz "Failed to request PCI memory resources\n"); 336fe56b9e6SYuval Mintz goto err1; 337fe56b9e6SYuval Mintz } 338fe56b9e6SYuval Mintz pci_set_master(pdev); 339fe56b9e6SYuval Mintz pci_save_state(pdev); 340fe56b9e6SYuval Mintz } 341fe56b9e6SYuval Mintz 3420dfaba6dSYuval Mintz pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 3430dfaba6dSYuval Mintz if (rev_id == PCI_REVISION_ID_ERROR_VAL) { 3440dfaba6dSYuval Mintz DP_NOTICE(cdev, 3450dfaba6dSYuval Mintz "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", 3460dfaba6dSYuval Mintz rev_id); 3470dfaba6dSYuval Mintz rc = -ENODEV; 3480dfaba6dSYuval Mintz goto err2; 3490dfaba6dSYuval Mintz } 350fe56b9e6SYuval Mintz if (!pci_is_pcie(pdev)) { 351fe56b9e6SYuval Mintz DP_NOTICE(cdev, "The bus is not PCI Express\n"); 352fe56b9e6SYuval Mintz rc = -EIO; 353fe56b9e6SYuval Mintz goto err2; 354fe56b9e6SYuval Mintz } 355fe56b9e6SYuval Mintz 356fe56b9e6SYuval Mintz cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); 357416cdf06SYuval Mintz if (IS_PF(cdev) && !cdev->pci_params.pm_cap) 358fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot find power management capability\n"); 359fe56b9e6SYuval Mintz 360fe56b9e6SYuval Mintz rc = qed_set_coherency_mask(cdev); 361fe56b9e6SYuval Mintz if (rc) 362fe56b9e6SYuval Mintz goto err2; 363fe56b9e6SYuval Mintz 364fe56b9e6SYuval Mintz cdev->pci_params.mem_start = pci_resource_start(pdev, 0); 365fe56b9e6SYuval Mintz cdev->pci_params.mem_end = pci_resource_end(pdev, 0); 366fe56b9e6SYuval Mintz cdev->pci_params.irq = pdev->irq; 367fe56b9e6SYuval Mintz 368fe56b9e6SYuval Mintz cdev->regview = pci_ioremap_bar(pdev, 0); 369fe56b9e6SYuval Mintz if (!cdev->regview) { 370fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map register space, aborting\n"); 371fe56b9e6SYuval Mintz rc = -ENOMEM; 372fe56b9e6SYuval Mintz goto err2; 373fe56b9e6SYuval Mintz } 374fe56b9e6SYuval Mintz 375fe56b9e6SYuval Mintz cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); 376fe56b9e6SYuval Mintz cdev->db_size = pci_resource_len(cdev->pdev, 2); 3771a850bfcSMintz, Yuval if (!cdev->db_size) { 3781a850bfcSMintz, Yuval if (IS_PF(cdev)) { 3791a850bfcSMintz, Yuval DP_NOTICE(cdev, "No Doorbell bar available\n"); 3801a850bfcSMintz, Yuval return -EINVAL; 3811a850bfcSMintz, Yuval } else { 3821a850bfcSMintz, Yuval return 0; 3831a850bfcSMintz, Yuval } 3841a850bfcSMintz, Yuval } 3851a850bfcSMintz, Yuval 386fe56b9e6SYuval Mintz cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); 3871a850bfcSMintz, Yuval 388fe56b9e6SYuval Mintz if (!cdev->doorbells) { 389fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map doorbell space\n"); 390fe56b9e6SYuval Mintz return -ENOMEM; 391fe56b9e6SYuval Mintz } 392fe56b9e6SYuval Mintz 3932196d831SSudarsana Reddy Kalluru /* AER (Advanced Error reporting) configuration */ 3942196d831SSudarsana Reddy Kalluru rc = pci_enable_pcie_error_reporting(pdev); 3952196d831SSudarsana Reddy Kalluru if (rc) 3962196d831SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 3972196d831SSudarsana Reddy Kalluru "Failed to configure PCIe AER [%d]\n", rc); 3982196d831SSudarsana Reddy Kalluru 399fe56b9e6SYuval Mintz return 0; 400fe56b9e6SYuval Mintz 401fe56b9e6SYuval Mintz err2: 402fe56b9e6SYuval Mintz pci_release_regions(pdev); 403fe56b9e6SYuval Mintz err1: 404fe56b9e6SYuval Mintz pci_disable_device(pdev); 405fe56b9e6SYuval Mintz err0: 406fe56b9e6SYuval Mintz return rc; 407fe56b9e6SYuval Mintz } 408fe56b9e6SYuval Mintz 409fe56b9e6SYuval Mintz int qed_fill_dev_info(struct qed_dev *cdev, 410fe56b9e6SYuval Mintz struct qed_dev_info *dev_info) 411fe56b9e6SYuval Mintz { 412c851a9dcSKalderon, Michal struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 413c851a9dcSKalderon, Michal struct qed_hw_info *hw_info = &p_hwfn->hw_info; 41419489c7fSChopra, Manish struct qed_tunnel_info *tun = &cdev->tunnel; 415cee4d264SManish Chopra struct qed_ptt *ptt; 416cee4d264SManish Chopra 417fe56b9e6SYuval Mintz memset(dev_info, 0, sizeof(struct qed_dev_info)); 418fe56b9e6SYuval Mintz 41919489c7fSChopra, Manish if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 42019489c7fSChopra, Manish tun->vxlan.b_mode_enabled) 42119489c7fSChopra, Manish dev_info->vxlan_enable = true; 42219489c7fSChopra, Manish 42319489c7fSChopra, Manish if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && 42419489c7fSChopra, Manish tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 42519489c7fSChopra, Manish tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 42619489c7fSChopra, Manish dev_info->gre_enable = true; 42719489c7fSChopra, Manish 42819489c7fSChopra, Manish if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && 42919489c7fSChopra, Manish tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 43019489c7fSChopra, Manish tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 43119489c7fSChopra, Manish dev_info->geneve_enable = true; 43219489c7fSChopra, Manish 433fe56b9e6SYuval Mintz dev_info->num_hwfns = cdev->num_hwfns; 434fe56b9e6SYuval Mintz dev_info->pci_mem_start = cdev->pci_params.mem_start; 435fe56b9e6SYuval Mintz dev_info->pci_mem_end = cdev->pci_params.mem_end; 436fe56b9e6SYuval Mintz dev_info->pci_irq = cdev->pci_params.irq; 437c851a9dcSKalderon, Michal dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn); 4389c79ddaaSMintz, Yuval dev_info->dev_type = cdev->type; 439c851a9dcSKalderon, Michal ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr); 440fe56b9e6SYuval Mintz 4411408cc1fSYuval Mintz if (IS_PF(cdev)) { 442fe56b9e6SYuval Mintz dev_info->fw_major = FW_MAJOR_VERSION; 443fe56b9e6SYuval Mintz dev_info->fw_minor = FW_MINOR_VERSION; 444fe56b9e6SYuval Mintz dev_info->fw_rev = FW_REVISION_VERSION; 445fe56b9e6SYuval Mintz dev_info->fw_eng = FW_ENGINEERING_VERSION; 4460bc5fe85SSudarsana Reddy Kalluru dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH, 4470bc5fe85SSudarsana Reddy Kalluru &cdev->mf_bits); 448831bfb0eSYuval Mintz dev_info->tx_switching = true; 44914d39648SMintz, Yuval 450c851a9dcSKalderon, Michal if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME) 45114d39648SMintz, Yuval dev_info->wol_support = true; 4523c5da942SMintz, Yuval 453df9c716dSSudarsana Reddy Kalluru dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn); 454df9c716dSSudarsana Reddy Kalluru 4553c5da942SMintz, Yuval dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; 4561408cc1fSYuval Mintz } else { 4571408cc1fSYuval Mintz qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, 4581408cc1fSYuval Mintz &dev_info->fw_minor, &dev_info->fw_rev, 4591408cc1fSYuval Mintz &dev_info->fw_eng); 4601408cc1fSYuval Mintz } 461fe56b9e6SYuval Mintz 4621408cc1fSYuval Mintz if (IS_PF(cdev)) { 463cee4d264SManish Chopra ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 464cee4d264SManish Chopra if (ptt) { 4651408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, 4661408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 4671408cc1fSYuval Mintz 468ae33666aSTomer Tayar qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, 469ae33666aSTomer Tayar &dev_info->mbi_version); 470ae33666aSTomer Tayar 471cee4d264SManish Chopra qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, 472cee4d264SManish Chopra &dev_info->flash_size); 473cee4d264SManish Chopra 474cee4d264SManish Chopra qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); 475cee4d264SManish Chopra } 4761408cc1fSYuval Mintz } else { 4771408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, 4781408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 4791408cc1fSYuval Mintz } 480cee4d264SManish Chopra 481c851a9dcSKalderon, Michal dev_info->mtu = hw_info->mtu; 4820fefbfbaSSudarsana Kalluru 483fe56b9e6SYuval Mintz return 0; 484fe56b9e6SYuval Mintz } 485fe56b9e6SYuval Mintz 486fe56b9e6SYuval Mintz static void qed_free_cdev(struct qed_dev *cdev) 487fe56b9e6SYuval Mintz { 488fe56b9e6SYuval Mintz kfree((void *)cdev); 489fe56b9e6SYuval Mintz } 490fe56b9e6SYuval Mintz 491fe56b9e6SYuval Mintz static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) 492fe56b9e6SYuval Mintz { 493fe56b9e6SYuval Mintz struct qed_dev *cdev; 494fe56b9e6SYuval Mintz 495fe56b9e6SYuval Mintz cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 496fe56b9e6SYuval Mintz if (!cdev) 497fe56b9e6SYuval Mintz return cdev; 498fe56b9e6SYuval Mintz 499fe56b9e6SYuval Mintz qed_init_struct(cdev); 500fe56b9e6SYuval Mintz 501fe56b9e6SYuval Mintz return cdev; 502fe56b9e6SYuval Mintz } 503fe56b9e6SYuval Mintz 504fe56b9e6SYuval Mintz /* Sets the requested power state */ 5051a635e48SYuval Mintz static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) 506fe56b9e6SYuval Mintz { 507fe56b9e6SYuval Mintz if (!cdev) 508fe56b9e6SYuval Mintz return -ENODEV; 509fe56b9e6SYuval Mintz 510fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); 511fe56b9e6SYuval Mintz return 0; 512fe56b9e6SYuval Mintz } 513fe56b9e6SYuval Mintz 514fe56b9e6SYuval Mintz /* probing */ 515fe56b9e6SYuval Mintz static struct qed_dev *qed_probe(struct pci_dev *pdev, 5161408cc1fSYuval Mintz struct qed_probe_params *params) 517fe56b9e6SYuval Mintz { 518fe56b9e6SYuval Mintz struct qed_dev *cdev; 519fe56b9e6SYuval Mintz int rc; 520fe56b9e6SYuval Mintz 521fe56b9e6SYuval Mintz cdev = qed_alloc_cdev(pdev); 522fe56b9e6SYuval Mintz if (!cdev) 523fe56b9e6SYuval Mintz goto err0; 524fe56b9e6SYuval Mintz 525712c3cbfSMintz, Yuval cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; 5261408cc1fSYuval Mintz cdev->protocol = params->protocol; 527fe56b9e6SYuval Mintz 5281408cc1fSYuval Mintz if (params->is_vf) 5291408cc1fSYuval Mintz cdev->b_is_vf = true; 5301408cc1fSYuval Mintz 5311408cc1fSYuval Mintz qed_init_dp(cdev, params->dp_module, params->dp_level); 532fe56b9e6SYuval Mintz 53364515dc8STomer Tayar cdev->recov_in_prog = params->recov_in_prog; 53464515dc8STomer Tayar 535fe56b9e6SYuval Mintz rc = qed_init_pci(cdev, pdev); 536fe56b9e6SYuval Mintz if (rc) { 537fe56b9e6SYuval Mintz DP_ERR(cdev, "init pci failed\n"); 538fe56b9e6SYuval Mintz goto err1; 539fe56b9e6SYuval Mintz } 540fe56b9e6SYuval Mintz DP_INFO(cdev, "PCI init completed successfully\n"); 541fe56b9e6SYuval Mintz 542fe56b9e6SYuval Mintz rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); 543fe56b9e6SYuval Mintz if (rc) { 544fe56b9e6SYuval Mintz DP_ERR(cdev, "hw prepare failed\n"); 545fe56b9e6SYuval Mintz goto err2; 546fe56b9e6SYuval Mintz } 547fe56b9e6SYuval Mintz 54820c4515aSEwan D. Milne DP_INFO(cdev, "qed_probe completed successfully\n"); 549fe56b9e6SYuval Mintz 550fe56b9e6SYuval Mintz return cdev; 551fe56b9e6SYuval Mintz 552fe56b9e6SYuval Mintz err2: 553fe56b9e6SYuval Mintz qed_free_pci(cdev); 554fe56b9e6SYuval Mintz err1: 555fe56b9e6SYuval Mintz qed_free_cdev(cdev); 556fe56b9e6SYuval Mintz err0: 557fe56b9e6SYuval Mintz return NULL; 558fe56b9e6SYuval Mintz } 559fe56b9e6SYuval Mintz 560fe56b9e6SYuval Mintz static void qed_remove(struct qed_dev *cdev) 561fe56b9e6SYuval Mintz { 562fe56b9e6SYuval Mintz if (!cdev) 563fe56b9e6SYuval Mintz return; 564fe56b9e6SYuval Mintz 565fe56b9e6SYuval Mintz qed_hw_remove(cdev); 566fe56b9e6SYuval Mintz 567fe56b9e6SYuval Mintz qed_free_pci(cdev); 568fe56b9e6SYuval Mintz 569fe56b9e6SYuval Mintz qed_set_power_state(cdev, PCI_D3hot); 570fe56b9e6SYuval Mintz 571fe56b9e6SYuval Mintz qed_free_cdev(cdev); 572fe56b9e6SYuval Mintz } 573fe56b9e6SYuval Mintz 574fe56b9e6SYuval Mintz static void qed_disable_msix(struct qed_dev *cdev) 575fe56b9e6SYuval Mintz { 576fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 577fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 578fe56b9e6SYuval Mintz kfree(cdev->int_params.msix_table); 579fe56b9e6SYuval Mintz } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { 580fe56b9e6SYuval Mintz pci_disable_msi(cdev->pdev); 581fe56b9e6SYuval Mintz } 582fe56b9e6SYuval Mintz 583fe56b9e6SYuval Mintz memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); 584fe56b9e6SYuval Mintz } 585fe56b9e6SYuval Mintz 586fe56b9e6SYuval Mintz static int qed_enable_msix(struct qed_dev *cdev, 587fe56b9e6SYuval Mintz struct qed_int_params *int_params) 588fe56b9e6SYuval Mintz { 589fe56b9e6SYuval Mintz int i, rc, cnt; 590fe56b9e6SYuval Mintz 591fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 592fe56b9e6SYuval Mintz 593fe56b9e6SYuval Mintz for (i = 0; i < cnt; i++) 594fe56b9e6SYuval Mintz int_params->msix_table[i].entry = i; 595fe56b9e6SYuval Mintz 596fe56b9e6SYuval Mintz rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, 597fe56b9e6SYuval Mintz int_params->in.min_msix_cnt, cnt); 598fe56b9e6SYuval Mintz if (rc < cnt && rc >= int_params->in.min_msix_cnt && 599fe56b9e6SYuval Mintz (rc % cdev->num_hwfns)) { 600fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 601fe56b9e6SYuval Mintz 602fe56b9e6SYuval Mintz /* If fastpath is initialized, we need at least one interrupt 603fe56b9e6SYuval Mintz * per hwfn [and the slow path interrupts]. New requested number 604fe56b9e6SYuval Mintz * should be a multiple of the number of hwfns. 605fe56b9e6SYuval Mintz */ 606fe56b9e6SYuval Mintz cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; 607fe56b9e6SYuval Mintz DP_NOTICE(cdev, 608fe56b9e6SYuval Mintz "Trying to enable MSI-X with less vectors (%d out of %d)\n", 609fe56b9e6SYuval Mintz cnt, int_params->in.num_vectors); 6101a635e48SYuval Mintz rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, 6111a635e48SYuval Mintz cnt); 612fe56b9e6SYuval Mintz if (!rc) 613fe56b9e6SYuval Mintz rc = cnt; 614fe56b9e6SYuval Mintz } 615fe56b9e6SYuval Mintz 616fe56b9e6SYuval Mintz if (rc > 0) { 617fe56b9e6SYuval Mintz /* MSI-x configuration was achieved */ 618fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSIX; 619fe56b9e6SYuval Mintz int_params->out.num_vectors = rc; 620fe56b9e6SYuval Mintz rc = 0; 621fe56b9e6SYuval Mintz } else { 622fe56b9e6SYuval Mintz DP_NOTICE(cdev, 623fe56b9e6SYuval Mintz "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", 624fe56b9e6SYuval Mintz cnt, rc); 625fe56b9e6SYuval Mintz } 626fe56b9e6SYuval Mintz 627fe56b9e6SYuval Mintz return rc; 628fe56b9e6SYuval Mintz } 629fe56b9e6SYuval Mintz 630fe56b9e6SYuval Mintz /* This function outputs the int mode and the number of enabled msix vector */ 631fe56b9e6SYuval Mintz static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) 632fe56b9e6SYuval Mintz { 633fe56b9e6SYuval Mintz struct qed_int_params *int_params = &cdev->int_params; 634fe56b9e6SYuval Mintz struct msix_entry *tbl; 635fe56b9e6SYuval Mintz int rc = 0, cnt; 636fe56b9e6SYuval Mintz 637fe56b9e6SYuval Mintz switch (int_params->in.int_mode) { 638fe56b9e6SYuval Mintz case QED_INT_MODE_MSIX: 639fe56b9e6SYuval Mintz /* Allocate MSIX table */ 640fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 641fe56b9e6SYuval Mintz int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); 642fe56b9e6SYuval Mintz if (!int_params->msix_table) { 643fe56b9e6SYuval Mintz rc = -ENOMEM; 644fe56b9e6SYuval Mintz goto out; 645fe56b9e6SYuval Mintz } 646fe56b9e6SYuval Mintz 647fe56b9e6SYuval Mintz /* Enable MSIX */ 648fe56b9e6SYuval Mintz rc = qed_enable_msix(cdev, int_params); 649fe56b9e6SYuval Mintz if (!rc) 650fe56b9e6SYuval Mintz goto out; 651fe56b9e6SYuval Mintz 652fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI-X\n"); 653fe56b9e6SYuval Mintz kfree(int_params->msix_table); 654fe56b9e6SYuval Mintz if (force_mode) 655fe56b9e6SYuval Mintz goto out; 656fe56b9e6SYuval Mintz /* Fallthrough */ 657fe56b9e6SYuval Mintz 658fe56b9e6SYuval Mintz case QED_INT_MODE_MSI: 659bb13ace7SSudarsana Reddy Kalluru if (cdev->num_hwfns == 1) { 660fe56b9e6SYuval Mintz rc = pci_enable_msi(cdev->pdev); 661fe56b9e6SYuval Mintz if (!rc) { 662fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSI; 663fe56b9e6SYuval Mintz goto out; 664fe56b9e6SYuval Mintz } 665fe56b9e6SYuval Mintz 666fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI\n"); 667fe56b9e6SYuval Mintz if (force_mode) 668fe56b9e6SYuval Mintz goto out; 669bb13ace7SSudarsana Reddy Kalluru } 670fe56b9e6SYuval Mintz /* Fallthrough */ 671fe56b9e6SYuval Mintz 672fe56b9e6SYuval Mintz case QED_INT_MODE_INTA: 673fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_INTA; 674fe56b9e6SYuval Mintz rc = 0; 675fe56b9e6SYuval Mintz goto out; 676fe56b9e6SYuval Mintz default: 677fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Unknown int_mode value %d\n", 678fe56b9e6SYuval Mintz int_params->in.int_mode); 679fe56b9e6SYuval Mintz rc = -EINVAL; 680fe56b9e6SYuval Mintz } 681fe56b9e6SYuval Mintz 682fe56b9e6SYuval Mintz out: 683525ef5c0SYuval Mintz if (!rc) 684525ef5c0SYuval Mintz DP_INFO(cdev, "Using %s interrupts\n", 685525ef5c0SYuval Mintz int_params->out.int_mode == QED_INT_MODE_INTA ? 686525ef5c0SYuval Mintz "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? 687525ef5c0SYuval Mintz "MSI" : "MSIX"); 688fe56b9e6SYuval Mintz cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; 689fe56b9e6SYuval Mintz 690fe56b9e6SYuval Mintz return rc; 691fe56b9e6SYuval Mintz } 692fe56b9e6SYuval Mintz 693fe56b9e6SYuval Mintz static void qed_simd_handler_config(struct qed_dev *cdev, void *token, 694fe56b9e6SYuval Mintz int index, void(*handler)(void *)) 695fe56b9e6SYuval Mintz { 696fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 697fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 698fe56b9e6SYuval Mintz 699fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].func = handler; 700fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].token = token; 701fe56b9e6SYuval Mintz } 702fe56b9e6SYuval Mintz 703fe56b9e6SYuval Mintz static void qed_simd_handler_clean(struct qed_dev *cdev, int index) 704fe56b9e6SYuval Mintz { 705fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 706fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 707fe56b9e6SYuval Mintz 708fe56b9e6SYuval Mintz memset(&hwfn->simd_proto_handler[relative_idx], 0, 709fe56b9e6SYuval Mintz sizeof(struct qed_simd_fp_handler)); 710fe56b9e6SYuval Mintz } 711fe56b9e6SYuval Mintz 712fe56b9e6SYuval Mintz static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) 713fe56b9e6SYuval Mintz { 714fe56b9e6SYuval Mintz tasklet_schedule((struct tasklet_struct *)tasklet); 715fe56b9e6SYuval Mintz return IRQ_HANDLED; 716fe56b9e6SYuval Mintz } 717fe56b9e6SYuval Mintz 718fe56b9e6SYuval Mintz static irqreturn_t qed_single_int(int irq, void *dev_instance) 719fe56b9e6SYuval Mintz { 720fe56b9e6SYuval Mintz struct qed_dev *cdev = (struct qed_dev *)dev_instance; 721fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 722fe56b9e6SYuval Mintz irqreturn_t rc = IRQ_NONE; 723fe56b9e6SYuval Mintz u64 status; 724fe56b9e6SYuval Mintz int i, j; 725fe56b9e6SYuval Mintz 726fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 727fe56b9e6SYuval Mintz status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); 728fe56b9e6SYuval Mintz 729fe56b9e6SYuval Mintz if (!status) 730fe56b9e6SYuval Mintz continue; 731fe56b9e6SYuval Mintz 732fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 733fe56b9e6SYuval Mintz 734fe56b9e6SYuval Mintz /* Slowpath interrupt */ 735fe56b9e6SYuval Mintz if (unlikely(status & 0x1)) { 736fe56b9e6SYuval Mintz tasklet_schedule(hwfn->sp_dpc); 737fe56b9e6SYuval Mintz status &= ~0x1; 738fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 739fe56b9e6SYuval Mintz } 740fe56b9e6SYuval Mintz 741fe56b9e6SYuval Mintz /* Fastpath interrupts */ 742fe56b9e6SYuval Mintz for (j = 0; j < 64; j++) { 743fe56b9e6SYuval Mintz if ((0x2ULL << j) & status) { 7443935a709SSudarsana Reddy Kalluru struct qed_simd_fp_handler *p_handler = 7453935a709SSudarsana Reddy Kalluru &hwfn->simd_proto_handler[j]; 7463935a709SSudarsana Reddy Kalluru 7473935a709SSudarsana Reddy Kalluru if (p_handler->func) 7483935a709SSudarsana Reddy Kalluru p_handler->func(p_handler->token); 7493935a709SSudarsana Reddy Kalluru else 7503935a709SSudarsana Reddy Kalluru DP_NOTICE(hwfn, 7513935a709SSudarsana Reddy Kalluru "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n", 7523935a709SSudarsana Reddy Kalluru j, status); 7533935a709SSudarsana Reddy Kalluru 754fe56b9e6SYuval Mintz status &= ~(0x2ULL << j); 755fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 756fe56b9e6SYuval Mintz } 757fe56b9e6SYuval Mintz } 758fe56b9e6SYuval Mintz 759fe56b9e6SYuval Mintz if (unlikely(status)) 760fe56b9e6SYuval Mintz DP_VERBOSE(hwfn, NETIF_MSG_INTR, 761fe56b9e6SYuval Mintz "got an unknown interrupt status 0x%llx\n", 762fe56b9e6SYuval Mintz status); 763fe56b9e6SYuval Mintz } 764fe56b9e6SYuval Mintz 765fe56b9e6SYuval Mintz return rc; 766fe56b9e6SYuval Mintz } 767fe56b9e6SYuval Mintz 7688f16bc97SSudarsana Kalluru int qed_slowpath_irq_req(struct qed_hwfn *hwfn) 769fe56b9e6SYuval Mintz { 7708f16bc97SSudarsana Kalluru struct qed_dev *cdev = hwfn->cdev; 771525ef5c0SYuval Mintz u32 int_mode; 7728f16bc97SSudarsana Kalluru int rc = 0; 7738f16bc97SSudarsana Kalluru u8 id; 774fe56b9e6SYuval Mintz 775525ef5c0SYuval Mintz int_mode = cdev->int_params.out.int_mode; 776525ef5c0SYuval Mintz if (int_mode == QED_INT_MODE_MSIX) { 7778f16bc97SSudarsana Kalluru id = hwfn->my_id; 7788f16bc97SSudarsana Kalluru snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", 7798f16bc97SSudarsana Kalluru id, cdev->pdev->bus->number, 7808f16bc97SSudarsana Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 7818f16bc97SSudarsana Kalluru rc = request_irq(cdev->int_params.msix_table[id].vector, 7828f16bc97SSudarsana Kalluru qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc); 783fe56b9e6SYuval Mintz } else { 784fe56b9e6SYuval Mintz unsigned long flags = 0; 785fe56b9e6SYuval Mintz 786fe56b9e6SYuval Mintz snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", 787fe56b9e6SYuval Mintz cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), 788fe56b9e6SYuval Mintz PCI_FUNC(cdev->pdev->devfn)); 789fe56b9e6SYuval Mintz 790fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) 791fe56b9e6SYuval Mintz flags |= IRQF_SHARED; 792fe56b9e6SYuval Mintz 793fe56b9e6SYuval Mintz rc = request_irq(cdev->pdev->irq, qed_single_int, 794fe56b9e6SYuval Mintz flags, cdev->name, cdev); 795fe56b9e6SYuval Mintz } 796fe56b9e6SYuval Mintz 797525ef5c0SYuval Mintz if (rc) 798525ef5c0SYuval Mintz DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); 799525ef5c0SYuval Mintz else 800525ef5c0SYuval Mintz DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), 801525ef5c0SYuval Mintz "Requested slowpath %s\n", 802525ef5c0SYuval Mintz (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); 803525ef5c0SYuval Mintz 804fe56b9e6SYuval Mintz return rc; 805fe56b9e6SYuval Mintz } 806fe56b9e6SYuval Mintz 80706892f2eSTomer Tayar static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) 80806892f2eSTomer Tayar { 80906892f2eSTomer Tayar /* Calling the disable function will make sure that any 81006892f2eSTomer Tayar * currently-running function is completed. The following call to the 81106892f2eSTomer Tayar * enable function makes this sequence a flush-like operation. 81206892f2eSTomer Tayar */ 81306892f2eSTomer Tayar if (p_hwfn->b_sp_dpc_enabled) { 81406892f2eSTomer Tayar tasklet_disable(p_hwfn->sp_dpc); 81506892f2eSTomer Tayar tasklet_enable(p_hwfn->sp_dpc); 81606892f2eSTomer Tayar } 81706892f2eSTomer Tayar } 81806892f2eSTomer Tayar 8191226337aSTomer Tayar void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) 8201226337aSTomer Tayar { 8211226337aSTomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 8221226337aSTomer Tayar u8 id = p_hwfn->my_id; 8231226337aSTomer Tayar u32 int_mode; 8241226337aSTomer Tayar 8251226337aSTomer Tayar int_mode = cdev->int_params.out.int_mode; 8261226337aSTomer Tayar if (int_mode == QED_INT_MODE_MSIX) 8271226337aSTomer Tayar synchronize_irq(cdev->int_params.msix_table[id].vector); 8281226337aSTomer Tayar else 8291226337aSTomer Tayar synchronize_irq(cdev->pdev->irq); 83006892f2eSTomer Tayar 83106892f2eSTomer Tayar qed_slowpath_tasklet_flush(p_hwfn); 8321226337aSTomer Tayar } 8331226337aSTomer Tayar 834fe56b9e6SYuval Mintz static void qed_slowpath_irq_free(struct qed_dev *cdev) 835fe56b9e6SYuval Mintz { 836fe56b9e6SYuval Mintz int i; 837fe56b9e6SYuval Mintz 838fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 839fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 8408f16bc97SSudarsana Kalluru if (!cdev->hwfns[i].b_int_requested) 8418f16bc97SSudarsana Kalluru break; 842fe56b9e6SYuval Mintz synchronize_irq(cdev->int_params.msix_table[i].vector); 843fe56b9e6SYuval Mintz free_irq(cdev->int_params.msix_table[i].vector, 844fe56b9e6SYuval Mintz cdev->hwfns[i].sp_dpc); 845fe56b9e6SYuval Mintz } 846fe56b9e6SYuval Mintz } else { 8478f16bc97SSudarsana Kalluru if (QED_LEADING_HWFN(cdev)->b_int_requested) 848fe56b9e6SYuval Mintz free_irq(cdev->pdev->irq, cdev); 849fe56b9e6SYuval Mintz } 8508f16bc97SSudarsana Kalluru qed_int_disable_post_isr_release(cdev); 851fe56b9e6SYuval Mintz } 852fe56b9e6SYuval Mintz 853fe56b9e6SYuval Mintz static int qed_nic_stop(struct qed_dev *cdev) 854fe56b9e6SYuval Mintz { 855fe56b9e6SYuval Mintz int i, rc; 856fe56b9e6SYuval Mintz 857fe56b9e6SYuval Mintz rc = qed_hw_stop(cdev); 858fe56b9e6SYuval Mintz 859fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 860fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 861fe56b9e6SYuval Mintz 862fe56b9e6SYuval Mintz if (p_hwfn->b_sp_dpc_enabled) { 863fe56b9e6SYuval Mintz tasklet_disable(p_hwfn->sp_dpc); 864fe56b9e6SYuval Mintz p_hwfn->b_sp_dpc_enabled = false; 865fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, 8662fdae034SColin Ian King "Disabled sp tasklet [hwfn %d] at %p\n", 867fe56b9e6SYuval Mintz i, p_hwfn->sp_dpc); 868fe56b9e6SYuval Mintz } 869fe56b9e6SYuval Mintz } 870fe56b9e6SYuval Mintz 871c965db44STomer Tayar qed_dbg_pf_exit(cdev); 872c965db44STomer Tayar 873fe56b9e6SYuval Mintz return rc; 874fe56b9e6SYuval Mintz } 875fe56b9e6SYuval Mintz 876fe56b9e6SYuval Mintz static int qed_nic_setup(struct qed_dev *cdev) 877fe56b9e6SYuval Mintz { 8780a7fb11cSYuval Mintz int rc, i; 8790a7fb11cSYuval Mintz 8800a7fb11cSYuval Mintz /* Determine if interface is going to require LL2 */ 8810a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) { 8820a7fb11cSYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 8830a7fb11cSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 8840a7fb11cSYuval Mintz 8850a7fb11cSYuval Mintz p_hwfn->using_ll2 = true; 8860a7fb11cSYuval Mintz } 8870a7fb11cSYuval Mintz } 888fe56b9e6SYuval Mintz 889fe56b9e6SYuval Mintz rc = qed_resc_alloc(cdev); 890fe56b9e6SYuval Mintz if (rc) 891fe56b9e6SYuval Mintz return rc; 892fe56b9e6SYuval Mintz 893fe56b9e6SYuval Mintz DP_INFO(cdev, "Allocated qed resources\n"); 894fe56b9e6SYuval Mintz 895fe56b9e6SYuval Mintz qed_resc_setup(cdev); 896fe56b9e6SYuval Mintz 897fe56b9e6SYuval Mintz return rc; 898fe56b9e6SYuval Mintz } 899fe56b9e6SYuval Mintz 900fe56b9e6SYuval Mintz static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) 901fe56b9e6SYuval Mintz { 902fe56b9e6SYuval Mintz int limit = 0; 903fe56b9e6SYuval Mintz 904fe56b9e6SYuval Mintz /* Mark the fastpath as free/used */ 905fe56b9e6SYuval Mintz cdev->int_params.fp_initialized = cnt ? true : false; 906fe56b9e6SYuval Mintz 907fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) 908fe56b9e6SYuval Mintz limit = cdev->num_hwfns * 63; 909fe56b9e6SYuval Mintz else if (cdev->int_params.fp_msix_cnt) 910fe56b9e6SYuval Mintz limit = cdev->int_params.fp_msix_cnt; 911fe56b9e6SYuval Mintz 912fe56b9e6SYuval Mintz if (!limit) 913fe56b9e6SYuval Mintz return -ENOMEM; 914fe56b9e6SYuval Mintz 915fe56b9e6SYuval Mintz return min_t(int, cnt, limit); 916fe56b9e6SYuval Mintz } 917fe56b9e6SYuval Mintz 918fe56b9e6SYuval Mintz static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) 919fe56b9e6SYuval Mintz { 920fe56b9e6SYuval Mintz memset(info, 0, sizeof(struct qed_int_info)); 921fe56b9e6SYuval Mintz 922fe56b9e6SYuval Mintz if (!cdev->int_params.fp_initialized) { 923fe56b9e6SYuval Mintz DP_INFO(cdev, 924fe56b9e6SYuval Mintz "Protocol driver requested interrupt information, but its support is not yet configured\n"); 925fe56b9e6SYuval Mintz return -EINVAL; 926fe56b9e6SYuval Mintz } 927fe56b9e6SYuval Mintz 928fe56b9e6SYuval Mintz /* Need to expose only MSI-X information; Single IRQ is handled solely 929fe56b9e6SYuval Mintz * by qed. 930fe56b9e6SYuval Mintz */ 931fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 932fe56b9e6SYuval Mintz int msix_base = cdev->int_params.fp_msix_base; 933fe56b9e6SYuval Mintz 934fe56b9e6SYuval Mintz info->msix_cnt = cdev->int_params.fp_msix_cnt; 935fe56b9e6SYuval Mintz info->msix = &cdev->int_params.msix_table[msix_base]; 936fe56b9e6SYuval Mintz } 937fe56b9e6SYuval Mintz 938fe56b9e6SYuval Mintz return 0; 939fe56b9e6SYuval Mintz } 940fe56b9e6SYuval Mintz 941fe56b9e6SYuval Mintz static int qed_slowpath_setup_int(struct qed_dev *cdev, 942fe56b9e6SYuval Mintz enum qed_int_mode int_mode) 943fe56b9e6SYuval Mintz { 9444ac801b7SYuval Mintz struct qed_sb_cnt_info sb_cnt_info; 9450189efb8SYuval Mintz int num_l2_queues = 0; 9464ac801b7SYuval Mintz int rc; 9474ac801b7SYuval Mintz int i; 948fe56b9e6SYuval Mintz 9491d2c2024SSudarsana Reddy Kalluru if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { 9501d2c2024SSudarsana Reddy Kalluru DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); 9511d2c2024SSudarsana Reddy Kalluru return -EINVAL; 9521d2c2024SSudarsana Reddy Kalluru } 9531d2c2024SSudarsana Reddy Kalluru 9541d2c2024SSudarsana Reddy Kalluru memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 955fe56b9e6SYuval Mintz cdev->int_params.in.int_mode = int_mode; 9564ac801b7SYuval Mintz for_each_hwfn(cdev, i) { 9574ac801b7SYuval Mintz memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); 9584ac801b7SYuval Mintz qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); 959726fdbe9SMintz, Yuval cdev->int_params.in.num_vectors += sb_cnt_info.cnt; 9604ac801b7SYuval Mintz cdev->int_params.in.num_vectors++; /* slowpath */ 9614ac801b7SYuval Mintz } 962fe56b9e6SYuval Mintz 963fe56b9e6SYuval Mintz /* We want a minimum of one slowpath and one fastpath vector per hwfn */ 964fe56b9e6SYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; 965fe56b9e6SYuval Mintz 966bb7858baSSudarsana Reddy Kalluru if (is_kdump_kernel()) { 967bb7858baSSudarsana Reddy Kalluru DP_INFO(cdev, 968bb7858baSSudarsana Reddy Kalluru "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", 969bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt); 970bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.num_vectors = 971bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt; 972bb7858baSSudarsana Reddy Kalluru } 973bb7858baSSudarsana Reddy Kalluru 974fe56b9e6SYuval Mintz rc = qed_set_int_mode(cdev, false); 975fe56b9e6SYuval Mintz if (rc) { 976fe56b9e6SYuval Mintz DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); 977fe56b9e6SYuval Mintz return rc; 978fe56b9e6SYuval Mintz } 979fe56b9e6SYuval Mintz 980fe56b9e6SYuval Mintz cdev->int_params.fp_msix_base = cdev->num_hwfns; 981fe56b9e6SYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - 982fe56b9e6SYuval Mintz cdev->num_hwfns; 983fe56b9e6SYuval Mintz 9842f782278SMintz, Yuval if (!IS_ENABLED(CONFIG_QED_RDMA) || 985c851a9dcSKalderon, Michal !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) 9860189efb8SYuval Mintz return 0; 9870189efb8SYuval Mintz 98851ff1725SRam Amrani for_each_hwfn(cdev, i) 98951ff1725SRam Amrani num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); 99051ff1725SRam Amrani 99151ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, 99251ff1725SRam Amrani "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n", 99351ff1725SRam Amrani cdev->int_params.fp_msix_cnt, num_l2_queues); 99451ff1725SRam Amrani 99551ff1725SRam Amrani if (cdev->int_params.fp_msix_cnt > num_l2_queues) { 99651ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 99751ff1725SRam Amrani (cdev->int_params.fp_msix_cnt - num_l2_queues) 99851ff1725SRam Amrani / cdev->num_hwfns; 99951ff1725SRam Amrani cdev->int_params.rdma_msix_base = 100051ff1725SRam Amrani cdev->int_params.fp_msix_base + num_l2_queues; 100151ff1725SRam Amrani cdev->int_params.fp_msix_cnt = num_l2_queues; 100251ff1725SRam Amrani } else { 100351ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 0; 100451ff1725SRam Amrani } 100551ff1725SRam Amrani 100651ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", 100751ff1725SRam Amrani cdev->int_params.rdma_msix_cnt, 100851ff1725SRam Amrani cdev->int_params.rdma_msix_base); 100951ff1725SRam Amrani 1010fe56b9e6SYuval Mintz return 0; 1011fe56b9e6SYuval Mintz } 1012fe56b9e6SYuval Mintz 10131408cc1fSYuval Mintz static int qed_slowpath_vf_setup_int(struct qed_dev *cdev) 10141408cc1fSYuval Mintz { 10151408cc1fSYuval Mintz int rc; 10161408cc1fSYuval Mintz 10171408cc1fSYuval Mintz memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 10181408cc1fSYuval Mintz cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; 10191408cc1fSYuval Mintz 10201408cc1fSYuval Mintz qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), 10211408cc1fSYuval Mintz &cdev->int_params.in.num_vectors); 10221408cc1fSYuval Mintz if (cdev->num_hwfns > 1) { 10231408cc1fSYuval Mintz u8 vectors = 0; 10241408cc1fSYuval Mintz 10251408cc1fSYuval Mintz qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); 10261408cc1fSYuval Mintz cdev->int_params.in.num_vectors += vectors; 10271408cc1fSYuval Mintz } 10281408cc1fSYuval Mintz 10291408cc1fSYuval Mintz /* We want a minimum of one fastpath vector per vf hwfn */ 10301408cc1fSYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; 10311408cc1fSYuval Mintz 10321408cc1fSYuval Mintz rc = qed_set_int_mode(cdev, true); 10331408cc1fSYuval Mintz if (rc) 10341408cc1fSYuval Mintz return rc; 10351408cc1fSYuval Mintz 10361408cc1fSYuval Mintz cdev->int_params.fp_msix_base = 0; 10371408cc1fSYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; 10381408cc1fSYuval Mintz 10391408cc1fSYuval Mintz return 0; 10401408cc1fSYuval Mintz } 10411408cc1fSYuval Mintz 1042fe56b9e6SYuval Mintz u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, 1043fe56b9e6SYuval Mintz u8 *input_buf, u32 max_size, u8 *unzip_buf) 1044fe56b9e6SYuval Mintz { 1045fe56b9e6SYuval Mintz int rc; 1046fe56b9e6SYuval Mintz 1047fe56b9e6SYuval Mintz p_hwfn->stream->next_in = input_buf; 1048fe56b9e6SYuval Mintz p_hwfn->stream->avail_in = input_len; 1049fe56b9e6SYuval Mintz p_hwfn->stream->next_out = unzip_buf; 1050fe56b9e6SYuval Mintz p_hwfn->stream->avail_out = max_size; 1051fe56b9e6SYuval Mintz 1052fe56b9e6SYuval Mintz rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); 1053fe56b9e6SYuval Mintz 1054fe56b9e6SYuval Mintz if (rc != Z_OK) { 1055fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", 1056fe56b9e6SYuval Mintz rc); 1057fe56b9e6SYuval Mintz return 0; 1058fe56b9e6SYuval Mintz } 1059fe56b9e6SYuval Mintz 1060fe56b9e6SYuval Mintz rc = zlib_inflate(p_hwfn->stream, Z_FINISH); 1061fe56b9e6SYuval Mintz zlib_inflateEnd(p_hwfn->stream); 1062fe56b9e6SYuval Mintz 1063fe56b9e6SYuval Mintz if (rc != Z_OK && rc != Z_STREAM_END) { 1064fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", 1065fe56b9e6SYuval Mintz p_hwfn->stream->msg, rc); 1066fe56b9e6SYuval Mintz return 0; 1067fe56b9e6SYuval Mintz } 1068fe56b9e6SYuval Mintz 1069fe56b9e6SYuval Mintz return p_hwfn->stream->total_out / 4; 1070fe56b9e6SYuval Mintz } 1071fe56b9e6SYuval Mintz 1072fe56b9e6SYuval Mintz static int qed_alloc_stream_mem(struct qed_dev *cdev) 1073fe56b9e6SYuval Mintz { 1074fe56b9e6SYuval Mintz int i; 1075fe56b9e6SYuval Mintz void *workspace; 1076fe56b9e6SYuval Mintz 1077fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1078fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 1079fe56b9e6SYuval Mintz 1080fe56b9e6SYuval Mintz p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); 1081fe56b9e6SYuval Mintz if (!p_hwfn->stream) 1082fe56b9e6SYuval Mintz return -ENOMEM; 1083fe56b9e6SYuval Mintz 1084fe56b9e6SYuval Mintz workspace = vzalloc(zlib_inflate_workspacesize()); 1085fe56b9e6SYuval Mintz if (!workspace) 1086fe56b9e6SYuval Mintz return -ENOMEM; 1087fe56b9e6SYuval Mintz p_hwfn->stream->workspace = workspace; 1088fe56b9e6SYuval Mintz } 1089fe56b9e6SYuval Mintz 1090fe56b9e6SYuval Mintz return 0; 1091fe56b9e6SYuval Mintz } 1092fe56b9e6SYuval Mintz 1093fe56b9e6SYuval Mintz static void qed_free_stream_mem(struct qed_dev *cdev) 1094fe56b9e6SYuval Mintz { 1095fe56b9e6SYuval Mintz int i; 1096fe56b9e6SYuval Mintz 1097fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1098fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 1099fe56b9e6SYuval Mintz 1100fe56b9e6SYuval Mintz if (!p_hwfn->stream) 1101fe56b9e6SYuval Mintz return; 1102fe56b9e6SYuval Mintz 1103fe56b9e6SYuval Mintz vfree(p_hwfn->stream->workspace); 1104fe56b9e6SYuval Mintz kfree(p_hwfn->stream); 1105fe56b9e6SYuval Mintz } 1106fe56b9e6SYuval Mintz } 1107fe56b9e6SYuval Mintz 1108fe56b9e6SYuval Mintz static void qed_update_pf_params(struct qed_dev *cdev, 1109fe56b9e6SYuval Mintz struct qed_pf_params *params) 1110fe56b9e6SYuval Mintz { 1111fe56b9e6SYuval Mintz int i; 1112fe56b9e6SYuval Mintz 11135c5f2609SRam Amrani if (IS_ENABLED(CONFIG_QED_RDMA)) { 11140189efb8SYuval Mintz params->rdma_pf_params.num_qps = QED_ROCE_QPS; 11150189efb8SYuval Mintz params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; 111639dbc646SYuval Bason params->rdma_pf_params.num_srqs = QED_RDMA_SRQS; 11170189efb8SYuval Mintz /* divide by 3 the MRs to avoid MF ILT overflow */ 11180189efb8SYuval Mintz params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; 1119fe56b9e6SYuval Mintz } 1120fe56b9e6SYuval Mintz 1121d51e4af5SChopra, Manish if (cdev->num_hwfns > 1 || IS_VF(cdev)) 1122d51e4af5SChopra, Manish params->eth_pf_params.num_arfs_filters = 0; 1123d51e4af5SChopra, Manish 1124e1d32acbSMintz, Yuval /* In case we might support RDMA, don't allow qede to be greedy 11255e7baf0fSManish Chopra * with the L2 contexts. Allow for 64 queues [rx, tx cos, xdp] 11265e7baf0fSManish Chopra * per hwfn. 1127e1d32acbSMintz, Yuval */ 1128c851a9dcSKalderon, Michal if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) { 1129e1d32acbSMintz, Yuval u16 *num_cons; 1130e1d32acbSMintz, Yuval 1131e1d32acbSMintz, Yuval num_cons = ¶ms->eth_pf_params.num_cons; 11325e7baf0fSManish Chopra *num_cons = min_t(u16, *num_cons, QED_MAX_L2_CONS); 1133e1d32acbSMintz, Yuval } 1134e1d32acbSMintz, Yuval 11355c5f2609SRam Amrani for (i = 0; i < cdev->num_hwfns; i++) { 11365c5f2609SRam Amrani struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 11375c5f2609SRam Amrani 11385c5f2609SRam Amrani p_hwfn->pf_params = *params; 11395c5f2609SRam Amrani } 11405c5f2609SRam Amrani } 11415c5f2609SRam Amrani 1142d4476b8aSDenis Bolotin #define QED_PERIODIC_DB_REC_COUNT 10 1143a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL_MS 100 1144a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL \ 1145a1b469b8SAriel Elior msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS) 1146a1b469b8SAriel Elior 1147a1b469b8SAriel Elior static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn, 1148a1b469b8SAriel Elior enum qed_slowpath_wq_flag wq_flag, 1149a1b469b8SAriel Elior unsigned long delay) 1150a1b469b8SAriel Elior { 1151a1b469b8SAriel Elior if (!hwfn->slowpath_wq_active) 1152a1b469b8SAriel Elior return -EINVAL; 1153a1b469b8SAriel Elior 1154a1b469b8SAriel Elior /* Memory barrier for setting atomic bit */ 1155a1b469b8SAriel Elior smp_mb__before_atomic(); 1156a1b469b8SAriel Elior set_bit(wq_flag, &hwfn->slowpath_task_flags); 1157a1b469b8SAriel Elior smp_mb__after_atomic(); 1158a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay); 1159a1b469b8SAriel Elior 1160a1b469b8SAriel Elior return 0; 1161a1b469b8SAriel Elior } 1162a1b469b8SAriel Elior 1163a1b469b8SAriel Elior void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn) 1164a1b469b8SAriel Elior { 1165a1b469b8SAriel Elior /* Reset periodic Doorbell Recovery counter */ 1166a1b469b8SAriel Elior p_hwfn->periodic_db_rec_count = QED_PERIODIC_DB_REC_COUNT; 1167a1b469b8SAriel Elior 1168a1b469b8SAriel Elior /* Don't schedule periodic Doorbell Recovery if already scheduled */ 1169a1b469b8SAriel Elior if (test_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1170a1b469b8SAriel Elior &p_hwfn->slowpath_task_flags)) 1171a1b469b8SAriel Elior return; 1172a1b469b8SAriel Elior 1173a1b469b8SAriel Elior qed_slowpath_delayed_work(p_hwfn, QED_SLOWPATH_PERIODIC_DB_REC, 1174a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1175a1b469b8SAriel Elior } 1176a1b469b8SAriel Elior 117759ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_wq_stop(struct qed_dev *cdev) 117859ccf86fSSudarsana Reddy Kalluru { 11793b85720dSYuval Basson int i; 118059ccf86fSSudarsana Reddy Kalluru 118159ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 118259ccf86fSSudarsana Reddy Kalluru return; 118359ccf86fSSudarsana Reddy Kalluru 118459ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 118559ccf86fSSudarsana Reddy Kalluru if (!cdev->hwfns[i].slowpath_wq) 118659ccf86fSSudarsana Reddy Kalluru continue; 118759ccf86fSSudarsana Reddy Kalluru 1188a1b469b8SAriel Elior /* Stop queuing new delayed works */ 1189a1b469b8SAriel Elior cdev->hwfns[i].slowpath_wq_active = false; 1190a1b469b8SAriel Elior 11913b85720dSYuval Basson cancel_delayed_work(&cdev->hwfns[i].slowpath_task); 119259ccf86fSSudarsana Reddy Kalluru destroy_workqueue(cdev->hwfns[i].slowpath_wq); 119359ccf86fSSudarsana Reddy Kalluru } 119459ccf86fSSudarsana Reddy Kalluru } 119559ccf86fSSudarsana Reddy Kalluru 119659ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_task(struct work_struct *work) 119759ccf86fSSudarsana Reddy Kalluru { 119859ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 119959ccf86fSSudarsana Reddy Kalluru slowpath_task.work); 120059ccf86fSSudarsana Reddy Kalluru struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 120159ccf86fSSudarsana Reddy Kalluru 120259ccf86fSSudarsana Reddy Kalluru if (!ptt) { 1203a1b469b8SAriel Elior if (hwfn->slowpath_wq_active) 1204a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, 1205a1b469b8SAriel Elior &hwfn->slowpath_task, 0); 1206a1b469b8SAriel Elior 120759ccf86fSSudarsana Reddy Kalluru return; 120859ccf86fSSudarsana Reddy Kalluru } 120959ccf86fSSudarsana Reddy Kalluru 121059ccf86fSSudarsana Reddy Kalluru if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ, 121159ccf86fSSudarsana Reddy Kalluru &hwfn->slowpath_task_flags)) 121259ccf86fSSudarsana Reddy Kalluru qed_mfw_process_tlv_req(hwfn, ptt); 121359ccf86fSSudarsana Reddy Kalluru 1214a1b469b8SAriel Elior if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1215a1b469b8SAriel Elior &hwfn->slowpath_task_flags)) { 1216a1b469b8SAriel Elior qed_db_rec_handler(hwfn, ptt); 1217a1b469b8SAriel Elior if (hwfn->periodic_db_rec_count--) 1218a1b469b8SAriel Elior qed_slowpath_delayed_work(hwfn, 1219a1b469b8SAriel Elior QED_SLOWPATH_PERIODIC_DB_REC, 1220a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1221a1b469b8SAriel Elior } 1222a1b469b8SAriel Elior 122359ccf86fSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 122459ccf86fSSudarsana Reddy Kalluru } 122559ccf86fSSudarsana Reddy Kalluru 122659ccf86fSSudarsana Reddy Kalluru static int qed_slowpath_wq_start(struct qed_dev *cdev) 122759ccf86fSSudarsana Reddy Kalluru { 122859ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn; 122959ccf86fSSudarsana Reddy Kalluru char name[NAME_SIZE]; 123059ccf86fSSudarsana Reddy Kalluru int i; 123159ccf86fSSudarsana Reddy Kalluru 123259ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 123359ccf86fSSudarsana Reddy Kalluru return 0; 123459ccf86fSSudarsana Reddy Kalluru 123559ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 123659ccf86fSSudarsana Reddy Kalluru hwfn = &cdev->hwfns[i]; 123759ccf86fSSudarsana Reddy Kalluru 123859ccf86fSSudarsana Reddy Kalluru snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", 123959ccf86fSSudarsana Reddy Kalluru cdev->pdev->bus->number, 124059ccf86fSSudarsana Reddy Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 124159ccf86fSSudarsana Reddy Kalluru 124259ccf86fSSudarsana Reddy Kalluru hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); 124359ccf86fSSudarsana Reddy Kalluru if (!hwfn->slowpath_wq) { 124459ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); 124559ccf86fSSudarsana Reddy Kalluru return -ENOMEM; 124659ccf86fSSudarsana Reddy Kalluru } 124759ccf86fSSudarsana Reddy Kalluru 124859ccf86fSSudarsana Reddy Kalluru INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task); 1249a1b469b8SAriel Elior hwfn->slowpath_wq_active = true; 125059ccf86fSSudarsana Reddy Kalluru } 125159ccf86fSSudarsana Reddy Kalluru 125259ccf86fSSudarsana Reddy Kalluru return 0; 125359ccf86fSSudarsana Reddy Kalluru } 125459ccf86fSSudarsana Reddy Kalluru 1255fe56b9e6SYuval Mintz static int qed_slowpath_start(struct qed_dev *cdev, 1256fe56b9e6SYuval Mintz struct qed_slowpath_params *params) 1257fe56b9e6SYuval Mintz { 12585d24bcf1STomer Tayar struct qed_drv_load_params drv_load_params; 1259c0c2d0b4SMintz, Yuval struct qed_hw_init_params hw_init_params; 1260fe56b9e6SYuval Mintz struct qed_mcp_drv_version drv_version; 126119968430SChopra, Manish struct qed_tunnel_info tunn_info; 1262fe56b9e6SYuval Mintz const u8 *data = NULL; 1263fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 1264c78c70faSSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 126537bff2b9SYuval Mintz int rc = -EINVAL; 126637bff2b9SYuval Mintz 126737bff2b9SYuval Mintz if (qed_iov_wq_start(cdev)) 126837bff2b9SYuval Mintz goto err; 1269fe56b9e6SYuval Mintz 127059ccf86fSSudarsana Reddy Kalluru if (qed_slowpath_wq_start(cdev)) 127159ccf86fSSudarsana Reddy Kalluru goto err; 127259ccf86fSSudarsana Reddy Kalluru 12731408cc1fSYuval Mintz if (IS_PF(cdev)) { 1274fe56b9e6SYuval Mintz rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, 1275fe56b9e6SYuval Mintz &cdev->pdev->dev); 1276fe56b9e6SYuval Mintz if (rc) { 1277fe56b9e6SYuval Mintz DP_NOTICE(cdev, 1278fe56b9e6SYuval Mintz "Failed to find fw file - /lib/firmware/%s\n", 1279fe56b9e6SYuval Mintz QED_FW_FILE_NAME); 1280fe56b9e6SYuval Mintz goto err; 1281fe56b9e6SYuval Mintz } 1282c78c70faSSudarsana Reddy Kalluru 1283d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) { 1284d51e4af5SChopra, Manish p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 1285d51e4af5SChopra, Manish if (p_ptt) { 1286d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; 1287d51e4af5SChopra, Manish } else { 1288d51e4af5SChopra, Manish DP_NOTICE(cdev, 1289d51e4af5SChopra, Manish "Failed to acquire PTT for aRFS\n"); 1290d51e4af5SChopra, Manish goto err; 1291d51e4af5SChopra, Manish } 1292d51e4af5SChopra, Manish } 12931408cc1fSYuval Mintz } 1294fe56b9e6SYuval Mintz 12950e191827SSudarsana Reddy Kalluru cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 1296fe56b9e6SYuval Mintz rc = qed_nic_setup(cdev); 1297fe56b9e6SYuval Mintz if (rc) 1298fe56b9e6SYuval Mintz goto err; 1299fe56b9e6SYuval Mintz 13001408cc1fSYuval Mintz if (IS_PF(cdev)) 1301fe56b9e6SYuval Mintz rc = qed_slowpath_setup_int(cdev, params->int_mode); 13021408cc1fSYuval Mintz else 13031408cc1fSYuval Mintz rc = qed_slowpath_vf_setup_int(cdev); 1304fe56b9e6SYuval Mintz if (rc) 1305fe56b9e6SYuval Mintz goto err1; 1306fe56b9e6SYuval Mintz 13071408cc1fSYuval Mintz if (IS_PF(cdev)) { 1308fe56b9e6SYuval Mintz /* Allocate stream for unzipping */ 1309fe56b9e6SYuval Mintz rc = qed_alloc_stream_mem(cdev); 13102591c280SJoe Perches if (rc) 13118f16bc97SSudarsana Kalluru goto err2; 1312fe56b9e6SYuval Mintz 13138ac1ed79SJoe Perches /* First Dword used to differentiate between various sources */ 1314351a4dedSYuval Mintz data = cdev->firmware->data + sizeof(u32); 1315c965db44STomer Tayar 1316c965db44STomer Tayar qed_dbg_pf_init(cdev); 13171408cc1fSYuval Mintz } 1318fe56b9e6SYuval Mintz 13191408cc1fSYuval Mintz /* Start the slowpath */ 1320c0c2d0b4SMintz, Yuval memset(&hw_init_params, 0, sizeof(hw_init_params)); 132119968430SChopra, Manish memset(&tunn_info, 0, sizeof(tunn_info)); 132219968430SChopra, Manish tunn_info.vxlan.b_mode_enabled = true; 132319968430SChopra, Manish tunn_info.l2_gre.b_mode_enabled = true; 132419968430SChopra, Manish tunn_info.ip_gre.b_mode_enabled = true; 132519968430SChopra, Manish tunn_info.l2_geneve.b_mode_enabled = true; 132619968430SChopra, Manish tunn_info.ip_geneve.b_mode_enabled = true; 132719968430SChopra, Manish tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 132819968430SChopra, Manish tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 132919968430SChopra, Manish tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133019968430SChopra, Manish tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133119968430SChopra, Manish tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 1332c0c2d0b4SMintz, Yuval hw_init_params.p_tunn = &tunn_info; 1333c0c2d0b4SMintz, Yuval hw_init_params.b_hw_start = true; 1334c0c2d0b4SMintz, Yuval hw_init_params.int_mode = cdev->int_params.out.int_mode; 1335c0c2d0b4SMintz, Yuval hw_init_params.allow_npar_tx_switch = true; 1336c0c2d0b4SMintz, Yuval hw_init_params.bin_fw_data = data; 1337c0c2d0b4SMintz, Yuval 13385d24bcf1STomer Tayar memset(&drv_load_params, 0, sizeof(drv_load_params)); 13395d24bcf1STomer Tayar drv_load_params.is_crash_kernel = is_kdump_kernel(); 13405d24bcf1STomer Tayar drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; 13415d24bcf1STomer Tayar drv_load_params.avoid_eng_reset = false; 13425d24bcf1STomer Tayar drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; 13435d24bcf1STomer Tayar hw_init_params.p_drv_load_params = &drv_load_params; 13445d24bcf1STomer Tayar 1345c0c2d0b4SMintz, Yuval rc = qed_hw_init(cdev, &hw_init_params); 1346fe56b9e6SYuval Mintz if (rc) 13478c925c44SYuval Mintz goto err2; 1348fe56b9e6SYuval Mintz 1349fe56b9e6SYuval Mintz DP_INFO(cdev, 1350fe56b9e6SYuval Mintz "HW initialization and function start completed successfully\n"); 1351fe56b9e6SYuval Mintz 1352eaf3c0c6SChopra, Manish if (IS_PF(cdev)) { 1353eaf3c0c6SChopra, Manish cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | 1354eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GENEVE_TUNN) | 1355eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGENEVE_TUNN) | 1356eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GRE_TUNN) | 1357eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGRE_TUNN)); 1358eaf3c0c6SChopra, Manish } 1359eaf3c0c6SChopra, Manish 13600a7fb11cSYuval Mintz /* Allocate LL2 interface if needed */ 13610a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->using_ll2) { 13620a7fb11cSYuval Mintz rc = qed_ll2_alloc_if(cdev); 13630a7fb11cSYuval Mintz if (rc) 13640a7fb11cSYuval Mintz goto err3; 13650a7fb11cSYuval Mintz } 13661408cc1fSYuval Mintz if (IS_PF(cdev)) { 1367fe56b9e6SYuval Mintz hwfn = QED_LEADING_HWFN(cdev); 1368fe56b9e6SYuval Mintz drv_version.version = (params->drv_major << 24) | 1369fe56b9e6SYuval Mintz (params->drv_minor << 16) | 1370fe56b9e6SYuval Mintz (params->drv_rev << 8) | 1371fe56b9e6SYuval Mintz (params->drv_eng); 1372fe56b9e6SYuval Mintz strlcpy(drv_version.name, params->name, 1373fe56b9e6SYuval Mintz MCP_DRV_VER_STR_SIZE - 4); 1374fe56b9e6SYuval Mintz rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, 1375fe56b9e6SYuval Mintz &drv_version); 1376fe56b9e6SYuval Mintz if (rc) { 1377fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed sending drv version command\n"); 1378de0e4fd2SWenwen Wang goto err4; 1379fe56b9e6SYuval Mintz } 13801408cc1fSYuval Mintz } 1381fe56b9e6SYuval Mintz 13828c925c44SYuval Mintz qed_reset_vport_stats(cdev); 13838c925c44SYuval Mintz 1384fe56b9e6SYuval Mintz return 0; 1385fe56b9e6SYuval Mintz 1386de0e4fd2SWenwen Wang err4: 1387de0e4fd2SWenwen Wang qed_ll2_dealloc_if(cdev); 13880a7fb11cSYuval Mintz err3: 13890a7fb11cSYuval Mintz qed_hw_stop(cdev); 1390fe56b9e6SYuval Mintz err2: 13918c925c44SYuval Mintz qed_hw_timers_stop_all(cdev); 13921408cc1fSYuval Mintz if (IS_PF(cdev)) 13938c925c44SYuval Mintz qed_slowpath_irq_free(cdev); 13948c925c44SYuval Mintz qed_free_stream_mem(cdev); 1395fe56b9e6SYuval Mintz qed_disable_msix(cdev); 1396fe56b9e6SYuval Mintz err1: 1397fe56b9e6SYuval Mintz qed_resc_free(cdev); 1398fe56b9e6SYuval Mintz err: 13991408cc1fSYuval Mintz if (IS_PF(cdev)) 1400fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1401fe56b9e6SYuval Mintz 1402d51e4af5SChopra, Manish if (IS_PF(cdev) && (cdev->num_hwfns == 1) && 1403d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt) 1404d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1405d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1406c78c70faSSudarsana Reddy Kalluru 140737bff2b9SYuval Mintz qed_iov_wq_stop(cdev, false); 140837bff2b9SYuval Mintz 140959ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 141059ccf86fSSudarsana Reddy Kalluru 1411fe56b9e6SYuval Mintz return rc; 1412fe56b9e6SYuval Mintz } 1413fe56b9e6SYuval Mintz 1414fe56b9e6SYuval Mintz static int qed_slowpath_stop(struct qed_dev *cdev) 1415fe56b9e6SYuval Mintz { 1416fe56b9e6SYuval Mintz if (!cdev) 1417fe56b9e6SYuval Mintz return -ENODEV; 1418fe56b9e6SYuval Mintz 141959ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 142059ccf86fSSudarsana Reddy Kalluru 14210a7fb11cSYuval Mintz qed_ll2_dealloc_if(cdev); 14220a7fb11cSYuval Mintz 14231408cc1fSYuval Mintz if (IS_PF(cdev)) { 1424d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) 1425d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1426d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1427fe56b9e6SYuval Mintz qed_free_stream_mem(cdev); 1428c5ac9319SYuval Mintz if (IS_QED_ETH_IF(cdev)) 14290b55e27dSYuval Mintz qed_sriov_disable(cdev, true); 14305f027d7aSMintz, Yuval } 1431fe56b9e6SYuval Mintz 1432fe56b9e6SYuval Mintz qed_nic_stop(cdev); 14335f027d7aSMintz, Yuval 14345f027d7aSMintz, Yuval if (IS_PF(cdev)) 1435fe56b9e6SYuval Mintz qed_slowpath_irq_free(cdev); 1436fe56b9e6SYuval Mintz 1437fe56b9e6SYuval Mintz qed_disable_msix(cdev); 14381226337aSTomer Tayar 14391226337aSTomer Tayar qed_resc_free(cdev); 1440fe56b9e6SYuval Mintz 144137bff2b9SYuval Mintz qed_iov_wq_stop(cdev, true); 144237bff2b9SYuval Mintz 14431408cc1fSYuval Mintz if (IS_PF(cdev)) 1444fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1445fe56b9e6SYuval Mintz 1446fe56b9e6SYuval Mintz return 0; 1447fe56b9e6SYuval Mintz } 1448fe56b9e6SYuval Mintz 1449712c3cbfSMintz, Yuval static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) 1450fe56b9e6SYuval Mintz { 1451fe56b9e6SYuval Mintz int i; 1452fe56b9e6SYuval Mintz 1453fe56b9e6SYuval Mintz memcpy(cdev->name, name, NAME_SIZE); 1454fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) 1455fe56b9e6SYuval Mintz snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); 1456fe56b9e6SYuval Mintz } 1457fe56b9e6SYuval Mintz 1458fe56b9e6SYuval Mintz static u32 qed_sb_init(struct qed_dev *cdev, 1459fe56b9e6SYuval Mintz struct qed_sb_info *sb_info, 1460fe56b9e6SYuval Mintz void *sb_virt_addr, 1461fe56b9e6SYuval Mintz dma_addr_t sb_phy_addr, u16 sb_id, 1462fe56b9e6SYuval Mintz enum qed_sb_type type) 1463fe56b9e6SYuval Mintz { 1464fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 146585750d74SMintz, Yuval struct qed_ptt *p_ptt; 1466fe56b9e6SYuval Mintz u16 rel_sb_id; 1467fe56b9e6SYuval Mintz u32 rc; 1468fe56b9e6SYuval Mintz 146908eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 147008eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 147108eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 147208eb1fb0SMichal Kalderon rel_sb_id = sb_id / cdev->num_hwfns; 147308eb1fb0SMichal Kalderon } else { 147408eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 147508eb1fb0SMichal Kalderon rel_sb_id = sb_id; 147608eb1fb0SMichal Kalderon } 1477fe56b9e6SYuval Mintz 1478fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1479fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 148008eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1481fe56b9e6SYuval Mintz 148285750d74SMintz, Yuval if (IS_PF(p_hwfn->cdev)) { 148385750d74SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 148485750d74SMintz, Yuval if (!p_ptt) 148585750d74SMintz, Yuval return -EBUSY; 148685750d74SMintz, Yuval 148785750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, 148885750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 148985750d74SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 149085750d74SMintz, Yuval } else { 149185750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, 149285750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 149385750d74SMintz, Yuval } 1494fe56b9e6SYuval Mintz 1495fe56b9e6SYuval Mintz return rc; 1496fe56b9e6SYuval Mintz } 1497fe56b9e6SYuval Mintz 1498fe56b9e6SYuval Mintz static u32 qed_sb_release(struct qed_dev *cdev, 149908eb1fb0SMichal Kalderon struct qed_sb_info *sb_info, 150008eb1fb0SMichal Kalderon u16 sb_id, 150108eb1fb0SMichal Kalderon enum qed_sb_type type) 1502fe56b9e6SYuval Mintz { 1503fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 1504fe56b9e6SYuval Mintz u16 rel_sb_id; 1505fe56b9e6SYuval Mintz u32 rc; 1506fe56b9e6SYuval Mintz 150708eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 150808eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 150908eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 1510fe56b9e6SYuval Mintz rel_sb_id = sb_id / cdev->num_hwfns; 151108eb1fb0SMichal Kalderon } else { 151208eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 151308eb1fb0SMichal Kalderon rel_sb_id = sb_id; 151408eb1fb0SMichal Kalderon } 1515fe56b9e6SYuval Mintz 1516fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1517fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 151808eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1519fe56b9e6SYuval Mintz 1520fe56b9e6SYuval Mintz rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); 1521fe56b9e6SYuval Mintz 1522fe56b9e6SYuval Mintz return rc; 1523fe56b9e6SYuval Mintz } 1524fe56b9e6SYuval Mintz 1525fe7cd2bfSYuval Mintz static bool qed_can_link_change(struct qed_dev *cdev) 1526fe7cd2bfSYuval Mintz { 1527fe7cd2bfSYuval Mintz return true; 1528fe7cd2bfSYuval Mintz } 1529fe7cd2bfSYuval Mintz 153099785a87SAlexander Lobakin static void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params, 153199785a87SAlexander Lobakin const struct qed_link_params *params) 153299785a87SAlexander Lobakin { 153399785a87SAlexander Lobakin struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed; 153499785a87SAlexander Lobakin const struct qed_mfw_speed_map *map; 153599785a87SAlexander Lobakin u32 i; 153699785a87SAlexander Lobakin 153799785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 153899785a87SAlexander Lobakin ext_speed->autoneg = !!params->autoneg; 153999785a87SAlexander Lobakin 154099785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 154199785a87SAlexander Lobakin ext_speed->advertised_speeds = 0; 154299785a87SAlexander Lobakin 154399785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) { 154499785a87SAlexander Lobakin map = qed_mfw_ext_maps + i; 154599785a87SAlexander Lobakin 154699785a87SAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 154799785a87SAlexander Lobakin ext_speed->advertised_speeds |= map->mfw_val; 154899785a87SAlexander Lobakin } 154999785a87SAlexander Lobakin } 155099785a87SAlexander Lobakin 155199785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) { 155299785a87SAlexander Lobakin switch (params->forced_speed) { 155399785a87SAlexander Lobakin case SPEED_1000: 155499785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_1G; 155599785a87SAlexander Lobakin break; 155699785a87SAlexander Lobakin case SPEED_10000: 155799785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_10G; 155899785a87SAlexander Lobakin break; 155999785a87SAlexander Lobakin case SPEED_20000: 156099785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_20G; 156199785a87SAlexander Lobakin break; 156299785a87SAlexander Lobakin case SPEED_25000: 156399785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_25G; 156499785a87SAlexander Lobakin break; 156599785a87SAlexander Lobakin case SPEED_40000: 156699785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_40G; 156799785a87SAlexander Lobakin break; 156899785a87SAlexander Lobakin case SPEED_50000: 156999785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_50G_R | 157099785a87SAlexander Lobakin QED_EXT_SPEED_50G_R2; 157199785a87SAlexander Lobakin break; 157299785a87SAlexander Lobakin case SPEED_100000: 157399785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 | 157499785a87SAlexander Lobakin QED_EXT_SPEED_100G_R4 | 157599785a87SAlexander Lobakin QED_EXT_SPEED_100G_P4; 157699785a87SAlexander Lobakin break; 157799785a87SAlexander Lobakin default: 157899785a87SAlexander Lobakin break; 157999785a87SAlexander Lobakin } 158099785a87SAlexander Lobakin } 158199785a87SAlexander Lobakin 158299785a87SAlexander Lobakin if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)) 158399785a87SAlexander Lobakin return; 158499785a87SAlexander Lobakin 158599785a87SAlexander Lobakin switch (params->forced_speed) { 158699785a87SAlexander Lobakin case SPEED_25000: 158799785a87SAlexander Lobakin switch (params->fec) { 158899785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 158999785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE; 159099785a87SAlexander Lobakin break; 159199785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 159299785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R; 159399785a87SAlexander Lobakin break; 159499785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 159599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528; 159699785a87SAlexander Lobakin break; 159799785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 159899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 | 159999785a87SAlexander Lobakin ETH_EXT_FEC_25G_BASE_R | 160099785a87SAlexander Lobakin ETH_EXT_FEC_25G_NONE; 160199785a87SAlexander Lobakin break; 160299785a87SAlexander Lobakin default: 160399785a87SAlexander Lobakin break; 160499785a87SAlexander Lobakin } 160599785a87SAlexander Lobakin 160699785a87SAlexander Lobakin break; 160799785a87SAlexander Lobakin case SPEED_40000: 160899785a87SAlexander Lobakin switch (params->fec) { 160999785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 161099785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE; 161199785a87SAlexander Lobakin break; 161299785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 161399785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R; 161499785a87SAlexander Lobakin break; 161599785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 161699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R | 161799785a87SAlexander Lobakin ETH_EXT_FEC_40G_NONE; 161899785a87SAlexander Lobakin break; 161999785a87SAlexander Lobakin default: 162099785a87SAlexander Lobakin break; 162199785a87SAlexander Lobakin } 162299785a87SAlexander Lobakin 162399785a87SAlexander Lobakin break; 162499785a87SAlexander Lobakin case SPEED_50000: 162599785a87SAlexander Lobakin switch (params->fec) { 162699785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 162799785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE; 162899785a87SAlexander Lobakin break; 162999785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 163099785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R; 163199785a87SAlexander Lobakin break; 163299785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 163399785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528; 163499785a87SAlexander Lobakin break; 163599785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 163699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 | 163799785a87SAlexander Lobakin ETH_EXT_FEC_50G_BASE_R | 163899785a87SAlexander Lobakin ETH_EXT_FEC_50G_NONE; 163999785a87SAlexander Lobakin break; 164099785a87SAlexander Lobakin default: 164199785a87SAlexander Lobakin break; 164299785a87SAlexander Lobakin } 164399785a87SAlexander Lobakin 164499785a87SAlexander Lobakin break; 164599785a87SAlexander Lobakin case SPEED_100000: 164699785a87SAlexander Lobakin switch (params->fec) { 164799785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 164899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE; 164999785a87SAlexander Lobakin break; 165099785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 165199785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R; 165299785a87SAlexander Lobakin break; 165399785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 165499785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528; 165599785a87SAlexander Lobakin break; 165699785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 165799785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 | 165899785a87SAlexander Lobakin ETH_EXT_FEC_100G_BASE_R | 165999785a87SAlexander Lobakin ETH_EXT_FEC_100G_NONE; 166099785a87SAlexander Lobakin break; 166199785a87SAlexander Lobakin default: 166299785a87SAlexander Lobakin break; 166399785a87SAlexander Lobakin } 166499785a87SAlexander Lobakin 166599785a87SAlexander Lobakin break; 166699785a87SAlexander Lobakin default: 166799785a87SAlexander Lobakin break; 166899785a87SAlexander Lobakin } 166999785a87SAlexander Lobakin } 167099785a87SAlexander Lobakin 1671351a4dedSYuval Mintz static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) 1672cc875c2eSYuval Mintz { 1673cc875c2eSYuval Mintz struct qed_mcp_link_params *link_params; 1674097818fcSAlexander Lobakin struct qed_mcp_link_speed_params *speed; 1675097818fcSAlexander Lobakin const struct qed_mfw_speed_map *map; 1676bdb5d8ecSAlexander Lobakin struct qed_hwfn *hwfn; 1677cc875c2eSYuval Mintz struct qed_ptt *ptt; 1678cc875c2eSYuval Mintz int rc; 1679097818fcSAlexander Lobakin u32 i; 1680cc875c2eSYuval Mintz 1681cc875c2eSYuval Mintz if (!cdev) 1682cc875c2eSYuval Mintz return -ENODEV; 1683cc875c2eSYuval Mintz 1684cc875c2eSYuval Mintz /* The link should be set only once per PF */ 1685cc875c2eSYuval Mintz hwfn = &cdev->hwfns[0]; 1686cc875c2eSYuval Mintz 168765ed2ffdSMintz, Yuval /* When VF wants to set link, force it to read the bulletin instead. 168865ed2ffdSMintz, Yuval * This mimics the PF behavior, where a noitification [both immediate 168965ed2ffdSMintz, Yuval * and possible later] would be generated when changing properties. 169065ed2ffdSMintz, Yuval */ 169165ed2ffdSMintz, Yuval if (IS_VF(cdev)) { 169265ed2ffdSMintz, Yuval qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); 169365ed2ffdSMintz, Yuval return 0; 169465ed2ffdSMintz, Yuval } 169565ed2ffdSMintz, Yuval 1696cc875c2eSYuval Mintz ptt = qed_ptt_acquire(hwfn); 1697cc875c2eSYuval Mintz if (!ptt) 1698cc875c2eSYuval Mintz return -EBUSY; 1699cc875c2eSYuval Mintz 1700cc875c2eSYuval Mintz link_params = qed_mcp_get_link_params(hwfn); 1701bdb5d8ecSAlexander Lobakin if (!link_params) 1702bdb5d8ecSAlexander Lobakin return -ENODATA; 1703bdb5d8ecSAlexander Lobakin 1704097818fcSAlexander Lobakin speed = &link_params->speed; 1705097818fcSAlexander Lobakin 1706cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 1707097818fcSAlexander Lobakin speed->autoneg = !!params->autoneg; 1708bdb5d8ecSAlexander Lobakin 1709cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 1710097818fcSAlexander Lobakin speed->advertised_speeds = 0; 1711bdb5d8ecSAlexander Lobakin 1712097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) { 1713097818fcSAlexander Lobakin map = qed_mfw_legacy_maps + i; 1714bdb5d8ecSAlexander Lobakin 1715097818fcSAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 1716097818fcSAlexander Lobakin speed->advertised_speeds |= map->mfw_val; 1717097818fcSAlexander Lobakin } 1718cc875c2eSYuval Mintz } 1719bdb5d8ecSAlexander Lobakin 1720cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) 1721097818fcSAlexander Lobakin speed->forced_speed = params->forced_speed; 1722097818fcSAlexander Lobakin 172399785a87SAlexander Lobakin if (qed_mcp_is_ext_speed_supported(hwfn)) 172499785a87SAlexander Lobakin qed_set_ext_speed_params(link_params, params); 172599785a87SAlexander Lobakin 1726a43f235fSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { 1727a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 1728a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = true; 1729a43f235fSSudarsana Reddy Kalluru else 1730a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = false; 1731a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) 1732a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = true; 1733a43f235fSSudarsana Reddy Kalluru else 1734a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = false; 1735a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) 1736a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = true; 1737a43f235fSSudarsana Reddy Kalluru else 1738a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = false; 1739a43f235fSSudarsana Reddy Kalluru } 1740097818fcSAlexander Lobakin 174103dc76caSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { 174203dc76caSSudarsana Reddy Kalluru switch (params->loopback_mode) { 174303dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_INT_PHY: 1744351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; 174503dc76caSSudarsana Reddy Kalluru break; 174603dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT_PHY: 1747351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; 174803dc76caSSudarsana Reddy Kalluru break; 174903dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT: 1750351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT; 175103dc76caSSudarsana Reddy Kalluru break; 175203dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_MAC: 1753351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_MAC; 175403dc76caSSudarsana Reddy Kalluru break; 175598e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123: 175698e675ecSAlexander Lobakin link_params->loopback_mode = 175798e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_0123; 175898e675ecSAlexander Lobakin break; 175998e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301: 176098e675ecSAlexander Lobakin link_params->loopback_mode = 176198e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_2301; 176298e675ecSAlexander Lobakin break; 176398e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_PCS_AH_ONLY: 176498e675ecSAlexander Lobakin link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY; 176598e675ecSAlexander Lobakin break; 176698e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY: 176798e675ecSAlexander Lobakin link_params->loopback_mode = 176898e675ecSAlexander Lobakin ETH_LOOPBACK_REVERSE_MAC_AH_ONLY; 176998e675ecSAlexander Lobakin break; 177098e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY: 177198e675ecSAlexander Lobakin link_params->loopback_mode = 177298e675ecSAlexander Lobakin ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY; 177398e675ecSAlexander Lobakin break; 177403dc76caSSudarsana Reddy Kalluru default: 1775351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_NONE; 177603dc76caSSudarsana Reddy Kalluru break; 177703dc76caSSudarsana Reddy Kalluru } 177803dc76caSSudarsana Reddy Kalluru } 1779cc875c2eSYuval Mintz 1780645874e5SSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) 1781645874e5SSudarsana Reddy Kalluru memcpy(&link_params->eee, ¶ms->eee, 1782645874e5SSudarsana Reddy Kalluru sizeof(link_params->eee)); 1783645874e5SSudarsana Reddy Kalluru 1784ae7e6937SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG) 1785ae7e6937SAlexander Lobakin link_params->fec = params->fec; 1786ae7e6937SAlexander Lobakin 1787cc875c2eSYuval Mintz rc = qed_mcp_set_link(hwfn, ptt, params->link_up); 1788cc875c2eSYuval Mintz 1789cc875c2eSYuval Mintz qed_ptt_release(hwfn, ptt); 1790cc875c2eSYuval Mintz 1791cc875c2eSYuval Mintz return rc; 1792cc875c2eSYuval Mintz } 1793cc875c2eSYuval Mintz 1794cc875c2eSYuval Mintz static int qed_get_port_type(u32 media_type) 1795cc875c2eSYuval Mintz { 1796cc875c2eSYuval Mintz int port_type; 1797cc875c2eSYuval Mintz 1798cc875c2eSYuval Mintz switch (media_type) { 1799cc875c2eSYuval Mintz case MEDIA_SFPP_10G_FIBER: 1800cc875c2eSYuval Mintz case MEDIA_SFP_1G_FIBER: 1801cc875c2eSYuval Mintz case MEDIA_XFP_FIBER: 1802b639f197SYuval Mintz case MEDIA_MODULE_FIBER: 1803cc875c2eSYuval Mintz port_type = PORT_FIBRE; 1804cc875c2eSYuval Mintz break; 1805cc875c2eSYuval Mintz case MEDIA_DA_TWINAX: 1806cc875c2eSYuval Mintz port_type = PORT_DA; 1807cc875c2eSYuval Mintz break; 1808cc875c2eSYuval Mintz case MEDIA_BASE_T: 1809cc875c2eSYuval Mintz port_type = PORT_TP; 1810cc875c2eSYuval Mintz break; 181199785a87SAlexander Lobakin case MEDIA_KR: 1812cc875c2eSYuval Mintz case MEDIA_NOT_PRESENT: 1813cc875c2eSYuval Mintz port_type = PORT_NONE; 1814cc875c2eSYuval Mintz break; 1815cc875c2eSYuval Mintz case MEDIA_UNSPECIFIED: 1816cc875c2eSYuval Mintz default: 1817cc875c2eSYuval Mintz port_type = PORT_OTHER; 1818cc875c2eSYuval Mintz break; 1819cc875c2eSYuval Mintz } 1820cc875c2eSYuval Mintz return port_type; 1821cc875c2eSYuval Mintz } 1822cc875c2eSYuval Mintz 182314b84e86SArnd Bergmann static int qed_get_link_data(struct qed_hwfn *hwfn, 182414b84e86SArnd Bergmann struct qed_mcp_link_params *params, 182514b84e86SArnd Bergmann struct qed_mcp_link_state *link, 182614b84e86SArnd Bergmann struct qed_mcp_link_capabilities *link_caps) 182714b84e86SArnd Bergmann { 182814b84e86SArnd Bergmann void *p; 182914b84e86SArnd Bergmann 183014b84e86SArnd Bergmann if (!IS_PF(hwfn->cdev)) { 183114b84e86SArnd Bergmann qed_vf_get_link_params(hwfn, params); 183214b84e86SArnd Bergmann qed_vf_get_link_state(hwfn, link); 183314b84e86SArnd Bergmann qed_vf_get_link_caps(hwfn, link_caps); 183414b84e86SArnd Bergmann 183514b84e86SArnd Bergmann return 0; 183614b84e86SArnd Bergmann } 183714b84e86SArnd Bergmann 183814b84e86SArnd Bergmann p = qed_mcp_get_link_params(hwfn); 183914b84e86SArnd Bergmann if (!p) 184014b84e86SArnd Bergmann return -ENXIO; 184114b84e86SArnd Bergmann memcpy(params, p, sizeof(*params)); 184214b84e86SArnd Bergmann 184314b84e86SArnd Bergmann p = qed_mcp_get_link_state(hwfn); 184414b84e86SArnd Bergmann if (!p) 184514b84e86SArnd Bergmann return -ENXIO; 184614b84e86SArnd Bergmann memcpy(link, p, sizeof(*link)); 184714b84e86SArnd Bergmann 184814b84e86SArnd Bergmann p = qed_mcp_get_link_capabilities(hwfn); 184914b84e86SArnd Bergmann if (!p) 185014b84e86SArnd Bergmann return -ENXIO; 185114b84e86SArnd Bergmann memcpy(link_caps, p, sizeof(*link_caps)); 185214b84e86SArnd Bergmann 185314b84e86SArnd Bergmann return 0; 185414b84e86SArnd Bergmann } 185514b84e86SArnd Bergmann 1856c56a8be7SRahul Verma static void qed_fill_link_capability(struct qed_hwfn *hwfn, 1857c56a8be7SRahul Verma struct qed_ptt *ptt, u32 capability, 1858bdb5d8ecSAlexander Lobakin unsigned long *if_caps) 1859c56a8be7SRahul Verma { 1860c56a8be7SRahul Verma u32 media_type, tcvr_state, tcvr_type; 1861c56a8be7SRahul Verma u32 speed_mask, board_cfg; 1862c56a8be7SRahul Verma 1863c56a8be7SRahul Verma if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) 1864c56a8be7SRahul Verma media_type = MEDIA_UNSPECIFIED; 1865c56a8be7SRahul Verma 1866c56a8be7SRahul Verma if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) 1867c56a8be7SRahul Verma tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; 1868c56a8be7SRahul Verma 1869c56a8be7SRahul Verma if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) 1870c56a8be7SRahul Verma speed_mask = 0xFFFFFFFF; 1871c56a8be7SRahul Verma 1872c56a8be7SRahul Verma if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) 1873c56a8be7SRahul Verma board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 1874c56a8be7SRahul Verma 1875c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 1876c56a8be7SRahul Verma "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", 1877c56a8be7SRahul Verma media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); 1878c56a8be7SRahul Verma 1879c56a8be7SRahul Verma switch (media_type) { 1880c56a8be7SRahul Verma case MEDIA_DA_TWINAX: 1881bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1882bdb5d8ecSAlexander Lobakin 1883c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1884bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 1885bdb5d8ecSAlexander Lobakin 1886c56a8be7SRahul Verma /* For DAC media multiple speed capabilities are supported */ 18879228b7c1SAlexander Lobakin capability |= speed_mask; 18889228b7c1SAlexander Lobakin 1889c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1890bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 1891c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1892bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseCR_Full); 18939228b7c1SAlexander Lobakin 1894c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 18959228b7c1SAlexander Lobakin switch (tcvr_type) { 18969228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_CR4: 18979228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 18989228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1899bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseCR4_Full); 19009228b7c1SAlexander Lobakin break; 19019228b7c1SAlexander Lobakin default: 19029228b7c1SAlexander Lobakin break; 19039228b7c1SAlexander Lobakin } 19049228b7c1SAlexander Lobakin 1905c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 1906bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseCR_Full); 1907c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1908bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseCR2_Full); 19099228b7c1SAlexander Lobakin 1910c56a8be7SRahul Verma if (capability & 1911c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 19129228b7c1SAlexander Lobakin switch (tcvr_type) { 19139228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_CR4: 19149228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1915bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseCR4_Full); 19169228b7c1SAlexander Lobakin break; 19179228b7c1SAlexander Lobakin default: 19189228b7c1SAlexander Lobakin break; 19199228b7c1SAlexander Lobakin } 1920bdb5d8ecSAlexander Lobakin 1921c56a8be7SRahul Verma break; 1922c56a8be7SRahul Verma case MEDIA_BASE_T: 1923bdb5d8ecSAlexander Lobakin phylink_set(if_caps, TP); 1924bdb5d8ecSAlexander Lobakin 1925c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { 1926c56a8be7SRahul Verma if (capability & 1927bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1928bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 1929c56a8be7SRahul Verma if (capability & 1930bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1931bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 1932c56a8be7SRahul Verma } 1933bdb5d8ecSAlexander Lobakin 1934c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { 1935bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1936bdb5d8ecSAlexander Lobakin 19379228b7c1SAlexander Lobakin switch (tcvr_type) { 19389228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1000BASET: 1939bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 19409228b7c1SAlexander Lobakin break; 19419228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_BASET: 1942bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 19439228b7c1SAlexander Lobakin break; 19449228b7c1SAlexander Lobakin default: 19459228b7c1SAlexander Lobakin break; 19469228b7c1SAlexander Lobakin } 1947c56a8be7SRahul Verma } 1948bdb5d8ecSAlexander Lobakin 1949c56a8be7SRahul Verma break; 1950c56a8be7SRahul Verma case MEDIA_SFP_1G_FIBER: 1951c56a8be7SRahul Verma case MEDIA_SFPP_10G_FIBER: 1952c56a8be7SRahul Verma case MEDIA_XFP_FIBER: 1953c56a8be7SRahul Verma case MEDIA_MODULE_FIBER: 1954bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 19559228b7c1SAlexander Lobakin capability |= speed_mask; 1956bdb5d8ecSAlexander Lobakin 19579228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 19589228b7c1SAlexander Lobakin switch (tcvr_type) { 19599228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_LX: 19609228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_SX: 19619228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 19629228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1963bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 19649228b7c1SAlexander Lobakin break; 19659228b7c1SAlexander Lobakin default: 19669228b7c1SAlexander Lobakin break; 1967c56a8be7SRahul Verma } 1968bdb5d8ecSAlexander Lobakin 19699228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19709228b7c1SAlexander Lobakin switch (tcvr_type) { 19719228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_SR: 19729228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 19739228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 19749228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 1975bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseSR_Full); 19769228b7c1SAlexander Lobakin break; 19779228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LR: 19789228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 19799228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 19809228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1981bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLR_Full); 19829228b7c1SAlexander Lobakin break; 19839228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LRM: 1984bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLRM_Full); 19859228b7c1SAlexander Lobakin break; 19869228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_ER: 1987bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseR_FEC); 19889228b7c1SAlexander Lobakin break; 19899228b7c1SAlexander Lobakin default: 19909228b7c1SAlexander Lobakin break; 1991c56a8be7SRahul Verma } 1992bdb5d8ecSAlexander Lobakin 1993c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1994bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 1995bdb5d8ecSAlexander Lobakin 19969228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 19979228b7c1SAlexander Lobakin switch (tcvr_type) { 19989228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_25G_SR: 19999228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 2000bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseSR_Full); 20019228b7c1SAlexander Lobakin break; 20029228b7c1SAlexander Lobakin default: 20039228b7c1SAlexander Lobakin break; 2004c56a8be7SRahul Verma } 2005bdb5d8ecSAlexander Lobakin 20069228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 20079228b7c1SAlexander Lobakin switch (tcvr_type) { 20089228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_LR4: 20099228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 20109228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2011bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseLR4_Full); 20129228b7c1SAlexander Lobakin break; 20139228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_SR4: 20149228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 20159228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2016bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseSR4_Full); 20179228b7c1SAlexander Lobakin break; 20189228b7c1SAlexander Lobakin default: 20199228b7c1SAlexander Lobakin break; 2020c56a8be7SRahul Verma } 2021bdb5d8ecSAlexander Lobakin 2022bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2023bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2024bdb5d8ecSAlexander Lobakin 2025c56a8be7SRahul Verma if (capability & 20269228b7c1SAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 20279228b7c1SAlexander Lobakin switch (tcvr_type) { 20289228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_SR4: 20299228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2030bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseSR4_Full); 20319228b7c1SAlexander Lobakin break; 20329228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 20339228b7c1SAlexander Lobakin phylink_set(if_caps, 100000baseLR4_ER4_Full); 20349228b7c1SAlexander Lobakin break; 20359228b7c1SAlexander Lobakin default: 20369228b7c1SAlexander Lobakin break; 2037c56a8be7SRahul Verma } 2038c56a8be7SRahul Verma 2039c56a8be7SRahul Verma break; 2040c56a8be7SRahul Verma case MEDIA_KR: 2041bdb5d8ecSAlexander Lobakin phylink_set(if_caps, Backplane); 2042bdb5d8ecSAlexander Lobakin 2043c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 2044bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 2045bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 2046bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 2047bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 2048bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseKR_Full); 2049bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 2050bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseKR_Full); 2051bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 2052bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseKR4_Full); 2053bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2054bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2055c56a8be7SRahul Verma if (capability & 2056c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 2057bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseKR4_Full); 2058bdb5d8ecSAlexander Lobakin 2059c56a8be7SRahul Verma break; 2060c56a8be7SRahul Verma case MEDIA_UNSPECIFIED: 2061c56a8be7SRahul Verma case MEDIA_NOT_PRESENT: 20629228b7c1SAlexander Lobakin default: 2063c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, 2064c56a8be7SRahul Verma "Unknown media and transceiver type;\n"); 2065c56a8be7SRahul Verma break; 2066c56a8be7SRahul Verma } 2067c56a8be7SRahul Verma } 2068c56a8be7SRahul Verma 20693c41486eSAlexander Lobakin static void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask) 20703c41486eSAlexander Lobakin { 20713c41486eSAlexander Lobakin *speed_mask = 0; 20723c41486eSAlexander Lobakin 20733c41486eSAlexander Lobakin if (caps & 20743c41486eSAlexander Lobakin (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD)) 20753c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 20763c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_10G) 20773c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 20783c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_20G) 20793c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; 20803c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_25G) 20813c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 20823c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_40G) 20833c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 20843c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_50G) 20853c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; 20863c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_100G) 20873c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; 20883c41486eSAlexander Lobakin } 20893c41486eSAlexander Lobakin 2090cc875c2eSYuval Mintz static void qed_fill_link(struct qed_hwfn *hwfn, 2091706d0891SRahul Verma struct qed_ptt *ptt, 2092cc875c2eSYuval Mintz struct qed_link_output *if_link) 2093cc875c2eSYuval Mintz { 2094c56a8be7SRahul Verma struct qed_mcp_link_capabilities link_caps; 2095cc875c2eSYuval Mintz struct qed_mcp_link_params params; 2096cc875c2eSYuval Mintz struct qed_mcp_link_state link; 20973c41486eSAlexander Lobakin u32 media_type, speed_mask; 2098cc875c2eSYuval Mintz 2099cc875c2eSYuval Mintz memset(if_link, 0, sizeof(*if_link)); 2100cc875c2eSYuval Mintz 2101cc875c2eSYuval Mintz /* Prepare source inputs */ 210214b84e86SArnd Bergmann if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { 210314b84e86SArnd Bergmann dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); 210414b84e86SArnd Bergmann return; 21051408cc1fSYuval Mintz } 2106cc875c2eSYuval Mintz 2107cc875c2eSYuval Mintz /* Set the link parameters to pass to protocol driver */ 2108cc875c2eSYuval Mintz if (link.link_up) 2109cc875c2eSYuval Mintz if_link->link_up = true; 2110cc875c2eSYuval Mintz 211199785a87SAlexander Lobakin if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) { 211299785a87SAlexander Lobakin if (link_caps.default_ext_autoneg) 211399785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 211499785a87SAlexander Lobakin 211599785a87SAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 211699785a87SAlexander Lobakin 211799785a87SAlexander Lobakin if (params.ext_speed.autoneg) 211899785a87SAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 211999785a87SAlexander Lobakin else 212099785a87SAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 212199785a87SAlexander Lobakin 212299785a87SAlexander Lobakin qed_fill_link_capability(hwfn, ptt, 212399785a87SAlexander Lobakin params.ext_speed.advertised_speeds, 212499785a87SAlexander Lobakin if_link->advertised_caps); 212599785a87SAlexander Lobakin } else { 212634f9199cSsudarsana.kalluru@cavium.com if (link_caps.default_speed_autoneg) 2127bdb5d8ecSAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 2128cc875c2eSYuval Mintz 2129bdb5d8ecSAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 2130bdb5d8ecSAlexander Lobakin 213134f9199cSsudarsana.kalluru@cavium.com if (params.speed.autoneg) 2132bdb5d8ecSAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 213334f9199cSsudarsana.kalluru@cavium.com else 2134bdb5d8ecSAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 213599785a87SAlexander Lobakin } 213699785a87SAlexander Lobakin 213799785a87SAlexander Lobakin if (params.pause.autoneg || 213899785a87SAlexander Lobakin (params.pause.forced_rx && params.pause.forced_tx)) 213999785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Asym_Pause); 214099785a87SAlexander Lobakin if (params.pause.autoneg || params.pause.forced_rx || 214199785a87SAlexander Lobakin params.pause.forced_tx) 214299785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Pause); 2143cc875c2eSYuval Mintz 2144ae7e6937SAlexander Lobakin if_link->sup_fec = link_caps.fec_default; 2145ae7e6937SAlexander Lobakin if_link->active_fec = params.fec; 2146ae7e6937SAlexander Lobakin 2147c56a8be7SRahul Verma /* Fill link advertised capability */ 2148c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, 2149bdb5d8ecSAlexander Lobakin if_link->advertised_caps); 21503c41486eSAlexander Lobakin 2151c56a8be7SRahul Verma /* Fill link supported capability */ 2152c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, 2153bdb5d8ecSAlexander Lobakin if_link->supported_caps); 2154cc875c2eSYuval Mintz 21553c41486eSAlexander Lobakin /* Fill partner advertised capability */ 21563c41486eSAlexander Lobakin qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask); 21573c41486eSAlexander Lobakin qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps); 21583c41486eSAlexander Lobakin 2159cc875c2eSYuval Mintz if (link.link_up) 2160cc875c2eSYuval Mintz if_link->speed = link.speed; 2161cc875c2eSYuval Mintz 2162cc875c2eSYuval Mintz /* TODO - fill duplex properly */ 2163cc875c2eSYuval Mintz if_link->duplex = DUPLEX_FULL; 2164706d0891SRahul Verma qed_mcp_get_media_type(hwfn, ptt, &media_type); 2165cc875c2eSYuval Mintz if_link->port = qed_get_port_type(media_type); 2166cc875c2eSYuval Mintz 2167cc875c2eSYuval Mintz if_link->autoneg = params.speed.autoneg; 2168cc875c2eSYuval Mintz 2169cc875c2eSYuval Mintz if (params.pause.autoneg) 2170cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 2171cc875c2eSYuval Mintz if (params.pause.forced_rx) 2172cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; 2173cc875c2eSYuval Mintz if (params.pause.forced_tx) 2174cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; 2175cc875c2eSYuval Mintz 2176cc875c2eSYuval Mintz if (link.an_complete) 2177bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Autoneg); 2178cc875c2eSYuval Mintz if (link.partner_adv_pause) 2179bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Pause); 2180cc875c2eSYuval Mintz if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || 2181cc875c2eSYuval Mintz link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) 2182bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Asym_Pause); 2183645874e5SSudarsana Reddy Kalluru 2184645874e5SSudarsana Reddy Kalluru if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) { 2185645874e5SSudarsana Reddy Kalluru if_link->eee_supported = false; 2186645874e5SSudarsana Reddy Kalluru } else { 2187645874e5SSudarsana Reddy Kalluru if_link->eee_supported = true; 2188645874e5SSudarsana Reddy Kalluru if_link->eee_active = link.eee_active; 2189645874e5SSudarsana Reddy Kalluru if_link->sup_caps = link_caps.eee_speed_caps; 2190645874e5SSudarsana Reddy Kalluru /* MFW clears adv_caps on eee disable; use configured value */ 2191645874e5SSudarsana Reddy Kalluru if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : 2192645874e5SSudarsana Reddy Kalluru params.eee.adv_caps; 2193645874e5SSudarsana Reddy Kalluru if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; 2194645874e5SSudarsana Reddy Kalluru if_link->eee.enable = params.eee.enable; 2195645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; 2196645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; 2197645874e5SSudarsana Reddy Kalluru } 2198cc875c2eSYuval Mintz } 2199cc875c2eSYuval Mintz 2200cc875c2eSYuval Mintz static void qed_get_current_link(struct qed_dev *cdev, 2201cc875c2eSYuval Mintz struct qed_link_output *if_link) 2202cc875c2eSYuval Mintz { 2203706d0891SRahul Verma struct qed_hwfn *hwfn; 2204706d0891SRahul Verma struct qed_ptt *ptt; 220536558c3dSYuval Mintz int i; 220636558c3dSYuval Mintz 2207706d0891SRahul Verma hwfn = &cdev->hwfns[0]; 2208706d0891SRahul Verma if (IS_PF(cdev)) { 2209706d0891SRahul Verma ptt = qed_ptt_acquire(hwfn); 2210706d0891SRahul Verma if (ptt) { 2211706d0891SRahul Verma qed_fill_link(hwfn, ptt, if_link); 2212706d0891SRahul Verma qed_ptt_release(hwfn, ptt); 2213706d0891SRahul Verma } else { 2214706d0891SRahul Verma DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); 2215706d0891SRahul Verma } 2216706d0891SRahul Verma } else { 2217706d0891SRahul Verma qed_fill_link(hwfn, NULL, if_link); 2218706d0891SRahul Verma } 221936558c3dSYuval Mintz 222036558c3dSYuval Mintz for_each_hwfn(cdev, i) 222136558c3dSYuval Mintz qed_inform_vf_link_state(&cdev->hwfns[i]); 2222cc875c2eSYuval Mintz } 2223cc875c2eSYuval Mintz 2224706d0891SRahul Verma void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2225cc875c2eSYuval Mintz { 2226cc875c2eSYuval Mintz void *cookie = hwfn->cdev->ops_cookie; 2227cc875c2eSYuval Mintz struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2228cc875c2eSYuval Mintz struct qed_link_output if_link; 2229cc875c2eSYuval Mintz 2230706d0891SRahul Verma qed_fill_link(hwfn, ptt, &if_link); 223136558c3dSYuval Mintz qed_inform_vf_link_state(hwfn); 2232cc875c2eSYuval Mintz 2233cc875c2eSYuval Mintz if (IS_LEAD_HWFN(hwfn) && cookie) 2234cc875c2eSYuval Mintz op->link_update(cookie, &if_link); 2235cc875c2eSYuval Mintz } 2236cc875c2eSYuval Mintz 2237699fed4aSSudarsana Reddy Kalluru void qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2238699fed4aSSudarsana Reddy Kalluru { 2239699fed4aSSudarsana Reddy Kalluru void *cookie = hwfn->cdev->ops_cookie; 2240699fed4aSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2241699fed4aSSudarsana Reddy Kalluru 2242699fed4aSSudarsana Reddy Kalluru if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update) 2243699fed4aSSudarsana Reddy Kalluru op->bw_update(cookie); 2244699fed4aSSudarsana Reddy Kalluru } 2245699fed4aSSudarsana Reddy Kalluru 2246fe56b9e6SYuval Mintz static int qed_drain(struct qed_dev *cdev) 2247fe56b9e6SYuval Mintz { 2248fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 2249fe56b9e6SYuval Mintz struct qed_ptt *ptt; 2250fe56b9e6SYuval Mintz int i, rc; 2251fe56b9e6SYuval Mintz 22521408cc1fSYuval Mintz if (IS_VF(cdev)) 22531408cc1fSYuval Mintz return 0; 22541408cc1fSYuval Mintz 2255fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 2256fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 2257fe56b9e6SYuval Mintz ptt = qed_ptt_acquire(hwfn); 2258fe56b9e6SYuval Mintz if (!ptt) { 2259fe56b9e6SYuval Mintz DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); 2260fe56b9e6SYuval Mintz return -EBUSY; 2261fe56b9e6SYuval Mintz } 2262fe56b9e6SYuval Mintz rc = qed_mcp_drain(hwfn, ptt); 22639aaa4e8bSDenis Bolotin qed_ptt_release(hwfn, ptt); 2264fe56b9e6SYuval Mintz if (rc) 2265fe56b9e6SYuval Mintz return rc; 2266fe56b9e6SYuval Mintz } 2267fe56b9e6SYuval Mintz 2268fe56b9e6SYuval Mintz return 0; 2269fe56b9e6SYuval Mintz } 2270fe56b9e6SYuval Mintz 22713a69cae8SSudarsana Reddy Kalluru static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev, 22723a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att *nvm_image, 22733a69cae8SSudarsana Reddy Kalluru u32 *crc) 22743a69cae8SSudarsana Reddy Kalluru { 22753a69cae8SSudarsana Reddy Kalluru u8 *buf = NULL; 22765ab90341SAlexander Lobakin int rc; 22773a69cae8SSudarsana Reddy Kalluru 22783a69cae8SSudarsana Reddy Kalluru /* Allocate a buffer for holding the nvram image */ 22793a69cae8SSudarsana Reddy Kalluru buf = kzalloc(nvm_image->length, GFP_KERNEL); 22803a69cae8SSudarsana Reddy Kalluru if (!buf) 22813a69cae8SSudarsana Reddy Kalluru return -ENOMEM; 22823a69cae8SSudarsana Reddy Kalluru 22833a69cae8SSudarsana Reddy Kalluru /* Read image into buffer */ 22843a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr, 22853a69cae8SSudarsana Reddy Kalluru buf, nvm_image->length); 22863a69cae8SSudarsana Reddy Kalluru if (rc) { 22873a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading image from nvm\n"); 22883a69cae8SSudarsana Reddy Kalluru goto out; 22893a69cae8SSudarsana Reddy Kalluru } 22903a69cae8SSudarsana Reddy Kalluru 22913a69cae8SSudarsana Reddy Kalluru /* Convert the buffer into big-endian format (excluding the 22923a69cae8SSudarsana Reddy Kalluru * closing 4 bytes of CRC). 22933a69cae8SSudarsana Reddy Kalluru */ 22945ab90341SAlexander Lobakin cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf, 22955ab90341SAlexander Lobakin DIV_ROUND_UP(nvm_image->length - 4, 4)); 22963a69cae8SSudarsana Reddy Kalluru 22973a69cae8SSudarsana Reddy Kalluru /* Calc CRC for the "actual" image buffer, i.e. not including 22983a69cae8SSudarsana Reddy Kalluru * the last 4 CRC bytes. 22993a69cae8SSudarsana Reddy Kalluru */ 23005ab90341SAlexander Lobakin *crc = ~crc32(~0U, buf, nvm_image->length - 4); 23015ab90341SAlexander Lobakin *crc = (__force u32)cpu_to_be32p(crc); 23023a69cae8SSudarsana Reddy Kalluru 23033a69cae8SSudarsana Reddy Kalluru out: 23043a69cae8SSudarsana Reddy Kalluru kfree(buf); 23053a69cae8SSudarsana Reddy Kalluru 23063a69cae8SSudarsana Reddy Kalluru return rc; 23073a69cae8SSudarsana Reddy Kalluru } 23083a69cae8SSudarsana Reddy Kalluru 23093a69cae8SSudarsana Reddy Kalluru /* Binary file format - 23103a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 23113a69cae8SSudarsana Reddy Kalluru * 0B | 0x4 [command index] | 23123a69cae8SSudarsana Reddy Kalluru * 4B | image_type | Options | Number of register settings | 23133a69cae8SSudarsana Reddy Kalluru * 8B | Value | 23143a69cae8SSudarsana Reddy Kalluru * 12B | Mask | 23153a69cae8SSudarsana Reddy Kalluru * 16B | Offset | 23163a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 23173a69cae8SSudarsana Reddy Kalluru * There can be several Value-Mask-Offset sets as specified by 'Number of...'. 23183a69cae8SSudarsana Reddy Kalluru * Options - 0'b - Calculate & Update CRC for image 23193a69cae8SSudarsana Reddy Kalluru */ 23203a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data, 23213a69cae8SSudarsana Reddy Kalluru bool *check_resp) 23223a69cae8SSudarsana Reddy Kalluru { 23233a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att nvm_image; 23243a69cae8SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn; 23253a69cae8SSudarsana Reddy Kalluru bool is_crc = false; 23263a69cae8SSudarsana Reddy Kalluru u32 image_type; 23273a69cae8SSudarsana Reddy Kalluru int rc = 0, i; 23283a69cae8SSudarsana Reddy Kalluru u16 len; 23293a69cae8SSudarsana Reddy Kalluru 23303a69cae8SSudarsana Reddy Kalluru *data += 4; 23313a69cae8SSudarsana Reddy Kalluru image_type = **data; 23323a69cae8SSudarsana Reddy Kalluru p_hwfn = QED_LEADING_HWFN(cdev); 23333a69cae8SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 23343a69cae8SSudarsana Reddy Kalluru if (image_type == p_hwfn->nvm_info.image_att[i].image_type) 23353a69cae8SSudarsana Reddy Kalluru break; 23363a69cae8SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 23373a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find nvram image of type %08x\n", 23383a69cae8SSudarsana Reddy Kalluru image_type); 23393a69cae8SSudarsana Reddy Kalluru return -ENOENT; 23403a69cae8SSudarsana Reddy Kalluru } 23413a69cae8SSudarsana Reddy Kalluru 23423a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 23433a69cae8SSudarsana Reddy Kalluru nvm_image.length = p_hwfn->nvm_info.image_att[i].len; 23443a69cae8SSudarsana Reddy Kalluru 23453a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 23463a69cae8SSudarsana Reddy Kalluru "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n", 23473a69cae8SSudarsana Reddy Kalluru **data, image_type, nvm_image.start_addr, 23483a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 1); 23493a69cae8SSudarsana Reddy Kalluru (*data)++; 23503a69cae8SSudarsana Reddy Kalluru is_crc = !!(**data & BIT(0)); 23513a69cae8SSudarsana Reddy Kalluru (*data)++; 23523a69cae8SSudarsana Reddy Kalluru len = *((u16 *)*data); 23533a69cae8SSudarsana Reddy Kalluru *data += 2; 23543a69cae8SSudarsana Reddy Kalluru if (is_crc) { 23553a69cae8SSudarsana Reddy Kalluru u32 crc = 0; 23563a69cae8SSudarsana Reddy Kalluru 23573a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc); 23583a69cae8SSudarsana Reddy Kalluru if (rc) { 23593a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc); 23603a69cae8SSudarsana Reddy Kalluru goto exit; 23613a69cae8SSudarsana Reddy Kalluru } 23623a69cae8SSudarsana Reddy Kalluru 23633a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 23643a69cae8SSudarsana Reddy Kalluru (nvm_image.start_addr + 23653a69cae8SSudarsana Reddy Kalluru nvm_image.length - 4), (u8 *)&crc, 4); 23663a69cae8SSudarsana Reddy Kalluru if (rc) 23673a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x, rc = %d\n", 23683a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 4, rc); 23693a69cae8SSudarsana Reddy Kalluru goto exit; 23703a69cae8SSudarsana Reddy Kalluru } 23713a69cae8SSudarsana Reddy Kalluru 23723a69cae8SSudarsana Reddy Kalluru /* Iterate over the values for setting */ 23733a69cae8SSudarsana Reddy Kalluru while (len) { 23743a69cae8SSudarsana Reddy Kalluru u32 offset, mask, value, cur_value; 23753a69cae8SSudarsana Reddy Kalluru u8 buf[4]; 23763a69cae8SSudarsana Reddy Kalluru 23773a69cae8SSudarsana Reddy Kalluru value = *((u32 *)*data); 23783a69cae8SSudarsana Reddy Kalluru *data += 4; 23793a69cae8SSudarsana Reddy Kalluru mask = *((u32 *)*data); 23803a69cae8SSudarsana Reddy Kalluru *data += 4; 23813a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)*data); 23823a69cae8SSudarsana Reddy Kalluru *data += 4; 23833a69cae8SSudarsana Reddy Kalluru 23843a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf, 23853a69cae8SSudarsana Reddy Kalluru 4); 23863a69cae8SSudarsana Reddy Kalluru if (rc) { 23873a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading from %08x\n", 23883a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 23893a69cae8SSudarsana Reddy Kalluru goto exit; 23903a69cae8SSudarsana Reddy Kalluru } 23913a69cae8SSudarsana Reddy Kalluru 23923a69cae8SSudarsana Reddy Kalluru cur_value = le32_to_cpu(*((__le32 *)buf)); 23933a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 23943a69cae8SSudarsana Reddy Kalluru "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n", 23953a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, cur_value, 23963a69cae8SSudarsana Reddy Kalluru (cur_value & ~mask) | (value & mask), value, mask); 23973a69cae8SSudarsana Reddy Kalluru value = (value & mask) | (cur_value & ~mask); 23983a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 23993a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, 24003a69cae8SSudarsana Reddy Kalluru (u8 *)&value, 4); 24013a69cae8SSudarsana Reddy Kalluru if (rc) { 24023a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x\n", 24033a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 24043a69cae8SSudarsana Reddy Kalluru goto exit; 24053a69cae8SSudarsana Reddy Kalluru } 24063a69cae8SSudarsana Reddy Kalluru 24073a69cae8SSudarsana Reddy Kalluru len--; 24083a69cae8SSudarsana Reddy Kalluru } 24093a69cae8SSudarsana Reddy Kalluru exit: 24103a69cae8SSudarsana Reddy Kalluru return rc; 24113a69cae8SSudarsana Reddy Kalluru } 24123a69cae8SSudarsana Reddy Kalluru 24133a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24143a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24153a69cae8SSudarsana Reddy Kalluru * 0B | 0x3 [command index] | 24163a69cae8SSudarsana Reddy Kalluru * 4B | b'0: check_response? | b'1-31 reserved | 24173a69cae8SSudarsana Reddy Kalluru * 8B | File-type | reserved | 2418057d2b19SSudarsana Reddy Kalluru * 12B | Image length in bytes | 24193a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24203a69cae8SSudarsana Reddy Kalluru * Start a new file of the provided type 24213a69cae8SSudarsana Reddy Kalluru */ 24223a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_start(struct qed_dev *cdev, 24233a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24243a69cae8SSudarsana Reddy Kalluru { 2425057d2b19SSudarsana Reddy Kalluru u32 file_type, file_size = 0; 24263a69cae8SSudarsana Reddy Kalluru int rc; 24273a69cae8SSudarsana Reddy Kalluru 24283a69cae8SSudarsana Reddy Kalluru *data += 4; 24293a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24303a69cae8SSudarsana Reddy Kalluru *data += 4; 2431057d2b19SSudarsana Reddy Kalluru file_type = **data; 24323a69cae8SSudarsana Reddy Kalluru 24333a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 2434057d2b19SSudarsana Reddy Kalluru "About to start a new file of type %02x\n", file_type); 2435057d2b19SSudarsana Reddy Kalluru if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) { 2436057d2b19SSudarsana Reddy Kalluru *data += 4; 2437057d2b19SSudarsana Reddy Kalluru file_size = *((u32 *)(*data)); 2438057d2b19SSudarsana Reddy Kalluru } 2439057d2b19SSudarsana Reddy Kalluru 2440057d2b19SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type, 2441057d2b19SSudarsana Reddy Kalluru (u8 *)(&file_size), 4); 24423a69cae8SSudarsana Reddy Kalluru *data += 4; 24433a69cae8SSudarsana Reddy Kalluru 24443a69cae8SSudarsana Reddy Kalluru return rc; 24453a69cae8SSudarsana Reddy Kalluru } 24463a69cae8SSudarsana Reddy Kalluru 24473a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24483a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24493a69cae8SSudarsana Reddy Kalluru * 0B | 0x2 [command index] | 24503a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24513a69cae8SSudarsana Reddy Kalluru * 8B | b'0: check_response? | b'1-31 reserved | 24523a69cae8SSudarsana Reddy Kalluru * 12B | Offset in bytes | 24533a69cae8SSudarsana Reddy Kalluru * 16B | Data ... | 24543a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24553a69cae8SSudarsana Reddy Kalluru * Write data as part of a file that was previously started. Data should be 24563a69cae8SSudarsana Reddy Kalluru * of length equal to that provided in the message 24573a69cae8SSudarsana Reddy Kalluru */ 24583a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_data(struct qed_dev *cdev, 24593a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24603a69cae8SSudarsana Reddy Kalluru { 24613a69cae8SSudarsana Reddy Kalluru u32 offset, len; 24623a69cae8SSudarsana Reddy Kalluru int rc; 24633a69cae8SSudarsana Reddy Kalluru 24643a69cae8SSudarsana Reddy Kalluru *data += 4; 24653a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 24663a69cae8SSudarsana Reddy Kalluru *data += 4; 24673a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24683a69cae8SSudarsana Reddy Kalluru *data += 4; 24693a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)(*data)); 24703a69cae8SSudarsana Reddy Kalluru *data += 4; 24713a69cae8SSudarsana Reddy Kalluru 24723a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 24733a69cae8SSudarsana Reddy Kalluru "About to write File-data: %08x bytes to offset %08x\n", 24743a69cae8SSudarsana Reddy Kalluru len, offset); 24753a69cae8SSudarsana Reddy Kalluru 24763a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset, 24773a69cae8SSudarsana Reddy Kalluru (char *)(*data), len); 24783a69cae8SSudarsana Reddy Kalluru *data += len; 24793a69cae8SSudarsana Reddy Kalluru 24803a69cae8SSudarsana Reddy Kalluru return rc; 24813a69cae8SSudarsana Reddy Kalluru } 24823a69cae8SSudarsana Reddy Kalluru 24833a69cae8SSudarsana Reddy Kalluru /* Binary file format [General header] - 24843a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24853a69cae8SSudarsana Reddy Kalluru * 0B | QED_NVM_SIGNATURE | 24863a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24873a69cae8SSudarsana Reddy Kalluru * 8B | Highest command in this batchfile | Reserved | 24883a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24893a69cae8SSudarsana Reddy Kalluru */ 24903a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_validate(struct qed_dev *cdev, 24913a69cae8SSudarsana Reddy Kalluru const struct firmware *image, 24923a69cae8SSudarsana Reddy Kalluru const u8 **data) 24933a69cae8SSudarsana Reddy Kalluru { 24943a69cae8SSudarsana Reddy Kalluru u32 signature, len; 24953a69cae8SSudarsana Reddy Kalluru 24963a69cae8SSudarsana Reddy Kalluru /* Check minimum size */ 24973a69cae8SSudarsana Reddy Kalluru if (image->size < 12) { 24983a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size); 24993a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25003a69cae8SSudarsana Reddy Kalluru } 25013a69cae8SSudarsana Reddy Kalluru 25023a69cae8SSudarsana Reddy Kalluru /* Check signature */ 25033a69cae8SSudarsana Reddy Kalluru signature = *((u32 *)(*data)); 25043a69cae8SSudarsana Reddy Kalluru if (signature != QED_NVM_SIGNATURE) { 25053a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Wrong signature '%08x'\n", signature); 25063a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25073a69cae8SSudarsana Reddy Kalluru } 25083a69cae8SSudarsana Reddy Kalluru 25093a69cae8SSudarsana Reddy Kalluru *data += 4; 25103a69cae8SSudarsana Reddy Kalluru /* Validate internal size equals the image-size */ 25113a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 25123a69cae8SSudarsana Reddy Kalluru if (len != image->size) { 25133a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n", 25143a69cae8SSudarsana Reddy Kalluru len, (u32)image->size); 25153a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25163a69cae8SSudarsana Reddy Kalluru } 25173a69cae8SSudarsana Reddy Kalluru 25183a69cae8SSudarsana Reddy Kalluru *data += 4; 25193a69cae8SSudarsana Reddy Kalluru /* Make sure driver familiar with all commands necessary for this */ 25203a69cae8SSudarsana Reddy Kalluru if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) { 25213a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n", 25223a69cae8SSudarsana Reddy Kalluru *((u16 *)(*data))); 25233a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25243a69cae8SSudarsana Reddy Kalluru } 25253a69cae8SSudarsana Reddy Kalluru 25263a69cae8SSudarsana Reddy Kalluru *data += 4; 25273a69cae8SSudarsana Reddy Kalluru 25283a69cae8SSudarsana Reddy Kalluru return 0; 25293a69cae8SSudarsana Reddy Kalluru } 25303a69cae8SSudarsana Reddy Kalluru 25310dabbe1bSSudarsana Reddy Kalluru /* Binary file format - 25320dabbe1bSSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 25330dabbe1bSSudarsana Reddy Kalluru * 0B | 0x5 [command index] | 25342da244a5SSudarsana Reddy Kalluru * 4B | Number of config attributes | Reserved | 25352da244a5SSudarsana Reddy Kalluru * 4B | Config ID | Entity ID | Length | 25362da244a5SSudarsana Reddy Kalluru * 4B | Value | 25370dabbe1bSSudarsana Reddy Kalluru * | | 25380dabbe1bSSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 25392da244a5SSudarsana Reddy Kalluru * There can be several cfg_id-entity_id-Length-Value sets as specified by 25402da244a5SSudarsana Reddy Kalluru * 'Number of config attributes'. 25410dabbe1bSSudarsana Reddy Kalluru * 25420dabbe1bSSudarsana Reddy Kalluru * The API parses config attributes from the user provided buffer and flashes 25430dabbe1bSSudarsana Reddy Kalluru * them to the respective NVM path using Management FW inerface. 25440dabbe1bSSudarsana Reddy Kalluru */ 25450dabbe1bSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data) 25460dabbe1bSSudarsana Reddy Kalluru { 25470dabbe1bSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 25480dabbe1bSSudarsana Reddy Kalluru u8 entity_id, len, buf[32]; 2549c63b0968SSudarsana Reddy Kalluru bool need_nvm_init = true; 25500dabbe1bSSudarsana Reddy Kalluru struct qed_ptt *ptt; 25510dabbe1bSSudarsana Reddy Kalluru u16 cfg_id, count; 25520dabbe1bSSudarsana Reddy Kalluru int rc = 0, i; 25530dabbe1bSSudarsana Reddy Kalluru u32 flags; 25540dabbe1bSSudarsana Reddy Kalluru 25550dabbe1bSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 25560dabbe1bSSudarsana Reddy Kalluru if (!ptt) 25570dabbe1bSSudarsana Reddy Kalluru return -EAGAIN; 25580dabbe1bSSudarsana Reddy Kalluru 25590dabbe1bSSudarsana Reddy Kalluru /* NVM CFG ID attribute header */ 25600dabbe1bSSudarsana Reddy Kalluru *data += 4; 25610dabbe1bSSudarsana Reddy Kalluru count = *((u16 *)*data); 25622da244a5SSudarsana Reddy Kalluru *data += 4; 25630dabbe1bSSudarsana Reddy Kalluru 25640dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 25652da244a5SSudarsana Reddy Kalluru "Read config ids: num_attrs = %0d\n", count); 2566c63b0968SSudarsana Reddy Kalluru /* NVM CFG ID attributes. Start loop index from 1 to avoid additional 2567c63b0968SSudarsana Reddy Kalluru * arithmetic operations in the implementation. 2568c63b0968SSudarsana Reddy Kalluru */ 2569c63b0968SSudarsana Reddy Kalluru for (i = 1; i <= count; i++) { 25700dabbe1bSSudarsana Reddy Kalluru cfg_id = *((u16 *)*data); 25710dabbe1bSSudarsana Reddy Kalluru *data += 2; 25722da244a5SSudarsana Reddy Kalluru entity_id = **data; 25732da244a5SSudarsana Reddy Kalluru (*data)++; 25740dabbe1bSSudarsana Reddy Kalluru len = **data; 25750dabbe1bSSudarsana Reddy Kalluru (*data)++; 25760dabbe1bSSudarsana Reddy Kalluru memcpy(buf, *data, len); 25770dabbe1bSSudarsana Reddy Kalluru *data += len; 25780dabbe1bSSudarsana Reddy Kalluru 2579c63b0968SSudarsana Reddy Kalluru flags = 0; 2580c63b0968SSudarsana Reddy Kalluru if (need_nvm_init) { 2581c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_INIT; 2582c63b0968SSudarsana Reddy Kalluru need_nvm_init = false; 2583c63b0968SSudarsana Reddy Kalluru } 2584c63b0968SSudarsana Reddy Kalluru 2585c63b0968SSudarsana Reddy Kalluru /* Commit to flash and free the resources */ 2586c63b0968SSudarsana Reddy Kalluru if (!(i % QED_NVM_CFG_MAX_ATTRS) || i == count) { 2587c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_COMMIT | 2588c63b0968SSudarsana Reddy Kalluru QED_NVM_CFG_OPTION_FREE; 2589c63b0968SSudarsana Reddy Kalluru need_nvm_init = true; 2590c63b0968SSudarsana Reddy Kalluru } 2591c63b0968SSudarsana Reddy Kalluru 2592c63b0968SSudarsana Reddy Kalluru if (entity_id) 2593c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_ENTITY_SEL; 25940dabbe1bSSudarsana Reddy Kalluru 25950dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 25962da244a5SSudarsana Reddy Kalluru "cfg_id = %d entity = %d len = %d\n", cfg_id, 25972da244a5SSudarsana Reddy Kalluru entity_id, len); 25980dabbe1bSSudarsana Reddy Kalluru rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags, 25990dabbe1bSSudarsana Reddy Kalluru buf, len); 26000dabbe1bSSudarsana Reddy Kalluru if (rc) { 26010dabbe1bSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id); 26020dabbe1bSSudarsana Reddy Kalluru break; 26030dabbe1bSSudarsana Reddy Kalluru } 26040dabbe1bSSudarsana Reddy Kalluru } 26050dabbe1bSSudarsana Reddy Kalluru 26060dabbe1bSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26070dabbe1bSSudarsana Reddy Kalluru 26080dabbe1bSSudarsana Reddy Kalluru return rc; 26090dabbe1bSSudarsana Reddy Kalluru } 26100dabbe1bSSudarsana Reddy Kalluru 26119e54ba7cSSudarsana Reddy Kalluru #define QED_MAX_NVM_BUF_LEN 32 26129e54ba7cSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_len(struct qed_dev *cdev, u32 cmd) 26139e54ba7cSSudarsana Reddy Kalluru { 26149e54ba7cSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26159e54ba7cSSudarsana Reddy Kalluru u8 buf[QED_MAX_NVM_BUF_LEN]; 26169e54ba7cSSudarsana Reddy Kalluru struct qed_ptt *ptt; 26179e54ba7cSSudarsana Reddy Kalluru u32 len; 26189e54ba7cSSudarsana Reddy Kalluru int rc; 26199e54ba7cSSudarsana Reddy Kalluru 26209e54ba7cSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26219e54ba7cSSudarsana Reddy Kalluru if (!ptt) 26229e54ba7cSSudarsana Reddy Kalluru return QED_MAX_NVM_BUF_LEN; 26239e54ba7cSSudarsana Reddy Kalluru 26249e54ba7cSSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, 0, QED_NVM_CFG_GET_FLAGS, buf, 26259e54ba7cSSudarsana Reddy Kalluru &len); 26269e54ba7cSSudarsana Reddy Kalluru if (rc || !len) { 26279e54ba7cSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26289e54ba7cSSudarsana Reddy Kalluru len = QED_MAX_NVM_BUF_LEN; 26299e54ba7cSSudarsana Reddy Kalluru } 26309e54ba7cSSudarsana Reddy Kalluru 26319e54ba7cSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26329e54ba7cSSudarsana Reddy Kalluru 26339e54ba7cSSudarsana Reddy Kalluru return len; 26349e54ba7cSSudarsana Reddy Kalluru } 26359e54ba7cSSudarsana Reddy Kalluru 26362d4c8495SSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_read(struct qed_dev *cdev, u8 **data, 26372d4c8495SSudarsana Reddy Kalluru u32 cmd, u32 entity_id) 26382d4c8495SSudarsana Reddy Kalluru { 26392d4c8495SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26402d4c8495SSudarsana Reddy Kalluru struct qed_ptt *ptt; 26412d4c8495SSudarsana Reddy Kalluru u32 flags, len; 26422d4c8495SSudarsana Reddy Kalluru int rc = 0; 26432d4c8495SSudarsana Reddy Kalluru 26442d4c8495SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26452d4c8495SSudarsana Reddy Kalluru if (!ptt) 26462d4c8495SSudarsana Reddy Kalluru return -EAGAIN; 26472d4c8495SSudarsana Reddy Kalluru 26482d4c8495SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26492d4c8495SSudarsana Reddy Kalluru "Read config cmd = %d entity id %d\n", cmd, entity_id); 26502d4c8495SSudarsana Reddy Kalluru flags = entity_id ? QED_NVM_CFG_GET_PF_FLAGS : QED_NVM_CFG_GET_FLAGS; 26512d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, entity_id, flags, *data, &len); 26522d4c8495SSudarsana Reddy Kalluru if (rc) 26532d4c8495SSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26542d4c8495SSudarsana Reddy Kalluru 26552d4c8495SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26562d4c8495SSudarsana Reddy Kalluru 26572d4c8495SSudarsana Reddy Kalluru return rc; 26582d4c8495SSudarsana Reddy Kalluru } 26592d4c8495SSudarsana Reddy Kalluru 26603a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash(struct qed_dev *cdev, const char *name) 26613a69cae8SSudarsana Reddy Kalluru { 26623a69cae8SSudarsana Reddy Kalluru const struct firmware *image; 26633a69cae8SSudarsana Reddy Kalluru const u8 *data, *data_end; 26643a69cae8SSudarsana Reddy Kalluru u32 cmd_type; 26653a69cae8SSudarsana Reddy Kalluru int rc; 26663a69cae8SSudarsana Reddy Kalluru 26673a69cae8SSudarsana Reddy Kalluru rc = request_firmware(&image, name, &cdev->pdev->dev); 26683a69cae8SSudarsana Reddy Kalluru if (rc) { 26693a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find '%s'\n", name); 26703a69cae8SSudarsana Reddy Kalluru return rc; 26713a69cae8SSudarsana Reddy Kalluru } 26723a69cae8SSudarsana Reddy Kalluru 26733a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26743a69cae8SSudarsana Reddy Kalluru "Flashing '%s' - firmware's data at %p, size is %08x\n", 26753a69cae8SSudarsana Reddy Kalluru name, image->data, (u32)image->size); 26763a69cae8SSudarsana Reddy Kalluru data = image->data; 26773a69cae8SSudarsana Reddy Kalluru data_end = data + image->size; 26783a69cae8SSudarsana Reddy Kalluru 26793a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_validate(cdev, image, &data); 26803a69cae8SSudarsana Reddy Kalluru if (rc) 26813a69cae8SSudarsana Reddy Kalluru goto exit; 26823a69cae8SSudarsana Reddy Kalluru 26833a69cae8SSudarsana Reddy Kalluru while (data < data_end) { 26843a69cae8SSudarsana Reddy Kalluru bool check_resp = false; 26853a69cae8SSudarsana Reddy Kalluru 26863a69cae8SSudarsana Reddy Kalluru /* Parse the actual command */ 26873a69cae8SSudarsana Reddy Kalluru cmd_type = *((u32 *)data); 26883a69cae8SSudarsana Reddy Kalluru switch (cmd_type) { 26893a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_DATA: 26903a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_data(cdev, &data, 26913a69cae8SSudarsana Reddy Kalluru &check_resp); 26923a69cae8SSudarsana Reddy Kalluru break; 26933a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_START: 26943a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_start(cdev, &data, 26953a69cae8SSudarsana Reddy Kalluru &check_resp); 26963a69cae8SSudarsana Reddy Kalluru break; 26973a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CHANGE: 26983a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access(cdev, &data, 26993a69cae8SSudarsana Reddy Kalluru &check_resp); 27003a69cae8SSudarsana Reddy Kalluru break; 27010dabbe1bSSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CFG_ID: 27020dabbe1bSSudarsana Reddy Kalluru rc = qed_nvm_flash_cfg_write(cdev, &data); 27030dabbe1bSSudarsana Reddy Kalluru break; 27043a69cae8SSudarsana Reddy Kalluru default: 27053a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Unknown command %08x\n", cmd_type); 27063a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27073a69cae8SSudarsana Reddy Kalluru goto exit; 27083a69cae8SSudarsana Reddy Kalluru } 27093a69cae8SSudarsana Reddy Kalluru 27103a69cae8SSudarsana Reddy Kalluru if (rc) { 27113a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Command %08x failed\n", cmd_type); 27123a69cae8SSudarsana Reddy Kalluru goto exit; 27133a69cae8SSudarsana Reddy Kalluru } 27143a69cae8SSudarsana Reddy Kalluru 27153a69cae8SSudarsana Reddy Kalluru /* Check response if needed */ 27163a69cae8SSudarsana Reddy Kalluru if (check_resp) { 27173a69cae8SSudarsana Reddy Kalluru u32 mcp_response = 0; 27183a69cae8SSudarsana Reddy Kalluru 27193a69cae8SSudarsana Reddy Kalluru if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) { 27203a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed getting MCP response\n"); 27213a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27223a69cae8SSudarsana Reddy Kalluru goto exit; 27233a69cae8SSudarsana Reddy Kalluru } 27243a69cae8SSudarsana Reddy Kalluru 27253a69cae8SSudarsana Reddy Kalluru switch (mcp_response & FW_MSG_CODE_MASK) { 27263a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_OK: 27273a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_OK: 27283a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK: 27293a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_PHY_OK: 27303a69cae8SSudarsana Reddy Kalluru break; 27313a69cae8SSudarsana Reddy Kalluru default: 27323a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "MFW returns error: %08x\n", 27333a69cae8SSudarsana Reddy Kalluru mcp_response); 27343a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27353a69cae8SSudarsana Reddy Kalluru goto exit; 27363a69cae8SSudarsana Reddy Kalluru } 27373a69cae8SSudarsana Reddy Kalluru } 27383a69cae8SSudarsana Reddy Kalluru } 27393a69cae8SSudarsana Reddy Kalluru 27403a69cae8SSudarsana Reddy Kalluru exit: 27413a69cae8SSudarsana Reddy Kalluru release_firmware(image); 27423a69cae8SSudarsana Reddy Kalluru 27433a69cae8SSudarsana Reddy Kalluru return rc; 27443a69cae8SSudarsana Reddy Kalluru } 27453a69cae8SSudarsana Reddy Kalluru 274620675b37SMintz, Yuval static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, 274720675b37SMintz, Yuval u8 *buf, u16 len) 274820675b37SMintz, Yuval { 274920675b37SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 275020675b37SMintz, Yuval 2751b60bfdfeSDenis Bolotin return qed_mcp_get_nvm_image(hwfn, type, buf, len); 275220675b37SMintz, Yuval } 275320675b37SMintz, Yuval 275464515dc8STomer Tayar void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) 275564515dc8STomer Tayar { 275664515dc8STomer Tayar struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 275764515dc8STomer Tayar void *cookie = p_hwfn->cdev->ops_cookie; 275864515dc8STomer Tayar 275964515dc8STomer Tayar if (ops && ops->schedule_recovery_handler) 276064515dc8STomer Tayar ops->schedule_recovery_handler(cookie); 276164515dc8STomer Tayar } 276264515dc8STomer Tayar 2763c6b7314dSAlexander Lobakin static const char * const qed_hw_err_type_descr[] = { 2764d639836aSIgor Russkikh [QED_HW_ERR_FAN_FAIL] = "Fan Failure", 2765d639836aSIgor Russkikh [QED_HW_ERR_MFW_RESP_FAIL] = "MFW Response Failure", 2766d639836aSIgor Russkikh [QED_HW_ERR_HW_ATTN] = "HW Attention", 2767d639836aSIgor Russkikh [QED_HW_ERR_DMAE_FAIL] = "DMAE Failure", 2768d639836aSIgor Russkikh [QED_HW_ERR_RAMROD_FAIL] = "Ramrod Failure", 2769d639836aSIgor Russkikh [QED_HW_ERR_FW_ASSERT] = "FW Assertion", 2770d639836aSIgor Russkikh [QED_HW_ERR_LAST] = "Unknown", 2771d639836aSIgor Russkikh }; 2772d639836aSIgor Russkikh 2773d639836aSIgor Russkikh void qed_hw_error_occurred(struct qed_hwfn *p_hwfn, 2774d639836aSIgor Russkikh enum qed_hw_err_type err_type) 2775d639836aSIgor Russkikh { 2776d639836aSIgor Russkikh struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 2777d639836aSIgor Russkikh void *cookie = p_hwfn->cdev->ops_cookie; 2778c6b7314dSAlexander Lobakin const char *err_str; 2779d639836aSIgor Russkikh 2780d639836aSIgor Russkikh if (err_type > QED_HW_ERR_LAST) 2781d639836aSIgor Russkikh err_type = QED_HW_ERR_LAST; 2782d639836aSIgor Russkikh err_str = qed_hw_err_type_descr[err_type]; 2783d639836aSIgor Russkikh 2784d639836aSIgor Russkikh DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str); 2785d639836aSIgor Russkikh 2786936c7ba4SIgor Russkikh /* Call the HW error handler of the protocol driver. 2787936c7ba4SIgor Russkikh * If it is not available - perform a minimal handling of preventing 2788936c7ba4SIgor Russkikh * HW attentions from being reasserted. 2789d639836aSIgor Russkikh */ 2790d639836aSIgor Russkikh if (ops && ops->schedule_hw_err_handler) 2791d639836aSIgor Russkikh ops->schedule_hw_err_handler(cookie, err_type); 2792936c7ba4SIgor Russkikh else 2793936c7ba4SIgor Russkikh qed_int_attn_clr_enable(p_hwfn->cdev, true); 2794d639836aSIgor Russkikh } 2795d639836aSIgor Russkikh 2796722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, 2797477f2d14SRahul Verma void *handle) 2798722003acSSudarsana Reddy Kalluru { 2799477f2d14SRahul Verma return qed_set_queue_coalesce(rx_coal, tx_coal, handle); 2800722003acSSudarsana Reddy Kalluru } 2801722003acSSudarsana Reddy Kalluru 280291420b83SSudarsana Kalluru static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) 280391420b83SSudarsana Kalluru { 280491420b83SSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 280591420b83SSudarsana Kalluru struct qed_ptt *ptt; 280691420b83SSudarsana Kalluru int status = 0; 280791420b83SSudarsana Kalluru 280891420b83SSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 280991420b83SSudarsana Kalluru if (!ptt) 281091420b83SSudarsana Kalluru return -EAGAIN; 281191420b83SSudarsana Kalluru 281291420b83SSudarsana Kalluru status = qed_mcp_set_led(hwfn, ptt, mode); 281391420b83SSudarsana Kalluru 281491420b83SSudarsana Kalluru qed_ptt_release(hwfn, ptt); 281591420b83SSudarsana Kalluru 281691420b83SSudarsana Kalluru return status; 281791420b83SSudarsana Kalluru } 281891420b83SSudarsana Kalluru 281964515dc8STomer Tayar static int qed_recovery_process(struct qed_dev *cdev) 282064515dc8STomer Tayar { 282164515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 282264515dc8STomer Tayar struct qed_ptt *p_ptt; 282364515dc8STomer Tayar int rc = 0; 282464515dc8STomer Tayar 282564515dc8STomer Tayar p_ptt = qed_ptt_acquire(p_hwfn); 282664515dc8STomer Tayar if (!p_ptt) 282764515dc8STomer Tayar return -EAGAIN; 282864515dc8STomer Tayar 282964515dc8STomer Tayar rc = qed_start_recovery_process(p_hwfn, p_ptt); 283064515dc8STomer Tayar 283164515dc8STomer Tayar qed_ptt_release(p_hwfn, p_ptt); 283264515dc8STomer Tayar 283364515dc8STomer Tayar return rc; 283464515dc8STomer Tayar } 283564515dc8STomer Tayar 283614d39648SMintz, Yuval static int qed_update_wol(struct qed_dev *cdev, bool enabled) 283714d39648SMintz, Yuval { 283814d39648SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 283914d39648SMintz, Yuval struct qed_ptt *ptt; 284014d39648SMintz, Yuval int rc = 0; 284114d39648SMintz, Yuval 284214d39648SMintz, Yuval if (IS_VF(cdev)) 284314d39648SMintz, Yuval return 0; 284414d39648SMintz, Yuval 284514d39648SMintz, Yuval ptt = qed_ptt_acquire(hwfn); 284614d39648SMintz, Yuval if (!ptt) 284714d39648SMintz, Yuval return -EAGAIN; 284814d39648SMintz, Yuval 284914d39648SMintz, Yuval rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED 285014d39648SMintz, Yuval : QED_OV_WOL_DISABLED); 285114d39648SMintz, Yuval if (rc) 285214d39648SMintz, Yuval goto out; 285314d39648SMintz, Yuval rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 285414d39648SMintz, Yuval 285514d39648SMintz, Yuval out: 285614d39648SMintz, Yuval qed_ptt_release(hwfn, ptt); 285714d39648SMintz, Yuval return rc; 285814d39648SMintz, Yuval } 285914d39648SMintz, Yuval 28600fefbfbaSSudarsana Kalluru static int qed_update_drv_state(struct qed_dev *cdev, bool active) 28610fefbfbaSSudarsana Kalluru { 28620fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28630fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28640fefbfbaSSudarsana Kalluru int status = 0; 28650fefbfbaSSudarsana Kalluru 28660fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28670fefbfbaSSudarsana Kalluru return 0; 28680fefbfbaSSudarsana Kalluru 28690fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 28700fefbfbaSSudarsana Kalluru if (!ptt) 28710fefbfbaSSudarsana Kalluru return -EAGAIN; 28720fefbfbaSSudarsana Kalluru 28730fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? 28740fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_ACTIVE : 28750fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_DISABLED); 28760fefbfbaSSudarsana Kalluru 28770fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 28780fefbfbaSSudarsana Kalluru 28790fefbfbaSSudarsana Kalluru return status; 28800fefbfbaSSudarsana Kalluru } 28810fefbfbaSSudarsana Kalluru 28820fefbfbaSSudarsana Kalluru static int qed_update_mac(struct qed_dev *cdev, u8 *mac) 28830fefbfbaSSudarsana Kalluru { 28840fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28850fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28860fefbfbaSSudarsana Kalluru int status = 0; 28870fefbfbaSSudarsana Kalluru 28880fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28890fefbfbaSSudarsana Kalluru return 0; 28900fefbfbaSSudarsana Kalluru 28910fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 28920fefbfbaSSudarsana Kalluru if (!ptt) 28930fefbfbaSSudarsana Kalluru return -EAGAIN; 28940fefbfbaSSudarsana Kalluru 28950fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mac(hwfn, ptt, mac); 28960fefbfbaSSudarsana Kalluru if (status) 28970fefbfbaSSudarsana Kalluru goto out; 28980fefbfbaSSudarsana Kalluru 28990fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29000fefbfbaSSudarsana Kalluru 29010fefbfbaSSudarsana Kalluru out: 29020fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29030fefbfbaSSudarsana Kalluru return status; 29040fefbfbaSSudarsana Kalluru } 29050fefbfbaSSudarsana Kalluru 29060fefbfbaSSudarsana Kalluru static int qed_update_mtu(struct qed_dev *cdev, u16 mtu) 29070fefbfbaSSudarsana Kalluru { 29080fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29090fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 29100fefbfbaSSudarsana Kalluru int status = 0; 29110fefbfbaSSudarsana Kalluru 29120fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 29130fefbfbaSSudarsana Kalluru return 0; 29140fefbfbaSSudarsana Kalluru 29150fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 29160fefbfbaSSudarsana Kalluru if (!ptt) 29170fefbfbaSSudarsana Kalluru return -EAGAIN; 29180fefbfbaSSudarsana Kalluru 29190fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); 29200fefbfbaSSudarsana Kalluru if (status) 29210fefbfbaSSudarsana Kalluru goto out; 29220fefbfbaSSudarsana Kalluru 29230fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29240fefbfbaSSudarsana Kalluru 29250fefbfbaSSudarsana Kalluru out: 29260fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29270fefbfbaSSudarsana Kalluru return status; 29280fefbfbaSSudarsana Kalluru } 29290fefbfbaSSudarsana Kalluru 2930b51dab46SSudarsana Reddy Kalluru static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 2931b51dab46SSudarsana Reddy Kalluru u8 dev_addr, u32 offset, u32 len) 2932b51dab46SSudarsana Reddy Kalluru { 2933b51dab46SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 2934b51dab46SSudarsana Reddy Kalluru struct qed_ptt *ptt; 2935b51dab46SSudarsana Reddy Kalluru int rc = 0; 2936b51dab46SSudarsana Reddy Kalluru 2937b51dab46SSudarsana Reddy Kalluru if (IS_VF(cdev)) 2938b51dab46SSudarsana Reddy Kalluru return 0; 2939b51dab46SSudarsana Reddy Kalluru 2940b51dab46SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 2941b51dab46SSudarsana Reddy Kalluru if (!ptt) 2942b51dab46SSudarsana Reddy Kalluru return -EAGAIN; 2943b51dab46SSudarsana Reddy Kalluru 2944b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr, 2945b51dab46SSudarsana Reddy Kalluru offset, len, buf); 2946b51dab46SSudarsana Reddy Kalluru 2947b51dab46SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 2948b51dab46SSudarsana Reddy Kalluru 2949b51dab46SSudarsana Reddy Kalluru return rc; 2950b51dab46SSudarsana Reddy Kalluru } 2951b51dab46SSudarsana Reddy Kalluru 29523b86bd07SSudarsana Reddy Kalluru static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val) 29533b86bd07SSudarsana Reddy Kalluru { 29543b86bd07SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29553b86bd07SSudarsana Reddy Kalluru struct qed_ptt *ptt; 29563b86bd07SSudarsana Reddy Kalluru int rc = 0; 29573b86bd07SSudarsana Reddy Kalluru 29583b86bd07SSudarsana Reddy Kalluru if (IS_VF(cdev)) 29593b86bd07SSudarsana Reddy Kalluru return 0; 29603b86bd07SSudarsana Reddy Kalluru 29613b86bd07SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 29623b86bd07SSudarsana Reddy Kalluru if (!ptt) 29633b86bd07SSudarsana Reddy Kalluru return -EAGAIN; 29643b86bd07SSudarsana Reddy Kalluru 29652d22bc83SMichal Kalderon rc = qed_dbg_grc_config(hwfn, cfg_id, val); 29663b86bd07SSudarsana Reddy Kalluru 29673b86bd07SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 29683b86bd07SSudarsana Reddy Kalluru 29693b86bd07SSudarsana Reddy Kalluru return rc; 29703b86bd07SSudarsana Reddy Kalluru } 29713b86bd07SSudarsana Reddy Kalluru 297208eb1fb0SMichal Kalderon static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev) 297308eb1fb0SMichal Kalderon { 297408eb1fb0SMichal Kalderon return QED_AFFIN_HWFN_IDX(cdev); 297508eb1fb0SMichal Kalderon } 297608eb1fb0SMichal Kalderon 29778c93beafSYuval Mintz static struct qed_selftest_ops qed_selftest_ops_pass = { 297803dc76caSSudarsana Reddy Kalluru .selftest_memory = &qed_selftest_memory, 297903dc76caSSudarsana Reddy Kalluru .selftest_interrupt = &qed_selftest_interrupt, 298003dc76caSSudarsana Reddy Kalluru .selftest_register = &qed_selftest_register, 298103dc76caSSudarsana Reddy Kalluru .selftest_clock = &qed_selftest_clock, 29827a4b21b7SMintz, Yuval .selftest_nvram = &qed_selftest_nvram, 298303dc76caSSudarsana Reddy Kalluru }; 298403dc76caSSudarsana Reddy Kalluru 2985fe56b9e6SYuval Mintz const struct qed_common_ops qed_common_ops_pass = { 298603dc76caSSudarsana Reddy Kalluru .selftest = &qed_selftest_ops_pass, 2987fe56b9e6SYuval Mintz .probe = &qed_probe, 2988fe56b9e6SYuval Mintz .remove = &qed_remove, 2989fe56b9e6SYuval Mintz .set_power_state = &qed_set_power_state, 2990712c3cbfSMintz, Yuval .set_name = &qed_set_name, 2991fe56b9e6SYuval Mintz .update_pf_params = &qed_update_pf_params, 2992fe56b9e6SYuval Mintz .slowpath_start = &qed_slowpath_start, 2993fe56b9e6SYuval Mintz .slowpath_stop = &qed_slowpath_stop, 2994fe56b9e6SYuval Mintz .set_fp_int = &qed_set_int_fp, 2995fe56b9e6SYuval Mintz .get_fp_int = &qed_get_int_fp, 2996fe56b9e6SYuval Mintz .sb_init = &qed_sb_init, 2997fe56b9e6SYuval Mintz .sb_release = &qed_sb_release, 2998fe56b9e6SYuval Mintz .simd_handler_config = &qed_simd_handler_config, 2999fe56b9e6SYuval Mintz .simd_handler_clean = &qed_simd_handler_clean, 30001e128c81SArun Easi .dbg_grc = &qed_dbg_grc, 30011e128c81SArun Easi .dbg_grc_size = &qed_dbg_grc_size, 3002fe7cd2bfSYuval Mintz .can_link_change = &qed_can_link_change, 3003cc875c2eSYuval Mintz .set_link = &qed_set_link, 3004cc875c2eSYuval Mintz .get_link = &qed_get_current_link, 3005fe56b9e6SYuval Mintz .drain = &qed_drain, 3006fe56b9e6SYuval Mintz .update_msglvl = &qed_init_dp, 3007755f982bSIgor Russkikh .devlink_register = qed_devlink_register, 3008755f982bSIgor Russkikh .devlink_unregister = qed_devlink_unregister, 3009e0971c83STomer Tayar .dbg_all_data = &qed_dbg_all_data, 3010e0971c83STomer Tayar .dbg_all_data_size = &qed_dbg_all_data_size, 3011fe56b9e6SYuval Mintz .chain_alloc = &qed_chain_alloc, 3012fe56b9e6SYuval Mintz .chain_free = &qed_chain_free, 30133a69cae8SSudarsana Reddy Kalluru .nvm_flash = &qed_nvm_flash, 301420675b37SMintz, Yuval .nvm_get_image = &qed_nvm_get_image, 3015722003acSSudarsana Reddy Kalluru .set_coalesce = &qed_set_coalesce, 301691420b83SSudarsana Kalluru .set_led = &qed_set_led, 301764515dc8STomer Tayar .recovery_process = &qed_recovery_process, 301864515dc8STomer Tayar .recovery_prolog = &qed_recovery_prolog, 3019936c7ba4SIgor Russkikh .attn_clr_enable = &qed_int_attn_clr_enable, 30200fefbfbaSSudarsana Kalluru .update_drv_state = &qed_update_drv_state, 30210fefbfbaSSudarsana Kalluru .update_mac = &qed_update_mac, 30220fefbfbaSSudarsana Kalluru .update_mtu = &qed_update_mtu, 302314d39648SMintz, Yuval .update_wol = &qed_update_wol, 30240e1f1044SAriel Elior .db_recovery_add = &qed_db_recovery_add, 30250e1f1044SAriel Elior .db_recovery_del = &qed_db_recovery_del, 3026b51dab46SSudarsana Reddy Kalluru .read_module_eeprom = &qed_read_module_eeprom, 302708eb1fb0SMichal Kalderon .get_affin_hwfn_idx = &qed_get_affin_hwfn_idx, 30282d4c8495SSudarsana Reddy Kalluru .read_nvm_cfg = &qed_nvm_flash_cfg_read, 30299e54ba7cSSudarsana Reddy Kalluru .read_nvm_cfg_len = &qed_nvm_flash_cfg_len, 30303b86bd07SSudarsana Reddy Kalluru .set_grc_config = &qed_set_grc_config, 3031fe56b9e6SYuval Mintz }; 30326c754246SSudarsana Reddy Kalluru 30336c754246SSudarsana Reddy Kalluru void qed_get_protocol_stats(struct qed_dev *cdev, 30346c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type type, 30356c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats *stats) 30366c754246SSudarsana Reddy Kalluru { 30376c754246SSudarsana Reddy Kalluru struct qed_eth_stats eth_stats; 30386c754246SSudarsana Reddy Kalluru 30396c754246SSudarsana Reddy Kalluru memset(stats, 0, sizeof(*stats)); 30406c754246SSudarsana Reddy Kalluru 30416c754246SSudarsana Reddy Kalluru switch (type) { 30426c754246SSudarsana Reddy Kalluru case QED_MCP_LAN_STATS: 30436c754246SSudarsana Reddy Kalluru qed_get_vport_stats(cdev, ð_stats); 30449c79ddaaSMintz, Yuval stats->lan_stats.ucast_rx_pkts = 30459c79ddaaSMintz, Yuval eth_stats.common.rx_ucast_pkts; 30469c79ddaaSMintz, Yuval stats->lan_stats.ucast_tx_pkts = 30479c79ddaaSMintz, Yuval eth_stats.common.tx_ucast_pkts; 30486c754246SSudarsana Reddy Kalluru stats->lan_stats.fcs_err = -1; 30496c754246SSudarsana Reddy Kalluru break; 30501e128c81SArun Easi case QED_MCP_FCOE_STATS: 30511e128c81SArun Easi qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); 30521e128c81SArun Easi break; 30532f2b2614SMintz, Yuval case QED_MCP_ISCSI_STATS: 30542f2b2614SMintz, Yuval qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); 30552f2b2614SMintz, Yuval break; 30566c754246SSudarsana Reddy Kalluru default: 3057512c7840SMintz, Yuval DP_VERBOSE(cdev, QED_MSG_SP, 3058512c7840SMintz, Yuval "Invalid protocol type = %d\n", type); 30596c754246SSudarsana Reddy Kalluru return; 30606c754246SSudarsana Reddy Kalluru } 30616c754246SSudarsana Reddy Kalluru } 30622528c389SSudarsana Reddy Kalluru 306359ccf86fSSudarsana Reddy Kalluru int qed_mfw_tlv_req(struct qed_hwfn *hwfn) 306459ccf86fSSudarsana Reddy Kalluru { 306559ccf86fSSudarsana Reddy Kalluru DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 306659ccf86fSSudarsana Reddy Kalluru "Scheduling slowpath task [Flag: %d]\n", 306759ccf86fSSudarsana Reddy Kalluru QED_SLOWPATH_MFW_TLV_REQ); 306859ccf86fSSudarsana Reddy Kalluru smp_mb__before_atomic(); 306959ccf86fSSudarsana Reddy Kalluru set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags); 307059ccf86fSSudarsana Reddy Kalluru smp_mb__after_atomic(); 307159ccf86fSSudarsana Reddy Kalluru queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 307259ccf86fSSudarsana Reddy Kalluru 307359ccf86fSSudarsana Reddy Kalluru return 0; 307459ccf86fSSudarsana Reddy Kalluru } 307559ccf86fSSudarsana Reddy Kalluru 307659ccf86fSSudarsana Reddy Kalluru static void 307759ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv) 307859ccf86fSSudarsana Reddy Kalluru { 307959ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = cdev->protocol_ops.common; 308059ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats_common *p_common; 308159ccf86fSSudarsana Reddy Kalluru struct qed_generic_tlvs gen_tlvs; 308259ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats stats; 308359ccf86fSSudarsana Reddy Kalluru int i; 308459ccf86fSSudarsana Reddy Kalluru 308559ccf86fSSudarsana Reddy Kalluru memset(&gen_tlvs, 0, sizeof(gen_tlvs)); 308659ccf86fSSudarsana Reddy Kalluru op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs); 308759ccf86fSSudarsana Reddy Kalluru 308859ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM) 308959ccf86fSSudarsana Reddy Kalluru tlv->flags.ipv4_csum_offload = true; 309059ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_LSO) 309159ccf86fSSudarsana Reddy Kalluru tlv->flags.lso_supported = true; 309259ccf86fSSudarsana Reddy Kalluru tlv->flags.b_set = true; 309359ccf86fSSudarsana Reddy Kalluru 309459ccf86fSSudarsana Reddy Kalluru for (i = 0; i < QED_TLV_MAC_COUNT; i++) { 309559ccf86fSSudarsana Reddy Kalluru if (is_valid_ether_addr(gen_tlvs.mac[i])) { 309659ccf86fSSudarsana Reddy Kalluru ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]); 309759ccf86fSSudarsana Reddy Kalluru tlv->mac_set[i] = true; 309859ccf86fSSudarsana Reddy Kalluru } 309959ccf86fSSudarsana Reddy Kalluru } 310059ccf86fSSudarsana Reddy Kalluru 310159ccf86fSSudarsana Reddy Kalluru qed_get_vport_stats(cdev, &stats); 310259ccf86fSSudarsana Reddy Kalluru p_common = &stats.common; 310359ccf86fSSudarsana Reddy Kalluru tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 310459ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_pkts; 310559ccf86fSSudarsana Reddy Kalluru tlv->rx_frames_set = true; 310659ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 310759ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_bytes; 310859ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 310959ccf86fSSudarsana Reddy Kalluru tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 311059ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_pkts; 311159ccf86fSSudarsana Reddy Kalluru tlv->tx_frames_set = true; 311259ccf86fSSudarsana Reddy Kalluru tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 311359ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_bytes; 311459ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 311559ccf86fSSudarsana Reddy Kalluru } 311659ccf86fSSudarsana Reddy Kalluru 31172528c389SSudarsana Reddy Kalluru int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type, 31182528c389SSudarsana Reddy Kalluru union qed_mfw_tlv_data *tlv_buf) 31192528c389SSudarsana Reddy Kalluru { 312059ccf86fSSudarsana Reddy Kalluru struct qed_dev *cdev = hwfn->cdev; 312159ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *ops; 312259ccf86fSSudarsana Reddy Kalluru 312359ccf86fSSudarsana Reddy Kalluru ops = cdev->protocol_ops.common; 312459ccf86fSSudarsana Reddy Kalluru if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) { 312559ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Can't collect TLV management info\n"); 31262528c389SSudarsana Reddy Kalluru return -EINVAL; 31272528c389SSudarsana Reddy Kalluru } 312859ccf86fSSudarsana Reddy Kalluru 312959ccf86fSSudarsana Reddy Kalluru switch (type) { 313059ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_GENERIC: 313159ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic); 313259ccf86fSSudarsana Reddy Kalluru break; 313359ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ETH: 313459ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth); 313559ccf86fSSudarsana Reddy Kalluru break; 313659ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_FCOE: 313759ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe); 313859ccf86fSSudarsana Reddy Kalluru break; 313959ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ISCSI: 314059ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi); 314159ccf86fSSudarsana Reddy Kalluru break; 314259ccf86fSSudarsana Reddy Kalluru default: 314359ccf86fSSudarsana Reddy Kalluru break; 314459ccf86fSSudarsana Reddy Kalluru } 314559ccf86fSSudarsana Reddy Kalluru 314659ccf86fSSudarsana Reddy Kalluru return 0; 314759ccf86fSSudarsana Reddy Kalluru } 3148