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 54224e04879SMichal Kalderon rc = qed_devlink_register(cdev); 54324e04879SMichal Kalderon if (rc) { 54424e04879SMichal Kalderon DP_INFO(cdev, "Failed to register devlink.\n"); 54524e04879SMichal Kalderon goto err2; 54624e04879SMichal Kalderon } 54724e04879SMichal Kalderon 548fe56b9e6SYuval Mintz rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); 549fe56b9e6SYuval Mintz if (rc) { 550fe56b9e6SYuval Mintz DP_ERR(cdev, "hw prepare failed\n"); 551fe56b9e6SYuval Mintz goto err2; 552fe56b9e6SYuval Mintz } 553fe56b9e6SYuval Mintz 55420c4515aSEwan D. Milne DP_INFO(cdev, "qed_probe completed successfully\n"); 555fe56b9e6SYuval Mintz 556fe56b9e6SYuval Mintz return cdev; 557fe56b9e6SYuval Mintz 558fe56b9e6SYuval Mintz err2: 559fe56b9e6SYuval Mintz qed_free_pci(cdev); 560fe56b9e6SYuval Mintz err1: 561fe56b9e6SYuval Mintz qed_free_cdev(cdev); 562fe56b9e6SYuval Mintz err0: 563fe56b9e6SYuval Mintz return NULL; 564fe56b9e6SYuval Mintz } 565fe56b9e6SYuval Mintz 566fe56b9e6SYuval Mintz static void qed_remove(struct qed_dev *cdev) 567fe56b9e6SYuval Mintz { 568fe56b9e6SYuval Mintz if (!cdev) 569fe56b9e6SYuval Mintz return; 570fe56b9e6SYuval Mintz 571fe56b9e6SYuval Mintz qed_hw_remove(cdev); 572fe56b9e6SYuval Mintz 573fe56b9e6SYuval Mintz qed_free_pci(cdev); 574fe56b9e6SYuval Mintz 575fe56b9e6SYuval Mintz qed_set_power_state(cdev, PCI_D3hot); 576fe56b9e6SYuval Mintz 57724e04879SMichal Kalderon qed_devlink_unregister(cdev); 57824e04879SMichal Kalderon 579fe56b9e6SYuval Mintz qed_free_cdev(cdev); 580fe56b9e6SYuval Mintz } 581fe56b9e6SYuval Mintz 582fe56b9e6SYuval Mintz static void qed_disable_msix(struct qed_dev *cdev) 583fe56b9e6SYuval Mintz { 584fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 585fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 586fe56b9e6SYuval Mintz kfree(cdev->int_params.msix_table); 587fe56b9e6SYuval Mintz } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { 588fe56b9e6SYuval Mintz pci_disable_msi(cdev->pdev); 589fe56b9e6SYuval Mintz } 590fe56b9e6SYuval Mintz 591fe56b9e6SYuval Mintz memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); 592fe56b9e6SYuval Mintz } 593fe56b9e6SYuval Mintz 594fe56b9e6SYuval Mintz static int qed_enable_msix(struct qed_dev *cdev, 595fe56b9e6SYuval Mintz struct qed_int_params *int_params) 596fe56b9e6SYuval Mintz { 597fe56b9e6SYuval Mintz int i, rc, cnt; 598fe56b9e6SYuval Mintz 599fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 600fe56b9e6SYuval Mintz 601fe56b9e6SYuval Mintz for (i = 0; i < cnt; i++) 602fe56b9e6SYuval Mintz int_params->msix_table[i].entry = i; 603fe56b9e6SYuval Mintz 604fe56b9e6SYuval Mintz rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, 605fe56b9e6SYuval Mintz int_params->in.min_msix_cnt, cnt); 606fe56b9e6SYuval Mintz if (rc < cnt && rc >= int_params->in.min_msix_cnt && 607fe56b9e6SYuval Mintz (rc % cdev->num_hwfns)) { 608fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 609fe56b9e6SYuval Mintz 610fe56b9e6SYuval Mintz /* If fastpath is initialized, we need at least one interrupt 611fe56b9e6SYuval Mintz * per hwfn [and the slow path interrupts]. New requested number 612fe56b9e6SYuval Mintz * should be a multiple of the number of hwfns. 613fe56b9e6SYuval Mintz */ 614fe56b9e6SYuval Mintz cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; 615fe56b9e6SYuval Mintz DP_NOTICE(cdev, 616fe56b9e6SYuval Mintz "Trying to enable MSI-X with less vectors (%d out of %d)\n", 617fe56b9e6SYuval Mintz cnt, int_params->in.num_vectors); 6181a635e48SYuval Mintz rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, 6191a635e48SYuval Mintz cnt); 620fe56b9e6SYuval Mintz if (!rc) 621fe56b9e6SYuval Mintz rc = cnt; 622fe56b9e6SYuval Mintz } 623fe56b9e6SYuval Mintz 624fe56b9e6SYuval Mintz if (rc > 0) { 625fe56b9e6SYuval Mintz /* MSI-x configuration was achieved */ 626fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSIX; 627fe56b9e6SYuval Mintz int_params->out.num_vectors = rc; 628fe56b9e6SYuval Mintz rc = 0; 629fe56b9e6SYuval Mintz } else { 630fe56b9e6SYuval Mintz DP_NOTICE(cdev, 631fe56b9e6SYuval Mintz "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", 632fe56b9e6SYuval Mintz cnt, rc); 633fe56b9e6SYuval Mintz } 634fe56b9e6SYuval Mintz 635fe56b9e6SYuval Mintz return rc; 636fe56b9e6SYuval Mintz } 637fe56b9e6SYuval Mintz 638fe56b9e6SYuval Mintz /* This function outputs the int mode and the number of enabled msix vector */ 639fe56b9e6SYuval Mintz static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) 640fe56b9e6SYuval Mintz { 641fe56b9e6SYuval Mintz struct qed_int_params *int_params = &cdev->int_params; 642fe56b9e6SYuval Mintz struct msix_entry *tbl; 643fe56b9e6SYuval Mintz int rc = 0, cnt; 644fe56b9e6SYuval Mintz 645fe56b9e6SYuval Mintz switch (int_params->in.int_mode) { 646fe56b9e6SYuval Mintz case QED_INT_MODE_MSIX: 647fe56b9e6SYuval Mintz /* Allocate MSIX table */ 648fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 649fe56b9e6SYuval Mintz int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); 650fe56b9e6SYuval Mintz if (!int_params->msix_table) { 651fe56b9e6SYuval Mintz rc = -ENOMEM; 652fe56b9e6SYuval Mintz goto out; 653fe56b9e6SYuval Mintz } 654fe56b9e6SYuval Mintz 655fe56b9e6SYuval Mintz /* Enable MSIX */ 656fe56b9e6SYuval Mintz rc = qed_enable_msix(cdev, int_params); 657fe56b9e6SYuval Mintz if (!rc) 658fe56b9e6SYuval Mintz goto out; 659fe56b9e6SYuval Mintz 660fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI-X\n"); 661fe56b9e6SYuval Mintz kfree(int_params->msix_table); 662fe56b9e6SYuval Mintz if (force_mode) 663fe56b9e6SYuval Mintz goto out; 664fe56b9e6SYuval Mintz /* Fallthrough */ 665fe56b9e6SYuval Mintz 666fe56b9e6SYuval Mintz case QED_INT_MODE_MSI: 667bb13ace7SSudarsana Reddy Kalluru if (cdev->num_hwfns == 1) { 668fe56b9e6SYuval Mintz rc = pci_enable_msi(cdev->pdev); 669fe56b9e6SYuval Mintz if (!rc) { 670fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSI; 671fe56b9e6SYuval Mintz goto out; 672fe56b9e6SYuval Mintz } 673fe56b9e6SYuval Mintz 674fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI\n"); 675fe56b9e6SYuval Mintz if (force_mode) 676fe56b9e6SYuval Mintz goto out; 677bb13ace7SSudarsana Reddy Kalluru } 678fe56b9e6SYuval Mintz /* Fallthrough */ 679fe56b9e6SYuval Mintz 680fe56b9e6SYuval Mintz case QED_INT_MODE_INTA: 681fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_INTA; 682fe56b9e6SYuval Mintz rc = 0; 683fe56b9e6SYuval Mintz goto out; 684fe56b9e6SYuval Mintz default: 685fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Unknown int_mode value %d\n", 686fe56b9e6SYuval Mintz int_params->in.int_mode); 687fe56b9e6SYuval Mintz rc = -EINVAL; 688fe56b9e6SYuval Mintz } 689fe56b9e6SYuval Mintz 690fe56b9e6SYuval Mintz out: 691525ef5c0SYuval Mintz if (!rc) 692525ef5c0SYuval Mintz DP_INFO(cdev, "Using %s interrupts\n", 693525ef5c0SYuval Mintz int_params->out.int_mode == QED_INT_MODE_INTA ? 694525ef5c0SYuval Mintz "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? 695525ef5c0SYuval Mintz "MSI" : "MSIX"); 696fe56b9e6SYuval Mintz cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; 697fe56b9e6SYuval Mintz 698fe56b9e6SYuval Mintz return rc; 699fe56b9e6SYuval Mintz } 700fe56b9e6SYuval Mintz 701fe56b9e6SYuval Mintz static void qed_simd_handler_config(struct qed_dev *cdev, void *token, 702fe56b9e6SYuval Mintz int index, void(*handler)(void *)) 703fe56b9e6SYuval Mintz { 704fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 705fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 706fe56b9e6SYuval Mintz 707fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].func = handler; 708fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].token = token; 709fe56b9e6SYuval Mintz } 710fe56b9e6SYuval Mintz 711fe56b9e6SYuval Mintz static void qed_simd_handler_clean(struct qed_dev *cdev, int index) 712fe56b9e6SYuval Mintz { 713fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 714fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 715fe56b9e6SYuval Mintz 716fe56b9e6SYuval Mintz memset(&hwfn->simd_proto_handler[relative_idx], 0, 717fe56b9e6SYuval Mintz sizeof(struct qed_simd_fp_handler)); 718fe56b9e6SYuval Mintz } 719fe56b9e6SYuval Mintz 720fe56b9e6SYuval Mintz static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) 721fe56b9e6SYuval Mintz { 722fe56b9e6SYuval Mintz tasklet_schedule((struct tasklet_struct *)tasklet); 723fe56b9e6SYuval Mintz return IRQ_HANDLED; 724fe56b9e6SYuval Mintz } 725fe56b9e6SYuval Mintz 726fe56b9e6SYuval Mintz static irqreturn_t qed_single_int(int irq, void *dev_instance) 727fe56b9e6SYuval Mintz { 728fe56b9e6SYuval Mintz struct qed_dev *cdev = (struct qed_dev *)dev_instance; 729fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 730fe56b9e6SYuval Mintz irqreturn_t rc = IRQ_NONE; 731fe56b9e6SYuval Mintz u64 status; 732fe56b9e6SYuval Mintz int i, j; 733fe56b9e6SYuval Mintz 734fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 735fe56b9e6SYuval Mintz status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); 736fe56b9e6SYuval Mintz 737fe56b9e6SYuval Mintz if (!status) 738fe56b9e6SYuval Mintz continue; 739fe56b9e6SYuval Mintz 740fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 741fe56b9e6SYuval Mintz 742fe56b9e6SYuval Mintz /* Slowpath interrupt */ 743fe56b9e6SYuval Mintz if (unlikely(status & 0x1)) { 744fe56b9e6SYuval Mintz tasklet_schedule(hwfn->sp_dpc); 745fe56b9e6SYuval Mintz status &= ~0x1; 746fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 747fe56b9e6SYuval Mintz } 748fe56b9e6SYuval Mintz 749fe56b9e6SYuval Mintz /* Fastpath interrupts */ 750fe56b9e6SYuval Mintz for (j = 0; j < 64; j++) { 751fe56b9e6SYuval Mintz if ((0x2ULL << j) & status) { 7523935a709SSudarsana Reddy Kalluru struct qed_simd_fp_handler *p_handler = 7533935a709SSudarsana Reddy Kalluru &hwfn->simd_proto_handler[j]; 7543935a709SSudarsana Reddy Kalluru 7553935a709SSudarsana Reddy Kalluru if (p_handler->func) 7563935a709SSudarsana Reddy Kalluru p_handler->func(p_handler->token); 7573935a709SSudarsana Reddy Kalluru else 7583935a709SSudarsana Reddy Kalluru DP_NOTICE(hwfn, 7593935a709SSudarsana Reddy Kalluru "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n", 7603935a709SSudarsana Reddy Kalluru j, status); 7613935a709SSudarsana Reddy Kalluru 762fe56b9e6SYuval Mintz status &= ~(0x2ULL << j); 763fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 764fe56b9e6SYuval Mintz } 765fe56b9e6SYuval Mintz } 766fe56b9e6SYuval Mintz 767fe56b9e6SYuval Mintz if (unlikely(status)) 768fe56b9e6SYuval Mintz DP_VERBOSE(hwfn, NETIF_MSG_INTR, 769fe56b9e6SYuval Mintz "got an unknown interrupt status 0x%llx\n", 770fe56b9e6SYuval Mintz status); 771fe56b9e6SYuval Mintz } 772fe56b9e6SYuval Mintz 773fe56b9e6SYuval Mintz return rc; 774fe56b9e6SYuval Mintz } 775fe56b9e6SYuval Mintz 7768f16bc97SSudarsana Kalluru int qed_slowpath_irq_req(struct qed_hwfn *hwfn) 777fe56b9e6SYuval Mintz { 7788f16bc97SSudarsana Kalluru struct qed_dev *cdev = hwfn->cdev; 779525ef5c0SYuval Mintz u32 int_mode; 7808f16bc97SSudarsana Kalluru int rc = 0; 7818f16bc97SSudarsana Kalluru u8 id; 782fe56b9e6SYuval Mintz 783525ef5c0SYuval Mintz int_mode = cdev->int_params.out.int_mode; 784525ef5c0SYuval Mintz if (int_mode == QED_INT_MODE_MSIX) { 7858f16bc97SSudarsana Kalluru id = hwfn->my_id; 7868f16bc97SSudarsana Kalluru snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", 7878f16bc97SSudarsana Kalluru id, cdev->pdev->bus->number, 7888f16bc97SSudarsana Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 7898f16bc97SSudarsana Kalluru rc = request_irq(cdev->int_params.msix_table[id].vector, 7908f16bc97SSudarsana Kalluru qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc); 791fe56b9e6SYuval Mintz } else { 792fe56b9e6SYuval Mintz unsigned long flags = 0; 793fe56b9e6SYuval Mintz 794fe56b9e6SYuval Mintz snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", 795fe56b9e6SYuval Mintz cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), 796fe56b9e6SYuval Mintz PCI_FUNC(cdev->pdev->devfn)); 797fe56b9e6SYuval Mintz 798fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) 799fe56b9e6SYuval Mintz flags |= IRQF_SHARED; 800fe56b9e6SYuval Mintz 801fe56b9e6SYuval Mintz rc = request_irq(cdev->pdev->irq, qed_single_int, 802fe56b9e6SYuval Mintz flags, cdev->name, cdev); 803fe56b9e6SYuval Mintz } 804fe56b9e6SYuval Mintz 805525ef5c0SYuval Mintz if (rc) 806525ef5c0SYuval Mintz DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); 807525ef5c0SYuval Mintz else 808525ef5c0SYuval Mintz DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), 809525ef5c0SYuval Mintz "Requested slowpath %s\n", 810525ef5c0SYuval Mintz (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); 811525ef5c0SYuval Mintz 812fe56b9e6SYuval Mintz return rc; 813fe56b9e6SYuval Mintz } 814fe56b9e6SYuval Mintz 81506892f2eSTomer Tayar static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) 81606892f2eSTomer Tayar { 81706892f2eSTomer Tayar /* Calling the disable function will make sure that any 81806892f2eSTomer Tayar * currently-running function is completed. The following call to the 81906892f2eSTomer Tayar * enable function makes this sequence a flush-like operation. 82006892f2eSTomer Tayar */ 82106892f2eSTomer Tayar if (p_hwfn->b_sp_dpc_enabled) { 82206892f2eSTomer Tayar tasklet_disable(p_hwfn->sp_dpc); 82306892f2eSTomer Tayar tasklet_enable(p_hwfn->sp_dpc); 82406892f2eSTomer Tayar } 82506892f2eSTomer Tayar } 82606892f2eSTomer Tayar 8271226337aSTomer Tayar void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) 8281226337aSTomer Tayar { 8291226337aSTomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 8301226337aSTomer Tayar u8 id = p_hwfn->my_id; 8311226337aSTomer Tayar u32 int_mode; 8321226337aSTomer Tayar 8331226337aSTomer Tayar int_mode = cdev->int_params.out.int_mode; 8341226337aSTomer Tayar if (int_mode == QED_INT_MODE_MSIX) 8351226337aSTomer Tayar synchronize_irq(cdev->int_params.msix_table[id].vector); 8361226337aSTomer Tayar else 8371226337aSTomer Tayar synchronize_irq(cdev->pdev->irq); 83806892f2eSTomer Tayar 83906892f2eSTomer Tayar qed_slowpath_tasklet_flush(p_hwfn); 8401226337aSTomer Tayar } 8411226337aSTomer Tayar 842fe56b9e6SYuval Mintz static void qed_slowpath_irq_free(struct qed_dev *cdev) 843fe56b9e6SYuval Mintz { 844fe56b9e6SYuval Mintz int i; 845fe56b9e6SYuval Mintz 846fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 847fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 8488f16bc97SSudarsana Kalluru if (!cdev->hwfns[i].b_int_requested) 8498f16bc97SSudarsana Kalluru break; 850fe56b9e6SYuval Mintz synchronize_irq(cdev->int_params.msix_table[i].vector); 851fe56b9e6SYuval Mintz free_irq(cdev->int_params.msix_table[i].vector, 852fe56b9e6SYuval Mintz cdev->hwfns[i].sp_dpc); 853fe56b9e6SYuval Mintz } 854fe56b9e6SYuval Mintz } else { 8558f16bc97SSudarsana Kalluru if (QED_LEADING_HWFN(cdev)->b_int_requested) 856fe56b9e6SYuval Mintz free_irq(cdev->pdev->irq, cdev); 857fe56b9e6SYuval Mintz } 8588f16bc97SSudarsana Kalluru qed_int_disable_post_isr_release(cdev); 859fe56b9e6SYuval Mintz } 860fe56b9e6SYuval Mintz 861fe56b9e6SYuval Mintz static int qed_nic_stop(struct qed_dev *cdev) 862fe56b9e6SYuval Mintz { 863fe56b9e6SYuval Mintz int i, rc; 864fe56b9e6SYuval Mintz 865fe56b9e6SYuval Mintz rc = qed_hw_stop(cdev); 866fe56b9e6SYuval Mintz 867fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 868fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 869fe56b9e6SYuval Mintz 870fe56b9e6SYuval Mintz if (p_hwfn->b_sp_dpc_enabled) { 871fe56b9e6SYuval Mintz tasklet_disable(p_hwfn->sp_dpc); 872fe56b9e6SYuval Mintz p_hwfn->b_sp_dpc_enabled = false; 873fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, 8742fdae034SColin Ian King "Disabled sp tasklet [hwfn %d] at %p\n", 875fe56b9e6SYuval Mintz i, p_hwfn->sp_dpc); 876fe56b9e6SYuval Mintz } 877fe56b9e6SYuval Mintz } 878fe56b9e6SYuval Mintz 879c965db44STomer Tayar qed_dbg_pf_exit(cdev); 880c965db44STomer Tayar 881fe56b9e6SYuval Mintz return rc; 882fe56b9e6SYuval Mintz } 883fe56b9e6SYuval Mintz 884fe56b9e6SYuval Mintz static int qed_nic_setup(struct qed_dev *cdev) 885fe56b9e6SYuval Mintz { 8860a7fb11cSYuval Mintz int rc, i; 8870a7fb11cSYuval Mintz 8880a7fb11cSYuval Mintz /* Determine if interface is going to require LL2 */ 8890a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) { 8900a7fb11cSYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 8910a7fb11cSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 8920a7fb11cSYuval Mintz 8930a7fb11cSYuval Mintz p_hwfn->using_ll2 = true; 8940a7fb11cSYuval Mintz } 8950a7fb11cSYuval Mintz } 896fe56b9e6SYuval Mintz 897fe56b9e6SYuval Mintz rc = qed_resc_alloc(cdev); 898fe56b9e6SYuval Mintz if (rc) 899fe56b9e6SYuval Mintz return rc; 900fe56b9e6SYuval Mintz 901fe56b9e6SYuval Mintz DP_INFO(cdev, "Allocated qed resources\n"); 902fe56b9e6SYuval Mintz 903fe56b9e6SYuval Mintz qed_resc_setup(cdev); 904fe56b9e6SYuval Mintz 905fe56b9e6SYuval Mintz return rc; 906fe56b9e6SYuval Mintz } 907fe56b9e6SYuval Mintz 908fe56b9e6SYuval Mintz static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) 909fe56b9e6SYuval Mintz { 910fe56b9e6SYuval Mintz int limit = 0; 911fe56b9e6SYuval Mintz 912fe56b9e6SYuval Mintz /* Mark the fastpath as free/used */ 913fe56b9e6SYuval Mintz cdev->int_params.fp_initialized = cnt ? true : false; 914fe56b9e6SYuval Mintz 915fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) 916fe56b9e6SYuval Mintz limit = cdev->num_hwfns * 63; 917fe56b9e6SYuval Mintz else if (cdev->int_params.fp_msix_cnt) 918fe56b9e6SYuval Mintz limit = cdev->int_params.fp_msix_cnt; 919fe56b9e6SYuval Mintz 920fe56b9e6SYuval Mintz if (!limit) 921fe56b9e6SYuval Mintz return -ENOMEM; 922fe56b9e6SYuval Mintz 923fe56b9e6SYuval Mintz return min_t(int, cnt, limit); 924fe56b9e6SYuval Mintz } 925fe56b9e6SYuval Mintz 926fe56b9e6SYuval Mintz static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) 927fe56b9e6SYuval Mintz { 928fe56b9e6SYuval Mintz memset(info, 0, sizeof(struct qed_int_info)); 929fe56b9e6SYuval Mintz 930fe56b9e6SYuval Mintz if (!cdev->int_params.fp_initialized) { 931fe56b9e6SYuval Mintz DP_INFO(cdev, 932fe56b9e6SYuval Mintz "Protocol driver requested interrupt information, but its support is not yet configured\n"); 933fe56b9e6SYuval Mintz return -EINVAL; 934fe56b9e6SYuval Mintz } 935fe56b9e6SYuval Mintz 936fe56b9e6SYuval Mintz /* Need to expose only MSI-X information; Single IRQ is handled solely 937fe56b9e6SYuval Mintz * by qed. 938fe56b9e6SYuval Mintz */ 939fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 940fe56b9e6SYuval Mintz int msix_base = cdev->int_params.fp_msix_base; 941fe56b9e6SYuval Mintz 942fe56b9e6SYuval Mintz info->msix_cnt = cdev->int_params.fp_msix_cnt; 943fe56b9e6SYuval Mintz info->msix = &cdev->int_params.msix_table[msix_base]; 944fe56b9e6SYuval Mintz } 945fe56b9e6SYuval Mintz 946fe56b9e6SYuval Mintz return 0; 947fe56b9e6SYuval Mintz } 948fe56b9e6SYuval Mintz 949fe56b9e6SYuval Mintz static int qed_slowpath_setup_int(struct qed_dev *cdev, 950fe56b9e6SYuval Mintz enum qed_int_mode int_mode) 951fe56b9e6SYuval Mintz { 9524ac801b7SYuval Mintz struct qed_sb_cnt_info sb_cnt_info; 9530189efb8SYuval Mintz int num_l2_queues = 0; 9544ac801b7SYuval Mintz int rc; 9554ac801b7SYuval Mintz int i; 956fe56b9e6SYuval Mintz 9571d2c2024SSudarsana Reddy Kalluru if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { 9581d2c2024SSudarsana Reddy Kalluru DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); 9591d2c2024SSudarsana Reddy Kalluru return -EINVAL; 9601d2c2024SSudarsana Reddy Kalluru } 9611d2c2024SSudarsana Reddy Kalluru 9621d2c2024SSudarsana Reddy Kalluru memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 963fe56b9e6SYuval Mintz cdev->int_params.in.int_mode = int_mode; 9644ac801b7SYuval Mintz for_each_hwfn(cdev, i) { 9654ac801b7SYuval Mintz memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); 9664ac801b7SYuval Mintz qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); 967726fdbe9SMintz, Yuval cdev->int_params.in.num_vectors += sb_cnt_info.cnt; 9684ac801b7SYuval Mintz cdev->int_params.in.num_vectors++; /* slowpath */ 9694ac801b7SYuval Mintz } 970fe56b9e6SYuval Mintz 971fe56b9e6SYuval Mintz /* We want a minimum of one slowpath and one fastpath vector per hwfn */ 972fe56b9e6SYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; 973fe56b9e6SYuval Mintz 974bb7858baSSudarsana Reddy Kalluru if (is_kdump_kernel()) { 975bb7858baSSudarsana Reddy Kalluru DP_INFO(cdev, 976bb7858baSSudarsana Reddy Kalluru "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", 977bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt); 978bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.num_vectors = 979bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt; 980bb7858baSSudarsana Reddy Kalluru } 981bb7858baSSudarsana Reddy Kalluru 982fe56b9e6SYuval Mintz rc = qed_set_int_mode(cdev, false); 983fe56b9e6SYuval Mintz if (rc) { 984fe56b9e6SYuval Mintz DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); 985fe56b9e6SYuval Mintz return rc; 986fe56b9e6SYuval Mintz } 987fe56b9e6SYuval Mintz 988fe56b9e6SYuval Mintz cdev->int_params.fp_msix_base = cdev->num_hwfns; 989fe56b9e6SYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - 990fe56b9e6SYuval Mintz cdev->num_hwfns; 991fe56b9e6SYuval Mintz 9922f782278SMintz, Yuval if (!IS_ENABLED(CONFIG_QED_RDMA) || 993c851a9dcSKalderon, Michal !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) 9940189efb8SYuval Mintz return 0; 9950189efb8SYuval Mintz 99651ff1725SRam Amrani for_each_hwfn(cdev, i) 99751ff1725SRam Amrani num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); 99851ff1725SRam Amrani 99951ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, 100051ff1725SRam Amrani "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n", 100151ff1725SRam Amrani cdev->int_params.fp_msix_cnt, num_l2_queues); 100251ff1725SRam Amrani 100351ff1725SRam Amrani if (cdev->int_params.fp_msix_cnt > num_l2_queues) { 100451ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 100551ff1725SRam Amrani (cdev->int_params.fp_msix_cnt - num_l2_queues) 100651ff1725SRam Amrani / cdev->num_hwfns; 100751ff1725SRam Amrani cdev->int_params.rdma_msix_base = 100851ff1725SRam Amrani cdev->int_params.fp_msix_base + num_l2_queues; 100951ff1725SRam Amrani cdev->int_params.fp_msix_cnt = num_l2_queues; 101051ff1725SRam Amrani } else { 101151ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 0; 101251ff1725SRam Amrani } 101351ff1725SRam Amrani 101451ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", 101551ff1725SRam Amrani cdev->int_params.rdma_msix_cnt, 101651ff1725SRam Amrani cdev->int_params.rdma_msix_base); 101751ff1725SRam Amrani 1018fe56b9e6SYuval Mintz return 0; 1019fe56b9e6SYuval Mintz } 1020fe56b9e6SYuval Mintz 10211408cc1fSYuval Mintz static int qed_slowpath_vf_setup_int(struct qed_dev *cdev) 10221408cc1fSYuval Mintz { 10231408cc1fSYuval Mintz int rc; 10241408cc1fSYuval Mintz 10251408cc1fSYuval Mintz memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 10261408cc1fSYuval Mintz cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; 10271408cc1fSYuval Mintz 10281408cc1fSYuval Mintz qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), 10291408cc1fSYuval Mintz &cdev->int_params.in.num_vectors); 10301408cc1fSYuval Mintz if (cdev->num_hwfns > 1) { 10311408cc1fSYuval Mintz u8 vectors = 0; 10321408cc1fSYuval Mintz 10331408cc1fSYuval Mintz qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); 10341408cc1fSYuval Mintz cdev->int_params.in.num_vectors += vectors; 10351408cc1fSYuval Mintz } 10361408cc1fSYuval Mintz 10371408cc1fSYuval Mintz /* We want a minimum of one fastpath vector per vf hwfn */ 10381408cc1fSYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; 10391408cc1fSYuval Mintz 10401408cc1fSYuval Mintz rc = qed_set_int_mode(cdev, true); 10411408cc1fSYuval Mintz if (rc) 10421408cc1fSYuval Mintz return rc; 10431408cc1fSYuval Mintz 10441408cc1fSYuval Mintz cdev->int_params.fp_msix_base = 0; 10451408cc1fSYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; 10461408cc1fSYuval Mintz 10471408cc1fSYuval Mintz return 0; 10481408cc1fSYuval Mintz } 10491408cc1fSYuval Mintz 1050fe56b9e6SYuval Mintz u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, 1051fe56b9e6SYuval Mintz u8 *input_buf, u32 max_size, u8 *unzip_buf) 1052fe56b9e6SYuval Mintz { 1053fe56b9e6SYuval Mintz int rc; 1054fe56b9e6SYuval Mintz 1055fe56b9e6SYuval Mintz p_hwfn->stream->next_in = input_buf; 1056fe56b9e6SYuval Mintz p_hwfn->stream->avail_in = input_len; 1057fe56b9e6SYuval Mintz p_hwfn->stream->next_out = unzip_buf; 1058fe56b9e6SYuval Mintz p_hwfn->stream->avail_out = max_size; 1059fe56b9e6SYuval Mintz 1060fe56b9e6SYuval Mintz rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); 1061fe56b9e6SYuval Mintz 1062fe56b9e6SYuval Mintz if (rc != Z_OK) { 1063fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", 1064fe56b9e6SYuval Mintz rc); 1065fe56b9e6SYuval Mintz return 0; 1066fe56b9e6SYuval Mintz } 1067fe56b9e6SYuval Mintz 1068fe56b9e6SYuval Mintz rc = zlib_inflate(p_hwfn->stream, Z_FINISH); 1069fe56b9e6SYuval Mintz zlib_inflateEnd(p_hwfn->stream); 1070fe56b9e6SYuval Mintz 1071fe56b9e6SYuval Mintz if (rc != Z_OK && rc != Z_STREAM_END) { 1072fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", 1073fe56b9e6SYuval Mintz p_hwfn->stream->msg, rc); 1074fe56b9e6SYuval Mintz return 0; 1075fe56b9e6SYuval Mintz } 1076fe56b9e6SYuval Mintz 1077fe56b9e6SYuval Mintz return p_hwfn->stream->total_out / 4; 1078fe56b9e6SYuval Mintz } 1079fe56b9e6SYuval Mintz 1080fe56b9e6SYuval Mintz static int qed_alloc_stream_mem(struct qed_dev *cdev) 1081fe56b9e6SYuval Mintz { 1082fe56b9e6SYuval Mintz int i; 1083fe56b9e6SYuval Mintz void *workspace; 1084fe56b9e6SYuval Mintz 1085fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1086fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 1087fe56b9e6SYuval Mintz 1088fe56b9e6SYuval Mintz p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); 1089fe56b9e6SYuval Mintz if (!p_hwfn->stream) 1090fe56b9e6SYuval Mintz return -ENOMEM; 1091fe56b9e6SYuval Mintz 1092fe56b9e6SYuval Mintz workspace = vzalloc(zlib_inflate_workspacesize()); 1093fe56b9e6SYuval Mintz if (!workspace) 1094fe56b9e6SYuval Mintz return -ENOMEM; 1095fe56b9e6SYuval Mintz p_hwfn->stream->workspace = workspace; 1096fe56b9e6SYuval Mintz } 1097fe56b9e6SYuval Mintz 1098fe56b9e6SYuval Mintz return 0; 1099fe56b9e6SYuval Mintz } 1100fe56b9e6SYuval Mintz 1101fe56b9e6SYuval Mintz static void qed_free_stream_mem(struct qed_dev *cdev) 1102fe56b9e6SYuval Mintz { 1103fe56b9e6SYuval Mintz int i; 1104fe56b9e6SYuval Mintz 1105fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1106fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 1107fe56b9e6SYuval Mintz 1108fe56b9e6SYuval Mintz if (!p_hwfn->stream) 1109fe56b9e6SYuval Mintz return; 1110fe56b9e6SYuval Mintz 1111fe56b9e6SYuval Mintz vfree(p_hwfn->stream->workspace); 1112fe56b9e6SYuval Mintz kfree(p_hwfn->stream); 1113fe56b9e6SYuval Mintz } 1114fe56b9e6SYuval Mintz } 1115fe56b9e6SYuval Mintz 1116fe56b9e6SYuval Mintz static void qed_update_pf_params(struct qed_dev *cdev, 1117fe56b9e6SYuval Mintz struct qed_pf_params *params) 1118fe56b9e6SYuval Mintz { 1119fe56b9e6SYuval Mintz int i; 1120fe56b9e6SYuval Mintz 11215c5f2609SRam Amrani if (IS_ENABLED(CONFIG_QED_RDMA)) { 11220189efb8SYuval Mintz params->rdma_pf_params.num_qps = QED_ROCE_QPS; 11230189efb8SYuval Mintz params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; 112439dbc646SYuval Bason params->rdma_pf_params.num_srqs = QED_RDMA_SRQS; 11250189efb8SYuval Mintz /* divide by 3 the MRs to avoid MF ILT overflow */ 11260189efb8SYuval Mintz params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; 1127fe56b9e6SYuval Mintz } 1128fe56b9e6SYuval Mintz 1129d51e4af5SChopra, Manish if (cdev->num_hwfns > 1 || IS_VF(cdev)) 1130d51e4af5SChopra, Manish params->eth_pf_params.num_arfs_filters = 0; 1131d51e4af5SChopra, Manish 1132e1d32acbSMintz, Yuval /* In case we might support RDMA, don't allow qede to be greedy 11335e7baf0fSManish Chopra * with the L2 contexts. Allow for 64 queues [rx, tx cos, xdp] 11345e7baf0fSManish Chopra * per hwfn. 1135e1d32acbSMintz, Yuval */ 1136c851a9dcSKalderon, Michal if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) { 1137e1d32acbSMintz, Yuval u16 *num_cons; 1138e1d32acbSMintz, Yuval 1139e1d32acbSMintz, Yuval num_cons = ¶ms->eth_pf_params.num_cons; 11405e7baf0fSManish Chopra *num_cons = min_t(u16, *num_cons, QED_MAX_L2_CONS); 1141e1d32acbSMintz, Yuval } 1142e1d32acbSMintz, Yuval 11435c5f2609SRam Amrani for (i = 0; i < cdev->num_hwfns; i++) { 11445c5f2609SRam Amrani struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 11455c5f2609SRam Amrani 11465c5f2609SRam Amrani p_hwfn->pf_params = *params; 11475c5f2609SRam Amrani } 11485c5f2609SRam Amrani } 11495c5f2609SRam Amrani 1150d4476b8aSDenis Bolotin #define QED_PERIODIC_DB_REC_COUNT 10 1151a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL_MS 100 1152a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL \ 1153a1b469b8SAriel Elior msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS) 1154a1b469b8SAriel Elior 1155a1b469b8SAriel Elior static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn, 1156a1b469b8SAriel Elior enum qed_slowpath_wq_flag wq_flag, 1157a1b469b8SAriel Elior unsigned long delay) 1158a1b469b8SAriel Elior { 1159a1b469b8SAriel Elior if (!hwfn->slowpath_wq_active) 1160a1b469b8SAriel Elior return -EINVAL; 1161a1b469b8SAriel Elior 1162a1b469b8SAriel Elior /* Memory barrier for setting atomic bit */ 1163a1b469b8SAriel Elior smp_mb__before_atomic(); 1164a1b469b8SAriel Elior set_bit(wq_flag, &hwfn->slowpath_task_flags); 1165a1b469b8SAriel Elior smp_mb__after_atomic(); 1166a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay); 1167a1b469b8SAriel Elior 1168a1b469b8SAriel Elior return 0; 1169a1b469b8SAriel Elior } 1170a1b469b8SAriel Elior 1171a1b469b8SAriel Elior void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn) 1172a1b469b8SAriel Elior { 1173a1b469b8SAriel Elior /* Reset periodic Doorbell Recovery counter */ 1174a1b469b8SAriel Elior p_hwfn->periodic_db_rec_count = QED_PERIODIC_DB_REC_COUNT; 1175a1b469b8SAriel Elior 1176a1b469b8SAriel Elior /* Don't schedule periodic Doorbell Recovery if already scheduled */ 1177a1b469b8SAriel Elior if (test_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1178a1b469b8SAriel Elior &p_hwfn->slowpath_task_flags)) 1179a1b469b8SAriel Elior return; 1180a1b469b8SAriel Elior 1181a1b469b8SAriel Elior qed_slowpath_delayed_work(p_hwfn, QED_SLOWPATH_PERIODIC_DB_REC, 1182a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1183a1b469b8SAriel Elior } 1184a1b469b8SAriel Elior 118559ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_wq_stop(struct qed_dev *cdev) 118659ccf86fSSudarsana Reddy Kalluru { 11873b85720dSYuval Basson int i; 118859ccf86fSSudarsana Reddy Kalluru 118959ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 119059ccf86fSSudarsana Reddy Kalluru return; 119159ccf86fSSudarsana Reddy Kalluru 119259ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 119359ccf86fSSudarsana Reddy Kalluru if (!cdev->hwfns[i].slowpath_wq) 119459ccf86fSSudarsana Reddy Kalluru continue; 119559ccf86fSSudarsana Reddy Kalluru 1196a1b469b8SAriel Elior /* Stop queuing new delayed works */ 1197a1b469b8SAriel Elior cdev->hwfns[i].slowpath_wq_active = false; 1198a1b469b8SAriel Elior 11993b85720dSYuval Basson cancel_delayed_work(&cdev->hwfns[i].slowpath_task); 120059ccf86fSSudarsana Reddy Kalluru destroy_workqueue(cdev->hwfns[i].slowpath_wq); 120159ccf86fSSudarsana Reddy Kalluru } 120259ccf86fSSudarsana Reddy Kalluru } 120359ccf86fSSudarsana Reddy Kalluru 120459ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_task(struct work_struct *work) 120559ccf86fSSudarsana Reddy Kalluru { 120659ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 120759ccf86fSSudarsana Reddy Kalluru slowpath_task.work); 120859ccf86fSSudarsana Reddy Kalluru struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 120959ccf86fSSudarsana Reddy Kalluru 121059ccf86fSSudarsana Reddy Kalluru if (!ptt) { 1211a1b469b8SAriel Elior if (hwfn->slowpath_wq_active) 1212a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, 1213a1b469b8SAriel Elior &hwfn->slowpath_task, 0); 1214a1b469b8SAriel Elior 121559ccf86fSSudarsana Reddy Kalluru return; 121659ccf86fSSudarsana Reddy Kalluru } 121759ccf86fSSudarsana Reddy Kalluru 121859ccf86fSSudarsana Reddy Kalluru if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ, 121959ccf86fSSudarsana Reddy Kalluru &hwfn->slowpath_task_flags)) 122059ccf86fSSudarsana Reddy Kalluru qed_mfw_process_tlv_req(hwfn, ptt); 122159ccf86fSSudarsana Reddy Kalluru 1222a1b469b8SAriel Elior if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1223a1b469b8SAriel Elior &hwfn->slowpath_task_flags)) { 1224a1b469b8SAriel Elior qed_db_rec_handler(hwfn, ptt); 1225a1b469b8SAriel Elior if (hwfn->periodic_db_rec_count--) 1226a1b469b8SAriel Elior qed_slowpath_delayed_work(hwfn, 1227a1b469b8SAriel Elior QED_SLOWPATH_PERIODIC_DB_REC, 1228a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1229a1b469b8SAriel Elior } 1230a1b469b8SAriel Elior 123159ccf86fSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 123259ccf86fSSudarsana Reddy Kalluru } 123359ccf86fSSudarsana Reddy Kalluru 123459ccf86fSSudarsana Reddy Kalluru static int qed_slowpath_wq_start(struct qed_dev *cdev) 123559ccf86fSSudarsana Reddy Kalluru { 123659ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn; 123759ccf86fSSudarsana Reddy Kalluru char name[NAME_SIZE]; 123859ccf86fSSudarsana Reddy Kalluru int i; 123959ccf86fSSudarsana Reddy Kalluru 124059ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 124159ccf86fSSudarsana Reddy Kalluru return 0; 124259ccf86fSSudarsana Reddy Kalluru 124359ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 124459ccf86fSSudarsana Reddy Kalluru hwfn = &cdev->hwfns[i]; 124559ccf86fSSudarsana Reddy Kalluru 124659ccf86fSSudarsana Reddy Kalluru snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", 124759ccf86fSSudarsana Reddy Kalluru cdev->pdev->bus->number, 124859ccf86fSSudarsana Reddy Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 124959ccf86fSSudarsana Reddy Kalluru 125059ccf86fSSudarsana Reddy Kalluru hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); 125159ccf86fSSudarsana Reddy Kalluru if (!hwfn->slowpath_wq) { 125259ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); 125359ccf86fSSudarsana Reddy Kalluru return -ENOMEM; 125459ccf86fSSudarsana Reddy Kalluru } 125559ccf86fSSudarsana Reddy Kalluru 125659ccf86fSSudarsana Reddy Kalluru INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task); 1257a1b469b8SAriel Elior hwfn->slowpath_wq_active = true; 125859ccf86fSSudarsana Reddy Kalluru } 125959ccf86fSSudarsana Reddy Kalluru 126059ccf86fSSudarsana Reddy Kalluru return 0; 126159ccf86fSSudarsana Reddy Kalluru } 126259ccf86fSSudarsana Reddy Kalluru 1263fe56b9e6SYuval Mintz static int qed_slowpath_start(struct qed_dev *cdev, 1264fe56b9e6SYuval Mintz struct qed_slowpath_params *params) 1265fe56b9e6SYuval Mintz { 12665d24bcf1STomer Tayar struct qed_drv_load_params drv_load_params; 1267c0c2d0b4SMintz, Yuval struct qed_hw_init_params hw_init_params; 1268fe56b9e6SYuval Mintz struct qed_mcp_drv_version drv_version; 126919968430SChopra, Manish struct qed_tunnel_info tunn_info; 1270fe56b9e6SYuval Mintz const u8 *data = NULL; 1271fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 1272c78c70faSSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 127337bff2b9SYuval Mintz int rc = -EINVAL; 127437bff2b9SYuval Mintz 127537bff2b9SYuval Mintz if (qed_iov_wq_start(cdev)) 127637bff2b9SYuval Mintz goto err; 1277fe56b9e6SYuval Mintz 127859ccf86fSSudarsana Reddy Kalluru if (qed_slowpath_wq_start(cdev)) 127959ccf86fSSudarsana Reddy Kalluru goto err; 128059ccf86fSSudarsana Reddy Kalluru 12811408cc1fSYuval Mintz if (IS_PF(cdev)) { 1282fe56b9e6SYuval Mintz rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, 1283fe56b9e6SYuval Mintz &cdev->pdev->dev); 1284fe56b9e6SYuval Mintz if (rc) { 1285fe56b9e6SYuval Mintz DP_NOTICE(cdev, 1286fe56b9e6SYuval Mintz "Failed to find fw file - /lib/firmware/%s\n", 1287fe56b9e6SYuval Mintz QED_FW_FILE_NAME); 1288fe56b9e6SYuval Mintz goto err; 1289fe56b9e6SYuval Mintz } 1290c78c70faSSudarsana Reddy Kalluru 1291d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) { 1292d51e4af5SChopra, Manish p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 1293d51e4af5SChopra, Manish if (p_ptt) { 1294d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; 1295d51e4af5SChopra, Manish } else { 1296d51e4af5SChopra, Manish DP_NOTICE(cdev, 1297d51e4af5SChopra, Manish "Failed to acquire PTT for aRFS\n"); 1298d51e4af5SChopra, Manish goto err; 1299d51e4af5SChopra, Manish } 1300d51e4af5SChopra, Manish } 13011408cc1fSYuval Mintz } 1302fe56b9e6SYuval Mintz 13030e191827SSudarsana Reddy Kalluru cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 1304fe56b9e6SYuval Mintz rc = qed_nic_setup(cdev); 1305fe56b9e6SYuval Mintz if (rc) 1306fe56b9e6SYuval Mintz goto err; 1307fe56b9e6SYuval Mintz 13081408cc1fSYuval Mintz if (IS_PF(cdev)) 1309fe56b9e6SYuval Mintz rc = qed_slowpath_setup_int(cdev, params->int_mode); 13101408cc1fSYuval Mintz else 13111408cc1fSYuval Mintz rc = qed_slowpath_vf_setup_int(cdev); 1312fe56b9e6SYuval Mintz if (rc) 1313fe56b9e6SYuval Mintz goto err1; 1314fe56b9e6SYuval Mintz 13151408cc1fSYuval Mintz if (IS_PF(cdev)) { 1316fe56b9e6SYuval Mintz /* Allocate stream for unzipping */ 1317fe56b9e6SYuval Mintz rc = qed_alloc_stream_mem(cdev); 13182591c280SJoe Perches if (rc) 13198f16bc97SSudarsana Kalluru goto err2; 1320fe56b9e6SYuval Mintz 13218ac1ed79SJoe Perches /* First Dword used to differentiate between various sources */ 1322351a4dedSYuval Mintz data = cdev->firmware->data + sizeof(u32); 1323c965db44STomer Tayar 1324c965db44STomer Tayar qed_dbg_pf_init(cdev); 13251408cc1fSYuval Mintz } 1326fe56b9e6SYuval Mintz 13271408cc1fSYuval Mintz /* Start the slowpath */ 1328c0c2d0b4SMintz, Yuval memset(&hw_init_params, 0, sizeof(hw_init_params)); 132919968430SChopra, Manish memset(&tunn_info, 0, sizeof(tunn_info)); 133019968430SChopra, Manish tunn_info.vxlan.b_mode_enabled = true; 133119968430SChopra, Manish tunn_info.l2_gre.b_mode_enabled = true; 133219968430SChopra, Manish tunn_info.ip_gre.b_mode_enabled = true; 133319968430SChopra, Manish tunn_info.l2_geneve.b_mode_enabled = true; 133419968430SChopra, Manish tunn_info.ip_geneve.b_mode_enabled = true; 133519968430SChopra, Manish tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133619968430SChopra, Manish tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133719968430SChopra, Manish tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133819968430SChopra, Manish tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133919968430SChopra, Manish tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 1340c0c2d0b4SMintz, Yuval hw_init_params.p_tunn = &tunn_info; 1341c0c2d0b4SMintz, Yuval hw_init_params.b_hw_start = true; 1342c0c2d0b4SMintz, Yuval hw_init_params.int_mode = cdev->int_params.out.int_mode; 1343c0c2d0b4SMintz, Yuval hw_init_params.allow_npar_tx_switch = true; 1344c0c2d0b4SMintz, Yuval hw_init_params.bin_fw_data = data; 1345c0c2d0b4SMintz, Yuval 13465d24bcf1STomer Tayar memset(&drv_load_params, 0, sizeof(drv_load_params)); 13475d24bcf1STomer Tayar drv_load_params.is_crash_kernel = is_kdump_kernel(); 13485d24bcf1STomer Tayar drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; 13495d24bcf1STomer Tayar drv_load_params.avoid_eng_reset = false; 13505d24bcf1STomer Tayar drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; 13515d24bcf1STomer Tayar hw_init_params.p_drv_load_params = &drv_load_params; 13525d24bcf1STomer Tayar 1353c0c2d0b4SMintz, Yuval rc = qed_hw_init(cdev, &hw_init_params); 1354fe56b9e6SYuval Mintz if (rc) 13558c925c44SYuval Mintz goto err2; 1356fe56b9e6SYuval Mintz 1357fe56b9e6SYuval Mintz DP_INFO(cdev, 1358fe56b9e6SYuval Mintz "HW initialization and function start completed successfully\n"); 1359fe56b9e6SYuval Mintz 1360eaf3c0c6SChopra, Manish if (IS_PF(cdev)) { 1361eaf3c0c6SChopra, Manish cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | 1362eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GENEVE_TUNN) | 1363eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGENEVE_TUNN) | 1364eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GRE_TUNN) | 1365eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGRE_TUNN)); 1366eaf3c0c6SChopra, Manish } 1367eaf3c0c6SChopra, Manish 13680a7fb11cSYuval Mintz /* Allocate LL2 interface if needed */ 13690a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->using_ll2) { 13700a7fb11cSYuval Mintz rc = qed_ll2_alloc_if(cdev); 13710a7fb11cSYuval Mintz if (rc) 13720a7fb11cSYuval Mintz goto err3; 13730a7fb11cSYuval Mintz } 13741408cc1fSYuval Mintz if (IS_PF(cdev)) { 1375fe56b9e6SYuval Mintz hwfn = QED_LEADING_HWFN(cdev); 1376fe56b9e6SYuval Mintz drv_version.version = (params->drv_major << 24) | 1377fe56b9e6SYuval Mintz (params->drv_minor << 16) | 1378fe56b9e6SYuval Mintz (params->drv_rev << 8) | 1379fe56b9e6SYuval Mintz (params->drv_eng); 1380fe56b9e6SYuval Mintz strlcpy(drv_version.name, params->name, 1381fe56b9e6SYuval Mintz MCP_DRV_VER_STR_SIZE - 4); 1382fe56b9e6SYuval Mintz rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, 1383fe56b9e6SYuval Mintz &drv_version); 1384fe56b9e6SYuval Mintz if (rc) { 1385fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed sending drv version command\n"); 1386de0e4fd2SWenwen Wang goto err4; 1387fe56b9e6SYuval Mintz } 13881408cc1fSYuval Mintz } 1389fe56b9e6SYuval Mintz 13908c925c44SYuval Mintz qed_reset_vport_stats(cdev); 13918c925c44SYuval Mintz 1392fe56b9e6SYuval Mintz return 0; 1393fe56b9e6SYuval Mintz 1394de0e4fd2SWenwen Wang err4: 1395de0e4fd2SWenwen Wang qed_ll2_dealloc_if(cdev); 13960a7fb11cSYuval Mintz err3: 13970a7fb11cSYuval Mintz qed_hw_stop(cdev); 1398fe56b9e6SYuval Mintz err2: 13998c925c44SYuval Mintz qed_hw_timers_stop_all(cdev); 14001408cc1fSYuval Mintz if (IS_PF(cdev)) 14018c925c44SYuval Mintz qed_slowpath_irq_free(cdev); 14028c925c44SYuval Mintz qed_free_stream_mem(cdev); 1403fe56b9e6SYuval Mintz qed_disable_msix(cdev); 1404fe56b9e6SYuval Mintz err1: 1405fe56b9e6SYuval Mintz qed_resc_free(cdev); 1406fe56b9e6SYuval Mintz err: 14071408cc1fSYuval Mintz if (IS_PF(cdev)) 1408fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1409fe56b9e6SYuval Mintz 1410d51e4af5SChopra, Manish if (IS_PF(cdev) && (cdev->num_hwfns == 1) && 1411d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt) 1412d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1413d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1414c78c70faSSudarsana Reddy Kalluru 141537bff2b9SYuval Mintz qed_iov_wq_stop(cdev, false); 141637bff2b9SYuval Mintz 141759ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 141859ccf86fSSudarsana Reddy Kalluru 1419fe56b9e6SYuval Mintz return rc; 1420fe56b9e6SYuval Mintz } 1421fe56b9e6SYuval Mintz 1422fe56b9e6SYuval Mintz static int qed_slowpath_stop(struct qed_dev *cdev) 1423fe56b9e6SYuval Mintz { 1424fe56b9e6SYuval Mintz if (!cdev) 1425fe56b9e6SYuval Mintz return -ENODEV; 1426fe56b9e6SYuval Mintz 142759ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 142859ccf86fSSudarsana Reddy Kalluru 14290a7fb11cSYuval Mintz qed_ll2_dealloc_if(cdev); 14300a7fb11cSYuval Mintz 14311408cc1fSYuval Mintz if (IS_PF(cdev)) { 1432d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) 1433d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1434d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1435fe56b9e6SYuval Mintz qed_free_stream_mem(cdev); 1436c5ac9319SYuval Mintz if (IS_QED_ETH_IF(cdev)) 14370b55e27dSYuval Mintz qed_sriov_disable(cdev, true); 14385f027d7aSMintz, Yuval } 1439fe56b9e6SYuval Mintz 1440fe56b9e6SYuval Mintz qed_nic_stop(cdev); 14415f027d7aSMintz, Yuval 14425f027d7aSMintz, Yuval if (IS_PF(cdev)) 1443fe56b9e6SYuval Mintz qed_slowpath_irq_free(cdev); 1444fe56b9e6SYuval Mintz 1445fe56b9e6SYuval Mintz qed_disable_msix(cdev); 14461226337aSTomer Tayar 14471226337aSTomer Tayar qed_resc_free(cdev); 1448fe56b9e6SYuval Mintz 144937bff2b9SYuval Mintz qed_iov_wq_stop(cdev, true); 145037bff2b9SYuval Mintz 14511408cc1fSYuval Mintz if (IS_PF(cdev)) 1452fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1453fe56b9e6SYuval Mintz 1454fe56b9e6SYuval Mintz return 0; 1455fe56b9e6SYuval Mintz } 1456fe56b9e6SYuval Mintz 1457712c3cbfSMintz, Yuval static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) 1458fe56b9e6SYuval Mintz { 1459fe56b9e6SYuval Mintz int i; 1460fe56b9e6SYuval Mintz 1461fe56b9e6SYuval Mintz memcpy(cdev->name, name, NAME_SIZE); 1462fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) 1463fe56b9e6SYuval Mintz snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); 1464fe56b9e6SYuval Mintz } 1465fe56b9e6SYuval Mintz 1466fe56b9e6SYuval Mintz static u32 qed_sb_init(struct qed_dev *cdev, 1467fe56b9e6SYuval Mintz struct qed_sb_info *sb_info, 1468fe56b9e6SYuval Mintz void *sb_virt_addr, 1469fe56b9e6SYuval Mintz dma_addr_t sb_phy_addr, u16 sb_id, 1470fe56b9e6SYuval Mintz enum qed_sb_type type) 1471fe56b9e6SYuval Mintz { 1472fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 147385750d74SMintz, Yuval struct qed_ptt *p_ptt; 1474fe56b9e6SYuval Mintz u16 rel_sb_id; 1475fe56b9e6SYuval Mintz u32 rc; 1476fe56b9e6SYuval Mintz 147708eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 147808eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 147908eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 148008eb1fb0SMichal Kalderon rel_sb_id = sb_id / cdev->num_hwfns; 148108eb1fb0SMichal Kalderon } else { 148208eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 148308eb1fb0SMichal Kalderon rel_sb_id = sb_id; 148408eb1fb0SMichal Kalderon } 1485fe56b9e6SYuval Mintz 1486fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1487fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 148808eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1489fe56b9e6SYuval Mintz 149085750d74SMintz, Yuval if (IS_PF(p_hwfn->cdev)) { 149185750d74SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 149285750d74SMintz, Yuval if (!p_ptt) 149385750d74SMintz, Yuval return -EBUSY; 149485750d74SMintz, Yuval 149585750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, 149685750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 149785750d74SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 149885750d74SMintz, Yuval } else { 149985750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, 150085750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 150185750d74SMintz, Yuval } 1502fe56b9e6SYuval Mintz 1503fe56b9e6SYuval Mintz return rc; 1504fe56b9e6SYuval Mintz } 1505fe56b9e6SYuval Mintz 1506fe56b9e6SYuval Mintz static u32 qed_sb_release(struct qed_dev *cdev, 150708eb1fb0SMichal Kalderon struct qed_sb_info *sb_info, 150808eb1fb0SMichal Kalderon u16 sb_id, 150908eb1fb0SMichal Kalderon enum qed_sb_type type) 1510fe56b9e6SYuval Mintz { 1511fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 1512fe56b9e6SYuval Mintz u16 rel_sb_id; 1513fe56b9e6SYuval Mintz u32 rc; 1514fe56b9e6SYuval Mintz 151508eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 151608eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 151708eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 1518fe56b9e6SYuval Mintz rel_sb_id = sb_id / cdev->num_hwfns; 151908eb1fb0SMichal Kalderon } else { 152008eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 152108eb1fb0SMichal Kalderon rel_sb_id = sb_id; 152208eb1fb0SMichal Kalderon } 1523fe56b9e6SYuval Mintz 1524fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1525fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 152608eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1527fe56b9e6SYuval Mintz 1528fe56b9e6SYuval Mintz rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); 1529fe56b9e6SYuval Mintz 1530fe56b9e6SYuval Mintz return rc; 1531fe56b9e6SYuval Mintz } 1532fe56b9e6SYuval Mintz 1533fe7cd2bfSYuval Mintz static bool qed_can_link_change(struct qed_dev *cdev) 1534fe7cd2bfSYuval Mintz { 1535fe7cd2bfSYuval Mintz return true; 1536fe7cd2bfSYuval Mintz } 1537fe7cd2bfSYuval Mintz 153899785a87SAlexander Lobakin static void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params, 153999785a87SAlexander Lobakin const struct qed_link_params *params) 154099785a87SAlexander Lobakin { 154199785a87SAlexander Lobakin struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed; 154299785a87SAlexander Lobakin const struct qed_mfw_speed_map *map; 154399785a87SAlexander Lobakin u32 i; 154499785a87SAlexander Lobakin 154599785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 154699785a87SAlexander Lobakin ext_speed->autoneg = !!params->autoneg; 154799785a87SAlexander Lobakin 154899785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 154999785a87SAlexander Lobakin ext_speed->advertised_speeds = 0; 155099785a87SAlexander Lobakin 155199785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) { 155299785a87SAlexander Lobakin map = qed_mfw_ext_maps + i; 155399785a87SAlexander Lobakin 155499785a87SAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 155599785a87SAlexander Lobakin ext_speed->advertised_speeds |= map->mfw_val; 155699785a87SAlexander Lobakin } 155799785a87SAlexander Lobakin } 155899785a87SAlexander Lobakin 155999785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) { 156099785a87SAlexander Lobakin switch (params->forced_speed) { 156199785a87SAlexander Lobakin case SPEED_1000: 156299785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_1G; 156399785a87SAlexander Lobakin break; 156499785a87SAlexander Lobakin case SPEED_10000: 156599785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_10G; 156699785a87SAlexander Lobakin break; 156799785a87SAlexander Lobakin case SPEED_20000: 156899785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_20G; 156999785a87SAlexander Lobakin break; 157099785a87SAlexander Lobakin case SPEED_25000: 157199785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_25G; 157299785a87SAlexander Lobakin break; 157399785a87SAlexander Lobakin case SPEED_40000: 157499785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_40G; 157599785a87SAlexander Lobakin break; 157699785a87SAlexander Lobakin case SPEED_50000: 157799785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_50G_R | 157899785a87SAlexander Lobakin QED_EXT_SPEED_50G_R2; 157999785a87SAlexander Lobakin break; 158099785a87SAlexander Lobakin case SPEED_100000: 158199785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 | 158299785a87SAlexander Lobakin QED_EXT_SPEED_100G_R4 | 158399785a87SAlexander Lobakin QED_EXT_SPEED_100G_P4; 158499785a87SAlexander Lobakin break; 158599785a87SAlexander Lobakin default: 158699785a87SAlexander Lobakin break; 158799785a87SAlexander Lobakin } 158899785a87SAlexander Lobakin } 158999785a87SAlexander Lobakin 159099785a87SAlexander Lobakin if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)) 159199785a87SAlexander Lobakin return; 159299785a87SAlexander Lobakin 159399785a87SAlexander Lobakin switch (params->forced_speed) { 159499785a87SAlexander Lobakin case SPEED_25000: 159599785a87SAlexander Lobakin switch (params->fec) { 159699785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 159799785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE; 159899785a87SAlexander Lobakin break; 159999785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 160099785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R; 160199785a87SAlexander Lobakin break; 160299785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 160399785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528; 160499785a87SAlexander Lobakin break; 160599785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 160699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 | 160799785a87SAlexander Lobakin ETH_EXT_FEC_25G_BASE_R | 160899785a87SAlexander Lobakin ETH_EXT_FEC_25G_NONE; 160999785a87SAlexander Lobakin break; 161099785a87SAlexander Lobakin default: 161199785a87SAlexander Lobakin break; 161299785a87SAlexander Lobakin } 161399785a87SAlexander Lobakin 161499785a87SAlexander Lobakin break; 161599785a87SAlexander Lobakin case SPEED_40000: 161699785a87SAlexander Lobakin switch (params->fec) { 161799785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 161899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE; 161999785a87SAlexander Lobakin break; 162099785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 162199785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R; 162299785a87SAlexander Lobakin break; 162399785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 162499785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R | 162599785a87SAlexander Lobakin ETH_EXT_FEC_40G_NONE; 162699785a87SAlexander Lobakin break; 162799785a87SAlexander Lobakin default: 162899785a87SAlexander Lobakin break; 162999785a87SAlexander Lobakin } 163099785a87SAlexander Lobakin 163199785a87SAlexander Lobakin break; 163299785a87SAlexander Lobakin case SPEED_50000: 163399785a87SAlexander Lobakin switch (params->fec) { 163499785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 163599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE; 163699785a87SAlexander Lobakin break; 163799785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 163899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R; 163999785a87SAlexander Lobakin break; 164099785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 164199785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528; 164299785a87SAlexander Lobakin break; 164399785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 164499785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 | 164599785a87SAlexander Lobakin ETH_EXT_FEC_50G_BASE_R | 164699785a87SAlexander Lobakin ETH_EXT_FEC_50G_NONE; 164799785a87SAlexander Lobakin break; 164899785a87SAlexander Lobakin default: 164999785a87SAlexander Lobakin break; 165099785a87SAlexander Lobakin } 165199785a87SAlexander Lobakin 165299785a87SAlexander Lobakin break; 165399785a87SAlexander Lobakin case SPEED_100000: 165499785a87SAlexander Lobakin switch (params->fec) { 165599785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 165699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE; 165799785a87SAlexander Lobakin break; 165899785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 165999785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R; 166099785a87SAlexander Lobakin break; 166199785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 166299785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528; 166399785a87SAlexander Lobakin break; 166499785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 166599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 | 166699785a87SAlexander Lobakin ETH_EXT_FEC_100G_BASE_R | 166799785a87SAlexander Lobakin ETH_EXT_FEC_100G_NONE; 166899785a87SAlexander Lobakin break; 166999785a87SAlexander Lobakin default: 167099785a87SAlexander Lobakin break; 167199785a87SAlexander Lobakin } 167299785a87SAlexander Lobakin 167399785a87SAlexander Lobakin break; 167499785a87SAlexander Lobakin default: 167599785a87SAlexander Lobakin break; 167699785a87SAlexander Lobakin } 167799785a87SAlexander Lobakin } 167899785a87SAlexander Lobakin 1679351a4dedSYuval Mintz static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) 1680cc875c2eSYuval Mintz { 1681cc875c2eSYuval Mintz struct qed_mcp_link_params *link_params; 1682097818fcSAlexander Lobakin struct qed_mcp_link_speed_params *speed; 1683097818fcSAlexander Lobakin const struct qed_mfw_speed_map *map; 1684bdb5d8ecSAlexander Lobakin struct qed_hwfn *hwfn; 1685cc875c2eSYuval Mintz struct qed_ptt *ptt; 1686cc875c2eSYuval Mintz int rc; 1687097818fcSAlexander Lobakin u32 i; 1688cc875c2eSYuval Mintz 1689cc875c2eSYuval Mintz if (!cdev) 1690cc875c2eSYuval Mintz return -ENODEV; 1691cc875c2eSYuval Mintz 1692cc875c2eSYuval Mintz /* The link should be set only once per PF */ 1693cc875c2eSYuval Mintz hwfn = &cdev->hwfns[0]; 1694cc875c2eSYuval Mintz 169565ed2ffdSMintz, Yuval /* When VF wants to set link, force it to read the bulletin instead. 169665ed2ffdSMintz, Yuval * This mimics the PF behavior, where a noitification [both immediate 169765ed2ffdSMintz, Yuval * and possible later] would be generated when changing properties. 169865ed2ffdSMintz, Yuval */ 169965ed2ffdSMintz, Yuval if (IS_VF(cdev)) { 170065ed2ffdSMintz, Yuval qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); 170165ed2ffdSMintz, Yuval return 0; 170265ed2ffdSMintz, Yuval } 170365ed2ffdSMintz, Yuval 1704cc875c2eSYuval Mintz ptt = qed_ptt_acquire(hwfn); 1705cc875c2eSYuval Mintz if (!ptt) 1706cc875c2eSYuval Mintz return -EBUSY; 1707cc875c2eSYuval Mintz 1708cc875c2eSYuval Mintz link_params = qed_mcp_get_link_params(hwfn); 1709bdb5d8ecSAlexander Lobakin if (!link_params) 1710bdb5d8ecSAlexander Lobakin return -ENODATA; 1711bdb5d8ecSAlexander Lobakin 1712097818fcSAlexander Lobakin speed = &link_params->speed; 1713097818fcSAlexander Lobakin 1714cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 1715097818fcSAlexander Lobakin speed->autoneg = !!params->autoneg; 1716bdb5d8ecSAlexander Lobakin 1717cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 1718097818fcSAlexander Lobakin speed->advertised_speeds = 0; 1719bdb5d8ecSAlexander Lobakin 1720097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) { 1721097818fcSAlexander Lobakin map = qed_mfw_legacy_maps + i; 1722bdb5d8ecSAlexander Lobakin 1723097818fcSAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 1724097818fcSAlexander Lobakin speed->advertised_speeds |= map->mfw_val; 1725097818fcSAlexander Lobakin } 1726cc875c2eSYuval Mintz } 1727bdb5d8ecSAlexander Lobakin 1728cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) 1729097818fcSAlexander Lobakin speed->forced_speed = params->forced_speed; 1730097818fcSAlexander Lobakin 173199785a87SAlexander Lobakin if (qed_mcp_is_ext_speed_supported(hwfn)) 173299785a87SAlexander Lobakin qed_set_ext_speed_params(link_params, params); 173399785a87SAlexander Lobakin 1734a43f235fSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { 1735a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 1736a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = true; 1737a43f235fSSudarsana Reddy Kalluru else 1738a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = false; 1739a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) 1740a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = true; 1741a43f235fSSudarsana Reddy Kalluru else 1742a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = false; 1743a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) 1744a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = true; 1745a43f235fSSudarsana Reddy Kalluru else 1746a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = false; 1747a43f235fSSudarsana Reddy Kalluru } 1748097818fcSAlexander Lobakin 174903dc76caSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { 175003dc76caSSudarsana Reddy Kalluru switch (params->loopback_mode) { 175103dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_INT_PHY: 1752351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; 175303dc76caSSudarsana Reddy Kalluru break; 175403dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT_PHY: 1755351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; 175603dc76caSSudarsana Reddy Kalluru break; 175703dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT: 1758351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT; 175903dc76caSSudarsana Reddy Kalluru break; 176003dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_MAC: 1761351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_MAC; 176203dc76caSSudarsana Reddy Kalluru break; 176398e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123: 176498e675ecSAlexander Lobakin link_params->loopback_mode = 176598e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_0123; 176698e675ecSAlexander Lobakin break; 176798e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301: 176898e675ecSAlexander Lobakin link_params->loopback_mode = 176998e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_2301; 177098e675ecSAlexander Lobakin break; 177198e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_PCS_AH_ONLY: 177298e675ecSAlexander Lobakin link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY; 177398e675ecSAlexander Lobakin break; 177498e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY: 177598e675ecSAlexander Lobakin link_params->loopback_mode = 177698e675ecSAlexander Lobakin ETH_LOOPBACK_REVERSE_MAC_AH_ONLY; 177798e675ecSAlexander Lobakin break; 177898e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY: 177998e675ecSAlexander Lobakin link_params->loopback_mode = 178098e675ecSAlexander Lobakin ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY; 178198e675ecSAlexander Lobakin break; 178203dc76caSSudarsana Reddy Kalluru default: 1783351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_NONE; 178403dc76caSSudarsana Reddy Kalluru break; 178503dc76caSSudarsana Reddy Kalluru } 178603dc76caSSudarsana Reddy Kalluru } 1787cc875c2eSYuval Mintz 1788645874e5SSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) 1789645874e5SSudarsana Reddy Kalluru memcpy(&link_params->eee, ¶ms->eee, 1790645874e5SSudarsana Reddy Kalluru sizeof(link_params->eee)); 1791645874e5SSudarsana Reddy Kalluru 1792ae7e6937SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG) 1793ae7e6937SAlexander Lobakin link_params->fec = params->fec; 1794ae7e6937SAlexander Lobakin 1795cc875c2eSYuval Mintz rc = qed_mcp_set_link(hwfn, ptt, params->link_up); 1796cc875c2eSYuval Mintz 1797cc875c2eSYuval Mintz qed_ptt_release(hwfn, ptt); 1798cc875c2eSYuval Mintz 1799cc875c2eSYuval Mintz return rc; 1800cc875c2eSYuval Mintz } 1801cc875c2eSYuval Mintz 1802cc875c2eSYuval Mintz static int qed_get_port_type(u32 media_type) 1803cc875c2eSYuval Mintz { 1804cc875c2eSYuval Mintz int port_type; 1805cc875c2eSYuval Mintz 1806cc875c2eSYuval Mintz switch (media_type) { 1807cc875c2eSYuval Mintz case MEDIA_SFPP_10G_FIBER: 1808cc875c2eSYuval Mintz case MEDIA_SFP_1G_FIBER: 1809cc875c2eSYuval Mintz case MEDIA_XFP_FIBER: 1810b639f197SYuval Mintz case MEDIA_MODULE_FIBER: 1811cc875c2eSYuval Mintz port_type = PORT_FIBRE; 1812cc875c2eSYuval Mintz break; 1813cc875c2eSYuval Mintz case MEDIA_DA_TWINAX: 1814cc875c2eSYuval Mintz port_type = PORT_DA; 1815cc875c2eSYuval Mintz break; 1816cc875c2eSYuval Mintz case MEDIA_BASE_T: 1817cc875c2eSYuval Mintz port_type = PORT_TP; 1818cc875c2eSYuval Mintz break; 181999785a87SAlexander Lobakin case MEDIA_KR: 1820cc875c2eSYuval Mintz case MEDIA_NOT_PRESENT: 1821cc875c2eSYuval Mintz port_type = PORT_NONE; 1822cc875c2eSYuval Mintz break; 1823cc875c2eSYuval Mintz case MEDIA_UNSPECIFIED: 1824cc875c2eSYuval Mintz default: 1825cc875c2eSYuval Mintz port_type = PORT_OTHER; 1826cc875c2eSYuval Mintz break; 1827cc875c2eSYuval Mintz } 1828cc875c2eSYuval Mintz return port_type; 1829cc875c2eSYuval Mintz } 1830cc875c2eSYuval Mintz 183114b84e86SArnd Bergmann static int qed_get_link_data(struct qed_hwfn *hwfn, 183214b84e86SArnd Bergmann struct qed_mcp_link_params *params, 183314b84e86SArnd Bergmann struct qed_mcp_link_state *link, 183414b84e86SArnd Bergmann struct qed_mcp_link_capabilities *link_caps) 183514b84e86SArnd Bergmann { 183614b84e86SArnd Bergmann void *p; 183714b84e86SArnd Bergmann 183814b84e86SArnd Bergmann if (!IS_PF(hwfn->cdev)) { 183914b84e86SArnd Bergmann qed_vf_get_link_params(hwfn, params); 184014b84e86SArnd Bergmann qed_vf_get_link_state(hwfn, link); 184114b84e86SArnd Bergmann qed_vf_get_link_caps(hwfn, link_caps); 184214b84e86SArnd Bergmann 184314b84e86SArnd Bergmann return 0; 184414b84e86SArnd Bergmann } 184514b84e86SArnd Bergmann 184614b84e86SArnd Bergmann p = qed_mcp_get_link_params(hwfn); 184714b84e86SArnd Bergmann if (!p) 184814b84e86SArnd Bergmann return -ENXIO; 184914b84e86SArnd Bergmann memcpy(params, p, sizeof(*params)); 185014b84e86SArnd Bergmann 185114b84e86SArnd Bergmann p = qed_mcp_get_link_state(hwfn); 185214b84e86SArnd Bergmann if (!p) 185314b84e86SArnd Bergmann return -ENXIO; 185414b84e86SArnd Bergmann memcpy(link, p, sizeof(*link)); 185514b84e86SArnd Bergmann 185614b84e86SArnd Bergmann p = qed_mcp_get_link_capabilities(hwfn); 185714b84e86SArnd Bergmann if (!p) 185814b84e86SArnd Bergmann return -ENXIO; 185914b84e86SArnd Bergmann memcpy(link_caps, p, sizeof(*link_caps)); 186014b84e86SArnd Bergmann 186114b84e86SArnd Bergmann return 0; 186214b84e86SArnd Bergmann } 186314b84e86SArnd Bergmann 1864c56a8be7SRahul Verma static void qed_fill_link_capability(struct qed_hwfn *hwfn, 1865c56a8be7SRahul Verma struct qed_ptt *ptt, u32 capability, 1866bdb5d8ecSAlexander Lobakin unsigned long *if_caps) 1867c56a8be7SRahul Verma { 1868c56a8be7SRahul Verma u32 media_type, tcvr_state, tcvr_type; 1869c56a8be7SRahul Verma u32 speed_mask, board_cfg; 1870c56a8be7SRahul Verma 1871c56a8be7SRahul Verma if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) 1872c56a8be7SRahul Verma media_type = MEDIA_UNSPECIFIED; 1873c56a8be7SRahul Verma 1874c56a8be7SRahul Verma if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) 1875c56a8be7SRahul Verma tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; 1876c56a8be7SRahul Verma 1877c56a8be7SRahul Verma if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) 1878c56a8be7SRahul Verma speed_mask = 0xFFFFFFFF; 1879c56a8be7SRahul Verma 1880c56a8be7SRahul Verma if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) 1881c56a8be7SRahul Verma board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 1882c56a8be7SRahul Verma 1883c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 1884c56a8be7SRahul Verma "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", 1885c56a8be7SRahul Verma media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); 1886c56a8be7SRahul Verma 1887c56a8be7SRahul Verma switch (media_type) { 1888c56a8be7SRahul Verma case MEDIA_DA_TWINAX: 1889bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1890bdb5d8ecSAlexander Lobakin 1891c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1892bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 1893bdb5d8ecSAlexander Lobakin 1894c56a8be7SRahul Verma /* For DAC media multiple speed capabilities are supported */ 18959228b7c1SAlexander Lobakin capability |= speed_mask; 18969228b7c1SAlexander Lobakin 1897c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1898bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 1899c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1900bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseCR_Full); 19019228b7c1SAlexander Lobakin 1902c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 19039228b7c1SAlexander Lobakin switch (tcvr_type) { 19049228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_CR4: 19059228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 19069228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1907bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseCR4_Full); 19089228b7c1SAlexander Lobakin break; 19099228b7c1SAlexander Lobakin default: 19109228b7c1SAlexander Lobakin break; 19119228b7c1SAlexander Lobakin } 19129228b7c1SAlexander Lobakin 1913c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 1914bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseCR_Full); 1915c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1916bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseCR2_Full); 19179228b7c1SAlexander Lobakin 1918c56a8be7SRahul Verma if (capability & 1919c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 19209228b7c1SAlexander Lobakin switch (tcvr_type) { 19219228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_CR4: 19229228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1923bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseCR4_Full); 19249228b7c1SAlexander Lobakin break; 19259228b7c1SAlexander Lobakin default: 19269228b7c1SAlexander Lobakin break; 19279228b7c1SAlexander Lobakin } 1928bdb5d8ecSAlexander Lobakin 1929c56a8be7SRahul Verma break; 1930c56a8be7SRahul Verma case MEDIA_BASE_T: 1931bdb5d8ecSAlexander Lobakin phylink_set(if_caps, TP); 1932bdb5d8ecSAlexander Lobakin 1933c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { 1934c56a8be7SRahul Verma if (capability & 1935bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1936bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 1937c56a8be7SRahul Verma if (capability & 1938bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1939bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 1940c56a8be7SRahul Verma } 1941bdb5d8ecSAlexander Lobakin 1942c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { 1943bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1944bdb5d8ecSAlexander Lobakin 19459228b7c1SAlexander Lobakin switch (tcvr_type) { 19469228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1000BASET: 1947bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 19489228b7c1SAlexander Lobakin break; 19499228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_BASET: 1950bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 19519228b7c1SAlexander Lobakin break; 19529228b7c1SAlexander Lobakin default: 19539228b7c1SAlexander Lobakin break; 19549228b7c1SAlexander Lobakin } 1955c56a8be7SRahul Verma } 1956bdb5d8ecSAlexander Lobakin 1957c56a8be7SRahul Verma break; 1958c56a8be7SRahul Verma case MEDIA_SFP_1G_FIBER: 1959c56a8be7SRahul Verma case MEDIA_SFPP_10G_FIBER: 1960c56a8be7SRahul Verma case MEDIA_XFP_FIBER: 1961c56a8be7SRahul Verma case MEDIA_MODULE_FIBER: 1962bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 19639228b7c1SAlexander Lobakin capability |= speed_mask; 1964bdb5d8ecSAlexander Lobakin 19659228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 19669228b7c1SAlexander Lobakin switch (tcvr_type) { 19679228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_LX: 19689228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_SX: 19699228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 19709228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1971bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 19729228b7c1SAlexander Lobakin break; 19739228b7c1SAlexander Lobakin default: 19749228b7c1SAlexander Lobakin break; 1975c56a8be7SRahul Verma } 1976bdb5d8ecSAlexander Lobakin 19779228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19789228b7c1SAlexander Lobakin switch (tcvr_type) { 19799228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_SR: 19809228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 19819228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 19829228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 1983bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseSR_Full); 19849228b7c1SAlexander Lobakin break; 19859228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LR: 19869228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 19879228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 19889228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1989bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLR_Full); 19909228b7c1SAlexander Lobakin break; 19919228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LRM: 1992bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLRM_Full); 19939228b7c1SAlexander Lobakin break; 19949228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_ER: 1995bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseR_FEC); 19969228b7c1SAlexander Lobakin break; 19979228b7c1SAlexander Lobakin default: 19989228b7c1SAlexander Lobakin break; 1999c56a8be7SRahul Verma } 2000bdb5d8ecSAlexander Lobakin 2001c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 2002bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 2003bdb5d8ecSAlexander Lobakin 20049228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 20059228b7c1SAlexander Lobakin switch (tcvr_type) { 20069228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_25G_SR: 20079228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 2008bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseSR_Full); 20099228b7c1SAlexander Lobakin break; 20109228b7c1SAlexander Lobakin default: 20119228b7c1SAlexander Lobakin break; 2012c56a8be7SRahul Verma } 2013bdb5d8ecSAlexander Lobakin 20149228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 20159228b7c1SAlexander Lobakin switch (tcvr_type) { 20169228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_LR4: 20179228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 20189228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2019bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseLR4_Full); 20209228b7c1SAlexander Lobakin break; 20219228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_SR4: 20229228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 20239228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2024bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseSR4_Full); 20259228b7c1SAlexander Lobakin break; 20269228b7c1SAlexander Lobakin default: 20279228b7c1SAlexander Lobakin break; 2028c56a8be7SRahul Verma } 2029bdb5d8ecSAlexander Lobakin 2030bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2031bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2032bdb5d8ecSAlexander Lobakin 2033c56a8be7SRahul Verma if (capability & 20349228b7c1SAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 20359228b7c1SAlexander Lobakin switch (tcvr_type) { 20369228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_SR4: 20379228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2038bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseSR4_Full); 20399228b7c1SAlexander Lobakin break; 20409228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 20419228b7c1SAlexander Lobakin phylink_set(if_caps, 100000baseLR4_ER4_Full); 20429228b7c1SAlexander Lobakin break; 20439228b7c1SAlexander Lobakin default: 20449228b7c1SAlexander Lobakin break; 2045c56a8be7SRahul Verma } 2046c56a8be7SRahul Verma 2047c56a8be7SRahul Verma break; 2048c56a8be7SRahul Verma case MEDIA_KR: 2049bdb5d8ecSAlexander Lobakin phylink_set(if_caps, Backplane); 2050bdb5d8ecSAlexander Lobakin 2051c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 2052bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 2053bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 2054bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 2055bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 2056bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseKR_Full); 2057bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 2058bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseKR_Full); 2059bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 2060bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseKR4_Full); 2061bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2062bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2063c56a8be7SRahul Verma if (capability & 2064c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 2065bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseKR4_Full); 2066bdb5d8ecSAlexander Lobakin 2067c56a8be7SRahul Verma break; 2068c56a8be7SRahul Verma case MEDIA_UNSPECIFIED: 2069c56a8be7SRahul Verma case MEDIA_NOT_PRESENT: 20709228b7c1SAlexander Lobakin default: 2071c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, 2072c56a8be7SRahul Verma "Unknown media and transceiver type;\n"); 2073c56a8be7SRahul Verma break; 2074c56a8be7SRahul Verma } 2075c56a8be7SRahul Verma } 2076c56a8be7SRahul Verma 20773c41486eSAlexander Lobakin static void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask) 20783c41486eSAlexander Lobakin { 20793c41486eSAlexander Lobakin *speed_mask = 0; 20803c41486eSAlexander Lobakin 20813c41486eSAlexander Lobakin if (caps & 20823c41486eSAlexander Lobakin (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD)) 20833c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 20843c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_10G) 20853c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 20863c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_20G) 20873c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; 20883c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_25G) 20893c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 20903c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_40G) 20913c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 20923c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_50G) 20933c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; 20943c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_100G) 20953c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; 20963c41486eSAlexander Lobakin } 20973c41486eSAlexander Lobakin 2098cc875c2eSYuval Mintz static void qed_fill_link(struct qed_hwfn *hwfn, 2099706d0891SRahul Verma struct qed_ptt *ptt, 2100cc875c2eSYuval Mintz struct qed_link_output *if_link) 2101cc875c2eSYuval Mintz { 2102c56a8be7SRahul Verma struct qed_mcp_link_capabilities link_caps; 2103cc875c2eSYuval Mintz struct qed_mcp_link_params params; 2104cc875c2eSYuval Mintz struct qed_mcp_link_state link; 21053c41486eSAlexander Lobakin u32 media_type, speed_mask; 2106cc875c2eSYuval Mintz 2107cc875c2eSYuval Mintz memset(if_link, 0, sizeof(*if_link)); 2108cc875c2eSYuval Mintz 2109cc875c2eSYuval Mintz /* Prepare source inputs */ 211014b84e86SArnd Bergmann if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { 211114b84e86SArnd Bergmann dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); 211214b84e86SArnd Bergmann return; 21131408cc1fSYuval Mintz } 2114cc875c2eSYuval Mintz 2115cc875c2eSYuval Mintz /* Set the link parameters to pass to protocol driver */ 2116cc875c2eSYuval Mintz if (link.link_up) 2117cc875c2eSYuval Mintz if_link->link_up = true; 2118cc875c2eSYuval Mintz 211999785a87SAlexander Lobakin if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) { 212099785a87SAlexander Lobakin if (link_caps.default_ext_autoneg) 212199785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 212299785a87SAlexander Lobakin 212399785a87SAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 212499785a87SAlexander Lobakin 212599785a87SAlexander Lobakin if (params.ext_speed.autoneg) 212699785a87SAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 212799785a87SAlexander Lobakin else 212899785a87SAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 212999785a87SAlexander Lobakin 213099785a87SAlexander Lobakin qed_fill_link_capability(hwfn, ptt, 213199785a87SAlexander Lobakin params.ext_speed.advertised_speeds, 213299785a87SAlexander Lobakin if_link->advertised_caps); 213399785a87SAlexander Lobakin } else { 213434f9199cSsudarsana.kalluru@cavium.com if (link_caps.default_speed_autoneg) 2135bdb5d8ecSAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 2136cc875c2eSYuval Mintz 2137bdb5d8ecSAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 2138bdb5d8ecSAlexander Lobakin 213934f9199cSsudarsana.kalluru@cavium.com if (params.speed.autoneg) 2140bdb5d8ecSAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 214134f9199cSsudarsana.kalluru@cavium.com else 2142bdb5d8ecSAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 214399785a87SAlexander Lobakin } 214499785a87SAlexander Lobakin 214599785a87SAlexander Lobakin if (params.pause.autoneg || 214699785a87SAlexander Lobakin (params.pause.forced_rx && params.pause.forced_tx)) 214799785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Asym_Pause); 214899785a87SAlexander Lobakin if (params.pause.autoneg || params.pause.forced_rx || 214999785a87SAlexander Lobakin params.pause.forced_tx) 215099785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Pause); 2151cc875c2eSYuval Mintz 2152ae7e6937SAlexander Lobakin if_link->sup_fec = link_caps.fec_default; 2153ae7e6937SAlexander Lobakin if_link->active_fec = params.fec; 2154ae7e6937SAlexander Lobakin 2155c56a8be7SRahul Verma /* Fill link advertised capability */ 2156c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, 2157bdb5d8ecSAlexander Lobakin if_link->advertised_caps); 21583c41486eSAlexander Lobakin 2159c56a8be7SRahul Verma /* Fill link supported capability */ 2160c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, 2161bdb5d8ecSAlexander Lobakin if_link->supported_caps); 2162cc875c2eSYuval Mintz 21633c41486eSAlexander Lobakin /* Fill partner advertised capability */ 21643c41486eSAlexander Lobakin qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask); 21653c41486eSAlexander Lobakin qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps); 21663c41486eSAlexander Lobakin 2167cc875c2eSYuval Mintz if (link.link_up) 2168cc875c2eSYuval Mintz if_link->speed = link.speed; 2169cc875c2eSYuval Mintz 2170cc875c2eSYuval Mintz /* TODO - fill duplex properly */ 2171cc875c2eSYuval Mintz if_link->duplex = DUPLEX_FULL; 2172706d0891SRahul Verma qed_mcp_get_media_type(hwfn, ptt, &media_type); 2173cc875c2eSYuval Mintz if_link->port = qed_get_port_type(media_type); 2174cc875c2eSYuval Mintz 2175cc875c2eSYuval Mintz if_link->autoneg = params.speed.autoneg; 2176cc875c2eSYuval Mintz 2177cc875c2eSYuval Mintz if (params.pause.autoneg) 2178cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 2179cc875c2eSYuval Mintz if (params.pause.forced_rx) 2180cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; 2181cc875c2eSYuval Mintz if (params.pause.forced_tx) 2182cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; 2183cc875c2eSYuval Mintz 2184cc875c2eSYuval Mintz if (link.an_complete) 2185bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Autoneg); 2186cc875c2eSYuval Mintz if (link.partner_adv_pause) 2187bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Pause); 2188cc875c2eSYuval Mintz if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || 2189cc875c2eSYuval Mintz link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) 2190bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Asym_Pause); 2191645874e5SSudarsana Reddy Kalluru 2192645874e5SSudarsana Reddy Kalluru if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) { 2193645874e5SSudarsana Reddy Kalluru if_link->eee_supported = false; 2194645874e5SSudarsana Reddy Kalluru } else { 2195645874e5SSudarsana Reddy Kalluru if_link->eee_supported = true; 2196645874e5SSudarsana Reddy Kalluru if_link->eee_active = link.eee_active; 2197645874e5SSudarsana Reddy Kalluru if_link->sup_caps = link_caps.eee_speed_caps; 2198645874e5SSudarsana Reddy Kalluru /* MFW clears adv_caps on eee disable; use configured value */ 2199645874e5SSudarsana Reddy Kalluru if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : 2200645874e5SSudarsana Reddy Kalluru params.eee.adv_caps; 2201645874e5SSudarsana Reddy Kalluru if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; 2202645874e5SSudarsana Reddy Kalluru if_link->eee.enable = params.eee.enable; 2203645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; 2204645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; 2205645874e5SSudarsana Reddy Kalluru } 2206cc875c2eSYuval Mintz } 2207cc875c2eSYuval Mintz 2208cc875c2eSYuval Mintz static void qed_get_current_link(struct qed_dev *cdev, 2209cc875c2eSYuval Mintz struct qed_link_output *if_link) 2210cc875c2eSYuval Mintz { 2211706d0891SRahul Verma struct qed_hwfn *hwfn; 2212706d0891SRahul Verma struct qed_ptt *ptt; 221336558c3dSYuval Mintz int i; 221436558c3dSYuval Mintz 2215706d0891SRahul Verma hwfn = &cdev->hwfns[0]; 2216706d0891SRahul Verma if (IS_PF(cdev)) { 2217706d0891SRahul Verma ptt = qed_ptt_acquire(hwfn); 2218706d0891SRahul Verma if (ptt) { 2219706d0891SRahul Verma qed_fill_link(hwfn, ptt, if_link); 2220706d0891SRahul Verma qed_ptt_release(hwfn, ptt); 2221706d0891SRahul Verma } else { 2222706d0891SRahul Verma DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); 2223706d0891SRahul Verma } 2224706d0891SRahul Verma } else { 2225706d0891SRahul Verma qed_fill_link(hwfn, NULL, if_link); 2226706d0891SRahul Verma } 222736558c3dSYuval Mintz 222836558c3dSYuval Mintz for_each_hwfn(cdev, i) 222936558c3dSYuval Mintz qed_inform_vf_link_state(&cdev->hwfns[i]); 2230cc875c2eSYuval Mintz } 2231cc875c2eSYuval Mintz 2232706d0891SRahul Verma void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2233cc875c2eSYuval Mintz { 2234cc875c2eSYuval Mintz void *cookie = hwfn->cdev->ops_cookie; 2235cc875c2eSYuval Mintz struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2236cc875c2eSYuval Mintz struct qed_link_output if_link; 2237cc875c2eSYuval Mintz 2238706d0891SRahul Verma qed_fill_link(hwfn, ptt, &if_link); 223936558c3dSYuval Mintz qed_inform_vf_link_state(hwfn); 2240cc875c2eSYuval Mintz 2241cc875c2eSYuval Mintz if (IS_LEAD_HWFN(hwfn) && cookie) 2242cc875c2eSYuval Mintz op->link_update(cookie, &if_link); 2243cc875c2eSYuval Mintz } 2244cc875c2eSYuval Mintz 2245699fed4aSSudarsana Reddy Kalluru void qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2246699fed4aSSudarsana Reddy Kalluru { 2247699fed4aSSudarsana Reddy Kalluru void *cookie = hwfn->cdev->ops_cookie; 2248699fed4aSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2249699fed4aSSudarsana Reddy Kalluru 2250699fed4aSSudarsana Reddy Kalluru if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update) 2251699fed4aSSudarsana Reddy Kalluru op->bw_update(cookie); 2252699fed4aSSudarsana Reddy Kalluru } 2253699fed4aSSudarsana Reddy Kalluru 2254fe56b9e6SYuval Mintz static int qed_drain(struct qed_dev *cdev) 2255fe56b9e6SYuval Mintz { 2256fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 2257fe56b9e6SYuval Mintz struct qed_ptt *ptt; 2258fe56b9e6SYuval Mintz int i, rc; 2259fe56b9e6SYuval Mintz 22601408cc1fSYuval Mintz if (IS_VF(cdev)) 22611408cc1fSYuval Mintz return 0; 22621408cc1fSYuval Mintz 2263fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 2264fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 2265fe56b9e6SYuval Mintz ptt = qed_ptt_acquire(hwfn); 2266fe56b9e6SYuval Mintz if (!ptt) { 2267fe56b9e6SYuval Mintz DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); 2268fe56b9e6SYuval Mintz return -EBUSY; 2269fe56b9e6SYuval Mintz } 2270fe56b9e6SYuval Mintz rc = qed_mcp_drain(hwfn, ptt); 22719aaa4e8bSDenis Bolotin qed_ptt_release(hwfn, ptt); 2272fe56b9e6SYuval Mintz if (rc) 2273fe56b9e6SYuval Mintz return rc; 2274fe56b9e6SYuval Mintz } 2275fe56b9e6SYuval Mintz 2276fe56b9e6SYuval Mintz return 0; 2277fe56b9e6SYuval Mintz } 2278fe56b9e6SYuval Mintz 22793a69cae8SSudarsana Reddy Kalluru static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev, 22803a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att *nvm_image, 22813a69cae8SSudarsana Reddy Kalluru u32 *crc) 22823a69cae8SSudarsana Reddy Kalluru { 22833a69cae8SSudarsana Reddy Kalluru u8 *buf = NULL; 22845ab90341SAlexander Lobakin int rc; 22853a69cae8SSudarsana Reddy Kalluru 22863a69cae8SSudarsana Reddy Kalluru /* Allocate a buffer for holding the nvram image */ 22873a69cae8SSudarsana Reddy Kalluru buf = kzalloc(nvm_image->length, GFP_KERNEL); 22883a69cae8SSudarsana Reddy Kalluru if (!buf) 22893a69cae8SSudarsana Reddy Kalluru return -ENOMEM; 22903a69cae8SSudarsana Reddy Kalluru 22913a69cae8SSudarsana Reddy Kalluru /* Read image into buffer */ 22923a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr, 22933a69cae8SSudarsana Reddy Kalluru buf, nvm_image->length); 22943a69cae8SSudarsana Reddy Kalluru if (rc) { 22953a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading image from nvm\n"); 22963a69cae8SSudarsana Reddy Kalluru goto out; 22973a69cae8SSudarsana Reddy Kalluru } 22983a69cae8SSudarsana Reddy Kalluru 22993a69cae8SSudarsana Reddy Kalluru /* Convert the buffer into big-endian format (excluding the 23003a69cae8SSudarsana Reddy Kalluru * closing 4 bytes of CRC). 23013a69cae8SSudarsana Reddy Kalluru */ 23025ab90341SAlexander Lobakin cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf, 23035ab90341SAlexander Lobakin DIV_ROUND_UP(nvm_image->length - 4, 4)); 23043a69cae8SSudarsana Reddy Kalluru 23053a69cae8SSudarsana Reddy Kalluru /* Calc CRC for the "actual" image buffer, i.e. not including 23063a69cae8SSudarsana Reddy Kalluru * the last 4 CRC bytes. 23073a69cae8SSudarsana Reddy Kalluru */ 23085ab90341SAlexander Lobakin *crc = ~crc32(~0U, buf, nvm_image->length - 4); 23095ab90341SAlexander Lobakin *crc = (__force u32)cpu_to_be32p(crc); 23103a69cae8SSudarsana Reddy Kalluru 23113a69cae8SSudarsana Reddy Kalluru out: 23123a69cae8SSudarsana Reddy Kalluru kfree(buf); 23133a69cae8SSudarsana Reddy Kalluru 23143a69cae8SSudarsana Reddy Kalluru return rc; 23153a69cae8SSudarsana Reddy Kalluru } 23163a69cae8SSudarsana Reddy Kalluru 23173a69cae8SSudarsana Reddy Kalluru /* Binary file format - 23183a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 23193a69cae8SSudarsana Reddy Kalluru * 0B | 0x4 [command index] | 23203a69cae8SSudarsana Reddy Kalluru * 4B | image_type | Options | Number of register settings | 23213a69cae8SSudarsana Reddy Kalluru * 8B | Value | 23223a69cae8SSudarsana Reddy Kalluru * 12B | Mask | 23233a69cae8SSudarsana Reddy Kalluru * 16B | Offset | 23243a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 23253a69cae8SSudarsana Reddy Kalluru * There can be several Value-Mask-Offset sets as specified by 'Number of...'. 23263a69cae8SSudarsana Reddy Kalluru * Options - 0'b - Calculate & Update CRC for image 23273a69cae8SSudarsana Reddy Kalluru */ 23283a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data, 23293a69cae8SSudarsana Reddy Kalluru bool *check_resp) 23303a69cae8SSudarsana Reddy Kalluru { 23313a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att nvm_image; 23323a69cae8SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn; 23333a69cae8SSudarsana Reddy Kalluru bool is_crc = false; 23343a69cae8SSudarsana Reddy Kalluru u32 image_type; 23353a69cae8SSudarsana Reddy Kalluru int rc = 0, i; 23363a69cae8SSudarsana Reddy Kalluru u16 len; 23373a69cae8SSudarsana Reddy Kalluru 23383a69cae8SSudarsana Reddy Kalluru *data += 4; 23393a69cae8SSudarsana Reddy Kalluru image_type = **data; 23403a69cae8SSudarsana Reddy Kalluru p_hwfn = QED_LEADING_HWFN(cdev); 23413a69cae8SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 23423a69cae8SSudarsana Reddy Kalluru if (image_type == p_hwfn->nvm_info.image_att[i].image_type) 23433a69cae8SSudarsana Reddy Kalluru break; 23443a69cae8SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 23453a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find nvram image of type %08x\n", 23463a69cae8SSudarsana Reddy Kalluru image_type); 23473a69cae8SSudarsana Reddy Kalluru return -ENOENT; 23483a69cae8SSudarsana Reddy Kalluru } 23493a69cae8SSudarsana Reddy Kalluru 23503a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 23513a69cae8SSudarsana Reddy Kalluru nvm_image.length = p_hwfn->nvm_info.image_att[i].len; 23523a69cae8SSudarsana Reddy Kalluru 23533a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 23543a69cae8SSudarsana Reddy Kalluru "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n", 23553a69cae8SSudarsana Reddy Kalluru **data, image_type, nvm_image.start_addr, 23563a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 1); 23573a69cae8SSudarsana Reddy Kalluru (*data)++; 23583a69cae8SSudarsana Reddy Kalluru is_crc = !!(**data & BIT(0)); 23593a69cae8SSudarsana Reddy Kalluru (*data)++; 23603a69cae8SSudarsana Reddy Kalluru len = *((u16 *)*data); 23613a69cae8SSudarsana Reddy Kalluru *data += 2; 23623a69cae8SSudarsana Reddy Kalluru if (is_crc) { 23633a69cae8SSudarsana Reddy Kalluru u32 crc = 0; 23643a69cae8SSudarsana Reddy Kalluru 23653a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc); 23663a69cae8SSudarsana Reddy Kalluru if (rc) { 23673a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc); 23683a69cae8SSudarsana Reddy Kalluru goto exit; 23693a69cae8SSudarsana Reddy Kalluru } 23703a69cae8SSudarsana Reddy Kalluru 23713a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 23723a69cae8SSudarsana Reddy Kalluru (nvm_image.start_addr + 23733a69cae8SSudarsana Reddy Kalluru nvm_image.length - 4), (u8 *)&crc, 4); 23743a69cae8SSudarsana Reddy Kalluru if (rc) 23753a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x, rc = %d\n", 23763a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 4, rc); 23773a69cae8SSudarsana Reddy Kalluru goto exit; 23783a69cae8SSudarsana Reddy Kalluru } 23793a69cae8SSudarsana Reddy Kalluru 23803a69cae8SSudarsana Reddy Kalluru /* Iterate over the values for setting */ 23813a69cae8SSudarsana Reddy Kalluru while (len) { 23823a69cae8SSudarsana Reddy Kalluru u32 offset, mask, value, cur_value; 23833a69cae8SSudarsana Reddy Kalluru u8 buf[4]; 23843a69cae8SSudarsana Reddy Kalluru 23853a69cae8SSudarsana Reddy Kalluru value = *((u32 *)*data); 23863a69cae8SSudarsana Reddy Kalluru *data += 4; 23873a69cae8SSudarsana Reddy Kalluru mask = *((u32 *)*data); 23883a69cae8SSudarsana Reddy Kalluru *data += 4; 23893a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)*data); 23903a69cae8SSudarsana Reddy Kalluru *data += 4; 23913a69cae8SSudarsana Reddy Kalluru 23923a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf, 23933a69cae8SSudarsana Reddy Kalluru 4); 23943a69cae8SSudarsana Reddy Kalluru if (rc) { 23953a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading from %08x\n", 23963a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 23973a69cae8SSudarsana Reddy Kalluru goto exit; 23983a69cae8SSudarsana Reddy Kalluru } 23993a69cae8SSudarsana Reddy Kalluru 24003a69cae8SSudarsana Reddy Kalluru cur_value = le32_to_cpu(*((__le32 *)buf)); 24013a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 24023a69cae8SSudarsana Reddy Kalluru "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n", 24033a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, cur_value, 24043a69cae8SSudarsana Reddy Kalluru (cur_value & ~mask) | (value & mask), value, mask); 24053a69cae8SSudarsana Reddy Kalluru value = (value & mask) | (cur_value & ~mask); 24063a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 24073a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, 24083a69cae8SSudarsana Reddy Kalluru (u8 *)&value, 4); 24093a69cae8SSudarsana Reddy Kalluru if (rc) { 24103a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x\n", 24113a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 24123a69cae8SSudarsana Reddy Kalluru goto exit; 24133a69cae8SSudarsana Reddy Kalluru } 24143a69cae8SSudarsana Reddy Kalluru 24153a69cae8SSudarsana Reddy Kalluru len--; 24163a69cae8SSudarsana Reddy Kalluru } 24173a69cae8SSudarsana Reddy Kalluru exit: 24183a69cae8SSudarsana Reddy Kalluru return rc; 24193a69cae8SSudarsana Reddy Kalluru } 24203a69cae8SSudarsana Reddy Kalluru 24213a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24223a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24233a69cae8SSudarsana Reddy Kalluru * 0B | 0x3 [command index] | 24243a69cae8SSudarsana Reddy Kalluru * 4B | b'0: check_response? | b'1-31 reserved | 24253a69cae8SSudarsana Reddy Kalluru * 8B | File-type | reserved | 2426057d2b19SSudarsana Reddy Kalluru * 12B | Image length in bytes | 24273a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24283a69cae8SSudarsana Reddy Kalluru * Start a new file of the provided type 24293a69cae8SSudarsana Reddy Kalluru */ 24303a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_start(struct qed_dev *cdev, 24313a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24323a69cae8SSudarsana Reddy Kalluru { 2433057d2b19SSudarsana Reddy Kalluru u32 file_type, file_size = 0; 24343a69cae8SSudarsana Reddy Kalluru int rc; 24353a69cae8SSudarsana Reddy Kalluru 24363a69cae8SSudarsana Reddy Kalluru *data += 4; 24373a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24383a69cae8SSudarsana Reddy Kalluru *data += 4; 2439057d2b19SSudarsana Reddy Kalluru file_type = **data; 24403a69cae8SSudarsana Reddy Kalluru 24413a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 2442057d2b19SSudarsana Reddy Kalluru "About to start a new file of type %02x\n", file_type); 2443057d2b19SSudarsana Reddy Kalluru if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) { 2444057d2b19SSudarsana Reddy Kalluru *data += 4; 2445057d2b19SSudarsana Reddy Kalluru file_size = *((u32 *)(*data)); 2446057d2b19SSudarsana Reddy Kalluru } 2447057d2b19SSudarsana Reddy Kalluru 2448057d2b19SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type, 2449057d2b19SSudarsana Reddy Kalluru (u8 *)(&file_size), 4); 24503a69cae8SSudarsana Reddy Kalluru *data += 4; 24513a69cae8SSudarsana Reddy Kalluru 24523a69cae8SSudarsana Reddy Kalluru return rc; 24533a69cae8SSudarsana Reddy Kalluru } 24543a69cae8SSudarsana Reddy Kalluru 24553a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24563a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24573a69cae8SSudarsana Reddy Kalluru * 0B | 0x2 [command index] | 24583a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24593a69cae8SSudarsana Reddy Kalluru * 8B | b'0: check_response? | b'1-31 reserved | 24603a69cae8SSudarsana Reddy Kalluru * 12B | Offset in bytes | 24613a69cae8SSudarsana Reddy Kalluru * 16B | Data ... | 24623a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24633a69cae8SSudarsana Reddy Kalluru * Write data as part of a file that was previously started. Data should be 24643a69cae8SSudarsana Reddy Kalluru * of length equal to that provided in the message 24653a69cae8SSudarsana Reddy Kalluru */ 24663a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_data(struct qed_dev *cdev, 24673a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24683a69cae8SSudarsana Reddy Kalluru { 24693a69cae8SSudarsana Reddy Kalluru u32 offset, len; 24703a69cae8SSudarsana Reddy Kalluru int rc; 24713a69cae8SSudarsana Reddy Kalluru 24723a69cae8SSudarsana Reddy Kalluru *data += 4; 24733a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 24743a69cae8SSudarsana Reddy Kalluru *data += 4; 24753a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24763a69cae8SSudarsana Reddy Kalluru *data += 4; 24773a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)(*data)); 24783a69cae8SSudarsana Reddy Kalluru *data += 4; 24793a69cae8SSudarsana Reddy Kalluru 24803a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 24813a69cae8SSudarsana Reddy Kalluru "About to write File-data: %08x bytes to offset %08x\n", 24823a69cae8SSudarsana Reddy Kalluru len, offset); 24833a69cae8SSudarsana Reddy Kalluru 24843a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset, 24853a69cae8SSudarsana Reddy Kalluru (char *)(*data), len); 24863a69cae8SSudarsana Reddy Kalluru *data += len; 24873a69cae8SSudarsana Reddy Kalluru 24883a69cae8SSudarsana Reddy Kalluru return rc; 24893a69cae8SSudarsana Reddy Kalluru } 24903a69cae8SSudarsana Reddy Kalluru 24913a69cae8SSudarsana Reddy Kalluru /* Binary file format [General header] - 24923a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24933a69cae8SSudarsana Reddy Kalluru * 0B | QED_NVM_SIGNATURE | 24943a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24953a69cae8SSudarsana Reddy Kalluru * 8B | Highest command in this batchfile | Reserved | 24963a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24973a69cae8SSudarsana Reddy Kalluru */ 24983a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_validate(struct qed_dev *cdev, 24993a69cae8SSudarsana Reddy Kalluru const struct firmware *image, 25003a69cae8SSudarsana Reddy Kalluru const u8 **data) 25013a69cae8SSudarsana Reddy Kalluru { 25023a69cae8SSudarsana Reddy Kalluru u32 signature, len; 25033a69cae8SSudarsana Reddy Kalluru 25043a69cae8SSudarsana Reddy Kalluru /* Check minimum size */ 25053a69cae8SSudarsana Reddy Kalluru if (image->size < 12) { 25063a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size); 25073a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25083a69cae8SSudarsana Reddy Kalluru } 25093a69cae8SSudarsana Reddy Kalluru 25103a69cae8SSudarsana Reddy Kalluru /* Check signature */ 25113a69cae8SSudarsana Reddy Kalluru signature = *((u32 *)(*data)); 25123a69cae8SSudarsana Reddy Kalluru if (signature != QED_NVM_SIGNATURE) { 25133a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Wrong signature '%08x'\n", signature); 25143a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25153a69cae8SSudarsana Reddy Kalluru } 25163a69cae8SSudarsana Reddy Kalluru 25173a69cae8SSudarsana Reddy Kalluru *data += 4; 25183a69cae8SSudarsana Reddy Kalluru /* Validate internal size equals the image-size */ 25193a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 25203a69cae8SSudarsana Reddy Kalluru if (len != image->size) { 25213a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n", 25223a69cae8SSudarsana Reddy Kalluru len, (u32)image->size); 25233a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25243a69cae8SSudarsana Reddy Kalluru } 25253a69cae8SSudarsana Reddy Kalluru 25263a69cae8SSudarsana Reddy Kalluru *data += 4; 25273a69cae8SSudarsana Reddy Kalluru /* Make sure driver familiar with all commands necessary for this */ 25283a69cae8SSudarsana Reddy Kalluru if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) { 25293a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n", 25303a69cae8SSudarsana Reddy Kalluru *((u16 *)(*data))); 25313a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25323a69cae8SSudarsana Reddy Kalluru } 25333a69cae8SSudarsana Reddy Kalluru 25343a69cae8SSudarsana Reddy Kalluru *data += 4; 25353a69cae8SSudarsana Reddy Kalluru 25363a69cae8SSudarsana Reddy Kalluru return 0; 25373a69cae8SSudarsana Reddy Kalluru } 25383a69cae8SSudarsana Reddy Kalluru 25390dabbe1bSSudarsana Reddy Kalluru /* Binary file format - 25400dabbe1bSSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 25410dabbe1bSSudarsana Reddy Kalluru * 0B | 0x5 [command index] | 25422da244a5SSudarsana Reddy Kalluru * 4B | Number of config attributes | Reserved | 25432da244a5SSudarsana Reddy Kalluru * 4B | Config ID | Entity ID | Length | 25442da244a5SSudarsana Reddy Kalluru * 4B | Value | 25450dabbe1bSSudarsana Reddy Kalluru * | | 25460dabbe1bSSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 25472da244a5SSudarsana Reddy Kalluru * There can be several cfg_id-entity_id-Length-Value sets as specified by 25482da244a5SSudarsana Reddy Kalluru * 'Number of config attributes'. 25490dabbe1bSSudarsana Reddy Kalluru * 25500dabbe1bSSudarsana Reddy Kalluru * The API parses config attributes from the user provided buffer and flashes 25510dabbe1bSSudarsana Reddy Kalluru * them to the respective NVM path using Management FW inerface. 25520dabbe1bSSudarsana Reddy Kalluru */ 25530dabbe1bSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data) 25540dabbe1bSSudarsana Reddy Kalluru { 25550dabbe1bSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 25560dabbe1bSSudarsana Reddy Kalluru u8 entity_id, len, buf[32]; 2557c63b0968SSudarsana Reddy Kalluru bool need_nvm_init = true; 25580dabbe1bSSudarsana Reddy Kalluru struct qed_ptt *ptt; 25590dabbe1bSSudarsana Reddy Kalluru u16 cfg_id, count; 25600dabbe1bSSudarsana Reddy Kalluru int rc = 0, i; 25610dabbe1bSSudarsana Reddy Kalluru u32 flags; 25620dabbe1bSSudarsana Reddy Kalluru 25630dabbe1bSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 25640dabbe1bSSudarsana Reddy Kalluru if (!ptt) 25650dabbe1bSSudarsana Reddy Kalluru return -EAGAIN; 25660dabbe1bSSudarsana Reddy Kalluru 25670dabbe1bSSudarsana Reddy Kalluru /* NVM CFG ID attribute header */ 25680dabbe1bSSudarsana Reddy Kalluru *data += 4; 25690dabbe1bSSudarsana Reddy Kalluru count = *((u16 *)*data); 25702da244a5SSudarsana Reddy Kalluru *data += 4; 25710dabbe1bSSudarsana Reddy Kalluru 25720dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 25732da244a5SSudarsana Reddy Kalluru "Read config ids: num_attrs = %0d\n", count); 2574c63b0968SSudarsana Reddy Kalluru /* NVM CFG ID attributes. Start loop index from 1 to avoid additional 2575c63b0968SSudarsana Reddy Kalluru * arithmetic operations in the implementation. 2576c63b0968SSudarsana Reddy Kalluru */ 2577c63b0968SSudarsana Reddy Kalluru for (i = 1; i <= count; i++) { 25780dabbe1bSSudarsana Reddy Kalluru cfg_id = *((u16 *)*data); 25790dabbe1bSSudarsana Reddy Kalluru *data += 2; 25802da244a5SSudarsana Reddy Kalluru entity_id = **data; 25812da244a5SSudarsana Reddy Kalluru (*data)++; 25820dabbe1bSSudarsana Reddy Kalluru len = **data; 25830dabbe1bSSudarsana Reddy Kalluru (*data)++; 25840dabbe1bSSudarsana Reddy Kalluru memcpy(buf, *data, len); 25850dabbe1bSSudarsana Reddy Kalluru *data += len; 25860dabbe1bSSudarsana Reddy Kalluru 2587c63b0968SSudarsana Reddy Kalluru flags = 0; 2588c63b0968SSudarsana Reddy Kalluru if (need_nvm_init) { 2589c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_INIT; 2590c63b0968SSudarsana Reddy Kalluru need_nvm_init = false; 2591c63b0968SSudarsana Reddy Kalluru } 2592c63b0968SSudarsana Reddy Kalluru 2593c63b0968SSudarsana Reddy Kalluru /* Commit to flash and free the resources */ 2594c63b0968SSudarsana Reddy Kalluru if (!(i % QED_NVM_CFG_MAX_ATTRS) || i == count) { 2595c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_COMMIT | 2596c63b0968SSudarsana Reddy Kalluru QED_NVM_CFG_OPTION_FREE; 2597c63b0968SSudarsana Reddy Kalluru need_nvm_init = true; 2598c63b0968SSudarsana Reddy Kalluru } 2599c63b0968SSudarsana Reddy Kalluru 2600c63b0968SSudarsana Reddy Kalluru if (entity_id) 2601c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_ENTITY_SEL; 26020dabbe1bSSudarsana Reddy Kalluru 26030dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26042da244a5SSudarsana Reddy Kalluru "cfg_id = %d entity = %d len = %d\n", cfg_id, 26052da244a5SSudarsana Reddy Kalluru entity_id, len); 26060dabbe1bSSudarsana Reddy Kalluru rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags, 26070dabbe1bSSudarsana Reddy Kalluru buf, len); 26080dabbe1bSSudarsana Reddy Kalluru if (rc) { 26090dabbe1bSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id); 26100dabbe1bSSudarsana Reddy Kalluru break; 26110dabbe1bSSudarsana Reddy Kalluru } 26120dabbe1bSSudarsana Reddy Kalluru } 26130dabbe1bSSudarsana Reddy Kalluru 26140dabbe1bSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26150dabbe1bSSudarsana Reddy Kalluru 26160dabbe1bSSudarsana Reddy Kalluru return rc; 26170dabbe1bSSudarsana Reddy Kalluru } 26180dabbe1bSSudarsana Reddy Kalluru 26199e54ba7cSSudarsana Reddy Kalluru #define QED_MAX_NVM_BUF_LEN 32 26209e54ba7cSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_len(struct qed_dev *cdev, u32 cmd) 26219e54ba7cSSudarsana Reddy Kalluru { 26229e54ba7cSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26239e54ba7cSSudarsana Reddy Kalluru u8 buf[QED_MAX_NVM_BUF_LEN]; 26249e54ba7cSSudarsana Reddy Kalluru struct qed_ptt *ptt; 26259e54ba7cSSudarsana Reddy Kalluru u32 len; 26269e54ba7cSSudarsana Reddy Kalluru int rc; 26279e54ba7cSSudarsana Reddy Kalluru 26289e54ba7cSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26299e54ba7cSSudarsana Reddy Kalluru if (!ptt) 26309e54ba7cSSudarsana Reddy Kalluru return QED_MAX_NVM_BUF_LEN; 26319e54ba7cSSudarsana Reddy Kalluru 26329e54ba7cSSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, 0, QED_NVM_CFG_GET_FLAGS, buf, 26339e54ba7cSSudarsana Reddy Kalluru &len); 26349e54ba7cSSudarsana Reddy Kalluru if (rc || !len) { 26359e54ba7cSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26369e54ba7cSSudarsana Reddy Kalluru len = QED_MAX_NVM_BUF_LEN; 26379e54ba7cSSudarsana Reddy Kalluru } 26389e54ba7cSSudarsana Reddy Kalluru 26399e54ba7cSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26409e54ba7cSSudarsana Reddy Kalluru 26419e54ba7cSSudarsana Reddy Kalluru return len; 26429e54ba7cSSudarsana Reddy Kalluru } 26439e54ba7cSSudarsana Reddy Kalluru 26442d4c8495SSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_read(struct qed_dev *cdev, u8 **data, 26452d4c8495SSudarsana Reddy Kalluru u32 cmd, u32 entity_id) 26462d4c8495SSudarsana Reddy Kalluru { 26472d4c8495SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26482d4c8495SSudarsana Reddy Kalluru struct qed_ptt *ptt; 26492d4c8495SSudarsana Reddy Kalluru u32 flags, len; 26502d4c8495SSudarsana Reddy Kalluru int rc = 0; 26512d4c8495SSudarsana Reddy Kalluru 26522d4c8495SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26532d4c8495SSudarsana Reddy Kalluru if (!ptt) 26542d4c8495SSudarsana Reddy Kalluru return -EAGAIN; 26552d4c8495SSudarsana Reddy Kalluru 26562d4c8495SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26572d4c8495SSudarsana Reddy Kalluru "Read config cmd = %d entity id %d\n", cmd, entity_id); 26582d4c8495SSudarsana Reddy Kalluru flags = entity_id ? QED_NVM_CFG_GET_PF_FLAGS : QED_NVM_CFG_GET_FLAGS; 26592d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, entity_id, flags, *data, &len); 26602d4c8495SSudarsana Reddy Kalluru if (rc) 26612d4c8495SSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26622d4c8495SSudarsana Reddy Kalluru 26632d4c8495SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26642d4c8495SSudarsana Reddy Kalluru 26652d4c8495SSudarsana Reddy Kalluru return rc; 26662d4c8495SSudarsana Reddy Kalluru } 26672d4c8495SSudarsana Reddy Kalluru 26683a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash(struct qed_dev *cdev, const char *name) 26693a69cae8SSudarsana Reddy Kalluru { 26703a69cae8SSudarsana Reddy Kalluru const struct firmware *image; 26713a69cae8SSudarsana Reddy Kalluru const u8 *data, *data_end; 26723a69cae8SSudarsana Reddy Kalluru u32 cmd_type; 26733a69cae8SSudarsana Reddy Kalluru int rc; 26743a69cae8SSudarsana Reddy Kalluru 26753a69cae8SSudarsana Reddy Kalluru rc = request_firmware(&image, name, &cdev->pdev->dev); 26763a69cae8SSudarsana Reddy Kalluru if (rc) { 26773a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find '%s'\n", name); 26783a69cae8SSudarsana Reddy Kalluru return rc; 26793a69cae8SSudarsana Reddy Kalluru } 26803a69cae8SSudarsana Reddy Kalluru 26813a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26823a69cae8SSudarsana Reddy Kalluru "Flashing '%s' - firmware's data at %p, size is %08x\n", 26833a69cae8SSudarsana Reddy Kalluru name, image->data, (u32)image->size); 26843a69cae8SSudarsana Reddy Kalluru data = image->data; 26853a69cae8SSudarsana Reddy Kalluru data_end = data + image->size; 26863a69cae8SSudarsana Reddy Kalluru 26873a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_validate(cdev, image, &data); 26883a69cae8SSudarsana Reddy Kalluru if (rc) 26893a69cae8SSudarsana Reddy Kalluru goto exit; 26903a69cae8SSudarsana Reddy Kalluru 26913a69cae8SSudarsana Reddy Kalluru while (data < data_end) { 26923a69cae8SSudarsana Reddy Kalluru bool check_resp = false; 26933a69cae8SSudarsana Reddy Kalluru 26943a69cae8SSudarsana Reddy Kalluru /* Parse the actual command */ 26953a69cae8SSudarsana Reddy Kalluru cmd_type = *((u32 *)data); 26963a69cae8SSudarsana Reddy Kalluru switch (cmd_type) { 26973a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_DATA: 26983a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_data(cdev, &data, 26993a69cae8SSudarsana Reddy Kalluru &check_resp); 27003a69cae8SSudarsana Reddy Kalluru break; 27013a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_START: 27023a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_start(cdev, &data, 27033a69cae8SSudarsana Reddy Kalluru &check_resp); 27043a69cae8SSudarsana Reddy Kalluru break; 27053a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CHANGE: 27063a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access(cdev, &data, 27073a69cae8SSudarsana Reddy Kalluru &check_resp); 27083a69cae8SSudarsana Reddy Kalluru break; 27090dabbe1bSSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CFG_ID: 27100dabbe1bSSudarsana Reddy Kalluru rc = qed_nvm_flash_cfg_write(cdev, &data); 27110dabbe1bSSudarsana Reddy Kalluru break; 27123a69cae8SSudarsana Reddy Kalluru default: 27133a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Unknown command %08x\n", cmd_type); 27143a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27153a69cae8SSudarsana Reddy Kalluru goto exit; 27163a69cae8SSudarsana Reddy Kalluru } 27173a69cae8SSudarsana Reddy Kalluru 27183a69cae8SSudarsana Reddy Kalluru if (rc) { 27193a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Command %08x failed\n", cmd_type); 27203a69cae8SSudarsana Reddy Kalluru goto exit; 27213a69cae8SSudarsana Reddy Kalluru } 27223a69cae8SSudarsana Reddy Kalluru 27233a69cae8SSudarsana Reddy Kalluru /* Check response if needed */ 27243a69cae8SSudarsana Reddy Kalluru if (check_resp) { 27253a69cae8SSudarsana Reddy Kalluru u32 mcp_response = 0; 27263a69cae8SSudarsana Reddy Kalluru 27273a69cae8SSudarsana Reddy Kalluru if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) { 27283a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed getting MCP response\n"); 27293a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27303a69cae8SSudarsana Reddy Kalluru goto exit; 27313a69cae8SSudarsana Reddy Kalluru } 27323a69cae8SSudarsana Reddy Kalluru 27333a69cae8SSudarsana Reddy Kalluru switch (mcp_response & FW_MSG_CODE_MASK) { 27343a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_OK: 27353a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_OK: 27363a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK: 27373a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_PHY_OK: 27383a69cae8SSudarsana Reddy Kalluru break; 27393a69cae8SSudarsana Reddy Kalluru default: 27403a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "MFW returns error: %08x\n", 27413a69cae8SSudarsana Reddy Kalluru mcp_response); 27423a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27433a69cae8SSudarsana Reddy Kalluru goto exit; 27443a69cae8SSudarsana Reddy Kalluru } 27453a69cae8SSudarsana Reddy Kalluru } 27463a69cae8SSudarsana Reddy Kalluru } 27473a69cae8SSudarsana Reddy Kalluru 27483a69cae8SSudarsana Reddy Kalluru exit: 27493a69cae8SSudarsana Reddy Kalluru release_firmware(image); 27503a69cae8SSudarsana Reddy Kalluru 27513a69cae8SSudarsana Reddy Kalluru return rc; 27523a69cae8SSudarsana Reddy Kalluru } 27533a69cae8SSudarsana Reddy Kalluru 275420675b37SMintz, Yuval static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, 275520675b37SMintz, Yuval u8 *buf, u16 len) 275620675b37SMintz, Yuval { 275720675b37SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 275820675b37SMintz, Yuval 2759b60bfdfeSDenis Bolotin return qed_mcp_get_nvm_image(hwfn, type, buf, len); 276020675b37SMintz, Yuval } 276120675b37SMintz, Yuval 276264515dc8STomer Tayar void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) 276364515dc8STomer Tayar { 276464515dc8STomer Tayar struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 276564515dc8STomer Tayar void *cookie = p_hwfn->cdev->ops_cookie; 276664515dc8STomer Tayar 276764515dc8STomer Tayar if (ops && ops->schedule_recovery_handler) 276864515dc8STomer Tayar ops->schedule_recovery_handler(cookie); 276964515dc8STomer Tayar } 277064515dc8STomer Tayar 2771c6b7314dSAlexander Lobakin static const char * const qed_hw_err_type_descr[] = { 2772d639836aSIgor Russkikh [QED_HW_ERR_FAN_FAIL] = "Fan Failure", 2773d639836aSIgor Russkikh [QED_HW_ERR_MFW_RESP_FAIL] = "MFW Response Failure", 2774d639836aSIgor Russkikh [QED_HW_ERR_HW_ATTN] = "HW Attention", 2775d639836aSIgor Russkikh [QED_HW_ERR_DMAE_FAIL] = "DMAE Failure", 2776d639836aSIgor Russkikh [QED_HW_ERR_RAMROD_FAIL] = "Ramrod Failure", 2777d639836aSIgor Russkikh [QED_HW_ERR_FW_ASSERT] = "FW Assertion", 2778d639836aSIgor Russkikh [QED_HW_ERR_LAST] = "Unknown", 2779d639836aSIgor Russkikh }; 2780d639836aSIgor Russkikh 2781d639836aSIgor Russkikh void qed_hw_error_occurred(struct qed_hwfn *p_hwfn, 2782d639836aSIgor Russkikh enum qed_hw_err_type err_type) 2783d639836aSIgor Russkikh { 2784d639836aSIgor Russkikh struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 2785d639836aSIgor Russkikh void *cookie = p_hwfn->cdev->ops_cookie; 2786c6b7314dSAlexander Lobakin const char *err_str; 2787d639836aSIgor Russkikh 2788d639836aSIgor Russkikh if (err_type > QED_HW_ERR_LAST) 2789d639836aSIgor Russkikh err_type = QED_HW_ERR_LAST; 2790d639836aSIgor Russkikh err_str = qed_hw_err_type_descr[err_type]; 2791d639836aSIgor Russkikh 2792d639836aSIgor Russkikh DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str); 2793d639836aSIgor Russkikh 2794936c7ba4SIgor Russkikh /* Call the HW error handler of the protocol driver. 2795936c7ba4SIgor Russkikh * If it is not available - perform a minimal handling of preventing 2796936c7ba4SIgor Russkikh * HW attentions from being reasserted. 2797d639836aSIgor Russkikh */ 2798d639836aSIgor Russkikh if (ops && ops->schedule_hw_err_handler) 2799d639836aSIgor Russkikh ops->schedule_hw_err_handler(cookie, err_type); 2800936c7ba4SIgor Russkikh else 2801936c7ba4SIgor Russkikh qed_int_attn_clr_enable(p_hwfn->cdev, true); 2802d639836aSIgor Russkikh } 2803d639836aSIgor Russkikh 2804722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, 2805477f2d14SRahul Verma void *handle) 2806722003acSSudarsana Reddy Kalluru { 2807477f2d14SRahul Verma return qed_set_queue_coalesce(rx_coal, tx_coal, handle); 2808722003acSSudarsana Reddy Kalluru } 2809722003acSSudarsana Reddy Kalluru 281091420b83SSudarsana Kalluru static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) 281191420b83SSudarsana Kalluru { 281291420b83SSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 281391420b83SSudarsana Kalluru struct qed_ptt *ptt; 281491420b83SSudarsana Kalluru int status = 0; 281591420b83SSudarsana Kalluru 281691420b83SSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 281791420b83SSudarsana Kalluru if (!ptt) 281891420b83SSudarsana Kalluru return -EAGAIN; 281991420b83SSudarsana Kalluru 282091420b83SSudarsana Kalluru status = qed_mcp_set_led(hwfn, ptt, mode); 282191420b83SSudarsana Kalluru 282291420b83SSudarsana Kalluru qed_ptt_release(hwfn, ptt); 282391420b83SSudarsana Kalluru 282491420b83SSudarsana Kalluru return status; 282591420b83SSudarsana Kalluru } 282691420b83SSudarsana Kalluru 282764515dc8STomer Tayar static int qed_recovery_process(struct qed_dev *cdev) 282864515dc8STomer Tayar { 282964515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 283064515dc8STomer Tayar struct qed_ptt *p_ptt; 283164515dc8STomer Tayar int rc = 0; 283264515dc8STomer Tayar 283364515dc8STomer Tayar p_ptt = qed_ptt_acquire(p_hwfn); 283464515dc8STomer Tayar if (!p_ptt) 283564515dc8STomer Tayar return -EAGAIN; 283664515dc8STomer Tayar 283764515dc8STomer Tayar rc = qed_start_recovery_process(p_hwfn, p_ptt); 283864515dc8STomer Tayar 283964515dc8STomer Tayar qed_ptt_release(p_hwfn, p_ptt); 284064515dc8STomer Tayar 284164515dc8STomer Tayar return rc; 284264515dc8STomer Tayar } 284364515dc8STomer Tayar 284414d39648SMintz, Yuval static int qed_update_wol(struct qed_dev *cdev, bool enabled) 284514d39648SMintz, Yuval { 284614d39648SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 284714d39648SMintz, Yuval struct qed_ptt *ptt; 284814d39648SMintz, Yuval int rc = 0; 284914d39648SMintz, Yuval 285014d39648SMintz, Yuval if (IS_VF(cdev)) 285114d39648SMintz, Yuval return 0; 285214d39648SMintz, Yuval 285314d39648SMintz, Yuval ptt = qed_ptt_acquire(hwfn); 285414d39648SMintz, Yuval if (!ptt) 285514d39648SMintz, Yuval return -EAGAIN; 285614d39648SMintz, Yuval 285714d39648SMintz, Yuval rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED 285814d39648SMintz, Yuval : QED_OV_WOL_DISABLED); 285914d39648SMintz, Yuval if (rc) 286014d39648SMintz, Yuval goto out; 286114d39648SMintz, Yuval rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 286214d39648SMintz, Yuval 286314d39648SMintz, Yuval out: 286414d39648SMintz, Yuval qed_ptt_release(hwfn, ptt); 286514d39648SMintz, Yuval return rc; 286614d39648SMintz, Yuval } 286714d39648SMintz, Yuval 28680fefbfbaSSudarsana Kalluru static int qed_update_drv_state(struct qed_dev *cdev, bool active) 28690fefbfbaSSudarsana Kalluru { 28700fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28710fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28720fefbfbaSSudarsana Kalluru int status = 0; 28730fefbfbaSSudarsana Kalluru 28740fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28750fefbfbaSSudarsana Kalluru return 0; 28760fefbfbaSSudarsana Kalluru 28770fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 28780fefbfbaSSudarsana Kalluru if (!ptt) 28790fefbfbaSSudarsana Kalluru return -EAGAIN; 28800fefbfbaSSudarsana Kalluru 28810fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? 28820fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_ACTIVE : 28830fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_DISABLED); 28840fefbfbaSSudarsana Kalluru 28850fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 28860fefbfbaSSudarsana Kalluru 28870fefbfbaSSudarsana Kalluru return status; 28880fefbfbaSSudarsana Kalluru } 28890fefbfbaSSudarsana Kalluru 28900fefbfbaSSudarsana Kalluru static int qed_update_mac(struct qed_dev *cdev, u8 *mac) 28910fefbfbaSSudarsana Kalluru { 28920fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28930fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28940fefbfbaSSudarsana Kalluru int status = 0; 28950fefbfbaSSudarsana Kalluru 28960fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28970fefbfbaSSudarsana Kalluru return 0; 28980fefbfbaSSudarsana Kalluru 28990fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 29000fefbfbaSSudarsana Kalluru if (!ptt) 29010fefbfbaSSudarsana Kalluru return -EAGAIN; 29020fefbfbaSSudarsana Kalluru 29030fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mac(hwfn, ptt, mac); 29040fefbfbaSSudarsana Kalluru if (status) 29050fefbfbaSSudarsana Kalluru goto out; 29060fefbfbaSSudarsana Kalluru 29070fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29080fefbfbaSSudarsana Kalluru 29090fefbfbaSSudarsana Kalluru out: 29100fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29110fefbfbaSSudarsana Kalluru return status; 29120fefbfbaSSudarsana Kalluru } 29130fefbfbaSSudarsana Kalluru 29140fefbfbaSSudarsana Kalluru static int qed_update_mtu(struct qed_dev *cdev, u16 mtu) 29150fefbfbaSSudarsana Kalluru { 29160fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29170fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 29180fefbfbaSSudarsana Kalluru int status = 0; 29190fefbfbaSSudarsana Kalluru 29200fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 29210fefbfbaSSudarsana Kalluru return 0; 29220fefbfbaSSudarsana Kalluru 29230fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 29240fefbfbaSSudarsana Kalluru if (!ptt) 29250fefbfbaSSudarsana Kalluru return -EAGAIN; 29260fefbfbaSSudarsana Kalluru 29270fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); 29280fefbfbaSSudarsana Kalluru if (status) 29290fefbfbaSSudarsana Kalluru goto out; 29300fefbfbaSSudarsana Kalluru 29310fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29320fefbfbaSSudarsana Kalluru 29330fefbfbaSSudarsana Kalluru out: 29340fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29350fefbfbaSSudarsana Kalluru return status; 29360fefbfbaSSudarsana Kalluru } 29370fefbfbaSSudarsana Kalluru 2938b51dab46SSudarsana Reddy Kalluru static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 2939b51dab46SSudarsana Reddy Kalluru u8 dev_addr, u32 offset, u32 len) 2940b51dab46SSudarsana Reddy Kalluru { 2941b51dab46SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 2942b51dab46SSudarsana Reddy Kalluru struct qed_ptt *ptt; 2943b51dab46SSudarsana Reddy Kalluru int rc = 0; 2944b51dab46SSudarsana Reddy Kalluru 2945b51dab46SSudarsana Reddy Kalluru if (IS_VF(cdev)) 2946b51dab46SSudarsana Reddy Kalluru return 0; 2947b51dab46SSudarsana Reddy Kalluru 2948b51dab46SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 2949b51dab46SSudarsana Reddy Kalluru if (!ptt) 2950b51dab46SSudarsana Reddy Kalluru return -EAGAIN; 2951b51dab46SSudarsana Reddy Kalluru 2952b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr, 2953b51dab46SSudarsana Reddy Kalluru offset, len, buf); 2954b51dab46SSudarsana Reddy Kalluru 2955b51dab46SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 2956b51dab46SSudarsana Reddy Kalluru 2957b51dab46SSudarsana Reddy Kalluru return rc; 2958b51dab46SSudarsana Reddy Kalluru } 2959b51dab46SSudarsana Reddy Kalluru 29603b86bd07SSudarsana Reddy Kalluru static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val) 29613b86bd07SSudarsana Reddy Kalluru { 29623b86bd07SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29633b86bd07SSudarsana Reddy Kalluru struct qed_ptt *ptt; 29643b86bd07SSudarsana Reddy Kalluru int rc = 0; 29653b86bd07SSudarsana Reddy Kalluru 29663b86bd07SSudarsana Reddy Kalluru if (IS_VF(cdev)) 29673b86bd07SSudarsana Reddy Kalluru return 0; 29683b86bd07SSudarsana Reddy Kalluru 29693b86bd07SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 29703b86bd07SSudarsana Reddy Kalluru if (!ptt) 29713b86bd07SSudarsana Reddy Kalluru return -EAGAIN; 29723b86bd07SSudarsana Reddy Kalluru 29732d22bc83SMichal Kalderon rc = qed_dbg_grc_config(hwfn, cfg_id, val); 29743b86bd07SSudarsana Reddy Kalluru 29753b86bd07SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 29763b86bd07SSudarsana Reddy Kalluru 29773b86bd07SSudarsana Reddy Kalluru return rc; 29783b86bd07SSudarsana Reddy Kalluru } 29793b86bd07SSudarsana Reddy Kalluru 298008eb1fb0SMichal Kalderon static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev) 298108eb1fb0SMichal Kalderon { 298208eb1fb0SMichal Kalderon return QED_AFFIN_HWFN_IDX(cdev); 298308eb1fb0SMichal Kalderon } 298408eb1fb0SMichal Kalderon 29858c93beafSYuval Mintz static struct qed_selftest_ops qed_selftest_ops_pass = { 298603dc76caSSudarsana Reddy Kalluru .selftest_memory = &qed_selftest_memory, 298703dc76caSSudarsana Reddy Kalluru .selftest_interrupt = &qed_selftest_interrupt, 298803dc76caSSudarsana Reddy Kalluru .selftest_register = &qed_selftest_register, 298903dc76caSSudarsana Reddy Kalluru .selftest_clock = &qed_selftest_clock, 29907a4b21b7SMintz, Yuval .selftest_nvram = &qed_selftest_nvram, 299103dc76caSSudarsana Reddy Kalluru }; 299203dc76caSSudarsana Reddy Kalluru 2993fe56b9e6SYuval Mintz const struct qed_common_ops qed_common_ops_pass = { 299403dc76caSSudarsana Reddy Kalluru .selftest = &qed_selftest_ops_pass, 2995fe56b9e6SYuval Mintz .probe = &qed_probe, 2996fe56b9e6SYuval Mintz .remove = &qed_remove, 2997fe56b9e6SYuval Mintz .set_power_state = &qed_set_power_state, 2998712c3cbfSMintz, Yuval .set_name = &qed_set_name, 2999fe56b9e6SYuval Mintz .update_pf_params = &qed_update_pf_params, 3000fe56b9e6SYuval Mintz .slowpath_start = &qed_slowpath_start, 3001fe56b9e6SYuval Mintz .slowpath_stop = &qed_slowpath_stop, 3002fe56b9e6SYuval Mintz .set_fp_int = &qed_set_int_fp, 3003fe56b9e6SYuval Mintz .get_fp_int = &qed_get_int_fp, 3004fe56b9e6SYuval Mintz .sb_init = &qed_sb_init, 3005fe56b9e6SYuval Mintz .sb_release = &qed_sb_release, 3006fe56b9e6SYuval Mintz .simd_handler_config = &qed_simd_handler_config, 3007fe56b9e6SYuval Mintz .simd_handler_clean = &qed_simd_handler_clean, 30081e128c81SArun Easi .dbg_grc = &qed_dbg_grc, 30091e128c81SArun Easi .dbg_grc_size = &qed_dbg_grc_size, 3010fe7cd2bfSYuval Mintz .can_link_change = &qed_can_link_change, 3011cc875c2eSYuval Mintz .set_link = &qed_set_link, 3012cc875c2eSYuval Mintz .get_link = &qed_get_current_link, 3013fe56b9e6SYuval Mintz .drain = &qed_drain, 3014fe56b9e6SYuval Mintz .update_msglvl = &qed_init_dp, 3015e0971c83STomer Tayar .dbg_all_data = &qed_dbg_all_data, 3016e0971c83STomer Tayar .dbg_all_data_size = &qed_dbg_all_data_size, 3017fe56b9e6SYuval Mintz .chain_alloc = &qed_chain_alloc, 3018fe56b9e6SYuval Mintz .chain_free = &qed_chain_free, 30193a69cae8SSudarsana Reddy Kalluru .nvm_flash = &qed_nvm_flash, 302020675b37SMintz, Yuval .nvm_get_image = &qed_nvm_get_image, 3021722003acSSudarsana Reddy Kalluru .set_coalesce = &qed_set_coalesce, 302291420b83SSudarsana Kalluru .set_led = &qed_set_led, 302364515dc8STomer Tayar .recovery_process = &qed_recovery_process, 302464515dc8STomer Tayar .recovery_prolog = &qed_recovery_prolog, 3025936c7ba4SIgor Russkikh .attn_clr_enable = &qed_int_attn_clr_enable, 30260fefbfbaSSudarsana Kalluru .update_drv_state = &qed_update_drv_state, 30270fefbfbaSSudarsana Kalluru .update_mac = &qed_update_mac, 30280fefbfbaSSudarsana Kalluru .update_mtu = &qed_update_mtu, 302914d39648SMintz, Yuval .update_wol = &qed_update_wol, 30300e1f1044SAriel Elior .db_recovery_add = &qed_db_recovery_add, 30310e1f1044SAriel Elior .db_recovery_del = &qed_db_recovery_del, 3032b51dab46SSudarsana Reddy Kalluru .read_module_eeprom = &qed_read_module_eeprom, 303308eb1fb0SMichal Kalderon .get_affin_hwfn_idx = &qed_get_affin_hwfn_idx, 30342d4c8495SSudarsana Reddy Kalluru .read_nvm_cfg = &qed_nvm_flash_cfg_read, 30359e54ba7cSSudarsana Reddy Kalluru .read_nvm_cfg_len = &qed_nvm_flash_cfg_len, 30363b86bd07SSudarsana Reddy Kalluru .set_grc_config = &qed_set_grc_config, 3037fe56b9e6SYuval Mintz }; 30386c754246SSudarsana Reddy Kalluru 30396c754246SSudarsana Reddy Kalluru void qed_get_protocol_stats(struct qed_dev *cdev, 30406c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type type, 30416c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats *stats) 30426c754246SSudarsana Reddy Kalluru { 30436c754246SSudarsana Reddy Kalluru struct qed_eth_stats eth_stats; 30446c754246SSudarsana Reddy Kalluru 30456c754246SSudarsana Reddy Kalluru memset(stats, 0, sizeof(*stats)); 30466c754246SSudarsana Reddy Kalluru 30476c754246SSudarsana Reddy Kalluru switch (type) { 30486c754246SSudarsana Reddy Kalluru case QED_MCP_LAN_STATS: 30496c754246SSudarsana Reddy Kalluru qed_get_vport_stats(cdev, ð_stats); 30509c79ddaaSMintz, Yuval stats->lan_stats.ucast_rx_pkts = 30519c79ddaaSMintz, Yuval eth_stats.common.rx_ucast_pkts; 30529c79ddaaSMintz, Yuval stats->lan_stats.ucast_tx_pkts = 30539c79ddaaSMintz, Yuval eth_stats.common.tx_ucast_pkts; 30546c754246SSudarsana Reddy Kalluru stats->lan_stats.fcs_err = -1; 30556c754246SSudarsana Reddy Kalluru break; 30561e128c81SArun Easi case QED_MCP_FCOE_STATS: 30571e128c81SArun Easi qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); 30581e128c81SArun Easi break; 30592f2b2614SMintz, Yuval case QED_MCP_ISCSI_STATS: 30602f2b2614SMintz, Yuval qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); 30612f2b2614SMintz, Yuval break; 30626c754246SSudarsana Reddy Kalluru default: 3063512c7840SMintz, Yuval DP_VERBOSE(cdev, QED_MSG_SP, 3064512c7840SMintz, Yuval "Invalid protocol type = %d\n", type); 30656c754246SSudarsana Reddy Kalluru return; 30666c754246SSudarsana Reddy Kalluru } 30676c754246SSudarsana Reddy Kalluru } 30682528c389SSudarsana Reddy Kalluru 306959ccf86fSSudarsana Reddy Kalluru int qed_mfw_tlv_req(struct qed_hwfn *hwfn) 307059ccf86fSSudarsana Reddy Kalluru { 307159ccf86fSSudarsana Reddy Kalluru DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 307259ccf86fSSudarsana Reddy Kalluru "Scheduling slowpath task [Flag: %d]\n", 307359ccf86fSSudarsana Reddy Kalluru QED_SLOWPATH_MFW_TLV_REQ); 307459ccf86fSSudarsana Reddy Kalluru smp_mb__before_atomic(); 307559ccf86fSSudarsana Reddy Kalluru set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags); 307659ccf86fSSudarsana Reddy Kalluru smp_mb__after_atomic(); 307759ccf86fSSudarsana Reddy Kalluru queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 307859ccf86fSSudarsana Reddy Kalluru 307959ccf86fSSudarsana Reddy Kalluru return 0; 308059ccf86fSSudarsana Reddy Kalluru } 308159ccf86fSSudarsana Reddy Kalluru 308259ccf86fSSudarsana Reddy Kalluru static void 308359ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv) 308459ccf86fSSudarsana Reddy Kalluru { 308559ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = cdev->protocol_ops.common; 308659ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats_common *p_common; 308759ccf86fSSudarsana Reddy Kalluru struct qed_generic_tlvs gen_tlvs; 308859ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats stats; 308959ccf86fSSudarsana Reddy Kalluru int i; 309059ccf86fSSudarsana Reddy Kalluru 309159ccf86fSSudarsana Reddy Kalluru memset(&gen_tlvs, 0, sizeof(gen_tlvs)); 309259ccf86fSSudarsana Reddy Kalluru op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs); 309359ccf86fSSudarsana Reddy Kalluru 309459ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM) 309559ccf86fSSudarsana Reddy Kalluru tlv->flags.ipv4_csum_offload = true; 309659ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_LSO) 309759ccf86fSSudarsana Reddy Kalluru tlv->flags.lso_supported = true; 309859ccf86fSSudarsana Reddy Kalluru tlv->flags.b_set = true; 309959ccf86fSSudarsana Reddy Kalluru 310059ccf86fSSudarsana Reddy Kalluru for (i = 0; i < QED_TLV_MAC_COUNT; i++) { 310159ccf86fSSudarsana Reddy Kalluru if (is_valid_ether_addr(gen_tlvs.mac[i])) { 310259ccf86fSSudarsana Reddy Kalluru ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]); 310359ccf86fSSudarsana Reddy Kalluru tlv->mac_set[i] = true; 310459ccf86fSSudarsana Reddy Kalluru } 310559ccf86fSSudarsana Reddy Kalluru } 310659ccf86fSSudarsana Reddy Kalluru 310759ccf86fSSudarsana Reddy Kalluru qed_get_vport_stats(cdev, &stats); 310859ccf86fSSudarsana Reddy Kalluru p_common = &stats.common; 310959ccf86fSSudarsana Reddy Kalluru tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 311059ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_pkts; 311159ccf86fSSudarsana Reddy Kalluru tlv->rx_frames_set = true; 311259ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 311359ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_bytes; 311459ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 311559ccf86fSSudarsana Reddy Kalluru tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 311659ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_pkts; 311759ccf86fSSudarsana Reddy Kalluru tlv->tx_frames_set = true; 311859ccf86fSSudarsana Reddy Kalluru tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 311959ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_bytes; 312059ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 312159ccf86fSSudarsana Reddy Kalluru } 312259ccf86fSSudarsana Reddy Kalluru 31232528c389SSudarsana Reddy Kalluru int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type, 31242528c389SSudarsana Reddy Kalluru union qed_mfw_tlv_data *tlv_buf) 31252528c389SSudarsana Reddy Kalluru { 312659ccf86fSSudarsana Reddy Kalluru struct qed_dev *cdev = hwfn->cdev; 312759ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *ops; 312859ccf86fSSudarsana Reddy Kalluru 312959ccf86fSSudarsana Reddy Kalluru ops = cdev->protocol_ops.common; 313059ccf86fSSudarsana Reddy Kalluru if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) { 313159ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Can't collect TLV management info\n"); 31322528c389SSudarsana Reddy Kalluru return -EINVAL; 31332528c389SSudarsana Reddy Kalluru } 313459ccf86fSSudarsana Reddy Kalluru 313559ccf86fSSudarsana Reddy Kalluru switch (type) { 313659ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_GENERIC: 313759ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic); 313859ccf86fSSudarsana Reddy Kalluru break; 313959ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ETH: 314059ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth); 314159ccf86fSSudarsana Reddy Kalluru break; 314259ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_FCOE: 314359ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe); 314459ccf86fSSudarsana Reddy Kalluru break; 314559ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ISCSI: 314659ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi); 314759ccf86fSSudarsana Reddy Kalluru break; 314859ccf86fSSudarsana Reddy Kalluru default: 314959ccf86fSSudarsana Reddy Kalluru break; 315059ccf86fSSudarsana Reddy Kalluru } 315159ccf86fSSudarsana Reddy Kalluru 315259ccf86fSSudarsana Reddy Kalluru return 0; 315359ccf86fSSudarsana Reddy Kalluru } 3154