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[] = 52*7a3febedSShai Malin "QLogic FastLinQ 4xxxx Core Module qed\n"; 53fe56b9e6SYuval Mintz 545abd7e92SYuval Mintz MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module"); 55fe56b9e6SYuval Mintz MODULE_LICENSE("GPL"); 56fe56b9e6SYuval Mintz 57fe56b9e6SYuval Mintz #define FW_FILE_VERSION \ 58fe56b9e6SYuval Mintz __stringify(FW_MAJOR_VERSION) "." \ 59fe56b9e6SYuval Mintz __stringify(FW_MINOR_VERSION) "." \ 60fe56b9e6SYuval Mintz __stringify(FW_REVISION_VERSION) "." \ 61fe56b9e6SYuval Mintz __stringify(FW_ENGINEERING_VERSION) 62fe56b9e6SYuval Mintz 63fe56b9e6SYuval Mintz #define QED_FW_FILE_NAME \ 64fe56b9e6SYuval Mintz "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" 65fe56b9e6SYuval Mintz 66d43d3f0fSYuval Mintz MODULE_FIRMWARE(QED_FW_FILE_NAME); 67d43d3f0fSYuval Mintz 68097818fcSAlexander Lobakin /* MFW speed capabilities maps */ 69097818fcSAlexander Lobakin 70097818fcSAlexander Lobakin struct qed_mfw_speed_map { 71097818fcSAlexander Lobakin u32 mfw_val; 72097818fcSAlexander Lobakin __ETHTOOL_DECLARE_LINK_MODE_MASK(caps); 73097818fcSAlexander Lobakin 74097818fcSAlexander Lobakin const u32 *cap_arr; 75097818fcSAlexander Lobakin u32 arr_size; 76097818fcSAlexander Lobakin }; 77097818fcSAlexander Lobakin 78097818fcSAlexander Lobakin #define QED_MFW_SPEED_MAP(type, arr) \ 79097818fcSAlexander Lobakin { \ 80097818fcSAlexander Lobakin .mfw_val = (type), \ 81097818fcSAlexander Lobakin .cap_arr = (arr), \ 82097818fcSAlexander Lobakin .arr_size = ARRAY_SIZE(arr), \ 83097818fcSAlexander Lobakin } 84097818fcSAlexander Lobakin 8599785a87SAlexander Lobakin static const u32 qed_mfw_ext_1g[] __initconst = { 8699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 8799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 8899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 8999785a87SAlexander Lobakin }; 9099785a87SAlexander Lobakin 9199785a87SAlexander Lobakin static const u32 qed_mfw_ext_10g[] __initconst = { 9299785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 9399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 9499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 9599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 9699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 9799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 9899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 9999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 10099785a87SAlexander Lobakin }; 10199785a87SAlexander Lobakin 10299785a87SAlexander Lobakin static const u32 qed_mfw_ext_20g[] __initconst = { 10399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 10499785a87SAlexander Lobakin }; 10599785a87SAlexander Lobakin 10699785a87SAlexander Lobakin static const u32 qed_mfw_ext_25g[] __initconst = { 10799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 10899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 10999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 11099785a87SAlexander Lobakin }; 11199785a87SAlexander Lobakin 11299785a87SAlexander Lobakin static const u32 qed_mfw_ext_40g[] __initconst = { 11399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 11499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 11599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 11699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 11799785a87SAlexander Lobakin }; 11899785a87SAlexander Lobakin 11999785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r[] __initconst = { 12099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 12199785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 12299785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 12399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 12499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 12599785a87SAlexander Lobakin }; 12699785a87SAlexander Lobakin 12799785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r2[] __initconst = { 12899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 12999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 13099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 13199785a87SAlexander Lobakin }; 13299785a87SAlexander Lobakin 13399785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r2[] __initconst = { 13499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 13599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 13699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 13799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 13899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 13999785a87SAlexander Lobakin }; 14099785a87SAlexander Lobakin 14199785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r4[] __initconst = { 14299785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 14399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 14499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 14599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 14699785a87SAlexander Lobakin }; 14799785a87SAlexander Lobakin 14899785a87SAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_ext_maps[] __ro_after_init = { 14999785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_1G, qed_mfw_ext_1g), 15099785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_10G, qed_mfw_ext_10g), 15199785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_20G, qed_mfw_ext_20g), 15299785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_25G, qed_mfw_ext_25g), 15399785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_40G, qed_mfw_ext_40g), 15499785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R, 15599785a87SAlexander Lobakin qed_mfw_ext_50g_base_r), 15699785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R2, 15799785a87SAlexander Lobakin qed_mfw_ext_50g_base_r2), 15899785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R2, 15999785a87SAlexander Lobakin qed_mfw_ext_100g_base_r2), 16099785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R4, 16199785a87SAlexander Lobakin qed_mfw_ext_100g_base_r4), 16299785a87SAlexander Lobakin }; 16399785a87SAlexander Lobakin 164097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_1g[] __initconst = { 165097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 166097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 167097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 168097818fcSAlexander Lobakin }; 169097818fcSAlexander Lobakin 170097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_10g[] __initconst = { 171097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 172097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 173097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 174097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 175097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 176097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 177097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 178097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 179097818fcSAlexander Lobakin }; 180097818fcSAlexander Lobakin 181097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_20g[] __initconst = { 182097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 183097818fcSAlexander Lobakin }; 184097818fcSAlexander Lobakin 185097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_25g[] __initconst = { 186097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 187097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 188097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 189097818fcSAlexander Lobakin }; 190097818fcSAlexander Lobakin 191097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_40g[] __initconst = { 192097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 193097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 194097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 195097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 196097818fcSAlexander Lobakin }; 197097818fcSAlexander Lobakin 198097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_50g[] __initconst = { 199097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 200097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 201097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 202097818fcSAlexander Lobakin }; 203097818fcSAlexander Lobakin 204097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_bb_100g[] __initconst = { 205097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 206097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 207097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 208097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 209097818fcSAlexander Lobakin }; 210097818fcSAlexander Lobakin 211097818fcSAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_legacy_maps[] __ro_after_init = { 212097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G, 213097818fcSAlexander Lobakin qed_mfw_legacy_1g), 214097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G, 215097818fcSAlexander Lobakin qed_mfw_legacy_10g), 216097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G, 217097818fcSAlexander Lobakin qed_mfw_legacy_20g), 218097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G, 219097818fcSAlexander Lobakin qed_mfw_legacy_25g), 220097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G, 221097818fcSAlexander Lobakin qed_mfw_legacy_40g), 222097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G, 223097818fcSAlexander Lobakin qed_mfw_legacy_50g), 224097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G, 225097818fcSAlexander Lobakin qed_mfw_legacy_bb_100g), 226097818fcSAlexander Lobakin }; 227097818fcSAlexander Lobakin 228097818fcSAlexander Lobakin static void __init qed_mfw_speed_map_populate(struct qed_mfw_speed_map *map) 229097818fcSAlexander Lobakin { 230097818fcSAlexander Lobakin linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps); 231097818fcSAlexander Lobakin 232097818fcSAlexander Lobakin map->cap_arr = NULL; 233097818fcSAlexander Lobakin map->arr_size = 0; 234097818fcSAlexander Lobakin } 235097818fcSAlexander Lobakin 236097818fcSAlexander Lobakin static void __init qed_mfw_speed_maps_init(void) 237097818fcSAlexander Lobakin { 238097818fcSAlexander Lobakin u32 i; 239097818fcSAlexander Lobakin 24099785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) 24199785a87SAlexander Lobakin qed_mfw_speed_map_populate(qed_mfw_ext_maps + i); 24299785a87SAlexander Lobakin 243097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) 244097818fcSAlexander Lobakin qed_mfw_speed_map_populate(qed_mfw_legacy_maps + i); 245097818fcSAlexander Lobakin } 246097818fcSAlexander Lobakin 247fe56b9e6SYuval Mintz static int __init qed_init(void) 248fe56b9e6SYuval Mintz { 249fe56b9e6SYuval Mintz pr_info("%s", version); 250fe56b9e6SYuval Mintz 251097818fcSAlexander Lobakin qed_mfw_speed_maps_init(); 252097818fcSAlexander Lobakin 253fe56b9e6SYuval Mintz return 0; 254fe56b9e6SYuval Mintz } 255fe56b9e6SYuval Mintz module_init(qed_init); 256097818fcSAlexander Lobakin 257097818fcSAlexander Lobakin static void __exit qed_exit(void) 258097818fcSAlexander Lobakin { 259097818fcSAlexander Lobakin /* To prevent marking this module as "permanent" */ 260097818fcSAlexander Lobakin } 261097818fcSAlexander Lobakin module_exit(qed_exit); 262fe56b9e6SYuval Mintz 263fe56b9e6SYuval Mintz /* Check if the DMA controller on the machine can properly handle the DMA 264fe56b9e6SYuval Mintz * addressing required by the device. 265fe56b9e6SYuval Mintz */ 266fe56b9e6SYuval Mintz static int qed_set_coherency_mask(struct qed_dev *cdev) 267fe56b9e6SYuval Mintz { 268fe56b9e6SYuval Mintz struct device *dev = &cdev->pdev->dev; 269fe56b9e6SYuval Mintz 270fe56b9e6SYuval Mintz if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { 271fe56b9e6SYuval Mintz if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { 272fe56b9e6SYuval Mintz DP_NOTICE(cdev, 273fe56b9e6SYuval Mintz "Can't request 64-bit consistent allocations\n"); 274fe56b9e6SYuval Mintz return -EIO; 275fe56b9e6SYuval Mintz } 276fe56b9e6SYuval Mintz } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { 277fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); 278fe56b9e6SYuval Mintz return -EIO; 279fe56b9e6SYuval Mintz } 280fe56b9e6SYuval Mintz 281fe56b9e6SYuval Mintz return 0; 282fe56b9e6SYuval Mintz } 283fe56b9e6SYuval Mintz 284fe56b9e6SYuval Mintz static void qed_free_pci(struct qed_dev *cdev) 285fe56b9e6SYuval Mintz { 286fe56b9e6SYuval Mintz struct pci_dev *pdev = cdev->pdev; 287fe56b9e6SYuval Mintz 2882196d831SSudarsana Reddy Kalluru pci_disable_pcie_error_reporting(pdev); 2892196d831SSudarsana Reddy Kalluru 2901a850bfcSMintz, Yuval if (cdev->doorbells && cdev->db_size) 291fe56b9e6SYuval Mintz iounmap(cdev->doorbells); 292fe56b9e6SYuval Mintz if (cdev->regview) 293fe56b9e6SYuval Mintz iounmap(cdev->regview); 294fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) 295fe56b9e6SYuval Mintz pci_release_regions(pdev); 296fe56b9e6SYuval Mintz 297fe56b9e6SYuval Mintz pci_disable_device(pdev); 298fe56b9e6SYuval Mintz } 299fe56b9e6SYuval Mintz 3000dfaba6dSYuval Mintz #define PCI_REVISION_ID_ERROR_VAL 0xff 3010dfaba6dSYuval Mintz 302fe56b9e6SYuval Mintz /* Performs PCI initializations as well as initializing PCI-related parameters 303fe56b9e6SYuval Mintz * in the device structrue. Returns 0 in case of success. 304fe56b9e6SYuval Mintz */ 3051a635e48SYuval Mintz static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) 306fe56b9e6SYuval Mintz { 3070dfaba6dSYuval Mintz u8 rev_id; 308fe56b9e6SYuval Mintz int rc; 309fe56b9e6SYuval Mintz 310fe56b9e6SYuval Mintz cdev->pdev = pdev; 311fe56b9e6SYuval Mintz 312fe56b9e6SYuval Mintz rc = pci_enable_device(pdev); 313fe56b9e6SYuval Mintz if (rc) { 314fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot enable PCI device\n"); 315fe56b9e6SYuval Mintz goto err0; 316fe56b9e6SYuval Mintz } 317fe56b9e6SYuval Mintz 318fe56b9e6SYuval Mintz if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 319fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #0\n"); 320fe56b9e6SYuval Mintz rc = -EIO; 321fe56b9e6SYuval Mintz goto err1; 322fe56b9e6SYuval Mintz } 323fe56b9e6SYuval Mintz 3241408cc1fSYuval Mintz if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 325fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #2\n"); 326fe56b9e6SYuval Mintz rc = -EIO; 327fe56b9e6SYuval Mintz goto err1; 328fe56b9e6SYuval Mintz } 329fe56b9e6SYuval Mintz 330fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) { 331fe56b9e6SYuval Mintz rc = pci_request_regions(pdev, "qed"); 332fe56b9e6SYuval Mintz if (rc) { 333fe56b9e6SYuval Mintz DP_NOTICE(cdev, 334fe56b9e6SYuval Mintz "Failed to request PCI memory resources\n"); 335fe56b9e6SYuval Mintz goto err1; 336fe56b9e6SYuval Mintz } 337fe56b9e6SYuval Mintz pci_set_master(pdev); 338fe56b9e6SYuval Mintz pci_save_state(pdev); 339fe56b9e6SYuval Mintz } 340fe56b9e6SYuval Mintz 3410dfaba6dSYuval Mintz pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 3420dfaba6dSYuval Mintz if (rev_id == PCI_REVISION_ID_ERROR_VAL) { 3430dfaba6dSYuval Mintz DP_NOTICE(cdev, 3440dfaba6dSYuval Mintz "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", 3450dfaba6dSYuval Mintz rev_id); 3460dfaba6dSYuval Mintz rc = -ENODEV; 3470dfaba6dSYuval Mintz goto err2; 3480dfaba6dSYuval Mintz } 349fe56b9e6SYuval Mintz if (!pci_is_pcie(pdev)) { 350fe56b9e6SYuval Mintz DP_NOTICE(cdev, "The bus is not PCI Express\n"); 351fe56b9e6SYuval Mintz rc = -EIO; 352fe56b9e6SYuval Mintz goto err2; 353fe56b9e6SYuval Mintz } 354fe56b9e6SYuval Mintz 355fe56b9e6SYuval Mintz cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); 356416cdf06SYuval Mintz if (IS_PF(cdev) && !cdev->pci_params.pm_cap) 357fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot find power management capability\n"); 358fe56b9e6SYuval Mintz 359fe56b9e6SYuval Mintz rc = qed_set_coherency_mask(cdev); 360fe56b9e6SYuval Mintz if (rc) 361fe56b9e6SYuval Mintz goto err2; 362fe56b9e6SYuval Mintz 363fe56b9e6SYuval Mintz cdev->pci_params.mem_start = pci_resource_start(pdev, 0); 364fe56b9e6SYuval Mintz cdev->pci_params.mem_end = pci_resource_end(pdev, 0); 365fe56b9e6SYuval Mintz cdev->pci_params.irq = pdev->irq; 366fe56b9e6SYuval Mintz 367fe56b9e6SYuval Mintz cdev->regview = pci_ioremap_bar(pdev, 0); 368fe56b9e6SYuval Mintz if (!cdev->regview) { 369fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map register space, aborting\n"); 370fe56b9e6SYuval Mintz rc = -ENOMEM; 371fe56b9e6SYuval Mintz goto err2; 372fe56b9e6SYuval Mintz } 373fe56b9e6SYuval Mintz 374fe56b9e6SYuval Mintz cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); 375fe56b9e6SYuval Mintz cdev->db_size = pci_resource_len(cdev->pdev, 2); 3761a850bfcSMintz, Yuval if (!cdev->db_size) { 3771a850bfcSMintz, Yuval if (IS_PF(cdev)) { 3781a850bfcSMintz, Yuval DP_NOTICE(cdev, "No Doorbell bar available\n"); 3791a850bfcSMintz, Yuval return -EINVAL; 3801a850bfcSMintz, Yuval } else { 3811a850bfcSMintz, Yuval return 0; 3821a850bfcSMintz, Yuval } 3831a850bfcSMintz, Yuval } 3841a850bfcSMintz, Yuval 385fe56b9e6SYuval Mintz cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); 3861a850bfcSMintz, Yuval 387fe56b9e6SYuval Mintz if (!cdev->doorbells) { 388fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map doorbell space\n"); 389fe56b9e6SYuval Mintz return -ENOMEM; 390fe56b9e6SYuval Mintz } 391fe56b9e6SYuval Mintz 3922196d831SSudarsana Reddy Kalluru /* AER (Advanced Error reporting) configuration */ 3932196d831SSudarsana Reddy Kalluru rc = pci_enable_pcie_error_reporting(pdev); 3942196d831SSudarsana Reddy Kalluru if (rc) 3952196d831SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 3962196d831SSudarsana Reddy Kalluru "Failed to configure PCIe AER [%d]\n", rc); 3972196d831SSudarsana Reddy Kalluru 398fe56b9e6SYuval Mintz return 0; 399fe56b9e6SYuval Mintz 400fe56b9e6SYuval Mintz err2: 401fe56b9e6SYuval Mintz pci_release_regions(pdev); 402fe56b9e6SYuval Mintz err1: 403fe56b9e6SYuval Mintz pci_disable_device(pdev); 404fe56b9e6SYuval Mintz err0: 405fe56b9e6SYuval Mintz return rc; 406fe56b9e6SYuval Mintz } 407fe56b9e6SYuval Mintz 408fe56b9e6SYuval Mintz int qed_fill_dev_info(struct qed_dev *cdev, 409fe56b9e6SYuval Mintz struct qed_dev_info *dev_info) 410fe56b9e6SYuval Mintz { 411c851a9dcSKalderon, Michal struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 412c851a9dcSKalderon, Michal struct qed_hw_info *hw_info = &p_hwfn->hw_info; 41319489c7fSChopra, Manish struct qed_tunnel_info *tun = &cdev->tunnel; 414cee4d264SManish Chopra struct qed_ptt *ptt; 415cee4d264SManish Chopra 416fe56b9e6SYuval Mintz memset(dev_info, 0, sizeof(struct qed_dev_info)); 417fe56b9e6SYuval Mintz 41819489c7fSChopra, Manish if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 41919489c7fSChopra, Manish tun->vxlan.b_mode_enabled) 42019489c7fSChopra, Manish dev_info->vxlan_enable = true; 42119489c7fSChopra, Manish 42219489c7fSChopra, Manish if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && 42319489c7fSChopra, Manish tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 42419489c7fSChopra, Manish tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 42519489c7fSChopra, Manish dev_info->gre_enable = true; 42619489c7fSChopra, Manish 42719489c7fSChopra, Manish if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && 42819489c7fSChopra, Manish tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 42919489c7fSChopra, Manish tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 43019489c7fSChopra, Manish dev_info->geneve_enable = true; 43119489c7fSChopra, Manish 432fe56b9e6SYuval Mintz dev_info->num_hwfns = cdev->num_hwfns; 433fe56b9e6SYuval Mintz dev_info->pci_mem_start = cdev->pci_params.mem_start; 434fe56b9e6SYuval Mintz dev_info->pci_mem_end = cdev->pci_params.mem_end; 435fe56b9e6SYuval Mintz dev_info->pci_irq = cdev->pci_params.irq; 436c851a9dcSKalderon, Michal dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn); 4379c79ddaaSMintz, Yuval dev_info->dev_type = cdev->type; 438c851a9dcSKalderon, Michal ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr); 439fe56b9e6SYuval Mintz 4401408cc1fSYuval Mintz if (IS_PF(cdev)) { 441fe56b9e6SYuval Mintz dev_info->fw_major = FW_MAJOR_VERSION; 442fe56b9e6SYuval Mintz dev_info->fw_minor = FW_MINOR_VERSION; 443fe56b9e6SYuval Mintz dev_info->fw_rev = FW_REVISION_VERSION; 444fe56b9e6SYuval Mintz dev_info->fw_eng = FW_ENGINEERING_VERSION; 4450bc5fe85SSudarsana Reddy Kalluru dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH, 4460bc5fe85SSudarsana Reddy Kalluru &cdev->mf_bits); 4472d2fe843SDmitry Bogdanov if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits)) 4482d2fe843SDmitry Bogdanov dev_info->b_arfs_capable = true; 449831bfb0eSYuval Mintz dev_info->tx_switching = true; 45014d39648SMintz, Yuval 451c851a9dcSKalderon, Michal if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME) 45214d39648SMintz, Yuval dev_info->wol_support = true; 4533c5da942SMintz, Yuval 454df9c716dSSudarsana Reddy Kalluru dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn); 455df9c716dSSudarsana Reddy Kalluru 4563c5da942SMintz, Yuval dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; 4571408cc1fSYuval Mintz } else { 4581408cc1fSYuval Mintz qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, 4591408cc1fSYuval Mintz &dev_info->fw_minor, &dev_info->fw_rev, 4601408cc1fSYuval Mintz &dev_info->fw_eng); 4611408cc1fSYuval Mintz } 462fe56b9e6SYuval Mintz 4631408cc1fSYuval Mintz if (IS_PF(cdev)) { 464cee4d264SManish Chopra ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 465cee4d264SManish Chopra if (ptt) { 4661408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, 4671408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 4681408cc1fSYuval Mintz 469ae33666aSTomer Tayar qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, 470ae33666aSTomer Tayar &dev_info->mbi_version); 471ae33666aSTomer Tayar 472cee4d264SManish Chopra qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, 473cee4d264SManish Chopra &dev_info->flash_size); 474cee4d264SManish Chopra 475cee4d264SManish Chopra qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); 476cee4d264SManish Chopra } 4771408cc1fSYuval Mintz } else { 4781408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, 4791408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 4801408cc1fSYuval Mintz } 481cee4d264SManish Chopra 482c851a9dcSKalderon, Michal dev_info->mtu = hw_info->mtu; 48353916a67SIgor Russkikh cdev->common_dev_info = *dev_info; 4840fefbfbaSSudarsana Kalluru 485fe56b9e6SYuval Mintz return 0; 486fe56b9e6SYuval Mintz } 487fe56b9e6SYuval Mintz 488fe56b9e6SYuval Mintz static void qed_free_cdev(struct qed_dev *cdev) 489fe56b9e6SYuval Mintz { 490fe56b9e6SYuval Mintz kfree((void *)cdev); 491fe56b9e6SYuval Mintz } 492fe56b9e6SYuval Mintz 493fe56b9e6SYuval Mintz static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) 494fe56b9e6SYuval Mintz { 495fe56b9e6SYuval Mintz struct qed_dev *cdev; 496fe56b9e6SYuval Mintz 497fe56b9e6SYuval Mintz cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 498fe56b9e6SYuval Mintz if (!cdev) 499fe56b9e6SYuval Mintz return cdev; 500fe56b9e6SYuval Mintz 501fe56b9e6SYuval Mintz qed_init_struct(cdev); 502fe56b9e6SYuval Mintz 503fe56b9e6SYuval Mintz return cdev; 504fe56b9e6SYuval Mintz } 505fe56b9e6SYuval Mintz 506fe56b9e6SYuval Mintz /* Sets the requested power state */ 5071a635e48SYuval Mintz static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) 508fe56b9e6SYuval Mintz { 509fe56b9e6SYuval Mintz if (!cdev) 510fe56b9e6SYuval Mintz return -ENODEV; 511fe56b9e6SYuval Mintz 512fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); 513fe56b9e6SYuval Mintz return 0; 514fe56b9e6SYuval Mintz } 515fe56b9e6SYuval Mintz 516fe56b9e6SYuval Mintz /* probing */ 517fe56b9e6SYuval Mintz static struct qed_dev *qed_probe(struct pci_dev *pdev, 5181408cc1fSYuval Mintz struct qed_probe_params *params) 519fe56b9e6SYuval Mintz { 520fe56b9e6SYuval Mintz struct qed_dev *cdev; 521fe56b9e6SYuval Mintz int rc; 522fe56b9e6SYuval Mintz 523fe56b9e6SYuval Mintz cdev = qed_alloc_cdev(pdev); 524fe56b9e6SYuval Mintz if (!cdev) 525fe56b9e6SYuval Mintz goto err0; 526fe56b9e6SYuval Mintz 527712c3cbfSMintz, Yuval cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; 5281408cc1fSYuval Mintz cdev->protocol = params->protocol; 529fe56b9e6SYuval Mintz 5301408cc1fSYuval Mintz if (params->is_vf) 5311408cc1fSYuval Mintz cdev->b_is_vf = true; 5321408cc1fSYuval Mintz 5331408cc1fSYuval Mintz qed_init_dp(cdev, params->dp_module, params->dp_level); 534fe56b9e6SYuval Mintz 53564515dc8STomer Tayar cdev->recov_in_prog = params->recov_in_prog; 53664515dc8STomer Tayar 537fe56b9e6SYuval Mintz rc = qed_init_pci(cdev, pdev); 538fe56b9e6SYuval Mintz if (rc) { 539fe56b9e6SYuval Mintz DP_ERR(cdev, "init pci failed\n"); 540fe56b9e6SYuval Mintz goto err1; 541fe56b9e6SYuval Mintz } 542fe56b9e6SYuval Mintz DP_INFO(cdev, "PCI init completed successfully\n"); 543fe56b9e6SYuval Mintz 544fe56b9e6SYuval Mintz rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); 545fe56b9e6SYuval Mintz if (rc) { 546fe56b9e6SYuval Mintz DP_ERR(cdev, "hw prepare failed\n"); 547fe56b9e6SYuval Mintz goto err2; 548fe56b9e6SYuval Mintz } 549fe56b9e6SYuval Mintz 55020c4515aSEwan D. Milne DP_INFO(cdev, "qed_probe completed successfully\n"); 551fe56b9e6SYuval Mintz 552fe56b9e6SYuval Mintz return cdev; 553fe56b9e6SYuval Mintz 554fe56b9e6SYuval Mintz err2: 555fe56b9e6SYuval Mintz qed_free_pci(cdev); 556fe56b9e6SYuval Mintz err1: 557fe56b9e6SYuval Mintz qed_free_cdev(cdev); 558fe56b9e6SYuval Mintz err0: 559fe56b9e6SYuval Mintz return NULL; 560fe56b9e6SYuval Mintz } 561fe56b9e6SYuval Mintz 562fe56b9e6SYuval Mintz static void qed_remove(struct qed_dev *cdev) 563fe56b9e6SYuval Mintz { 564fe56b9e6SYuval Mintz if (!cdev) 565fe56b9e6SYuval Mintz return; 566fe56b9e6SYuval Mintz 567fe56b9e6SYuval Mintz qed_hw_remove(cdev); 568fe56b9e6SYuval Mintz 569fe56b9e6SYuval Mintz qed_free_pci(cdev); 570fe56b9e6SYuval Mintz 571fe56b9e6SYuval Mintz qed_set_power_state(cdev, PCI_D3hot); 572fe56b9e6SYuval Mintz 573fe56b9e6SYuval Mintz qed_free_cdev(cdev); 574fe56b9e6SYuval Mintz } 575fe56b9e6SYuval Mintz 576fe56b9e6SYuval Mintz static void qed_disable_msix(struct qed_dev *cdev) 577fe56b9e6SYuval Mintz { 578fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 579fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 580fe56b9e6SYuval Mintz kfree(cdev->int_params.msix_table); 581fe56b9e6SYuval Mintz } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { 582fe56b9e6SYuval Mintz pci_disable_msi(cdev->pdev); 583fe56b9e6SYuval Mintz } 584fe56b9e6SYuval Mintz 585fe56b9e6SYuval Mintz memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); 586fe56b9e6SYuval Mintz } 587fe56b9e6SYuval Mintz 588fe56b9e6SYuval Mintz static int qed_enable_msix(struct qed_dev *cdev, 589fe56b9e6SYuval Mintz struct qed_int_params *int_params) 590fe56b9e6SYuval Mintz { 591fe56b9e6SYuval Mintz int i, rc, cnt; 592fe56b9e6SYuval Mintz 593fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 594fe56b9e6SYuval Mintz 595fe56b9e6SYuval Mintz for (i = 0; i < cnt; i++) 596fe56b9e6SYuval Mintz int_params->msix_table[i].entry = i; 597fe56b9e6SYuval Mintz 598fe56b9e6SYuval Mintz rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, 599fe56b9e6SYuval Mintz int_params->in.min_msix_cnt, cnt); 600fe56b9e6SYuval Mintz if (rc < cnt && rc >= int_params->in.min_msix_cnt && 601fe56b9e6SYuval Mintz (rc % cdev->num_hwfns)) { 602fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 603fe56b9e6SYuval Mintz 604fe56b9e6SYuval Mintz /* If fastpath is initialized, we need at least one interrupt 605fe56b9e6SYuval Mintz * per hwfn [and the slow path interrupts]. New requested number 606fe56b9e6SYuval Mintz * should be a multiple of the number of hwfns. 607fe56b9e6SYuval Mintz */ 608fe56b9e6SYuval Mintz cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; 609fe56b9e6SYuval Mintz DP_NOTICE(cdev, 610fe56b9e6SYuval Mintz "Trying to enable MSI-X with less vectors (%d out of %d)\n", 611fe56b9e6SYuval Mintz cnt, int_params->in.num_vectors); 6121a635e48SYuval Mintz rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, 6131a635e48SYuval Mintz cnt); 614fe56b9e6SYuval Mintz if (!rc) 615fe56b9e6SYuval Mintz rc = cnt; 616fe56b9e6SYuval Mintz } 617fe56b9e6SYuval Mintz 618fe56b9e6SYuval Mintz if (rc > 0) { 619fe56b9e6SYuval Mintz /* MSI-x configuration was achieved */ 620fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSIX; 621fe56b9e6SYuval Mintz int_params->out.num_vectors = rc; 622fe56b9e6SYuval Mintz rc = 0; 623fe56b9e6SYuval Mintz } else { 624fe56b9e6SYuval Mintz DP_NOTICE(cdev, 625fe56b9e6SYuval Mintz "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", 626fe56b9e6SYuval Mintz cnt, rc); 627fe56b9e6SYuval Mintz } 628fe56b9e6SYuval Mintz 629fe56b9e6SYuval Mintz return rc; 630fe56b9e6SYuval Mintz } 631fe56b9e6SYuval Mintz 632fe56b9e6SYuval Mintz /* This function outputs the int mode and the number of enabled msix vector */ 633fe56b9e6SYuval Mintz static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) 634fe56b9e6SYuval Mintz { 635fe56b9e6SYuval Mintz struct qed_int_params *int_params = &cdev->int_params; 636fe56b9e6SYuval Mintz struct msix_entry *tbl; 637fe56b9e6SYuval Mintz int rc = 0, cnt; 638fe56b9e6SYuval Mintz 639fe56b9e6SYuval Mintz switch (int_params->in.int_mode) { 640fe56b9e6SYuval Mintz case QED_INT_MODE_MSIX: 641fe56b9e6SYuval Mintz /* Allocate MSIX table */ 642fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 643fe56b9e6SYuval Mintz int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); 644fe56b9e6SYuval Mintz if (!int_params->msix_table) { 645fe56b9e6SYuval Mintz rc = -ENOMEM; 646fe56b9e6SYuval Mintz goto out; 647fe56b9e6SYuval Mintz } 648fe56b9e6SYuval Mintz 649fe56b9e6SYuval Mintz /* Enable MSIX */ 650fe56b9e6SYuval Mintz rc = qed_enable_msix(cdev, int_params); 651fe56b9e6SYuval Mintz if (!rc) 652fe56b9e6SYuval Mintz goto out; 653fe56b9e6SYuval Mintz 654fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI-X\n"); 655fe56b9e6SYuval Mintz kfree(int_params->msix_table); 656fe56b9e6SYuval Mintz if (force_mode) 657fe56b9e6SYuval Mintz goto out; 658df561f66SGustavo A. R. Silva fallthrough; 659fe56b9e6SYuval Mintz 660fe56b9e6SYuval Mintz case QED_INT_MODE_MSI: 661bb13ace7SSudarsana Reddy Kalluru if (cdev->num_hwfns == 1) { 662fe56b9e6SYuval Mintz rc = pci_enable_msi(cdev->pdev); 663fe56b9e6SYuval Mintz if (!rc) { 664fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSI; 665fe56b9e6SYuval Mintz goto out; 666fe56b9e6SYuval Mintz } 667fe56b9e6SYuval Mintz 668fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI\n"); 669fe56b9e6SYuval Mintz if (force_mode) 670fe56b9e6SYuval Mintz goto out; 671bb13ace7SSudarsana Reddy Kalluru } 672df561f66SGustavo A. R. Silva fallthrough; 673fe56b9e6SYuval Mintz 674fe56b9e6SYuval Mintz case QED_INT_MODE_INTA: 675fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_INTA; 676fe56b9e6SYuval Mintz rc = 0; 677fe56b9e6SYuval Mintz goto out; 678fe56b9e6SYuval Mintz default: 679fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Unknown int_mode value %d\n", 680fe56b9e6SYuval Mintz int_params->in.int_mode); 681fe56b9e6SYuval Mintz rc = -EINVAL; 682fe56b9e6SYuval Mintz } 683fe56b9e6SYuval Mintz 684fe56b9e6SYuval Mintz out: 685525ef5c0SYuval Mintz if (!rc) 686525ef5c0SYuval Mintz DP_INFO(cdev, "Using %s interrupts\n", 687525ef5c0SYuval Mintz int_params->out.int_mode == QED_INT_MODE_INTA ? 688525ef5c0SYuval Mintz "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? 689525ef5c0SYuval Mintz "MSI" : "MSIX"); 690fe56b9e6SYuval Mintz cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; 691fe56b9e6SYuval Mintz 692fe56b9e6SYuval Mintz return rc; 693fe56b9e6SYuval Mintz } 694fe56b9e6SYuval Mintz 695fe56b9e6SYuval Mintz static void qed_simd_handler_config(struct qed_dev *cdev, void *token, 696fe56b9e6SYuval Mintz int index, void(*handler)(void *)) 697fe56b9e6SYuval Mintz { 698fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 699fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 700fe56b9e6SYuval Mintz 701fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].func = handler; 702fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].token = token; 703fe56b9e6SYuval Mintz } 704fe56b9e6SYuval Mintz 705fe56b9e6SYuval Mintz static void qed_simd_handler_clean(struct qed_dev *cdev, int index) 706fe56b9e6SYuval Mintz { 707fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 708fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 709fe56b9e6SYuval Mintz 710fe56b9e6SYuval Mintz memset(&hwfn->simd_proto_handler[relative_idx], 0, 711fe56b9e6SYuval Mintz sizeof(struct qed_simd_fp_handler)); 712fe56b9e6SYuval Mintz } 713fe56b9e6SYuval Mintz 714fe56b9e6SYuval Mintz static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) 715fe56b9e6SYuval Mintz { 716fe56b9e6SYuval Mintz tasklet_schedule((struct tasklet_struct *)tasklet); 717fe56b9e6SYuval Mintz return IRQ_HANDLED; 718fe56b9e6SYuval Mintz } 719fe56b9e6SYuval Mintz 720fe56b9e6SYuval Mintz static irqreturn_t qed_single_int(int irq, void *dev_instance) 721fe56b9e6SYuval Mintz { 722fe56b9e6SYuval Mintz struct qed_dev *cdev = (struct qed_dev *)dev_instance; 723fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 724fe56b9e6SYuval Mintz irqreturn_t rc = IRQ_NONE; 725fe56b9e6SYuval Mintz u64 status; 726fe56b9e6SYuval Mintz int i, j; 727fe56b9e6SYuval Mintz 728fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 729fe56b9e6SYuval Mintz status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); 730fe56b9e6SYuval Mintz 731fe56b9e6SYuval Mintz if (!status) 732fe56b9e6SYuval Mintz continue; 733fe56b9e6SYuval Mintz 734fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 735fe56b9e6SYuval Mintz 736fe56b9e6SYuval Mintz /* Slowpath interrupt */ 737fe56b9e6SYuval Mintz if (unlikely(status & 0x1)) { 738b5f0a3bfSAllen Pais tasklet_schedule(&hwfn->sp_dpc); 739fe56b9e6SYuval Mintz status &= ~0x1; 740fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 741fe56b9e6SYuval Mintz } 742fe56b9e6SYuval Mintz 743fe56b9e6SYuval Mintz /* Fastpath interrupts */ 744fe56b9e6SYuval Mintz for (j = 0; j < 64; j++) { 745fe56b9e6SYuval Mintz if ((0x2ULL << j) & status) { 7463935a709SSudarsana Reddy Kalluru struct qed_simd_fp_handler *p_handler = 7473935a709SSudarsana Reddy Kalluru &hwfn->simd_proto_handler[j]; 7483935a709SSudarsana Reddy Kalluru 7493935a709SSudarsana Reddy Kalluru if (p_handler->func) 7503935a709SSudarsana Reddy Kalluru p_handler->func(p_handler->token); 7513935a709SSudarsana Reddy Kalluru else 7523935a709SSudarsana Reddy Kalluru DP_NOTICE(hwfn, 7533935a709SSudarsana Reddy Kalluru "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n", 7543935a709SSudarsana Reddy Kalluru j, status); 7553935a709SSudarsana Reddy Kalluru 756fe56b9e6SYuval Mintz status &= ~(0x2ULL << j); 757fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 758fe56b9e6SYuval Mintz } 759fe56b9e6SYuval Mintz } 760fe56b9e6SYuval Mintz 761fe56b9e6SYuval Mintz if (unlikely(status)) 762fe56b9e6SYuval Mintz DP_VERBOSE(hwfn, NETIF_MSG_INTR, 763fe56b9e6SYuval Mintz "got an unknown interrupt status 0x%llx\n", 764fe56b9e6SYuval Mintz status); 765fe56b9e6SYuval Mintz } 766fe56b9e6SYuval Mintz 767fe56b9e6SYuval Mintz return rc; 768fe56b9e6SYuval Mintz } 769fe56b9e6SYuval Mintz 7708f16bc97SSudarsana Kalluru int qed_slowpath_irq_req(struct qed_hwfn *hwfn) 771fe56b9e6SYuval Mintz { 7728f16bc97SSudarsana Kalluru struct qed_dev *cdev = hwfn->cdev; 773525ef5c0SYuval Mintz u32 int_mode; 7748f16bc97SSudarsana Kalluru int rc = 0; 7758f16bc97SSudarsana Kalluru u8 id; 776fe56b9e6SYuval Mintz 777525ef5c0SYuval Mintz int_mode = cdev->int_params.out.int_mode; 778525ef5c0SYuval Mintz if (int_mode == QED_INT_MODE_MSIX) { 7798f16bc97SSudarsana Kalluru id = hwfn->my_id; 7808f16bc97SSudarsana Kalluru snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", 7818f16bc97SSudarsana Kalluru id, cdev->pdev->bus->number, 7828f16bc97SSudarsana Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 7838f16bc97SSudarsana Kalluru rc = request_irq(cdev->int_params.msix_table[id].vector, 784b5f0a3bfSAllen Pais qed_msix_sp_int, 0, hwfn->name, &hwfn->sp_dpc); 785fe56b9e6SYuval Mintz } else { 786fe56b9e6SYuval Mintz unsigned long flags = 0; 787fe56b9e6SYuval Mintz 788fe56b9e6SYuval Mintz snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", 789fe56b9e6SYuval Mintz cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), 790fe56b9e6SYuval Mintz PCI_FUNC(cdev->pdev->devfn)); 791fe56b9e6SYuval Mintz 792fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) 793fe56b9e6SYuval Mintz flags |= IRQF_SHARED; 794fe56b9e6SYuval Mintz 795fe56b9e6SYuval Mintz rc = request_irq(cdev->pdev->irq, qed_single_int, 796fe56b9e6SYuval Mintz flags, cdev->name, cdev); 797fe56b9e6SYuval Mintz } 798fe56b9e6SYuval Mintz 799525ef5c0SYuval Mintz if (rc) 800525ef5c0SYuval Mintz DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); 801525ef5c0SYuval Mintz else 802525ef5c0SYuval Mintz DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), 803525ef5c0SYuval Mintz "Requested slowpath %s\n", 804525ef5c0SYuval Mintz (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); 805525ef5c0SYuval Mintz 806fe56b9e6SYuval Mintz return rc; 807fe56b9e6SYuval Mintz } 808fe56b9e6SYuval Mintz 80906892f2eSTomer Tayar static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) 81006892f2eSTomer Tayar { 81106892f2eSTomer Tayar /* Calling the disable function will make sure that any 81206892f2eSTomer Tayar * currently-running function is completed. The following call to the 81306892f2eSTomer Tayar * enable function makes this sequence a flush-like operation. 81406892f2eSTomer Tayar */ 81506892f2eSTomer Tayar if (p_hwfn->b_sp_dpc_enabled) { 816b5f0a3bfSAllen Pais tasklet_disable(&p_hwfn->sp_dpc); 817b5f0a3bfSAllen Pais tasklet_enable(&p_hwfn->sp_dpc); 81806892f2eSTomer Tayar } 81906892f2eSTomer Tayar } 82006892f2eSTomer Tayar 8211226337aSTomer Tayar void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) 8221226337aSTomer Tayar { 8231226337aSTomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 8241226337aSTomer Tayar u8 id = p_hwfn->my_id; 8251226337aSTomer Tayar u32 int_mode; 8261226337aSTomer Tayar 8271226337aSTomer Tayar int_mode = cdev->int_params.out.int_mode; 8281226337aSTomer Tayar if (int_mode == QED_INT_MODE_MSIX) 8291226337aSTomer Tayar synchronize_irq(cdev->int_params.msix_table[id].vector); 8301226337aSTomer Tayar else 8311226337aSTomer Tayar synchronize_irq(cdev->pdev->irq); 83206892f2eSTomer Tayar 83306892f2eSTomer Tayar qed_slowpath_tasklet_flush(p_hwfn); 8341226337aSTomer Tayar } 8351226337aSTomer Tayar 836fe56b9e6SYuval Mintz static void qed_slowpath_irq_free(struct qed_dev *cdev) 837fe56b9e6SYuval Mintz { 838fe56b9e6SYuval Mintz int i; 839fe56b9e6SYuval Mintz 840fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 841fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 8428f16bc97SSudarsana Kalluru if (!cdev->hwfns[i].b_int_requested) 8438f16bc97SSudarsana Kalluru break; 844fe56b9e6SYuval Mintz synchronize_irq(cdev->int_params.msix_table[i].vector); 845fe56b9e6SYuval Mintz free_irq(cdev->int_params.msix_table[i].vector, 846b5f0a3bfSAllen Pais &cdev->hwfns[i].sp_dpc); 847fe56b9e6SYuval Mintz } 848fe56b9e6SYuval Mintz } else { 8498f16bc97SSudarsana Kalluru if (QED_LEADING_HWFN(cdev)->b_int_requested) 850fe56b9e6SYuval Mintz free_irq(cdev->pdev->irq, cdev); 851fe56b9e6SYuval Mintz } 8528f16bc97SSudarsana Kalluru qed_int_disable_post_isr_release(cdev); 853fe56b9e6SYuval Mintz } 854fe56b9e6SYuval Mintz 855fe56b9e6SYuval Mintz static int qed_nic_stop(struct qed_dev *cdev) 856fe56b9e6SYuval Mintz { 857fe56b9e6SYuval Mintz int i, rc; 858fe56b9e6SYuval Mintz 859fe56b9e6SYuval Mintz rc = qed_hw_stop(cdev); 860fe56b9e6SYuval Mintz 861fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 862fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 863fe56b9e6SYuval Mintz 864fe56b9e6SYuval Mintz if (p_hwfn->b_sp_dpc_enabled) { 865b5f0a3bfSAllen Pais tasklet_disable(&p_hwfn->sp_dpc); 866fe56b9e6SYuval Mintz p_hwfn->b_sp_dpc_enabled = false; 867fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, 8682fdae034SColin Ian King "Disabled sp tasklet [hwfn %d] at %p\n", 869b5f0a3bfSAllen Pais i, &p_hwfn->sp_dpc); 870fe56b9e6SYuval Mintz } 871fe56b9e6SYuval Mintz } 872fe56b9e6SYuval Mintz 873c965db44STomer Tayar qed_dbg_pf_exit(cdev); 874c965db44STomer Tayar 875fe56b9e6SYuval Mintz return rc; 876fe56b9e6SYuval Mintz } 877fe56b9e6SYuval Mintz 878fe56b9e6SYuval Mintz static int qed_nic_setup(struct qed_dev *cdev) 879fe56b9e6SYuval Mintz { 8800a7fb11cSYuval Mintz int rc, i; 8810a7fb11cSYuval Mintz 8820a7fb11cSYuval Mintz /* Determine if interface is going to require LL2 */ 8830a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) { 8840a7fb11cSYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 8850a7fb11cSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 8860a7fb11cSYuval Mintz 8870a7fb11cSYuval Mintz p_hwfn->using_ll2 = true; 8880a7fb11cSYuval Mintz } 8890a7fb11cSYuval Mintz } 890fe56b9e6SYuval Mintz 891fe56b9e6SYuval Mintz rc = qed_resc_alloc(cdev); 892fe56b9e6SYuval Mintz if (rc) 893fe56b9e6SYuval Mintz return rc; 894fe56b9e6SYuval Mintz 895fe56b9e6SYuval Mintz DP_INFO(cdev, "Allocated qed resources\n"); 896fe56b9e6SYuval Mintz 897fe56b9e6SYuval Mintz qed_resc_setup(cdev); 898fe56b9e6SYuval Mintz 899fe56b9e6SYuval Mintz return rc; 900fe56b9e6SYuval Mintz } 901fe56b9e6SYuval Mintz 902fe56b9e6SYuval Mintz static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) 903fe56b9e6SYuval Mintz { 904fe56b9e6SYuval Mintz int limit = 0; 905fe56b9e6SYuval Mintz 906fe56b9e6SYuval Mintz /* Mark the fastpath as free/used */ 907fe56b9e6SYuval Mintz cdev->int_params.fp_initialized = cnt ? true : false; 908fe56b9e6SYuval Mintz 909fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) 910fe56b9e6SYuval Mintz limit = cdev->num_hwfns * 63; 911fe56b9e6SYuval Mintz else if (cdev->int_params.fp_msix_cnt) 912fe56b9e6SYuval Mintz limit = cdev->int_params.fp_msix_cnt; 913fe56b9e6SYuval Mintz 914fe56b9e6SYuval Mintz if (!limit) 915fe56b9e6SYuval Mintz return -ENOMEM; 916fe56b9e6SYuval Mintz 917fe56b9e6SYuval Mintz return min_t(int, cnt, limit); 918fe56b9e6SYuval Mintz } 919fe56b9e6SYuval Mintz 920fe56b9e6SYuval Mintz static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) 921fe56b9e6SYuval Mintz { 922fe56b9e6SYuval Mintz memset(info, 0, sizeof(struct qed_int_info)); 923fe56b9e6SYuval Mintz 924fe56b9e6SYuval Mintz if (!cdev->int_params.fp_initialized) { 925fe56b9e6SYuval Mintz DP_INFO(cdev, 926fe56b9e6SYuval Mintz "Protocol driver requested interrupt information, but its support is not yet configured\n"); 927fe56b9e6SYuval Mintz return -EINVAL; 928fe56b9e6SYuval Mintz } 929fe56b9e6SYuval Mintz 930fe56b9e6SYuval Mintz /* Need to expose only MSI-X information; Single IRQ is handled solely 931fe56b9e6SYuval Mintz * by qed. 932fe56b9e6SYuval Mintz */ 933fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 934fe56b9e6SYuval Mintz int msix_base = cdev->int_params.fp_msix_base; 935fe56b9e6SYuval Mintz 936fe56b9e6SYuval Mintz info->msix_cnt = cdev->int_params.fp_msix_cnt; 937fe56b9e6SYuval Mintz info->msix = &cdev->int_params.msix_table[msix_base]; 938fe56b9e6SYuval Mintz } 939fe56b9e6SYuval Mintz 940fe56b9e6SYuval Mintz return 0; 941fe56b9e6SYuval Mintz } 942fe56b9e6SYuval Mintz 943fe56b9e6SYuval Mintz static int qed_slowpath_setup_int(struct qed_dev *cdev, 944fe56b9e6SYuval Mintz enum qed_int_mode int_mode) 945fe56b9e6SYuval Mintz { 9464ac801b7SYuval Mintz struct qed_sb_cnt_info sb_cnt_info; 9470189efb8SYuval Mintz int num_l2_queues = 0; 9484ac801b7SYuval Mintz int rc; 9494ac801b7SYuval Mintz int i; 950fe56b9e6SYuval Mintz 9511d2c2024SSudarsana Reddy Kalluru if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { 9521d2c2024SSudarsana Reddy Kalluru DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); 9531d2c2024SSudarsana Reddy Kalluru return -EINVAL; 9541d2c2024SSudarsana Reddy Kalluru } 9551d2c2024SSudarsana Reddy Kalluru 9561d2c2024SSudarsana Reddy Kalluru memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 957fe56b9e6SYuval Mintz cdev->int_params.in.int_mode = int_mode; 9584ac801b7SYuval Mintz for_each_hwfn(cdev, i) { 9594ac801b7SYuval Mintz memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); 9604ac801b7SYuval Mintz qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); 961726fdbe9SMintz, Yuval cdev->int_params.in.num_vectors += sb_cnt_info.cnt; 9624ac801b7SYuval Mintz cdev->int_params.in.num_vectors++; /* slowpath */ 9634ac801b7SYuval Mintz } 964fe56b9e6SYuval Mintz 965fe56b9e6SYuval Mintz /* We want a minimum of one slowpath and one fastpath vector per hwfn */ 966fe56b9e6SYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; 967fe56b9e6SYuval Mintz 968bb7858baSSudarsana Reddy Kalluru if (is_kdump_kernel()) { 969bb7858baSSudarsana Reddy Kalluru DP_INFO(cdev, 970bb7858baSSudarsana Reddy Kalluru "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", 971bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt); 972bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.num_vectors = 973bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt; 974bb7858baSSudarsana Reddy Kalluru } 975bb7858baSSudarsana Reddy Kalluru 976fe56b9e6SYuval Mintz rc = qed_set_int_mode(cdev, false); 977fe56b9e6SYuval Mintz if (rc) { 978fe56b9e6SYuval Mintz DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); 979fe56b9e6SYuval Mintz return rc; 980fe56b9e6SYuval Mintz } 981fe56b9e6SYuval Mintz 982fe56b9e6SYuval Mintz cdev->int_params.fp_msix_base = cdev->num_hwfns; 983fe56b9e6SYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - 984fe56b9e6SYuval Mintz cdev->num_hwfns; 985fe56b9e6SYuval Mintz 9862f782278SMintz, Yuval if (!IS_ENABLED(CONFIG_QED_RDMA) || 987c851a9dcSKalderon, Michal !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) 9880189efb8SYuval Mintz return 0; 9890189efb8SYuval Mintz 99051ff1725SRam Amrani for_each_hwfn(cdev, i) 99151ff1725SRam Amrani num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); 99251ff1725SRam Amrani 99351ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, 99451ff1725SRam Amrani "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n", 99551ff1725SRam Amrani cdev->int_params.fp_msix_cnt, num_l2_queues); 99651ff1725SRam Amrani 99751ff1725SRam Amrani if (cdev->int_params.fp_msix_cnt > num_l2_queues) { 99851ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 99951ff1725SRam Amrani (cdev->int_params.fp_msix_cnt - num_l2_queues) 100051ff1725SRam Amrani / cdev->num_hwfns; 100151ff1725SRam Amrani cdev->int_params.rdma_msix_base = 100251ff1725SRam Amrani cdev->int_params.fp_msix_base + num_l2_queues; 100351ff1725SRam Amrani cdev->int_params.fp_msix_cnt = num_l2_queues; 100451ff1725SRam Amrani } else { 100551ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 0; 100651ff1725SRam Amrani } 100751ff1725SRam Amrani 100851ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", 100951ff1725SRam Amrani cdev->int_params.rdma_msix_cnt, 101051ff1725SRam Amrani cdev->int_params.rdma_msix_base); 101151ff1725SRam Amrani 1012fe56b9e6SYuval Mintz return 0; 1013fe56b9e6SYuval Mintz } 1014fe56b9e6SYuval Mintz 10151408cc1fSYuval Mintz static int qed_slowpath_vf_setup_int(struct qed_dev *cdev) 10161408cc1fSYuval Mintz { 10171408cc1fSYuval Mintz int rc; 10181408cc1fSYuval Mintz 10191408cc1fSYuval Mintz memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 10201408cc1fSYuval Mintz cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; 10211408cc1fSYuval Mintz 10221408cc1fSYuval Mintz qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), 10231408cc1fSYuval Mintz &cdev->int_params.in.num_vectors); 10241408cc1fSYuval Mintz if (cdev->num_hwfns > 1) { 10251408cc1fSYuval Mintz u8 vectors = 0; 10261408cc1fSYuval Mintz 10271408cc1fSYuval Mintz qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); 10281408cc1fSYuval Mintz cdev->int_params.in.num_vectors += vectors; 10291408cc1fSYuval Mintz } 10301408cc1fSYuval Mintz 10311408cc1fSYuval Mintz /* We want a minimum of one fastpath vector per vf hwfn */ 10321408cc1fSYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; 10331408cc1fSYuval Mintz 10341408cc1fSYuval Mintz rc = qed_set_int_mode(cdev, true); 10351408cc1fSYuval Mintz if (rc) 10361408cc1fSYuval Mintz return rc; 10371408cc1fSYuval Mintz 10381408cc1fSYuval Mintz cdev->int_params.fp_msix_base = 0; 10391408cc1fSYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; 10401408cc1fSYuval Mintz 10411408cc1fSYuval Mintz return 0; 10421408cc1fSYuval Mintz } 10431408cc1fSYuval Mintz 1044fe56b9e6SYuval Mintz u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, 1045fe56b9e6SYuval Mintz u8 *input_buf, u32 max_size, u8 *unzip_buf) 1046fe56b9e6SYuval Mintz { 1047fe56b9e6SYuval Mintz int rc; 1048fe56b9e6SYuval Mintz 1049fe56b9e6SYuval Mintz p_hwfn->stream->next_in = input_buf; 1050fe56b9e6SYuval Mintz p_hwfn->stream->avail_in = input_len; 1051fe56b9e6SYuval Mintz p_hwfn->stream->next_out = unzip_buf; 1052fe56b9e6SYuval Mintz p_hwfn->stream->avail_out = max_size; 1053fe56b9e6SYuval Mintz 1054fe56b9e6SYuval Mintz rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); 1055fe56b9e6SYuval Mintz 1056fe56b9e6SYuval Mintz if (rc != Z_OK) { 1057fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", 1058fe56b9e6SYuval Mintz rc); 1059fe56b9e6SYuval Mintz return 0; 1060fe56b9e6SYuval Mintz } 1061fe56b9e6SYuval Mintz 1062fe56b9e6SYuval Mintz rc = zlib_inflate(p_hwfn->stream, Z_FINISH); 1063fe56b9e6SYuval Mintz zlib_inflateEnd(p_hwfn->stream); 1064fe56b9e6SYuval Mintz 1065fe56b9e6SYuval Mintz if (rc != Z_OK && rc != Z_STREAM_END) { 1066fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", 1067fe56b9e6SYuval Mintz p_hwfn->stream->msg, rc); 1068fe56b9e6SYuval Mintz return 0; 1069fe56b9e6SYuval Mintz } 1070fe56b9e6SYuval Mintz 1071fe56b9e6SYuval Mintz return p_hwfn->stream->total_out / 4; 1072fe56b9e6SYuval Mintz } 1073fe56b9e6SYuval Mintz 1074fe56b9e6SYuval Mintz static int qed_alloc_stream_mem(struct qed_dev *cdev) 1075fe56b9e6SYuval Mintz { 1076fe56b9e6SYuval Mintz int i; 1077fe56b9e6SYuval Mintz void *workspace; 1078fe56b9e6SYuval Mintz 1079fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1080fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 1081fe56b9e6SYuval Mintz 1082fe56b9e6SYuval Mintz p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); 1083fe56b9e6SYuval Mintz if (!p_hwfn->stream) 1084fe56b9e6SYuval Mintz return -ENOMEM; 1085fe56b9e6SYuval Mintz 1086fe56b9e6SYuval Mintz workspace = vzalloc(zlib_inflate_workspacesize()); 1087fe56b9e6SYuval Mintz if (!workspace) 1088fe56b9e6SYuval Mintz return -ENOMEM; 1089fe56b9e6SYuval Mintz p_hwfn->stream->workspace = workspace; 1090fe56b9e6SYuval Mintz } 1091fe56b9e6SYuval Mintz 1092fe56b9e6SYuval Mintz return 0; 1093fe56b9e6SYuval Mintz } 1094fe56b9e6SYuval Mintz 1095fe56b9e6SYuval Mintz static void qed_free_stream_mem(struct qed_dev *cdev) 1096fe56b9e6SYuval Mintz { 1097fe56b9e6SYuval Mintz int i; 1098fe56b9e6SYuval Mintz 1099fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1100fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 1101fe56b9e6SYuval Mintz 1102fe56b9e6SYuval Mintz if (!p_hwfn->stream) 1103fe56b9e6SYuval Mintz return; 1104fe56b9e6SYuval Mintz 1105fe56b9e6SYuval Mintz vfree(p_hwfn->stream->workspace); 1106fe56b9e6SYuval Mintz kfree(p_hwfn->stream); 1107fe56b9e6SYuval Mintz } 1108fe56b9e6SYuval Mintz } 1109fe56b9e6SYuval Mintz 1110fe56b9e6SYuval Mintz static void qed_update_pf_params(struct qed_dev *cdev, 1111fe56b9e6SYuval Mintz struct qed_pf_params *params) 1112fe56b9e6SYuval Mintz { 1113fe56b9e6SYuval Mintz int i; 1114fe56b9e6SYuval Mintz 11155c5f2609SRam Amrani if (IS_ENABLED(CONFIG_QED_RDMA)) { 11160189efb8SYuval Mintz params->rdma_pf_params.num_qps = QED_ROCE_QPS; 11170189efb8SYuval Mintz params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; 111839dbc646SYuval Bason params->rdma_pf_params.num_srqs = QED_RDMA_SRQS; 11190189efb8SYuval Mintz /* divide by 3 the MRs to avoid MF ILT overflow */ 11200189efb8SYuval Mintz params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; 1121fe56b9e6SYuval Mintz } 1122fe56b9e6SYuval Mintz 1123d51e4af5SChopra, Manish if (cdev->num_hwfns > 1 || IS_VF(cdev)) 1124d51e4af5SChopra, Manish params->eth_pf_params.num_arfs_filters = 0; 1125d51e4af5SChopra, Manish 1126e1d32acbSMintz, Yuval /* In case we might support RDMA, don't allow qede to be greedy 11275e7baf0fSManish Chopra * with the L2 contexts. Allow for 64 queues [rx, tx cos, xdp] 11285e7baf0fSManish Chopra * per hwfn. 1129e1d32acbSMintz, Yuval */ 1130c851a9dcSKalderon, Michal if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) { 1131e1d32acbSMintz, Yuval u16 *num_cons; 1132e1d32acbSMintz, Yuval 1133e1d32acbSMintz, Yuval num_cons = ¶ms->eth_pf_params.num_cons; 11345e7baf0fSManish Chopra *num_cons = min_t(u16, *num_cons, QED_MAX_L2_CONS); 1135e1d32acbSMintz, Yuval } 1136e1d32acbSMintz, Yuval 11375c5f2609SRam Amrani for (i = 0; i < cdev->num_hwfns; i++) { 11385c5f2609SRam Amrani struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 11395c5f2609SRam Amrani 11405c5f2609SRam Amrani p_hwfn->pf_params = *params; 11415c5f2609SRam Amrani } 11425c5f2609SRam Amrani } 11435c5f2609SRam Amrani 1144d4476b8aSDenis Bolotin #define QED_PERIODIC_DB_REC_COUNT 10 1145a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL_MS 100 1146a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL \ 1147a1b469b8SAriel Elior msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS) 1148a1b469b8SAriel Elior 1149a1b469b8SAriel Elior static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn, 1150a1b469b8SAriel Elior enum qed_slowpath_wq_flag wq_flag, 1151a1b469b8SAriel Elior unsigned long delay) 1152a1b469b8SAriel Elior { 1153a1b469b8SAriel Elior if (!hwfn->slowpath_wq_active) 1154a1b469b8SAriel Elior return -EINVAL; 1155a1b469b8SAriel Elior 1156a1b469b8SAriel Elior /* Memory barrier for setting atomic bit */ 1157a1b469b8SAriel Elior smp_mb__before_atomic(); 1158a1b469b8SAriel Elior set_bit(wq_flag, &hwfn->slowpath_task_flags); 1159a1b469b8SAriel Elior smp_mb__after_atomic(); 1160a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay); 1161a1b469b8SAriel Elior 1162a1b469b8SAriel Elior return 0; 1163a1b469b8SAriel Elior } 1164a1b469b8SAriel Elior 1165a1b469b8SAriel Elior void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn) 1166a1b469b8SAriel Elior { 1167a1b469b8SAriel Elior /* Reset periodic Doorbell Recovery counter */ 1168a1b469b8SAriel Elior p_hwfn->periodic_db_rec_count = QED_PERIODIC_DB_REC_COUNT; 1169a1b469b8SAriel Elior 1170a1b469b8SAriel Elior /* Don't schedule periodic Doorbell Recovery if already scheduled */ 1171a1b469b8SAriel Elior if (test_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1172a1b469b8SAriel Elior &p_hwfn->slowpath_task_flags)) 1173a1b469b8SAriel Elior return; 1174a1b469b8SAriel Elior 1175a1b469b8SAriel Elior qed_slowpath_delayed_work(p_hwfn, QED_SLOWPATH_PERIODIC_DB_REC, 1176a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1177a1b469b8SAriel Elior } 1178a1b469b8SAriel Elior 117959ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_wq_stop(struct qed_dev *cdev) 118059ccf86fSSudarsana Reddy Kalluru { 11813b85720dSYuval Basson int i; 118259ccf86fSSudarsana Reddy Kalluru 118359ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 118459ccf86fSSudarsana Reddy Kalluru return; 118559ccf86fSSudarsana Reddy Kalluru 118659ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 118759ccf86fSSudarsana Reddy Kalluru if (!cdev->hwfns[i].slowpath_wq) 118859ccf86fSSudarsana Reddy Kalluru continue; 118959ccf86fSSudarsana Reddy Kalluru 1190a1b469b8SAriel Elior /* Stop queuing new delayed works */ 1191a1b469b8SAriel Elior cdev->hwfns[i].slowpath_wq_active = false; 1192a1b469b8SAriel Elior 11933b85720dSYuval Basson cancel_delayed_work(&cdev->hwfns[i].slowpath_task); 119459ccf86fSSudarsana Reddy Kalluru destroy_workqueue(cdev->hwfns[i].slowpath_wq); 119559ccf86fSSudarsana Reddy Kalluru } 119659ccf86fSSudarsana Reddy Kalluru } 119759ccf86fSSudarsana Reddy Kalluru 119859ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_task(struct work_struct *work) 119959ccf86fSSudarsana Reddy Kalluru { 120059ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 120159ccf86fSSudarsana Reddy Kalluru slowpath_task.work); 120259ccf86fSSudarsana Reddy Kalluru struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 120359ccf86fSSudarsana Reddy Kalluru 120459ccf86fSSudarsana Reddy Kalluru if (!ptt) { 1205a1b469b8SAriel Elior if (hwfn->slowpath_wq_active) 1206a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, 1207a1b469b8SAriel Elior &hwfn->slowpath_task, 0); 1208a1b469b8SAriel Elior 120959ccf86fSSudarsana Reddy Kalluru return; 121059ccf86fSSudarsana Reddy Kalluru } 121159ccf86fSSudarsana Reddy Kalluru 121259ccf86fSSudarsana Reddy Kalluru if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ, 121359ccf86fSSudarsana Reddy Kalluru &hwfn->slowpath_task_flags)) 121459ccf86fSSudarsana Reddy Kalluru qed_mfw_process_tlv_req(hwfn, ptt); 121559ccf86fSSudarsana Reddy Kalluru 1216a1b469b8SAriel Elior if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1217a1b469b8SAriel Elior &hwfn->slowpath_task_flags)) { 1218a1b469b8SAriel Elior qed_db_rec_handler(hwfn, ptt); 1219a1b469b8SAriel Elior if (hwfn->periodic_db_rec_count--) 1220a1b469b8SAriel Elior qed_slowpath_delayed_work(hwfn, 1221a1b469b8SAriel Elior QED_SLOWPATH_PERIODIC_DB_REC, 1222a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1223a1b469b8SAriel Elior } 1224a1b469b8SAriel Elior 122559ccf86fSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 122659ccf86fSSudarsana Reddy Kalluru } 122759ccf86fSSudarsana Reddy Kalluru 122859ccf86fSSudarsana Reddy Kalluru static int qed_slowpath_wq_start(struct qed_dev *cdev) 122959ccf86fSSudarsana Reddy Kalluru { 123059ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn; 123159ccf86fSSudarsana Reddy Kalluru char name[NAME_SIZE]; 123259ccf86fSSudarsana Reddy Kalluru int i; 123359ccf86fSSudarsana Reddy Kalluru 123459ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 123559ccf86fSSudarsana Reddy Kalluru return 0; 123659ccf86fSSudarsana Reddy Kalluru 123759ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 123859ccf86fSSudarsana Reddy Kalluru hwfn = &cdev->hwfns[i]; 123959ccf86fSSudarsana Reddy Kalluru 124059ccf86fSSudarsana Reddy Kalluru snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", 124159ccf86fSSudarsana Reddy Kalluru cdev->pdev->bus->number, 124259ccf86fSSudarsana Reddy Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 124359ccf86fSSudarsana Reddy Kalluru 124459ccf86fSSudarsana Reddy Kalluru hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); 124559ccf86fSSudarsana Reddy Kalluru if (!hwfn->slowpath_wq) { 124659ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); 124759ccf86fSSudarsana Reddy Kalluru return -ENOMEM; 124859ccf86fSSudarsana Reddy Kalluru } 124959ccf86fSSudarsana Reddy Kalluru 125059ccf86fSSudarsana Reddy Kalluru INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task); 1251a1b469b8SAriel Elior hwfn->slowpath_wq_active = true; 125259ccf86fSSudarsana Reddy Kalluru } 125359ccf86fSSudarsana Reddy Kalluru 125459ccf86fSSudarsana Reddy Kalluru return 0; 125559ccf86fSSudarsana Reddy Kalluru } 125659ccf86fSSudarsana Reddy Kalluru 1257fe56b9e6SYuval Mintz static int qed_slowpath_start(struct qed_dev *cdev, 1258fe56b9e6SYuval Mintz struct qed_slowpath_params *params) 1259fe56b9e6SYuval Mintz { 12605d24bcf1STomer Tayar struct qed_drv_load_params drv_load_params; 1261c0c2d0b4SMintz, Yuval struct qed_hw_init_params hw_init_params; 1262fe56b9e6SYuval Mintz struct qed_mcp_drv_version drv_version; 126319968430SChopra, Manish struct qed_tunnel_info tunn_info; 1264fe56b9e6SYuval Mintz const u8 *data = NULL; 1265fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 1266c78c70faSSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 126737bff2b9SYuval Mintz int rc = -EINVAL; 126837bff2b9SYuval Mintz 126937bff2b9SYuval Mintz if (qed_iov_wq_start(cdev)) 127037bff2b9SYuval Mintz goto err; 1271fe56b9e6SYuval Mintz 127259ccf86fSSudarsana Reddy Kalluru if (qed_slowpath_wq_start(cdev)) 127359ccf86fSSudarsana Reddy Kalluru goto err; 127459ccf86fSSudarsana Reddy Kalluru 12751408cc1fSYuval Mintz if (IS_PF(cdev)) { 1276fe56b9e6SYuval Mintz rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, 1277fe56b9e6SYuval Mintz &cdev->pdev->dev); 1278fe56b9e6SYuval Mintz if (rc) { 1279fe56b9e6SYuval Mintz DP_NOTICE(cdev, 1280fe56b9e6SYuval Mintz "Failed to find fw file - /lib/firmware/%s\n", 1281fe56b9e6SYuval Mintz QED_FW_FILE_NAME); 1282fe56b9e6SYuval Mintz goto err; 1283fe56b9e6SYuval Mintz } 1284c78c70faSSudarsana Reddy Kalluru 1285d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) { 1286d51e4af5SChopra, Manish p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 1287d51e4af5SChopra, Manish if (p_ptt) { 1288d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; 1289d51e4af5SChopra, Manish } else { 1290d51e4af5SChopra, Manish DP_NOTICE(cdev, 1291d51e4af5SChopra, Manish "Failed to acquire PTT for aRFS\n"); 1292d51e4af5SChopra, Manish goto err; 1293d51e4af5SChopra, Manish } 1294d51e4af5SChopra, Manish } 12951408cc1fSYuval Mintz } 1296fe56b9e6SYuval Mintz 12970e191827SSudarsana Reddy Kalluru cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 1298fe56b9e6SYuval Mintz rc = qed_nic_setup(cdev); 1299fe56b9e6SYuval Mintz if (rc) 1300fe56b9e6SYuval Mintz goto err; 1301fe56b9e6SYuval Mintz 13021408cc1fSYuval Mintz if (IS_PF(cdev)) 1303fe56b9e6SYuval Mintz rc = qed_slowpath_setup_int(cdev, params->int_mode); 13041408cc1fSYuval Mintz else 13051408cc1fSYuval Mintz rc = qed_slowpath_vf_setup_int(cdev); 1306fe56b9e6SYuval Mintz if (rc) 1307fe56b9e6SYuval Mintz goto err1; 1308fe56b9e6SYuval Mintz 13091408cc1fSYuval Mintz if (IS_PF(cdev)) { 1310fe56b9e6SYuval Mintz /* Allocate stream for unzipping */ 1311fe56b9e6SYuval Mintz rc = qed_alloc_stream_mem(cdev); 13122591c280SJoe Perches if (rc) 13138f16bc97SSudarsana Kalluru goto err2; 1314fe56b9e6SYuval Mintz 13158ac1ed79SJoe Perches /* First Dword used to differentiate between various sources */ 1316351a4dedSYuval Mintz data = cdev->firmware->data + sizeof(u32); 1317c965db44STomer Tayar 1318c965db44STomer Tayar qed_dbg_pf_init(cdev); 13191408cc1fSYuval Mintz } 1320fe56b9e6SYuval Mintz 13211408cc1fSYuval Mintz /* Start the slowpath */ 1322c0c2d0b4SMintz, Yuval memset(&hw_init_params, 0, sizeof(hw_init_params)); 132319968430SChopra, Manish memset(&tunn_info, 0, sizeof(tunn_info)); 132419968430SChopra, Manish tunn_info.vxlan.b_mode_enabled = true; 132519968430SChopra, Manish tunn_info.l2_gre.b_mode_enabled = true; 132619968430SChopra, Manish tunn_info.ip_gre.b_mode_enabled = true; 132719968430SChopra, Manish tunn_info.l2_geneve.b_mode_enabled = true; 132819968430SChopra, Manish tunn_info.ip_geneve.b_mode_enabled = true; 132919968430SChopra, Manish tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133019968430SChopra, Manish tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133119968430SChopra, Manish tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133219968430SChopra, Manish tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133319968430SChopra, Manish tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 1334c0c2d0b4SMintz, Yuval hw_init_params.p_tunn = &tunn_info; 1335c0c2d0b4SMintz, Yuval hw_init_params.b_hw_start = true; 1336c0c2d0b4SMintz, Yuval hw_init_params.int_mode = cdev->int_params.out.int_mode; 1337c0c2d0b4SMintz, Yuval hw_init_params.allow_npar_tx_switch = true; 1338c0c2d0b4SMintz, Yuval hw_init_params.bin_fw_data = data; 1339c0c2d0b4SMintz, Yuval 13405d24bcf1STomer Tayar memset(&drv_load_params, 0, sizeof(drv_load_params)); 13415d24bcf1STomer Tayar drv_load_params.is_crash_kernel = is_kdump_kernel(); 13425d24bcf1STomer Tayar drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; 13435d24bcf1STomer Tayar drv_load_params.avoid_eng_reset = false; 13445d24bcf1STomer Tayar drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; 13455d24bcf1STomer Tayar hw_init_params.p_drv_load_params = &drv_load_params; 13465d24bcf1STomer Tayar 1347c0c2d0b4SMintz, Yuval rc = qed_hw_init(cdev, &hw_init_params); 1348fe56b9e6SYuval Mintz if (rc) 13498c925c44SYuval Mintz goto err2; 1350fe56b9e6SYuval Mintz 1351fe56b9e6SYuval Mintz DP_INFO(cdev, 1352fe56b9e6SYuval Mintz "HW initialization and function start completed successfully\n"); 1353fe56b9e6SYuval Mintz 1354eaf3c0c6SChopra, Manish if (IS_PF(cdev)) { 1355eaf3c0c6SChopra, Manish cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | 1356eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GENEVE_TUNN) | 1357eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGENEVE_TUNN) | 1358eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GRE_TUNN) | 1359eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGRE_TUNN)); 1360eaf3c0c6SChopra, Manish } 1361eaf3c0c6SChopra, Manish 13620a7fb11cSYuval Mintz /* Allocate LL2 interface if needed */ 13630a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->using_ll2) { 13640a7fb11cSYuval Mintz rc = qed_ll2_alloc_if(cdev); 13650a7fb11cSYuval Mintz if (rc) 13660a7fb11cSYuval Mintz goto err3; 13670a7fb11cSYuval Mintz } 13681408cc1fSYuval Mintz if (IS_PF(cdev)) { 1369fe56b9e6SYuval Mintz hwfn = QED_LEADING_HWFN(cdev); 1370fe56b9e6SYuval Mintz drv_version.version = (params->drv_major << 24) | 1371fe56b9e6SYuval Mintz (params->drv_minor << 16) | 1372fe56b9e6SYuval Mintz (params->drv_rev << 8) | 1373fe56b9e6SYuval Mintz (params->drv_eng); 1374fe56b9e6SYuval Mintz strlcpy(drv_version.name, params->name, 1375fe56b9e6SYuval Mintz MCP_DRV_VER_STR_SIZE - 4); 1376fe56b9e6SYuval Mintz rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, 1377fe56b9e6SYuval Mintz &drv_version); 1378fe56b9e6SYuval Mintz if (rc) { 1379fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed sending drv version command\n"); 1380de0e4fd2SWenwen Wang goto err4; 1381fe56b9e6SYuval Mintz } 13821408cc1fSYuval Mintz } 1383fe56b9e6SYuval Mintz 13848c925c44SYuval Mintz qed_reset_vport_stats(cdev); 13858c925c44SYuval Mintz 1386fe56b9e6SYuval Mintz return 0; 1387fe56b9e6SYuval Mintz 1388de0e4fd2SWenwen Wang err4: 1389de0e4fd2SWenwen Wang qed_ll2_dealloc_if(cdev); 13900a7fb11cSYuval Mintz err3: 13910a7fb11cSYuval Mintz qed_hw_stop(cdev); 1392fe56b9e6SYuval Mintz err2: 13938c925c44SYuval Mintz qed_hw_timers_stop_all(cdev); 13941408cc1fSYuval Mintz if (IS_PF(cdev)) 13958c925c44SYuval Mintz qed_slowpath_irq_free(cdev); 13968c925c44SYuval Mintz qed_free_stream_mem(cdev); 1397fe56b9e6SYuval Mintz qed_disable_msix(cdev); 1398fe56b9e6SYuval Mintz err1: 1399fe56b9e6SYuval Mintz qed_resc_free(cdev); 1400fe56b9e6SYuval Mintz err: 14011408cc1fSYuval Mintz if (IS_PF(cdev)) 1402fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1403fe56b9e6SYuval Mintz 1404d51e4af5SChopra, Manish if (IS_PF(cdev) && (cdev->num_hwfns == 1) && 1405d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt) 1406d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1407d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1408c78c70faSSudarsana Reddy Kalluru 140937bff2b9SYuval Mintz qed_iov_wq_stop(cdev, false); 141037bff2b9SYuval Mintz 141159ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 141259ccf86fSSudarsana Reddy Kalluru 1413fe56b9e6SYuval Mintz return rc; 1414fe56b9e6SYuval Mintz } 1415fe56b9e6SYuval Mintz 1416fe56b9e6SYuval Mintz static int qed_slowpath_stop(struct qed_dev *cdev) 1417fe56b9e6SYuval Mintz { 1418fe56b9e6SYuval Mintz if (!cdev) 1419fe56b9e6SYuval Mintz return -ENODEV; 1420fe56b9e6SYuval Mintz 142159ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 142259ccf86fSSudarsana Reddy Kalluru 14230a7fb11cSYuval Mintz qed_ll2_dealloc_if(cdev); 14240a7fb11cSYuval Mintz 14251408cc1fSYuval Mintz if (IS_PF(cdev)) { 1426d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) 1427d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1428d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1429fe56b9e6SYuval Mintz qed_free_stream_mem(cdev); 1430c5ac9319SYuval Mintz if (IS_QED_ETH_IF(cdev)) 14310b55e27dSYuval Mintz qed_sriov_disable(cdev, true); 14325f027d7aSMintz, Yuval } 1433fe56b9e6SYuval Mintz 1434fe56b9e6SYuval Mintz qed_nic_stop(cdev); 14355f027d7aSMintz, Yuval 14365f027d7aSMintz, Yuval if (IS_PF(cdev)) 1437fe56b9e6SYuval Mintz qed_slowpath_irq_free(cdev); 1438fe56b9e6SYuval Mintz 1439fe56b9e6SYuval Mintz qed_disable_msix(cdev); 14401226337aSTomer Tayar 14411226337aSTomer Tayar qed_resc_free(cdev); 1442fe56b9e6SYuval Mintz 144337bff2b9SYuval Mintz qed_iov_wq_stop(cdev, true); 144437bff2b9SYuval Mintz 14451408cc1fSYuval Mintz if (IS_PF(cdev)) 1446fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1447fe56b9e6SYuval Mintz 1448fe56b9e6SYuval Mintz return 0; 1449fe56b9e6SYuval Mintz } 1450fe56b9e6SYuval Mintz 1451712c3cbfSMintz, Yuval static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) 1452fe56b9e6SYuval Mintz { 1453fe56b9e6SYuval Mintz int i; 1454fe56b9e6SYuval Mintz 1455fe56b9e6SYuval Mintz memcpy(cdev->name, name, NAME_SIZE); 1456fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) 1457fe56b9e6SYuval Mintz snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); 1458fe56b9e6SYuval Mintz } 1459fe56b9e6SYuval Mintz 1460fe56b9e6SYuval Mintz static u32 qed_sb_init(struct qed_dev *cdev, 1461fe56b9e6SYuval Mintz struct qed_sb_info *sb_info, 1462fe56b9e6SYuval Mintz void *sb_virt_addr, 1463fe56b9e6SYuval Mintz dma_addr_t sb_phy_addr, u16 sb_id, 1464fe56b9e6SYuval Mintz enum qed_sb_type type) 1465fe56b9e6SYuval Mintz { 1466fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 146785750d74SMintz, Yuval struct qed_ptt *p_ptt; 1468fe56b9e6SYuval Mintz u16 rel_sb_id; 1469fe56b9e6SYuval Mintz u32 rc; 1470fe56b9e6SYuval Mintz 147108eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 147208eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 147308eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 147408eb1fb0SMichal Kalderon rel_sb_id = sb_id / cdev->num_hwfns; 147508eb1fb0SMichal Kalderon } else { 147608eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 147708eb1fb0SMichal Kalderon rel_sb_id = sb_id; 147808eb1fb0SMichal Kalderon } 1479fe56b9e6SYuval Mintz 1480fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1481fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 148208eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1483fe56b9e6SYuval Mintz 148485750d74SMintz, Yuval if (IS_PF(p_hwfn->cdev)) { 148585750d74SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 148685750d74SMintz, Yuval if (!p_ptt) 148785750d74SMintz, Yuval return -EBUSY; 148885750d74SMintz, Yuval 148985750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, 149085750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 149185750d74SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 149285750d74SMintz, Yuval } else { 149385750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, 149485750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 149585750d74SMintz, Yuval } 1496fe56b9e6SYuval Mintz 1497fe56b9e6SYuval Mintz return rc; 1498fe56b9e6SYuval Mintz } 1499fe56b9e6SYuval Mintz 1500fe56b9e6SYuval Mintz static u32 qed_sb_release(struct qed_dev *cdev, 150108eb1fb0SMichal Kalderon struct qed_sb_info *sb_info, 150208eb1fb0SMichal Kalderon u16 sb_id, 150308eb1fb0SMichal Kalderon enum qed_sb_type type) 1504fe56b9e6SYuval Mintz { 1505fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 1506fe56b9e6SYuval Mintz u16 rel_sb_id; 1507fe56b9e6SYuval Mintz u32 rc; 1508fe56b9e6SYuval Mintz 150908eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 151008eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 151108eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 1512fe56b9e6SYuval Mintz rel_sb_id = sb_id / cdev->num_hwfns; 151308eb1fb0SMichal Kalderon } else { 151408eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 151508eb1fb0SMichal Kalderon rel_sb_id = sb_id; 151608eb1fb0SMichal Kalderon } 1517fe56b9e6SYuval Mintz 1518fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1519fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 152008eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1521fe56b9e6SYuval Mintz 1522fe56b9e6SYuval Mintz rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); 1523fe56b9e6SYuval Mintz 1524fe56b9e6SYuval Mintz return rc; 1525fe56b9e6SYuval Mintz } 1526fe56b9e6SYuval Mintz 1527fe7cd2bfSYuval Mintz static bool qed_can_link_change(struct qed_dev *cdev) 1528fe7cd2bfSYuval Mintz { 1529fe7cd2bfSYuval Mintz return true; 1530fe7cd2bfSYuval Mintz } 1531fe7cd2bfSYuval Mintz 153299785a87SAlexander Lobakin static void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params, 153399785a87SAlexander Lobakin const struct qed_link_params *params) 153499785a87SAlexander Lobakin { 153599785a87SAlexander Lobakin struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed; 153699785a87SAlexander Lobakin const struct qed_mfw_speed_map *map; 153799785a87SAlexander Lobakin u32 i; 153899785a87SAlexander Lobakin 153999785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 154099785a87SAlexander Lobakin ext_speed->autoneg = !!params->autoneg; 154199785a87SAlexander Lobakin 154299785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 154399785a87SAlexander Lobakin ext_speed->advertised_speeds = 0; 154499785a87SAlexander Lobakin 154599785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) { 154699785a87SAlexander Lobakin map = qed_mfw_ext_maps + i; 154799785a87SAlexander Lobakin 154899785a87SAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 154999785a87SAlexander Lobakin ext_speed->advertised_speeds |= map->mfw_val; 155099785a87SAlexander Lobakin } 155199785a87SAlexander Lobakin } 155299785a87SAlexander Lobakin 155399785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) { 155499785a87SAlexander Lobakin switch (params->forced_speed) { 155599785a87SAlexander Lobakin case SPEED_1000: 155699785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_1G; 155799785a87SAlexander Lobakin break; 155899785a87SAlexander Lobakin case SPEED_10000: 155999785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_10G; 156099785a87SAlexander Lobakin break; 156199785a87SAlexander Lobakin case SPEED_20000: 156299785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_20G; 156399785a87SAlexander Lobakin break; 156499785a87SAlexander Lobakin case SPEED_25000: 156599785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_25G; 156699785a87SAlexander Lobakin break; 156799785a87SAlexander Lobakin case SPEED_40000: 156899785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_40G; 156999785a87SAlexander Lobakin break; 157099785a87SAlexander Lobakin case SPEED_50000: 157199785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_50G_R | 157299785a87SAlexander Lobakin QED_EXT_SPEED_50G_R2; 157399785a87SAlexander Lobakin break; 157499785a87SAlexander Lobakin case SPEED_100000: 157599785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 | 157699785a87SAlexander Lobakin QED_EXT_SPEED_100G_R4 | 157799785a87SAlexander Lobakin QED_EXT_SPEED_100G_P4; 157899785a87SAlexander Lobakin break; 157999785a87SAlexander Lobakin default: 158099785a87SAlexander Lobakin break; 158199785a87SAlexander Lobakin } 158299785a87SAlexander Lobakin } 158399785a87SAlexander Lobakin 158499785a87SAlexander Lobakin if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)) 158599785a87SAlexander Lobakin return; 158699785a87SAlexander Lobakin 158799785a87SAlexander Lobakin switch (params->forced_speed) { 158899785a87SAlexander Lobakin case SPEED_25000: 158999785a87SAlexander Lobakin switch (params->fec) { 159099785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 159199785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE; 159299785a87SAlexander Lobakin break; 159399785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 159499785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R; 159599785a87SAlexander Lobakin break; 159699785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 159799785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528; 159899785a87SAlexander Lobakin break; 159999785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 160099785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 | 160199785a87SAlexander Lobakin ETH_EXT_FEC_25G_BASE_R | 160299785a87SAlexander Lobakin ETH_EXT_FEC_25G_NONE; 160399785a87SAlexander Lobakin break; 160499785a87SAlexander Lobakin default: 160599785a87SAlexander Lobakin break; 160699785a87SAlexander Lobakin } 160799785a87SAlexander Lobakin 160899785a87SAlexander Lobakin break; 160999785a87SAlexander Lobakin case SPEED_40000: 161099785a87SAlexander Lobakin switch (params->fec) { 161199785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 161299785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE; 161399785a87SAlexander Lobakin break; 161499785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 161599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R; 161699785a87SAlexander Lobakin break; 161799785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 161899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R | 161999785a87SAlexander Lobakin ETH_EXT_FEC_40G_NONE; 162099785a87SAlexander Lobakin break; 162199785a87SAlexander Lobakin default: 162299785a87SAlexander Lobakin break; 162399785a87SAlexander Lobakin } 162499785a87SAlexander Lobakin 162599785a87SAlexander Lobakin break; 162699785a87SAlexander Lobakin case SPEED_50000: 162799785a87SAlexander Lobakin switch (params->fec) { 162899785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 162999785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE; 163099785a87SAlexander Lobakin break; 163199785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 163299785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R; 163399785a87SAlexander Lobakin break; 163499785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 163599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528; 163699785a87SAlexander Lobakin break; 163799785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 163899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 | 163999785a87SAlexander Lobakin ETH_EXT_FEC_50G_BASE_R | 164099785a87SAlexander Lobakin ETH_EXT_FEC_50G_NONE; 164199785a87SAlexander Lobakin break; 164299785a87SAlexander Lobakin default: 164399785a87SAlexander Lobakin break; 164499785a87SAlexander Lobakin } 164599785a87SAlexander Lobakin 164699785a87SAlexander Lobakin break; 164799785a87SAlexander Lobakin case SPEED_100000: 164899785a87SAlexander Lobakin switch (params->fec) { 164999785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 165099785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE; 165199785a87SAlexander Lobakin break; 165299785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 165399785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R; 165499785a87SAlexander Lobakin break; 165599785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 165699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528; 165799785a87SAlexander Lobakin break; 165899785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 165999785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 | 166099785a87SAlexander Lobakin ETH_EXT_FEC_100G_BASE_R | 166199785a87SAlexander Lobakin ETH_EXT_FEC_100G_NONE; 166299785a87SAlexander Lobakin break; 166399785a87SAlexander Lobakin default: 166499785a87SAlexander Lobakin break; 166599785a87SAlexander Lobakin } 166699785a87SAlexander Lobakin 166799785a87SAlexander Lobakin break; 166899785a87SAlexander Lobakin default: 166999785a87SAlexander Lobakin break; 167099785a87SAlexander Lobakin } 167199785a87SAlexander Lobakin } 167299785a87SAlexander Lobakin 1673351a4dedSYuval Mintz static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) 1674cc875c2eSYuval Mintz { 1675cc875c2eSYuval Mintz struct qed_mcp_link_params *link_params; 1676097818fcSAlexander Lobakin struct qed_mcp_link_speed_params *speed; 1677097818fcSAlexander Lobakin const struct qed_mfw_speed_map *map; 1678bdb5d8ecSAlexander Lobakin struct qed_hwfn *hwfn; 1679cc875c2eSYuval Mintz struct qed_ptt *ptt; 1680cc875c2eSYuval Mintz int rc; 1681097818fcSAlexander Lobakin u32 i; 1682cc875c2eSYuval Mintz 1683cc875c2eSYuval Mintz if (!cdev) 1684cc875c2eSYuval Mintz return -ENODEV; 1685cc875c2eSYuval Mintz 1686cc875c2eSYuval Mintz /* The link should be set only once per PF */ 1687cc875c2eSYuval Mintz hwfn = &cdev->hwfns[0]; 1688cc875c2eSYuval Mintz 168965ed2ffdSMintz, Yuval /* When VF wants to set link, force it to read the bulletin instead. 169065ed2ffdSMintz, Yuval * This mimics the PF behavior, where a noitification [both immediate 169165ed2ffdSMintz, Yuval * and possible later] would be generated when changing properties. 169265ed2ffdSMintz, Yuval */ 169365ed2ffdSMintz, Yuval if (IS_VF(cdev)) { 169465ed2ffdSMintz, Yuval qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); 169565ed2ffdSMintz, Yuval return 0; 169665ed2ffdSMintz, Yuval } 169765ed2ffdSMintz, Yuval 1698cc875c2eSYuval Mintz ptt = qed_ptt_acquire(hwfn); 1699cc875c2eSYuval Mintz if (!ptt) 1700cc875c2eSYuval Mintz return -EBUSY; 1701cc875c2eSYuval Mintz 1702cc875c2eSYuval Mintz link_params = qed_mcp_get_link_params(hwfn); 1703bdb5d8ecSAlexander Lobakin if (!link_params) 1704bdb5d8ecSAlexander Lobakin return -ENODATA; 1705bdb5d8ecSAlexander Lobakin 1706097818fcSAlexander Lobakin speed = &link_params->speed; 1707097818fcSAlexander Lobakin 1708cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 1709097818fcSAlexander Lobakin speed->autoneg = !!params->autoneg; 1710bdb5d8ecSAlexander Lobakin 1711cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 1712097818fcSAlexander Lobakin speed->advertised_speeds = 0; 1713bdb5d8ecSAlexander Lobakin 1714097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) { 1715097818fcSAlexander Lobakin map = qed_mfw_legacy_maps + i; 1716bdb5d8ecSAlexander Lobakin 1717097818fcSAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 1718097818fcSAlexander Lobakin speed->advertised_speeds |= map->mfw_val; 1719097818fcSAlexander Lobakin } 1720cc875c2eSYuval Mintz } 1721bdb5d8ecSAlexander Lobakin 1722cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) 1723097818fcSAlexander Lobakin speed->forced_speed = params->forced_speed; 1724097818fcSAlexander Lobakin 172599785a87SAlexander Lobakin if (qed_mcp_is_ext_speed_supported(hwfn)) 172699785a87SAlexander Lobakin qed_set_ext_speed_params(link_params, params); 172799785a87SAlexander Lobakin 1728a43f235fSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { 1729a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 1730a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = true; 1731a43f235fSSudarsana Reddy Kalluru else 1732a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = false; 1733a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) 1734a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = true; 1735a43f235fSSudarsana Reddy Kalluru else 1736a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = false; 1737a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) 1738a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = true; 1739a43f235fSSudarsana Reddy Kalluru else 1740a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = false; 1741a43f235fSSudarsana Reddy Kalluru } 1742097818fcSAlexander Lobakin 174303dc76caSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { 174403dc76caSSudarsana Reddy Kalluru switch (params->loopback_mode) { 174503dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_INT_PHY: 1746351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; 174703dc76caSSudarsana Reddy Kalluru break; 174803dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT_PHY: 1749351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; 175003dc76caSSudarsana Reddy Kalluru break; 175103dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT: 1752351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT; 175303dc76caSSudarsana Reddy Kalluru break; 175403dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_MAC: 1755351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_MAC; 175603dc76caSSudarsana Reddy Kalluru break; 175798e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123: 175898e675ecSAlexander Lobakin link_params->loopback_mode = 175998e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_0123; 176098e675ecSAlexander Lobakin break; 176198e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301: 176298e675ecSAlexander Lobakin link_params->loopback_mode = 176398e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_2301; 176498e675ecSAlexander Lobakin break; 176598e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_PCS_AH_ONLY: 176698e675ecSAlexander Lobakin link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY; 176798e675ecSAlexander Lobakin break; 176898e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY: 176998e675ecSAlexander Lobakin link_params->loopback_mode = 177098e675ecSAlexander Lobakin ETH_LOOPBACK_REVERSE_MAC_AH_ONLY; 177198e675ecSAlexander Lobakin break; 177298e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY: 177398e675ecSAlexander Lobakin link_params->loopback_mode = 177498e675ecSAlexander Lobakin ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY; 177598e675ecSAlexander Lobakin break; 177603dc76caSSudarsana Reddy Kalluru default: 1777351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_NONE; 177803dc76caSSudarsana Reddy Kalluru break; 177903dc76caSSudarsana Reddy Kalluru } 178003dc76caSSudarsana Reddy Kalluru } 1781cc875c2eSYuval Mintz 1782645874e5SSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) 1783645874e5SSudarsana Reddy Kalluru memcpy(&link_params->eee, ¶ms->eee, 1784645874e5SSudarsana Reddy Kalluru sizeof(link_params->eee)); 1785645874e5SSudarsana Reddy Kalluru 1786ae7e6937SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG) 1787ae7e6937SAlexander Lobakin link_params->fec = params->fec; 1788ae7e6937SAlexander Lobakin 1789cc875c2eSYuval Mintz rc = qed_mcp_set_link(hwfn, ptt, params->link_up); 1790cc875c2eSYuval Mintz 1791cc875c2eSYuval Mintz qed_ptt_release(hwfn, ptt); 1792cc875c2eSYuval Mintz 1793cc875c2eSYuval Mintz return rc; 1794cc875c2eSYuval Mintz } 1795cc875c2eSYuval Mintz 1796cc875c2eSYuval Mintz static int qed_get_port_type(u32 media_type) 1797cc875c2eSYuval Mintz { 1798cc875c2eSYuval Mintz int port_type; 1799cc875c2eSYuval Mintz 1800cc875c2eSYuval Mintz switch (media_type) { 1801cc875c2eSYuval Mintz case MEDIA_SFPP_10G_FIBER: 1802cc875c2eSYuval Mintz case MEDIA_SFP_1G_FIBER: 1803cc875c2eSYuval Mintz case MEDIA_XFP_FIBER: 1804b639f197SYuval Mintz case MEDIA_MODULE_FIBER: 1805cc875c2eSYuval Mintz port_type = PORT_FIBRE; 1806cc875c2eSYuval Mintz break; 1807cc875c2eSYuval Mintz case MEDIA_DA_TWINAX: 1808cc875c2eSYuval Mintz port_type = PORT_DA; 1809cc875c2eSYuval Mintz break; 1810cc875c2eSYuval Mintz case MEDIA_BASE_T: 1811cc875c2eSYuval Mintz port_type = PORT_TP; 1812cc875c2eSYuval Mintz break; 181399785a87SAlexander Lobakin case MEDIA_KR: 1814cc875c2eSYuval Mintz case MEDIA_NOT_PRESENT: 1815cc875c2eSYuval Mintz port_type = PORT_NONE; 1816cc875c2eSYuval Mintz break; 1817cc875c2eSYuval Mintz case MEDIA_UNSPECIFIED: 1818cc875c2eSYuval Mintz default: 1819cc875c2eSYuval Mintz port_type = PORT_OTHER; 1820cc875c2eSYuval Mintz break; 1821cc875c2eSYuval Mintz } 1822cc875c2eSYuval Mintz return port_type; 1823cc875c2eSYuval Mintz } 1824cc875c2eSYuval Mintz 182514b84e86SArnd Bergmann static int qed_get_link_data(struct qed_hwfn *hwfn, 182614b84e86SArnd Bergmann struct qed_mcp_link_params *params, 182714b84e86SArnd Bergmann struct qed_mcp_link_state *link, 182814b84e86SArnd Bergmann struct qed_mcp_link_capabilities *link_caps) 182914b84e86SArnd Bergmann { 183014b84e86SArnd Bergmann void *p; 183114b84e86SArnd Bergmann 183214b84e86SArnd Bergmann if (!IS_PF(hwfn->cdev)) { 183314b84e86SArnd Bergmann qed_vf_get_link_params(hwfn, params); 183414b84e86SArnd Bergmann qed_vf_get_link_state(hwfn, link); 183514b84e86SArnd Bergmann qed_vf_get_link_caps(hwfn, link_caps); 183614b84e86SArnd Bergmann 183714b84e86SArnd Bergmann return 0; 183814b84e86SArnd Bergmann } 183914b84e86SArnd Bergmann 184014b84e86SArnd Bergmann p = qed_mcp_get_link_params(hwfn); 184114b84e86SArnd Bergmann if (!p) 184214b84e86SArnd Bergmann return -ENXIO; 184314b84e86SArnd Bergmann memcpy(params, p, sizeof(*params)); 184414b84e86SArnd Bergmann 184514b84e86SArnd Bergmann p = qed_mcp_get_link_state(hwfn); 184614b84e86SArnd Bergmann if (!p) 184714b84e86SArnd Bergmann return -ENXIO; 184814b84e86SArnd Bergmann memcpy(link, p, sizeof(*link)); 184914b84e86SArnd Bergmann 185014b84e86SArnd Bergmann p = qed_mcp_get_link_capabilities(hwfn); 185114b84e86SArnd Bergmann if (!p) 185214b84e86SArnd Bergmann return -ENXIO; 185314b84e86SArnd Bergmann memcpy(link_caps, p, sizeof(*link_caps)); 185414b84e86SArnd Bergmann 185514b84e86SArnd Bergmann return 0; 185614b84e86SArnd Bergmann } 185714b84e86SArnd Bergmann 1858c56a8be7SRahul Verma static void qed_fill_link_capability(struct qed_hwfn *hwfn, 1859c56a8be7SRahul Verma struct qed_ptt *ptt, u32 capability, 1860bdb5d8ecSAlexander Lobakin unsigned long *if_caps) 1861c56a8be7SRahul Verma { 1862c56a8be7SRahul Verma u32 media_type, tcvr_state, tcvr_type; 1863c56a8be7SRahul Verma u32 speed_mask, board_cfg; 1864c56a8be7SRahul Verma 1865c56a8be7SRahul Verma if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) 1866c56a8be7SRahul Verma media_type = MEDIA_UNSPECIFIED; 1867c56a8be7SRahul Verma 1868c56a8be7SRahul Verma if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) 1869c56a8be7SRahul Verma tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; 1870c56a8be7SRahul Verma 1871c56a8be7SRahul Verma if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) 1872c56a8be7SRahul Verma speed_mask = 0xFFFFFFFF; 1873c56a8be7SRahul Verma 1874c56a8be7SRahul Verma if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) 1875c56a8be7SRahul Verma board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 1876c56a8be7SRahul Verma 1877c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 1878c56a8be7SRahul Verma "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", 1879c56a8be7SRahul Verma media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); 1880c56a8be7SRahul Verma 1881c56a8be7SRahul Verma switch (media_type) { 1882c56a8be7SRahul Verma case MEDIA_DA_TWINAX: 1883bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1884bdb5d8ecSAlexander Lobakin 1885c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1886bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 1887bdb5d8ecSAlexander Lobakin 1888c56a8be7SRahul Verma /* For DAC media multiple speed capabilities are supported */ 18899228b7c1SAlexander Lobakin capability |= speed_mask; 18909228b7c1SAlexander Lobakin 1891c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1892bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 1893c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1894bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseCR_Full); 18959228b7c1SAlexander Lobakin 1896c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 18979228b7c1SAlexander Lobakin switch (tcvr_type) { 18989228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_CR4: 18999228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 19009228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1901bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseCR4_Full); 19029228b7c1SAlexander Lobakin break; 19039228b7c1SAlexander Lobakin default: 19049228b7c1SAlexander Lobakin break; 19059228b7c1SAlexander Lobakin } 19069228b7c1SAlexander Lobakin 1907c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 1908bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseCR_Full); 1909c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1910bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseCR2_Full); 19119228b7c1SAlexander Lobakin 1912c56a8be7SRahul Verma if (capability & 1913c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 19149228b7c1SAlexander Lobakin switch (tcvr_type) { 19159228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_CR4: 19169228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1917bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseCR4_Full); 19189228b7c1SAlexander Lobakin break; 19199228b7c1SAlexander Lobakin default: 19209228b7c1SAlexander Lobakin break; 19219228b7c1SAlexander Lobakin } 1922bdb5d8ecSAlexander Lobakin 1923c56a8be7SRahul Verma break; 1924c56a8be7SRahul Verma case MEDIA_BASE_T: 1925bdb5d8ecSAlexander Lobakin phylink_set(if_caps, TP); 1926bdb5d8ecSAlexander Lobakin 1927c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { 1928c56a8be7SRahul Verma if (capability & 1929bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1930bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 1931c56a8be7SRahul Verma if (capability & 1932bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1933bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 1934c56a8be7SRahul Verma } 1935bdb5d8ecSAlexander Lobakin 1936c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { 1937bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1938bdb5d8ecSAlexander Lobakin 19399228b7c1SAlexander Lobakin switch (tcvr_type) { 19409228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1000BASET: 1941bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 19429228b7c1SAlexander Lobakin break; 19439228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_BASET: 1944bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 19459228b7c1SAlexander Lobakin break; 19469228b7c1SAlexander Lobakin default: 19479228b7c1SAlexander Lobakin break; 19489228b7c1SAlexander Lobakin } 1949c56a8be7SRahul Verma } 1950bdb5d8ecSAlexander Lobakin 1951c56a8be7SRahul Verma break; 1952c56a8be7SRahul Verma case MEDIA_SFP_1G_FIBER: 1953c56a8be7SRahul Verma case MEDIA_SFPP_10G_FIBER: 1954c56a8be7SRahul Verma case MEDIA_XFP_FIBER: 1955c56a8be7SRahul Verma case MEDIA_MODULE_FIBER: 1956bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 19579228b7c1SAlexander Lobakin capability |= speed_mask; 1958bdb5d8ecSAlexander Lobakin 19599228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 19609228b7c1SAlexander Lobakin switch (tcvr_type) { 19619228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_LX: 19629228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_SX: 19639228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 19649228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1965bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 19669228b7c1SAlexander Lobakin break; 19679228b7c1SAlexander Lobakin default: 19689228b7c1SAlexander Lobakin break; 1969c56a8be7SRahul Verma } 1970bdb5d8ecSAlexander Lobakin 19719228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19729228b7c1SAlexander Lobakin switch (tcvr_type) { 19739228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_SR: 19749228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 19759228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 19769228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 1977bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseSR_Full); 19789228b7c1SAlexander Lobakin break; 19799228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LR: 19809228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 19819228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 19829228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1983bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLR_Full); 19849228b7c1SAlexander Lobakin break; 19859228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LRM: 1986bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLRM_Full); 19879228b7c1SAlexander Lobakin break; 19889228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_ER: 1989bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseR_FEC); 19909228b7c1SAlexander Lobakin break; 19919228b7c1SAlexander Lobakin default: 19929228b7c1SAlexander Lobakin break; 1993c56a8be7SRahul Verma } 1994bdb5d8ecSAlexander Lobakin 1995c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1996bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 1997bdb5d8ecSAlexander Lobakin 19989228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 19999228b7c1SAlexander Lobakin switch (tcvr_type) { 20009228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_25G_SR: 20019228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 2002bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseSR_Full); 20039228b7c1SAlexander Lobakin break; 20049228b7c1SAlexander Lobakin default: 20059228b7c1SAlexander Lobakin break; 2006c56a8be7SRahul Verma } 2007bdb5d8ecSAlexander Lobakin 20089228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 20099228b7c1SAlexander Lobakin switch (tcvr_type) { 20109228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_LR4: 20119228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 20129228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2013bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseLR4_Full); 20149228b7c1SAlexander Lobakin break; 20159228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_SR4: 20169228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 20179228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2018bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseSR4_Full); 20199228b7c1SAlexander Lobakin break; 20209228b7c1SAlexander Lobakin default: 20219228b7c1SAlexander Lobakin break; 2022c56a8be7SRahul Verma } 2023bdb5d8ecSAlexander Lobakin 2024bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2025bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2026bdb5d8ecSAlexander Lobakin 2027c56a8be7SRahul Verma if (capability & 20289228b7c1SAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 20299228b7c1SAlexander Lobakin switch (tcvr_type) { 20309228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_SR4: 20319228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2032bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseSR4_Full); 20339228b7c1SAlexander Lobakin break; 20349228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 20359228b7c1SAlexander Lobakin phylink_set(if_caps, 100000baseLR4_ER4_Full); 20369228b7c1SAlexander Lobakin break; 20379228b7c1SAlexander Lobakin default: 20389228b7c1SAlexander Lobakin break; 2039c56a8be7SRahul Verma } 2040c56a8be7SRahul Verma 2041c56a8be7SRahul Verma break; 2042c56a8be7SRahul Verma case MEDIA_KR: 2043bdb5d8ecSAlexander Lobakin phylink_set(if_caps, Backplane); 2044bdb5d8ecSAlexander Lobakin 2045c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 2046bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 2047bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 2048bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 2049bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 2050bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseKR_Full); 2051bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 2052bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseKR_Full); 2053bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 2054bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseKR4_Full); 2055bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2056bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2057c56a8be7SRahul Verma if (capability & 2058c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 2059bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseKR4_Full); 2060bdb5d8ecSAlexander Lobakin 2061c56a8be7SRahul Verma break; 2062c56a8be7SRahul Verma case MEDIA_UNSPECIFIED: 2063c56a8be7SRahul Verma case MEDIA_NOT_PRESENT: 20649228b7c1SAlexander Lobakin default: 2065c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, 2066c56a8be7SRahul Verma "Unknown media and transceiver type;\n"); 2067c56a8be7SRahul Verma break; 2068c56a8be7SRahul Verma } 2069c56a8be7SRahul Verma } 2070c56a8be7SRahul Verma 20713c41486eSAlexander Lobakin static void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask) 20723c41486eSAlexander Lobakin { 20733c41486eSAlexander Lobakin *speed_mask = 0; 20743c41486eSAlexander Lobakin 20753c41486eSAlexander Lobakin if (caps & 20763c41486eSAlexander Lobakin (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD)) 20773c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 20783c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_10G) 20793c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 20803c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_20G) 20813c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; 20823c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_25G) 20833c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 20843c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_40G) 20853c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 20863c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_50G) 20873c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; 20883c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_100G) 20893c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; 20903c41486eSAlexander Lobakin } 20913c41486eSAlexander Lobakin 2092cc875c2eSYuval Mintz static void qed_fill_link(struct qed_hwfn *hwfn, 2093706d0891SRahul Verma struct qed_ptt *ptt, 2094cc875c2eSYuval Mintz struct qed_link_output *if_link) 2095cc875c2eSYuval Mintz { 2096c56a8be7SRahul Verma struct qed_mcp_link_capabilities link_caps; 2097cc875c2eSYuval Mintz struct qed_mcp_link_params params; 2098cc875c2eSYuval Mintz struct qed_mcp_link_state link; 20993c41486eSAlexander Lobakin u32 media_type, speed_mask; 2100cc875c2eSYuval Mintz 2101cc875c2eSYuval Mintz memset(if_link, 0, sizeof(*if_link)); 2102cc875c2eSYuval Mintz 2103cc875c2eSYuval Mintz /* Prepare source inputs */ 210414b84e86SArnd Bergmann if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { 210514b84e86SArnd Bergmann dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); 210614b84e86SArnd Bergmann return; 21071408cc1fSYuval Mintz } 2108cc875c2eSYuval Mintz 2109cc875c2eSYuval Mintz /* Set the link parameters to pass to protocol driver */ 2110cc875c2eSYuval Mintz if (link.link_up) 2111cc875c2eSYuval Mintz if_link->link_up = true; 2112cc875c2eSYuval Mintz 211399785a87SAlexander Lobakin if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) { 211499785a87SAlexander Lobakin if (link_caps.default_ext_autoneg) 211599785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 211699785a87SAlexander Lobakin 211799785a87SAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 211899785a87SAlexander Lobakin 211999785a87SAlexander Lobakin if (params.ext_speed.autoneg) 212099785a87SAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 212199785a87SAlexander Lobakin else 212299785a87SAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 212399785a87SAlexander Lobakin 212499785a87SAlexander Lobakin qed_fill_link_capability(hwfn, ptt, 212599785a87SAlexander Lobakin params.ext_speed.advertised_speeds, 212699785a87SAlexander Lobakin if_link->advertised_caps); 212799785a87SAlexander Lobakin } else { 212834f9199cSsudarsana.kalluru@cavium.com if (link_caps.default_speed_autoneg) 2129bdb5d8ecSAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 2130cc875c2eSYuval Mintz 2131bdb5d8ecSAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 2132bdb5d8ecSAlexander Lobakin 213334f9199cSsudarsana.kalluru@cavium.com if (params.speed.autoneg) 2134bdb5d8ecSAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 213534f9199cSsudarsana.kalluru@cavium.com else 2136bdb5d8ecSAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 213799785a87SAlexander Lobakin } 213899785a87SAlexander Lobakin 213999785a87SAlexander Lobakin if (params.pause.autoneg || 214099785a87SAlexander Lobakin (params.pause.forced_rx && params.pause.forced_tx)) 214199785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Asym_Pause); 214299785a87SAlexander Lobakin if (params.pause.autoneg || params.pause.forced_rx || 214399785a87SAlexander Lobakin params.pause.forced_tx) 214499785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Pause); 2145cc875c2eSYuval Mintz 2146ae7e6937SAlexander Lobakin if_link->sup_fec = link_caps.fec_default; 2147ae7e6937SAlexander Lobakin if_link->active_fec = params.fec; 2148ae7e6937SAlexander Lobakin 2149c56a8be7SRahul Verma /* Fill link advertised capability */ 2150c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, 2151bdb5d8ecSAlexander Lobakin if_link->advertised_caps); 21523c41486eSAlexander Lobakin 2153c56a8be7SRahul Verma /* Fill link supported capability */ 2154c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, 2155bdb5d8ecSAlexander Lobakin if_link->supported_caps); 2156cc875c2eSYuval Mintz 21573c41486eSAlexander Lobakin /* Fill partner advertised capability */ 21583c41486eSAlexander Lobakin qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask); 21593c41486eSAlexander Lobakin qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps); 21603c41486eSAlexander Lobakin 2161cc875c2eSYuval Mintz if (link.link_up) 2162cc875c2eSYuval Mintz if_link->speed = link.speed; 2163cc875c2eSYuval Mintz 2164cc875c2eSYuval Mintz /* TODO - fill duplex properly */ 2165cc875c2eSYuval Mintz if_link->duplex = DUPLEX_FULL; 2166706d0891SRahul Verma qed_mcp_get_media_type(hwfn, ptt, &media_type); 2167cc875c2eSYuval Mintz if_link->port = qed_get_port_type(media_type); 2168cc875c2eSYuval Mintz 2169cc875c2eSYuval Mintz if_link->autoneg = params.speed.autoneg; 2170cc875c2eSYuval Mintz 2171cc875c2eSYuval Mintz if (params.pause.autoneg) 2172cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 2173cc875c2eSYuval Mintz if (params.pause.forced_rx) 2174cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; 2175cc875c2eSYuval Mintz if (params.pause.forced_tx) 2176cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; 2177cc875c2eSYuval Mintz 2178cc875c2eSYuval Mintz if (link.an_complete) 2179bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Autoneg); 2180cc875c2eSYuval Mintz if (link.partner_adv_pause) 2181bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Pause); 2182cc875c2eSYuval Mintz if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || 2183cc875c2eSYuval Mintz link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) 2184bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Asym_Pause); 2185645874e5SSudarsana Reddy Kalluru 2186645874e5SSudarsana Reddy Kalluru if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) { 2187645874e5SSudarsana Reddy Kalluru if_link->eee_supported = false; 2188645874e5SSudarsana Reddy Kalluru } else { 2189645874e5SSudarsana Reddy Kalluru if_link->eee_supported = true; 2190645874e5SSudarsana Reddy Kalluru if_link->eee_active = link.eee_active; 2191645874e5SSudarsana Reddy Kalluru if_link->sup_caps = link_caps.eee_speed_caps; 2192645874e5SSudarsana Reddy Kalluru /* MFW clears adv_caps on eee disable; use configured value */ 2193645874e5SSudarsana Reddy Kalluru if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : 2194645874e5SSudarsana Reddy Kalluru params.eee.adv_caps; 2195645874e5SSudarsana Reddy Kalluru if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; 2196645874e5SSudarsana Reddy Kalluru if_link->eee.enable = params.eee.enable; 2197645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; 2198645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; 2199645874e5SSudarsana Reddy Kalluru } 2200cc875c2eSYuval Mintz } 2201cc875c2eSYuval Mintz 2202cc875c2eSYuval Mintz static void qed_get_current_link(struct qed_dev *cdev, 2203cc875c2eSYuval Mintz struct qed_link_output *if_link) 2204cc875c2eSYuval Mintz { 2205706d0891SRahul Verma struct qed_hwfn *hwfn; 2206706d0891SRahul Verma struct qed_ptt *ptt; 220736558c3dSYuval Mintz int i; 220836558c3dSYuval Mintz 2209706d0891SRahul Verma hwfn = &cdev->hwfns[0]; 2210706d0891SRahul Verma if (IS_PF(cdev)) { 2211706d0891SRahul Verma ptt = qed_ptt_acquire(hwfn); 2212706d0891SRahul Verma if (ptt) { 2213706d0891SRahul Verma qed_fill_link(hwfn, ptt, if_link); 2214706d0891SRahul Verma qed_ptt_release(hwfn, ptt); 2215706d0891SRahul Verma } else { 2216706d0891SRahul Verma DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); 2217706d0891SRahul Verma } 2218706d0891SRahul Verma } else { 2219706d0891SRahul Verma qed_fill_link(hwfn, NULL, if_link); 2220706d0891SRahul Verma } 222136558c3dSYuval Mintz 222236558c3dSYuval Mintz for_each_hwfn(cdev, i) 222336558c3dSYuval Mintz qed_inform_vf_link_state(&cdev->hwfns[i]); 2224cc875c2eSYuval Mintz } 2225cc875c2eSYuval Mintz 2226706d0891SRahul Verma void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2227cc875c2eSYuval Mintz { 2228cc875c2eSYuval Mintz void *cookie = hwfn->cdev->ops_cookie; 2229cc875c2eSYuval Mintz struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2230cc875c2eSYuval Mintz struct qed_link_output if_link; 2231cc875c2eSYuval Mintz 2232706d0891SRahul Verma qed_fill_link(hwfn, ptt, &if_link); 223336558c3dSYuval Mintz qed_inform_vf_link_state(hwfn); 2234cc875c2eSYuval Mintz 2235cc875c2eSYuval Mintz if (IS_LEAD_HWFN(hwfn) && cookie) 2236cc875c2eSYuval Mintz op->link_update(cookie, &if_link); 2237cc875c2eSYuval Mintz } 2238cc875c2eSYuval Mintz 2239699fed4aSSudarsana Reddy Kalluru void qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2240699fed4aSSudarsana Reddy Kalluru { 2241699fed4aSSudarsana Reddy Kalluru void *cookie = hwfn->cdev->ops_cookie; 2242699fed4aSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2243699fed4aSSudarsana Reddy Kalluru 2244699fed4aSSudarsana Reddy Kalluru if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update) 2245699fed4aSSudarsana Reddy Kalluru op->bw_update(cookie); 2246699fed4aSSudarsana Reddy Kalluru } 2247699fed4aSSudarsana Reddy Kalluru 2248fe56b9e6SYuval Mintz static int qed_drain(struct qed_dev *cdev) 2249fe56b9e6SYuval Mintz { 2250fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 2251fe56b9e6SYuval Mintz struct qed_ptt *ptt; 2252fe56b9e6SYuval Mintz int i, rc; 2253fe56b9e6SYuval Mintz 22541408cc1fSYuval Mintz if (IS_VF(cdev)) 22551408cc1fSYuval Mintz return 0; 22561408cc1fSYuval Mintz 2257fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 2258fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 2259fe56b9e6SYuval Mintz ptt = qed_ptt_acquire(hwfn); 2260fe56b9e6SYuval Mintz if (!ptt) { 2261fe56b9e6SYuval Mintz DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); 2262fe56b9e6SYuval Mintz return -EBUSY; 2263fe56b9e6SYuval Mintz } 2264fe56b9e6SYuval Mintz rc = qed_mcp_drain(hwfn, ptt); 22659aaa4e8bSDenis Bolotin qed_ptt_release(hwfn, ptt); 2266fe56b9e6SYuval Mintz if (rc) 2267fe56b9e6SYuval Mintz return rc; 2268fe56b9e6SYuval Mintz } 2269fe56b9e6SYuval Mintz 2270fe56b9e6SYuval Mintz return 0; 2271fe56b9e6SYuval Mintz } 2272fe56b9e6SYuval Mintz 22733a69cae8SSudarsana Reddy Kalluru static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev, 22743a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att *nvm_image, 22753a69cae8SSudarsana Reddy Kalluru u32 *crc) 22763a69cae8SSudarsana Reddy Kalluru { 22773a69cae8SSudarsana Reddy Kalluru u8 *buf = NULL; 22785ab90341SAlexander Lobakin int rc; 22793a69cae8SSudarsana Reddy Kalluru 22803a69cae8SSudarsana Reddy Kalluru /* Allocate a buffer for holding the nvram image */ 22813a69cae8SSudarsana Reddy Kalluru buf = kzalloc(nvm_image->length, GFP_KERNEL); 22823a69cae8SSudarsana Reddy Kalluru if (!buf) 22833a69cae8SSudarsana Reddy Kalluru return -ENOMEM; 22843a69cae8SSudarsana Reddy Kalluru 22853a69cae8SSudarsana Reddy Kalluru /* Read image into buffer */ 22863a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr, 22873a69cae8SSudarsana Reddy Kalluru buf, nvm_image->length); 22883a69cae8SSudarsana Reddy Kalluru if (rc) { 22893a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading image from nvm\n"); 22903a69cae8SSudarsana Reddy Kalluru goto out; 22913a69cae8SSudarsana Reddy Kalluru } 22923a69cae8SSudarsana Reddy Kalluru 22933a69cae8SSudarsana Reddy Kalluru /* Convert the buffer into big-endian format (excluding the 22943a69cae8SSudarsana Reddy Kalluru * closing 4 bytes of CRC). 22953a69cae8SSudarsana Reddy Kalluru */ 22965ab90341SAlexander Lobakin cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf, 22975ab90341SAlexander Lobakin DIV_ROUND_UP(nvm_image->length - 4, 4)); 22983a69cae8SSudarsana Reddy Kalluru 22993a69cae8SSudarsana Reddy Kalluru /* Calc CRC for the "actual" image buffer, i.e. not including 23003a69cae8SSudarsana Reddy Kalluru * the last 4 CRC bytes. 23013a69cae8SSudarsana Reddy Kalluru */ 23025ab90341SAlexander Lobakin *crc = ~crc32(~0U, buf, nvm_image->length - 4); 23035ab90341SAlexander Lobakin *crc = (__force u32)cpu_to_be32p(crc); 23043a69cae8SSudarsana Reddy Kalluru 23053a69cae8SSudarsana Reddy Kalluru out: 23063a69cae8SSudarsana Reddy Kalluru kfree(buf); 23073a69cae8SSudarsana Reddy Kalluru 23083a69cae8SSudarsana Reddy Kalluru return rc; 23093a69cae8SSudarsana Reddy Kalluru } 23103a69cae8SSudarsana Reddy Kalluru 23113a69cae8SSudarsana Reddy Kalluru /* Binary file format - 23123a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 23133a69cae8SSudarsana Reddy Kalluru * 0B | 0x4 [command index] | 23143a69cae8SSudarsana Reddy Kalluru * 4B | image_type | Options | Number of register settings | 23153a69cae8SSudarsana Reddy Kalluru * 8B | Value | 23163a69cae8SSudarsana Reddy Kalluru * 12B | Mask | 23173a69cae8SSudarsana Reddy Kalluru * 16B | Offset | 23183a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 23193a69cae8SSudarsana Reddy Kalluru * There can be several Value-Mask-Offset sets as specified by 'Number of...'. 23203a69cae8SSudarsana Reddy Kalluru * Options - 0'b - Calculate & Update CRC for image 23213a69cae8SSudarsana Reddy Kalluru */ 23223a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data, 23233a69cae8SSudarsana Reddy Kalluru bool *check_resp) 23243a69cae8SSudarsana Reddy Kalluru { 23253a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att nvm_image; 23263a69cae8SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn; 23273a69cae8SSudarsana Reddy Kalluru bool is_crc = false; 23283a69cae8SSudarsana Reddy Kalluru u32 image_type; 23293a69cae8SSudarsana Reddy Kalluru int rc = 0, i; 23303a69cae8SSudarsana Reddy Kalluru u16 len; 23313a69cae8SSudarsana Reddy Kalluru 23323a69cae8SSudarsana Reddy Kalluru *data += 4; 23333a69cae8SSudarsana Reddy Kalluru image_type = **data; 23343a69cae8SSudarsana Reddy Kalluru p_hwfn = QED_LEADING_HWFN(cdev); 23353a69cae8SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 23363a69cae8SSudarsana Reddy Kalluru if (image_type == p_hwfn->nvm_info.image_att[i].image_type) 23373a69cae8SSudarsana Reddy Kalluru break; 23383a69cae8SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 23393a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find nvram image of type %08x\n", 23403a69cae8SSudarsana Reddy Kalluru image_type); 23413a69cae8SSudarsana Reddy Kalluru return -ENOENT; 23423a69cae8SSudarsana Reddy Kalluru } 23433a69cae8SSudarsana Reddy Kalluru 23443a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 23453a69cae8SSudarsana Reddy Kalluru nvm_image.length = p_hwfn->nvm_info.image_att[i].len; 23463a69cae8SSudarsana Reddy Kalluru 23473a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 23483a69cae8SSudarsana Reddy Kalluru "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n", 23493a69cae8SSudarsana Reddy Kalluru **data, image_type, nvm_image.start_addr, 23503a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 1); 23513a69cae8SSudarsana Reddy Kalluru (*data)++; 23523a69cae8SSudarsana Reddy Kalluru is_crc = !!(**data & BIT(0)); 23533a69cae8SSudarsana Reddy Kalluru (*data)++; 23543a69cae8SSudarsana Reddy Kalluru len = *((u16 *)*data); 23553a69cae8SSudarsana Reddy Kalluru *data += 2; 23563a69cae8SSudarsana Reddy Kalluru if (is_crc) { 23573a69cae8SSudarsana Reddy Kalluru u32 crc = 0; 23583a69cae8SSudarsana Reddy Kalluru 23593a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc); 23603a69cae8SSudarsana Reddy Kalluru if (rc) { 23613a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc); 23623a69cae8SSudarsana Reddy Kalluru goto exit; 23633a69cae8SSudarsana Reddy Kalluru } 23643a69cae8SSudarsana Reddy Kalluru 23653a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 23663a69cae8SSudarsana Reddy Kalluru (nvm_image.start_addr + 23673a69cae8SSudarsana Reddy Kalluru nvm_image.length - 4), (u8 *)&crc, 4); 23683a69cae8SSudarsana Reddy Kalluru if (rc) 23693a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x, rc = %d\n", 23703a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 4, rc); 23713a69cae8SSudarsana Reddy Kalluru goto exit; 23723a69cae8SSudarsana Reddy Kalluru } 23733a69cae8SSudarsana Reddy Kalluru 23743a69cae8SSudarsana Reddy Kalluru /* Iterate over the values for setting */ 23753a69cae8SSudarsana Reddy Kalluru while (len) { 23763a69cae8SSudarsana Reddy Kalluru u32 offset, mask, value, cur_value; 23773a69cae8SSudarsana Reddy Kalluru u8 buf[4]; 23783a69cae8SSudarsana Reddy Kalluru 23793a69cae8SSudarsana Reddy Kalluru value = *((u32 *)*data); 23803a69cae8SSudarsana Reddy Kalluru *data += 4; 23813a69cae8SSudarsana Reddy Kalluru mask = *((u32 *)*data); 23823a69cae8SSudarsana Reddy Kalluru *data += 4; 23833a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)*data); 23843a69cae8SSudarsana Reddy Kalluru *data += 4; 23853a69cae8SSudarsana Reddy Kalluru 23863a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf, 23873a69cae8SSudarsana Reddy Kalluru 4); 23883a69cae8SSudarsana Reddy Kalluru if (rc) { 23893a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading from %08x\n", 23903a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 23913a69cae8SSudarsana Reddy Kalluru goto exit; 23923a69cae8SSudarsana Reddy Kalluru } 23933a69cae8SSudarsana Reddy Kalluru 23943a69cae8SSudarsana Reddy Kalluru cur_value = le32_to_cpu(*((__le32 *)buf)); 23953a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 23963a69cae8SSudarsana Reddy Kalluru "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n", 23973a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, cur_value, 23983a69cae8SSudarsana Reddy Kalluru (cur_value & ~mask) | (value & mask), value, mask); 23993a69cae8SSudarsana Reddy Kalluru value = (value & mask) | (cur_value & ~mask); 24003a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 24013a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, 24023a69cae8SSudarsana Reddy Kalluru (u8 *)&value, 4); 24033a69cae8SSudarsana Reddy Kalluru if (rc) { 24043a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x\n", 24053a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 24063a69cae8SSudarsana Reddy Kalluru goto exit; 24073a69cae8SSudarsana Reddy Kalluru } 24083a69cae8SSudarsana Reddy Kalluru 24093a69cae8SSudarsana Reddy Kalluru len--; 24103a69cae8SSudarsana Reddy Kalluru } 24113a69cae8SSudarsana Reddy Kalluru exit: 24123a69cae8SSudarsana Reddy Kalluru return rc; 24133a69cae8SSudarsana Reddy Kalluru } 24143a69cae8SSudarsana Reddy Kalluru 24153a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24163a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24173a69cae8SSudarsana Reddy Kalluru * 0B | 0x3 [command index] | 24183a69cae8SSudarsana Reddy Kalluru * 4B | b'0: check_response? | b'1-31 reserved | 24193a69cae8SSudarsana Reddy Kalluru * 8B | File-type | reserved | 2420057d2b19SSudarsana Reddy Kalluru * 12B | Image length in bytes | 24213a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24223a69cae8SSudarsana Reddy Kalluru * Start a new file of the provided type 24233a69cae8SSudarsana Reddy Kalluru */ 24243a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_start(struct qed_dev *cdev, 24253a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24263a69cae8SSudarsana Reddy Kalluru { 2427057d2b19SSudarsana Reddy Kalluru u32 file_type, file_size = 0; 24283a69cae8SSudarsana Reddy Kalluru int rc; 24293a69cae8SSudarsana Reddy Kalluru 24303a69cae8SSudarsana Reddy Kalluru *data += 4; 24313a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24323a69cae8SSudarsana Reddy Kalluru *data += 4; 2433057d2b19SSudarsana Reddy Kalluru file_type = **data; 24343a69cae8SSudarsana Reddy Kalluru 24353a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 2436057d2b19SSudarsana Reddy Kalluru "About to start a new file of type %02x\n", file_type); 2437057d2b19SSudarsana Reddy Kalluru if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) { 2438057d2b19SSudarsana Reddy Kalluru *data += 4; 2439057d2b19SSudarsana Reddy Kalluru file_size = *((u32 *)(*data)); 2440057d2b19SSudarsana Reddy Kalluru } 2441057d2b19SSudarsana Reddy Kalluru 2442057d2b19SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type, 2443057d2b19SSudarsana Reddy Kalluru (u8 *)(&file_size), 4); 24443a69cae8SSudarsana Reddy Kalluru *data += 4; 24453a69cae8SSudarsana Reddy Kalluru 24463a69cae8SSudarsana Reddy Kalluru return rc; 24473a69cae8SSudarsana Reddy Kalluru } 24483a69cae8SSudarsana Reddy Kalluru 24493a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24503a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24513a69cae8SSudarsana Reddy Kalluru * 0B | 0x2 [command index] | 24523a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24533a69cae8SSudarsana Reddy Kalluru * 8B | b'0: check_response? | b'1-31 reserved | 24543a69cae8SSudarsana Reddy Kalluru * 12B | Offset in bytes | 24553a69cae8SSudarsana Reddy Kalluru * 16B | Data ... | 24563a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24573a69cae8SSudarsana Reddy Kalluru * Write data as part of a file that was previously started. Data should be 24583a69cae8SSudarsana Reddy Kalluru * of length equal to that provided in the message 24593a69cae8SSudarsana Reddy Kalluru */ 24603a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_data(struct qed_dev *cdev, 24613a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24623a69cae8SSudarsana Reddy Kalluru { 24633a69cae8SSudarsana Reddy Kalluru u32 offset, len; 24643a69cae8SSudarsana Reddy Kalluru int rc; 24653a69cae8SSudarsana Reddy Kalluru 24663a69cae8SSudarsana Reddy Kalluru *data += 4; 24673a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 24683a69cae8SSudarsana Reddy Kalluru *data += 4; 24693a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24703a69cae8SSudarsana Reddy Kalluru *data += 4; 24713a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)(*data)); 24723a69cae8SSudarsana Reddy Kalluru *data += 4; 24733a69cae8SSudarsana Reddy Kalluru 24743a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 24753a69cae8SSudarsana Reddy Kalluru "About to write File-data: %08x bytes to offset %08x\n", 24763a69cae8SSudarsana Reddy Kalluru len, offset); 24773a69cae8SSudarsana Reddy Kalluru 24783a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset, 24793a69cae8SSudarsana Reddy Kalluru (char *)(*data), len); 24803a69cae8SSudarsana Reddy Kalluru *data += len; 24813a69cae8SSudarsana Reddy Kalluru 24823a69cae8SSudarsana Reddy Kalluru return rc; 24833a69cae8SSudarsana Reddy Kalluru } 24843a69cae8SSudarsana Reddy Kalluru 24853a69cae8SSudarsana Reddy Kalluru /* Binary file format [General header] - 24863a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24873a69cae8SSudarsana Reddy Kalluru * 0B | QED_NVM_SIGNATURE | 24883a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24893a69cae8SSudarsana Reddy Kalluru * 8B | Highest command in this batchfile | Reserved | 24903a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24913a69cae8SSudarsana Reddy Kalluru */ 24923a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_validate(struct qed_dev *cdev, 24933a69cae8SSudarsana Reddy Kalluru const struct firmware *image, 24943a69cae8SSudarsana Reddy Kalluru const u8 **data) 24953a69cae8SSudarsana Reddy Kalluru { 24963a69cae8SSudarsana Reddy Kalluru u32 signature, len; 24973a69cae8SSudarsana Reddy Kalluru 24983a69cae8SSudarsana Reddy Kalluru /* Check minimum size */ 24993a69cae8SSudarsana Reddy Kalluru if (image->size < 12) { 25003a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size); 25013a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25023a69cae8SSudarsana Reddy Kalluru } 25033a69cae8SSudarsana Reddy Kalluru 25043a69cae8SSudarsana Reddy Kalluru /* Check signature */ 25053a69cae8SSudarsana Reddy Kalluru signature = *((u32 *)(*data)); 25063a69cae8SSudarsana Reddy Kalluru if (signature != QED_NVM_SIGNATURE) { 25073a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Wrong signature '%08x'\n", signature); 25083a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25093a69cae8SSudarsana Reddy Kalluru } 25103a69cae8SSudarsana Reddy Kalluru 25113a69cae8SSudarsana Reddy Kalluru *data += 4; 25123a69cae8SSudarsana Reddy Kalluru /* Validate internal size equals the image-size */ 25133a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 25143a69cae8SSudarsana Reddy Kalluru if (len != image->size) { 25153a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n", 25163a69cae8SSudarsana Reddy Kalluru len, (u32)image->size); 25173a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25183a69cae8SSudarsana Reddy Kalluru } 25193a69cae8SSudarsana Reddy Kalluru 25203a69cae8SSudarsana Reddy Kalluru *data += 4; 25213a69cae8SSudarsana Reddy Kalluru /* Make sure driver familiar with all commands necessary for this */ 25223a69cae8SSudarsana Reddy Kalluru if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) { 25233a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n", 25243a69cae8SSudarsana Reddy Kalluru *((u16 *)(*data))); 25253a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25263a69cae8SSudarsana Reddy Kalluru } 25273a69cae8SSudarsana Reddy Kalluru 25283a69cae8SSudarsana Reddy Kalluru *data += 4; 25293a69cae8SSudarsana Reddy Kalluru 25303a69cae8SSudarsana Reddy Kalluru return 0; 25313a69cae8SSudarsana Reddy Kalluru } 25323a69cae8SSudarsana Reddy Kalluru 25330dabbe1bSSudarsana Reddy Kalluru /* Binary file format - 25340dabbe1bSSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 25350dabbe1bSSudarsana Reddy Kalluru * 0B | 0x5 [command index] | 25362da244a5SSudarsana Reddy Kalluru * 4B | Number of config attributes | Reserved | 25372da244a5SSudarsana Reddy Kalluru * 4B | Config ID | Entity ID | Length | 25382da244a5SSudarsana Reddy Kalluru * 4B | Value | 25390dabbe1bSSudarsana Reddy Kalluru * | | 25400dabbe1bSSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 25412da244a5SSudarsana Reddy Kalluru * There can be several cfg_id-entity_id-Length-Value sets as specified by 25422da244a5SSudarsana Reddy Kalluru * 'Number of config attributes'. 25430dabbe1bSSudarsana Reddy Kalluru * 25440dabbe1bSSudarsana Reddy Kalluru * The API parses config attributes from the user provided buffer and flashes 25450dabbe1bSSudarsana Reddy Kalluru * them to the respective NVM path using Management FW inerface. 25460dabbe1bSSudarsana Reddy Kalluru */ 25470dabbe1bSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data) 25480dabbe1bSSudarsana Reddy Kalluru { 25490dabbe1bSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 25500dabbe1bSSudarsana Reddy Kalluru u8 entity_id, len, buf[32]; 2551c63b0968SSudarsana Reddy Kalluru bool need_nvm_init = true; 25520dabbe1bSSudarsana Reddy Kalluru struct qed_ptt *ptt; 25530dabbe1bSSudarsana Reddy Kalluru u16 cfg_id, count; 25540dabbe1bSSudarsana Reddy Kalluru int rc = 0, i; 25550dabbe1bSSudarsana Reddy Kalluru u32 flags; 25560dabbe1bSSudarsana Reddy Kalluru 25570dabbe1bSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 25580dabbe1bSSudarsana Reddy Kalluru if (!ptt) 25590dabbe1bSSudarsana Reddy Kalluru return -EAGAIN; 25600dabbe1bSSudarsana Reddy Kalluru 25610dabbe1bSSudarsana Reddy Kalluru /* NVM CFG ID attribute header */ 25620dabbe1bSSudarsana Reddy Kalluru *data += 4; 25630dabbe1bSSudarsana Reddy Kalluru count = *((u16 *)*data); 25642da244a5SSudarsana Reddy Kalluru *data += 4; 25650dabbe1bSSudarsana Reddy Kalluru 25660dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 25672da244a5SSudarsana Reddy Kalluru "Read config ids: num_attrs = %0d\n", count); 2568c63b0968SSudarsana Reddy Kalluru /* NVM CFG ID attributes. Start loop index from 1 to avoid additional 2569c63b0968SSudarsana Reddy Kalluru * arithmetic operations in the implementation. 2570c63b0968SSudarsana Reddy Kalluru */ 2571c63b0968SSudarsana Reddy Kalluru for (i = 1; i <= count; i++) { 25720dabbe1bSSudarsana Reddy Kalluru cfg_id = *((u16 *)*data); 25730dabbe1bSSudarsana Reddy Kalluru *data += 2; 25742da244a5SSudarsana Reddy Kalluru entity_id = **data; 25752da244a5SSudarsana Reddy Kalluru (*data)++; 25760dabbe1bSSudarsana Reddy Kalluru len = **data; 25770dabbe1bSSudarsana Reddy Kalluru (*data)++; 25780dabbe1bSSudarsana Reddy Kalluru memcpy(buf, *data, len); 25790dabbe1bSSudarsana Reddy Kalluru *data += len; 25800dabbe1bSSudarsana Reddy Kalluru 2581c63b0968SSudarsana Reddy Kalluru flags = 0; 2582c63b0968SSudarsana Reddy Kalluru if (need_nvm_init) { 2583c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_INIT; 2584c63b0968SSudarsana Reddy Kalluru need_nvm_init = false; 2585c63b0968SSudarsana Reddy Kalluru } 2586c63b0968SSudarsana Reddy Kalluru 2587c63b0968SSudarsana Reddy Kalluru /* Commit to flash and free the resources */ 2588c63b0968SSudarsana Reddy Kalluru if (!(i % QED_NVM_CFG_MAX_ATTRS) || i == count) { 2589c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_COMMIT | 2590c63b0968SSudarsana Reddy Kalluru QED_NVM_CFG_OPTION_FREE; 2591c63b0968SSudarsana Reddy Kalluru need_nvm_init = true; 2592c63b0968SSudarsana Reddy Kalluru } 2593c63b0968SSudarsana Reddy Kalluru 2594c63b0968SSudarsana Reddy Kalluru if (entity_id) 2595c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_ENTITY_SEL; 25960dabbe1bSSudarsana Reddy Kalluru 25970dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 25982da244a5SSudarsana Reddy Kalluru "cfg_id = %d entity = %d len = %d\n", cfg_id, 25992da244a5SSudarsana Reddy Kalluru entity_id, len); 26000dabbe1bSSudarsana Reddy Kalluru rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags, 26010dabbe1bSSudarsana Reddy Kalluru buf, len); 26020dabbe1bSSudarsana Reddy Kalluru if (rc) { 26030dabbe1bSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id); 26040dabbe1bSSudarsana Reddy Kalluru break; 26050dabbe1bSSudarsana Reddy Kalluru } 26060dabbe1bSSudarsana Reddy Kalluru } 26070dabbe1bSSudarsana Reddy Kalluru 26080dabbe1bSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26090dabbe1bSSudarsana Reddy Kalluru 26100dabbe1bSSudarsana Reddy Kalluru return rc; 26110dabbe1bSSudarsana Reddy Kalluru } 26120dabbe1bSSudarsana Reddy Kalluru 26139e54ba7cSSudarsana Reddy Kalluru #define QED_MAX_NVM_BUF_LEN 32 26149e54ba7cSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_len(struct qed_dev *cdev, u32 cmd) 26159e54ba7cSSudarsana Reddy Kalluru { 26169e54ba7cSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26179e54ba7cSSudarsana Reddy Kalluru u8 buf[QED_MAX_NVM_BUF_LEN]; 26189e54ba7cSSudarsana Reddy Kalluru struct qed_ptt *ptt; 26199e54ba7cSSudarsana Reddy Kalluru u32 len; 26209e54ba7cSSudarsana Reddy Kalluru int rc; 26219e54ba7cSSudarsana Reddy Kalluru 26229e54ba7cSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26239e54ba7cSSudarsana Reddy Kalluru if (!ptt) 26249e54ba7cSSudarsana Reddy Kalluru return QED_MAX_NVM_BUF_LEN; 26259e54ba7cSSudarsana Reddy Kalluru 26269e54ba7cSSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, 0, QED_NVM_CFG_GET_FLAGS, buf, 26279e54ba7cSSudarsana Reddy Kalluru &len); 26289e54ba7cSSudarsana Reddy Kalluru if (rc || !len) { 26299e54ba7cSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26309e54ba7cSSudarsana Reddy Kalluru len = QED_MAX_NVM_BUF_LEN; 26319e54ba7cSSudarsana Reddy Kalluru } 26329e54ba7cSSudarsana Reddy Kalluru 26339e54ba7cSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26349e54ba7cSSudarsana Reddy Kalluru 26359e54ba7cSSudarsana Reddy Kalluru return len; 26369e54ba7cSSudarsana Reddy Kalluru } 26379e54ba7cSSudarsana Reddy Kalluru 26382d4c8495SSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_read(struct qed_dev *cdev, u8 **data, 26392d4c8495SSudarsana Reddy Kalluru u32 cmd, u32 entity_id) 26402d4c8495SSudarsana Reddy Kalluru { 26412d4c8495SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26422d4c8495SSudarsana Reddy Kalluru struct qed_ptt *ptt; 26432d4c8495SSudarsana Reddy Kalluru u32 flags, len; 26442d4c8495SSudarsana Reddy Kalluru int rc = 0; 26452d4c8495SSudarsana Reddy Kalluru 26462d4c8495SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26472d4c8495SSudarsana Reddy Kalluru if (!ptt) 26482d4c8495SSudarsana Reddy Kalluru return -EAGAIN; 26492d4c8495SSudarsana Reddy Kalluru 26502d4c8495SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26512d4c8495SSudarsana Reddy Kalluru "Read config cmd = %d entity id %d\n", cmd, entity_id); 26522d4c8495SSudarsana Reddy Kalluru flags = entity_id ? QED_NVM_CFG_GET_PF_FLAGS : QED_NVM_CFG_GET_FLAGS; 26532d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, entity_id, flags, *data, &len); 26542d4c8495SSudarsana Reddy Kalluru if (rc) 26552d4c8495SSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26562d4c8495SSudarsana Reddy Kalluru 26572d4c8495SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26582d4c8495SSudarsana Reddy Kalluru 26592d4c8495SSudarsana Reddy Kalluru return rc; 26602d4c8495SSudarsana Reddy Kalluru } 26612d4c8495SSudarsana Reddy Kalluru 26623a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash(struct qed_dev *cdev, const char *name) 26633a69cae8SSudarsana Reddy Kalluru { 26643a69cae8SSudarsana Reddy Kalluru const struct firmware *image; 26653a69cae8SSudarsana Reddy Kalluru const u8 *data, *data_end; 26663a69cae8SSudarsana Reddy Kalluru u32 cmd_type; 26673a69cae8SSudarsana Reddy Kalluru int rc; 26683a69cae8SSudarsana Reddy Kalluru 26693a69cae8SSudarsana Reddy Kalluru rc = request_firmware(&image, name, &cdev->pdev->dev); 26703a69cae8SSudarsana Reddy Kalluru if (rc) { 26713a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find '%s'\n", name); 26723a69cae8SSudarsana Reddy Kalluru return rc; 26733a69cae8SSudarsana Reddy Kalluru } 26743a69cae8SSudarsana Reddy Kalluru 26753a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26763a69cae8SSudarsana Reddy Kalluru "Flashing '%s' - firmware's data at %p, size is %08x\n", 26773a69cae8SSudarsana Reddy Kalluru name, image->data, (u32)image->size); 26783a69cae8SSudarsana Reddy Kalluru data = image->data; 26793a69cae8SSudarsana Reddy Kalluru data_end = data + image->size; 26803a69cae8SSudarsana Reddy Kalluru 26813a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_validate(cdev, image, &data); 26823a69cae8SSudarsana Reddy Kalluru if (rc) 26833a69cae8SSudarsana Reddy Kalluru goto exit; 26843a69cae8SSudarsana Reddy Kalluru 26853a69cae8SSudarsana Reddy Kalluru while (data < data_end) { 26863a69cae8SSudarsana Reddy Kalluru bool check_resp = false; 26873a69cae8SSudarsana Reddy Kalluru 26883a69cae8SSudarsana Reddy Kalluru /* Parse the actual command */ 26893a69cae8SSudarsana Reddy Kalluru cmd_type = *((u32 *)data); 26903a69cae8SSudarsana Reddy Kalluru switch (cmd_type) { 26913a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_DATA: 26923a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_data(cdev, &data, 26933a69cae8SSudarsana Reddy Kalluru &check_resp); 26943a69cae8SSudarsana Reddy Kalluru break; 26953a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_START: 26963a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_start(cdev, &data, 26973a69cae8SSudarsana Reddy Kalluru &check_resp); 26983a69cae8SSudarsana Reddy Kalluru break; 26993a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CHANGE: 27003a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access(cdev, &data, 27013a69cae8SSudarsana Reddy Kalluru &check_resp); 27023a69cae8SSudarsana Reddy Kalluru break; 27030dabbe1bSSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CFG_ID: 27040dabbe1bSSudarsana Reddy Kalluru rc = qed_nvm_flash_cfg_write(cdev, &data); 27050dabbe1bSSudarsana Reddy Kalluru break; 27063a69cae8SSudarsana Reddy Kalluru default: 27073a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Unknown command %08x\n", cmd_type); 27083a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27093a69cae8SSudarsana Reddy Kalluru goto exit; 27103a69cae8SSudarsana Reddy Kalluru } 27113a69cae8SSudarsana Reddy Kalluru 27123a69cae8SSudarsana Reddy Kalluru if (rc) { 27133a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Command %08x failed\n", cmd_type); 27143a69cae8SSudarsana Reddy Kalluru goto exit; 27153a69cae8SSudarsana Reddy Kalluru } 27163a69cae8SSudarsana Reddy Kalluru 27173a69cae8SSudarsana Reddy Kalluru /* Check response if needed */ 27183a69cae8SSudarsana Reddy Kalluru if (check_resp) { 27193a69cae8SSudarsana Reddy Kalluru u32 mcp_response = 0; 27203a69cae8SSudarsana Reddy Kalluru 27213a69cae8SSudarsana Reddy Kalluru if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) { 27223a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed getting MCP response\n"); 27233a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27243a69cae8SSudarsana Reddy Kalluru goto exit; 27253a69cae8SSudarsana Reddy Kalluru } 27263a69cae8SSudarsana Reddy Kalluru 27273a69cae8SSudarsana Reddy Kalluru switch (mcp_response & FW_MSG_CODE_MASK) { 27283a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_OK: 27293a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_OK: 27303a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK: 27313a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_PHY_OK: 27323a69cae8SSudarsana Reddy Kalluru break; 27333a69cae8SSudarsana Reddy Kalluru default: 27343a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "MFW returns error: %08x\n", 27353a69cae8SSudarsana Reddy Kalluru mcp_response); 27363a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27373a69cae8SSudarsana Reddy Kalluru goto exit; 27383a69cae8SSudarsana Reddy Kalluru } 27393a69cae8SSudarsana Reddy Kalluru } 27403a69cae8SSudarsana Reddy Kalluru } 27413a69cae8SSudarsana Reddy Kalluru 27423a69cae8SSudarsana Reddy Kalluru exit: 27433a69cae8SSudarsana Reddy Kalluru release_firmware(image); 27443a69cae8SSudarsana Reddy Kalluru 27453a69cae8SSudarsana Reddy Kalluru return rc; 27463a69cae8SSudarsana Reddy Kalluru } 27473a69cae8SSudarsana Reddy Kalluru 274820675b37SMintz, Yuval static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, 274920675b37SMintz, Yuval u8 *buf, u16 len) 275020675b37SMintz, Yuval { 275120675b37SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 275220675b37SMintz, Yuval 2753b60bfdfeSDenis Bolotin return qed_mcp_get_nvm_image(hwfn, type, buf, len); 275420675b37SMintz, Yuval } 275520675b37SMintz, Yuval 275664515dc8STomer Tayar void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) 275764515dc8STomer Tayar { 275864515dc8STomer Tayar struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 275964515dc8STomer Tayar void *cookie = p_hwfn->cdev->ops_cookie; 276064515dc8STomer Tayar 276164515dc8STomer Tayar if (ops && ops->schedule_recovery_handler) 276264515dc8STomer Tayar ops->schedule_recovery_handler(cookie); 276364515dc8STomer Tayar } 276464515dc8STomer Tayar 2765c6b7314dSAlexander Lobakin static const char * const qed_hw_err_type_descr[] = { 2766d639836aSIgor Russkikh [QED_HW_ERR_FAN_FAIL] = "Fan Failure", 2767d639836aSIgor Russkikh [QED_HW_ERR_MFW_RESP_FAIL] = "MFW Response Failure", 2768d639836aSIgor Russkikh [QED_HW_ERR_HW_ATTN] = "HW Attention", 2769d639836aSIgor Russkikh [QED_HW_ERR_DMAE_FAIL] = "DMAE Failure", 2770d639836aSIgor Russkikh [QED_HW_ERR_RAMROD_FAIL] = "Ramrod Failure", 2771d639836aSIgor Russkikh [QED_HW_ERR_FW_ASSERT] = "FW Assertion", 2772d639836aSIgor Russkikh [QED_HW_ERR_LAST] = "Unknown", 2773d639836aSIgor Russkikh }; 2774d639836aSIgor Russkikh 2775d639836aSIgor Russkikh void qed_hw_error_occurred(struct qed_hwfn *p_hwfn, 2776d639836aSIgor Russkikh enum qed_hw_err_type err_type) 2777d639836aSIgor Russkikh { 2778d639836aSIgor Russkikh struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 2779d639836aSIgor Russkikh void *cookie = p_hwfn->cdev->ops_cookie; 2780c6b7314dSAlexander Lobakin const char *err_str; 2781d639836aSIgor Russkikh 2782d639836aSIgor Russkikh if (err_type > QED_HW_ERR_LAST) 2783d639836aSIgor Russkikh err_type = QED_HW_ERR_LAST; 2784d639836aSIgor Russkikh err_str = qed_hw_err_type_descr[err_type]; 2785d639836aSIgor Russkikh 2786d639836aSIgor Russkikh DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str); 2787d639836aSIgor Russkikh 2788936c7ba4SIgor Russkikh /* Call the HW error handler of the protocol driver. 2789936c7ba4SIgor Russkikh * If it is not available - perform a minimal handling of preventing 2790936c7ba4SIgor Russkikh * HW attentions from being reasserted. 2791d639836aSIgor Russkikh */ 2792d639836aSIgor Russkikh if (ops && ops->schedule_hw_err_handler) 2793d639836aSIgor Russkikh ops->schedule_hw_err_handler(cookie, err_type); 2794936c7ba4SIgor Russkikh else 2795936c7ba4SIgor Russkikh qed_int_attn_clr_enable(p_hwfn->cdev, true); 2796d639836aSIgor Russkikh } 2797d639836aSIgor Russkikh 2798722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, 2799477f2d14SRahul Verma void *handle) 2800722003acSSudarsana Reddy Kalluru { 2801477f2d14SRahul Verma return qed_set_queue_coalesce(rx_coal, tx_coal, handle); 2802722003acSSudarsana Reddy Kalluru } 2803722003acSSudarsana Reddy Kalluru 280491420b83SSudarsana Kalluru static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) 280591420b83SSudarsana Kalluru { 280691420b83SSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 280791420b83SSudarsana Kalluru struct qed_ptt *ptt; 280891420b83SSudarsana Kalluru int status = 0; 280991420b83SSudarsana Kalluru 281091420b83SSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 281191420b83SSudarsana Kalluru if (!ptt) 281291420b83SSudarsana Kalluru return -EAGAIN; 281391420b83SSudarsana Kalluru 281491420b83SSudarsana Kalluru status = qed_mcp_set_led(hwfn, ptt, mode); 281591420b83SSudarsana Kalluru 281691420b83SSudarsana Kalluru qed_ptt_release(hwfn, ptt); 281791420b83SSudarsana Kalluru 281891420b83SSudarsana Kalluru return status; 281991420b83SSudarsana Kalluru } 282091420b83SSudarsana Kalluru 2821b228cb16SIgor Russkikh int qed_recovery_process(struct qed_dev *cdev) 282264515dc8STomer Tayar { 282364515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 282464515dc8STomer Tayar struct qed_ptt *p_ptt; 282564515dc8STomer Tayar int rc = 0; 282664515dc8STomer Tayar 282764515dc8STomer Tayar p_ptt = qed_ptt_acquire(p_hwfn); 282864515dc8STomer Tayar if (!p_ptt) 282964515dc8STomer Tayar return -EAGAIN; 283064515dc8STomer Tayar 283164515dc8STomer Tayar rc = qed_start_recovery_process(p_hwfn, p_ptt); 283264515dc8STomer Tayar 283364515dc8STomer Tayar qed_ptt_release(p_hwfn, p_ptt); 283464515dc8STomer Tayar 283564515dc8STomer Tayar return rc; 283664515dc8STomer Tayar } 283764515dc8STomer Tayar 283814d39648SMintz, Yuval static int qed_update_wol(struct qed_dev *cdev, bool enabled) 283914d39648SMintz, Yuval { 284014d39648SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 284114d39648SMintz, Yuval struct qed_ptt *ptt; 284214d39648SMintz, Yuval int rc = 0; 284314d39648SMintz, Yuval 284414d39648SMintz, Yuval if (IS_VF(cdev)) 284514d39648SMintz, Yuval return 0; 284614d39648SMintz, Yuval 284714d39648SMintz, Yuval ptt = qed_ptt_acquire(hwfn); 284814d39648SMintz, Yuval if (!ptt) 284914d39648SMintz, Yuval return -EAGAIN; 285014d39648SMintz, Yuval 285114d39648SMintz, Yuval rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED 285214d39648SMintz, Yuval : QED_OV_WOL_DISABLED); 285314d39648SMintz, Yuval if (rc) 285414d39648SMintz, Yuval goto out; 285514d39648SMintz, Yuval rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 285614d39648SMintz, Yuval 285714d39648SMintz, Yuval out: 285814d39648SMintz, Yuval qed_ptt_release(hwfn, ptt); 285914d39648SMintz, Yuval return rc; 286014d39648SMintz, Yuval } 286114d39648SMintz, Yuval 28620fefbfbaSSudarsana Kalluru static int qed_update_drv_state(struct qed_dev *cdev, bool active) 28630fefbfbaSSudarsana Kalluru { 28640fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28650fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28660fefbfbaSSudarsana Kalluru int status = 0; 28670fefbfbaSSudarsana Kalluru 28680fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28690fefbfbaSSudarsana Kalluru return 0; 28700fefbfbaSSudarsana Kalluru 28710fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 28720fefbfbaSSudarsana Kalluru if (!ptt) 28730fefbfbaSSudarsana Kalluru return -EAGAIN; 28740fefbfbaSSudarsana Kalluru 28750fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? 28760fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_ACTIVE : 28770fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_DISABLED); 28780fefbfbaSSudarsana Kalluru 28790fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 28800fefbfbaSSudarsana Kalluru 28810fefbfbaSSudarsana Kalluru return status; 28820fefbfbaSSudarsana Kalluru } 28830fefbfbaSSudarsana Kalluru 28840fefbfbaSSudarsana Kalluru static int qed_update_mac(struct qed_dev *cdev, u8 *mac) 28850fefbfbaSSudarsana Kalluru { 28860fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28870fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28880fefbfbaSSudarsana Kalluru int status = 0; 28890fefbfbaSSudarsana Kalluru 28900fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28910fefbfbaSSudarsana Kalluru return 0; 28920fefbfbaSSudarsana Kalluru 28930fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 28940fefbfbaSSudarsana Kalluru if (!ptt) 28950fefbfbaSSudarsana Kalluru return -EAGAIN; 28960fefbfbaSSudarsana Kalluru 28970fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mac(hwfn, ptt, mac); 28980fefbfbaSSudarsana Kalluru if (status) 28990fefbfbaSSudarsana Kalluru goto out; 29000fefbfbaSSudarsana Kalluru 29010fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29020fefbfbaSSudarsana Kalluru 29030fefbfbaSSudarsana Kalluru out: 29040fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29050fefbfbaSSudarsana Kalluru return status; 29060fefbfbaSSudarsana Kalluru } 29070fefbfbaSSudarsana Kalluru 29080fefbfbaSSudarsana Kalluru static int qed_update_mtu(struct qed_dev *cdev, u16 mtu) 29090fefbfbaSSudarsana Kalluru { 29100fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29110fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 29120fefbfbaSSudarsana Kalluru int status = 0; 29130fefbfbaSSudarsana Kalluru 29140fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 29150fefbfbaSSudarsana Kalluru return 0; 29160fefbfbaSSudarsana Kalluru 29170fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 29180fefbfbaSSudarsana Kalluru if (!ptt) 29190fefbfbaSSudarsana Kalluru return -EAGAIN; 29200fefbfbaSSudarsana Kalluru 29210fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); 29220fefbfbaSSudarsana Kalluru if (status) 29230fefbfbaSSudarsana Kalluru goto out; 29240fefbfbaSSudarsana Kalluru 29250fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29260fefbfbaSSudarsana Kalluru 29270fefbfbaSSudarsana Kalluru out: 29280fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29290fefbfbaSSudarsana Kalluru return status; 29300fefbfbaSSudarsana Kalluru } 29310fefbfbaSSudarsana Kalluru 2932b51dab46SSudarsana Reddy Kalluru static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 2933b51dab46SSudarsana Reddy Kalluru u8 dev_addr, u32 offset, u32 len) 2934b51dab46SSudarsana Reddy Kalluru { 2935b51dab46SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 2936b51dab46SSudarsana Reddy Kalluru struct qed_ptt *ptt; 2937b51dab46SSudarsana Reddy Kalluru int rc = 0; 2938b51dab46SSudarsana Reddy Kalluru 2939b51dab46SSudarsana Reddy Kalluru if (IS_VF(cdev)) 2940b51dab46SSudarsana Reddy Kalluru return 0; 2941b51dab46SSudarsana Reddy Kalluru 2942b51dab46SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 2943b51dab46SSudarsana Reddy Kalluru if (!ptt) 2944b51dab46SSudarsana Reddy Kalluru return -EAGAIN; 2945b51dab46SSudarsana Reddy Kalluru 2946b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr, 2947b51dab46SSudarsana Reddy Kalluru offset, len, buf); 2948b51dab46SSudarsana Reddy Kalluru 2949b51dab46SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 2950b51dab46SSudarsana Reddy Kalluru 2951b51dab46SSudarsana Reddy Kalluru return rc; 2952b51dab46SSudarsana Reddy Kalluru } 2953b51dab46SSudarsana Reddy Kalluru 29543b86bd07SSudarsana Reddy Kalluru static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val) 29553b86bd07SSudarsana Reddy Kalluru { 29563b86bd07SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29573b86bd07SSudarsana Reddy Kalluru struct qed_ptt *ptt; 29583b86bd07SSudarsana Reddy Kalluru int rc = 0; 29593b86bd07SSudarsana Reddy Kalluru 29603b86bd07SSudarsana Reddy Kalluru if (IS_VF(cdev)) 29613b86bd07SSudarsana Reddy Kalluru return 0; 29623b86bd07SSudarsana Reddy Kalluru 29633b86bd07SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 29643b86bd07SSudarsana Reddy Kalluru if (!ptt) 29653b86bd07SSudarsana Reddy Kalluru return -EAGAIN; 29663b86bd07SSudarsana Reddy Kalluru 29672d22bc83SMichal Kalderon rc = qed_dbg_grc_config(hwfn, cfg_id, val); 29683b86bd07SSudarsana Reddy Kalluru 29693b86bd07SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 29703b86bd07SSudarsana Reddy Kalluru 29713b86bd07SSudarsana Reddy Kalluru return rc; 29723b86bd07SSudarsana Reddy Kalluru } 29733b86bd07SSudarsana Reddy Kalluru 297408eb1fb0SMichal Kalderon static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev) 297508eb1fb0SMichal Kalderon { 297608eb1fb0SMichal Kalderon return QED_AFFIN_HWFN_IDX(cdev); 297708eb1fb0SMichal Kalderon } 297808eb1fb0SMichal Kalderon 29798c93beafSYuval Mintz static struct qed_selftest_ops qed_selftest_ops_pass = { 298003dc76caSSudarsana Reddy Kalluru .selftest_memory = &qed_selftest_memory, 298103dc76caSSudarsana Reddy Kalluru .selftest_interrupt = &qed_selftest_interrupt, 298203dc76caSSudarsana Reddy Kalluru .selftest_register = &qed_selftest_register, 298303dc76caSSudarsana Reddy Kalluru .selftest_clock = &qed_selftest_clock, 29847a4b21b7SMintz, Yuval .selftest_nvram = &qed_selftest_nvram, 298503dc76caSSudarsana Reddy Kalluru }; 298603dc76caSSudarsana Reddy Kalluru 2987fe56b9e6SYuval Mintz const struct qed_common_ops qed_common_ops_pass = { 298803dc76caSSudarsana Reddy Kalluru .selftest = &qed_selftest_ops_pass, 2989fe56b9e6SYuval Mintz .probe = &qed_probe, 2990fe56b9e6SYuval Mintz .remove = &qed_remove, 2991fe56b9e6SYuval Mintz .set_power_state = &qed_set_power_state, 2992712c3cbfSMintz, Yuval .set_name = &qed_set_name, 2993fe56b9e6SYuval Mintz .update_pf_params = &qed_update_pf_params, 2994fe56b9e6SYuval Mintz .slowpath_start = &qed_slowpath_start, 2995fe56b9e6SYuval Mintz .slowpath_stop = &qed_slowpath_stop, 2996fe56b9e6SYuval Mintz .set_fp_int = &qed_set_int_fp, 2997fe56b9e6SYuval Mintz .get_fp_int = &qed_get_int_fp, 2998fe56b9e6SYuval Mintz .sb_init = &qed_sb_init, 2999fe56b9e6SYuval Mintz .sb_release = &qed_sb_release, 3000fe56b9e6SYuval Mintz .simd_handler_config = &qed_simd_handler_config, 3001fe56b9e6SYuval Mintz .simd_handler_clean = &qed_simd_handler_clean, 30021e128c81SArun Easi .dbg_grc = &qed_dbg_grc, 30031e128c81SArun Easi .dbg_grc_size = &qed_dbg_grc_size, 3004fe7cd2bfSYuval Mintz .can_link_change = &qed_can_link_change, 3005cc875c2eSYuval Mintz .set_link = &qed_set_link, 3006cc875c2eSYuval Mintz .get_link = &qed_get_current_link, 3007fe56b9e6SYuval Mintz .drain = &qed_drain, 3008fe56b9e6SYuval Mintz .update_msglvl = &qed_init_dp, 3009755f982bSIgor Russkikh .devlink_register = qed_devlink_register, 3010755f982bSIgor Russkikh .devlink_unregister = qed_devlink_unregister, 30114f5a8db2SIgor Russkikh .report_fatal_error = qed_report_fatal_error, 3012e0971c83STomer Tayar .dbg_all_data = &qed_dbg_all_data, 3013e0971c83STomer Tayar .dbg_all_data_size = &qed_dbg_all_data_size, 3014fe56b9e6SYuval Mintz .chain_alloc = &qed_chain_alloc, 3015fe56b9e6SYuval Mintz .chain_free = &qed_chain_free, 30163a69cae8SSudarsana Reddy Kalluru .nvm_flash = &qed_nvm_flash, 301720675b37SMintz, Yuval .nvm_get_image = &qed_nvm_get_image, 3018722003acSSudarsana Reddy Kalluru .set_coalesce = &qed_set_coalesce, 301991420b83SSudarsana Kalluru .set_led = &qed_set_led, 302064515dc8STomer Tayar .recovery_process = &qed_recovery_process, 302164515dc8STomer Tayar .recovery_prolog = &qed_recovery_prolog, 3022936c7ba4SIgor Russkikh .attn_clr_enable = &qed_int_attn_clr_enable, 30230fefbfbaSSudarsana Kalluru .update_drv_state = &qed_update_drv_state, 30240fefbfbaSSudarsana Kalluru .update_mac = &qed_update_mac, 30250fefbfbaSSudarsana Kalluru .update_mtu = &qed_update_mtu, 302614d39648SMintz, Yuval .update_wol = &qed_update_wol, 30270e1f1044SAriel Elior .db_recovery_add = &qed_db_recovery_add, 30280e1f1044SAriel Elior .db_recovery_del = &qed_db_recovery_del, 3029b51dab46SSudarsana Reddy Kalluru .read_module_eeprom = &qed_read_module_eeprom, 303008eb1fb0SMichal Kalderon .get_affin_hwfn_idx = &qed_get_affin_hwfn_idx, 30312d4c8495SSudarsana Reddy Kalluru .read_nvm_cfg = &qed_nvm_flash_cfg_read, 30329e54ba7cSSudarsana Reddy Kalluru .read_nvm_cfg_len = &qed_nvm_flash_cfg_len, 30333b86bd07SSudarsana Reddy Kalluru .set_grc_config = &qed_set_grc_config, 3034fe56b9e6SYuval Mintz }; 30356c754246SSudarsana Reddy Kalluru 30366c754246SSudarsana Reddy Kalluru void qed_get_protocol_stats(struct qed_dev *cdev, 30376c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type type, 30386c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats *stats) 30396c754246SSudarsana Reddy Kalluru { 30406c754246SSudarsana Reddy Kalluru struct qed_eth_stats eth_stats; 30416c754246SSudarsana Reddy Kalluru 30426c754246SSudarsana Reddy Kalluru memset(stats, 0, sizeof(*stats)); 30436c754246SSudarsana Reddy Kalluru 30446c754246SSudarsana Reddy Kalluru switch (type) { 30456c754246SSudarsana Reddy Kalluru case QED_MCP_LAN_STATS: 30466c754246SSudarsana Reddy Kalluru qed_get_vport_stats(cdev, ð_stats); 30479c79ddaaSMintz, Yuval stats->lan_stats.ucast_rx_pkts = 30489c79ddaaSMintz, Yuval eth_stats.common.rx_ucast_pkts; 30499c79ddaaSMintz, Yuval stats->lan_stats.ucast_tx_pkts = 30509c79ddaaSMintz, Yuval eth_stats.common.tx_ucast_pkts; 30516c754246SSudarsana Reddy Kalluru stats->lan_stats.fcs_err = -1; 30526c754246SSudarsana Reddy Kalluru break; 30531e128c81SArun Easi case QED_MCP_FCOE_STATS: 30541e128c81SArun Easi qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); 30551e128c81SArun Easi break; 30562f2b2614SMintz, Yuval case QED_MCP_ISCSI_STATS: 30572f2b2614SMintz, Yuval qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); 30582f2b2614SMintz, Yuval break; 30596c754246SSudarsana Reddy Kalluru default: 3060512c7840SMintz, Yuval DP_VERBOSE(cdev, QED_MSG_SP, 3061512c7840SMintz, Yuval "Invalid protocol type = %d\n", type); 30626c754246SSudarsana Reddy Kalluru return; 30636c754246SSudarsana Reddy Kalluru } 30646c754246SSudarsana Reddy Kalluru } 30652528c389SSudarsana Reddy Kalluru 306659ccf86fSSudarsana Reddy Kalluru int qed_mfw_tlv_req(struct qed_hwfn *hwfn) 306759ccf86fSSudarsana Reddy Kalluru { 306859ccf86fSSudarsana Reddy Kalluru DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 306959ccf86fSSudarsana Reddy Kalluru "Scheduling slowpath task [Flag: %d]\n", 307059ccf86fSSudarsana Reddy Kalluru QED_SLOWPATH_MFW_TLV_REQ); 307159ccf86fSSudarsana Reddy Kalluru smp_mb__before_atomic(); 307259ccf86fSSudarsana Reddy Kalluru set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags); 307359ccf86fSSudarsana Reddy Kalluru smp_mb__after_atomic(); 307459ccf86fSSudarsana Reddy Kalluru queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 307559ccf86fSSudarsana Reddy Kalluru 307659ccf86fSSudarsana Reddy Kalluru return 0; 307759ccf86fSSudarsana Reddy Kalluru } 307859ccf86fSSudarsana Reddy Kalluru 307959ccf86fSSudarsana Reddy Kalluru static void 308059ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv) 308159ccf86fSSudarsana Reddy Kalluru { 308259ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = cdev->protocol_ops.common; 308359ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats_common *p_common; 308459ccf86fSSudarsana Reddy Kalluru struct qed_generic_tlvs gen_tlvs; 308559ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats stats; 308659ccf86fSSudarsana Reddy Kalluru int i; 308759ccf86fSSudarsana Reddy Kalluru 308859ccf86fSSudarsana Reddy Kalluru memset(&gen_tlvs, 0, sizeof(gen_tlvs)); 308959ccf86fSSudarsana Reddy Kalluru op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs); 309059ccf86fSSudarsana Reddy Kalluru 309159ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM) 309259ccf86fSSudarsana Reddy Kalluru tlv->flags.ipv4_csum_offload = true; 309359ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_LSO) 309459ccf86fSSudarsana Reddy Kalluru tlv->flags.lso_supported = true; 309559ccf86fSSudarsana Reddy Kalluru tlv->flags.b_set = true; 309659ccf86fSSudarsana Reddy Kalluru 309759ccf86fSSudarsana Reddy Kalluru for (i = 0; i < QED_TLV_MAC_COUNT; i++) { 309859ccf86fSSudarsana Reddy Kalluru if (is_valid_ether_addr(gen_tlvs.mac[i])) { 309959ccf86fSSudarsana Reddy Kalluru ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]); 310059ccf86fSSudarsana Reddy Kalluru tlv->mac_set[i] = true; 310159ccf86fSSudarsana Reddy Kalluru } 310259ccf86fSSudarsana Reddy Kalluru } 310359ccf86fSSudarsana Reddy Kalluru 310459ccf86fSSudarsana Reddy Kalluru qed_get_vport_stats(cdev, &stats); 310559ccf86fSSudarsana Reddy Kalluru p_common = &stats.common; 310659ccf86fSSudarsana Reddy Kalluru tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 310759ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_pkts; 310859ccf86fSSudarsana Reddy Kalluru tlv->rx_frames_set = true; 310959ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 311059ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_bytes; 311159ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 311259ccf86fSSudarsana Reddy Kalluru tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 311359ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_pkts; 311459ccf86fSSudarsana Reddy Kalluru tlv->tx_frames_set = true; 311559ccf86fSSudarsana Reddy Kalluru tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 311659ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_bytes; 311759ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 311859ccf86fSSudarsana Reddy Kalluru } 311959ccf86fSSudarsana Reddy Kalluru 31202528c389SSudarsana Reddy Kalluru int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type, 31212528c389SSudarsana Reddy Kalluru union qed_mfw_tlv_data *tlv_buf) 31222528c389SSudarsana Reddy Kalluru { 312359ccf86fSSudarsana Reddy Kalluru struct qed_dev *cdev = hwfn->cdev; 312459ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *ops; 312559ccf86fSSudarsana Reddy Kalluru 312659ccf86fSSudarsana Reddy Kalluru ops = cdev->protocol_ops.common; 312759ccf86fSSudarsana Reddy Kalluru if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) { 312859ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Can't collect TLV management info\n"); 31292528c389SSudarsana Reddy Kalluru return -EINVAL; 31302528c389SSudarsana Reddy Kalluru } 313159ccf86fSSudarsana Reddy Kalluru 313259ccf86fSSudarsana Reddy Kalluru switch (type) { 313359ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_GENERIC: 313459ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic); 313559ccf86fSSudarsana Reddy Kalluru break; 313659ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ETH: 313759ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth); 313859ccf86fSSudarsana Reddy Kalluru break; 313959ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_FCOE: 314059ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe); 314159ccf86fSSudarsana Reddy Kalluru break; 314259ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ISCSI: 314359ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi); 314459ccf86fSSudarsana Reddy Kalluru break; 314559ccf86fSSudarsana Reddy Kalluru default: 314659ccf86fSSudarsana Reddy Kalluru break; 314759ccf86fSSudarsana Reddy Kalluru } 314859ccf86fSSudarsana Reddy Kalluru 314959ccf86fSSudarsana Reddy Kalluru return 0; 315059ccf86fSSudarsana Reddy Kalluru } 3151