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[] = 527a3febedSShai 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_25g[] __initconst = { 10399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 10499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 10599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 10699785a87SAlexander Lobakin }; 10799785a87SAlexander Lobakin 10899785a87SAlexander Lobakin static const u32 qed_mfw_ext_40g[] __initconst = { 10999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 11099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 11199785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 11299785a87SAlexander Lobakin ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 11399785a87SAlexander Lobakin }; 11499785a87SAlexander Lobakin 11599785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r[] __initconst = { 11699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 11799785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 11899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 11999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 12099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 12199785a87SAlexander Lobakin }; 12299785a87SAlexander Lobakin 12399785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r2[] __initconst = { 12499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 12599785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 12699785a87SAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 12799785a87SAlexander Lobakin }; 12899785a87SAlexander Lobakin 12999785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r2[] __initconst = { 13099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 13199785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 13299785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 13399785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 13499785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 13599785a87SAlexander Lobakin }; 13699785a87SAlexander Lobakin 13799785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r4[] __initconst = { 13899785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 13999785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 14099785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 14199785a87SAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 14299785a87SAlexander Lobakin }; 14399785a87SAlexander Lobakin 14499785a87SAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_ext_maps[] __ro_after_init = { 14599785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_1G, qed_mfw_ext_1g), 14699785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_10G, qed_mfw_ext_10g), 14799785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_25G, qed_mfw_ext_25g), 14899785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_40G, qed_mfw_ext_40g), 14999785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R, 15099785a87SAlexander Lobakin qed_mfw_ext_50g_base_r), 15199785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R2, 15299785a87SAlexander Lobakin qed_mfw_ext_50g_base_r2), 15399785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R2, 15499785a87SAlexander Lobakin qed_mfw_ext_100g_base_r2), 15599785a87SAlexander Lobakin QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R4, 15699785a87SAlexander Lobakin qed_mfw_ext_100g_base_r4), 15799785a87SAlexander Lobakin }; 15899785a87SAlexander Lobakin 159097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_1g[] __initconst = { 160097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 161097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 162097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 163097818fcSAlexander Lobakin }; 164097818fcSAlexander Lobakin 165097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_10g[] __initconst = { 166097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 167097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 168097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 169097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 170097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 171097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 172097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 173097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 174097818fcSAlexander Lobakin }; 175097818fcSAlexander Lobakin 176097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_20g[] __initconst = { 177097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 178097818fcSAlexander Lobakin }; 179097818fcSAlexander Lobakin 180097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_25g[] __initconst = { 181097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 182097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 183097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 184097818fcSAlexander Lobakin }; 185097818fcSAlexander Lobakin 186097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_40g[] __initconst = { 187097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 188097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 189097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 190097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 191097818fcSAlexander Lobakin }; 192097818fcSAlexander Lobakin 193097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_50g[] __initconst = { 194097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 195097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 196097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 197097818fcSAlexander Lobakin }; 198097818fcSAlexander Lobakin 199097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_bb_100g[] __initconst = { 200097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 201097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 202097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 203097818fcSAlexander Lobakin ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 204097818fcSAlexander Lobakin }; 205097818fcSAlexander Lobakin 206097818fcSAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_legacy_maps[] __ro_after_init = { 207097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G, 208097818fcSAlexander Lobakin qed_mfw_legacy_1g), 209097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G, 210097818fcSAlexander Lobakin qed_mfw_legacy_10g), 211097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G, 212097818fcSAlexander Lobakin qed_mfw_legacy_20g), 213097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G, 214097818fcSAlexander Lobakin qed_mfw_legacy_25g), 215097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G, 216097818fcSAlexander Lobakin qed_mfw_legacy_40g), 217097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G, 218097818fcSAlexander Lobakin qed_mfw_legacy_50g), 219097818fcSAlexander Lobakin QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G, 220097818fcSAlexander Lobakin qed_mfw_legacy_bb_100g), 221097818fcSAlexander Lobakin }; 222097818fcSAlexander Lobakin 223097818fcSAlexander Lobakin static void __init qed_mfw_speed_map_populate(struct qed_mfw_speed_map *map) 224097818fcSAlexander Lobakin { 225097818fcSAlexander Lobakin linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps); 226097818fcSAlexander Lobakin 227097818fcSAlexander Lobakin map->cap_arr = NULL; 228097818fcSAlexander Lobakin map->arr_size = 0; 229097818fcSAlexander Lobakin } 230097818fcSAlexander Lobakin 231097818fcSAlexander Lobakin static void __init qed_mfw_speed_maps_init(void) 232097818fcSAlexander Lobakin { 233097818fcSAlexander Lobakin u32 i; 234097818fcSAlexander Lobakin 23599785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) 23699785a87SAlexander Lobakin qed_mfw_speed_map_populate(qed_mfw_ext_maps + i); 23799785a87SAlexander Lobakin 238097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) 239097818fcSAlexander Lobakin qed_mfw_speed_map_populate(qed_mfw_legacy_maps + i); 240097818fcSAlexander Lobakin } 241097818fcSAlexander Lobakin 242fe56b9e6SYuval Mintz static int __init qed_init(void) 243fe56b9e6SYuval Mintz { 244fe56b9e6SYuval Mintz pr_info("%s", version); 245fe56b9e6SYuval Mintz 246097818fcSAlexander Lobakin qed_mfw_speed_maps_init(); 247097818fcSAlexander Lobakin 248fe56b9e6SYuval Mintz return 0; 249fe56b9e6SYuval Mintz } 250fe56b9e6SYuval Mintz module_init(qed_init); 251097818fcSAlexander Lobakin 252097818fcSAlexander Lobakin static void __exit qed_exit(void) 253097818fcSAlexander Lobakin { 254097818fcSAlexander Lobakin /* To prevent marking this module as "permanent" */ 255097818fcSAlexander Lobakin } 256097818fcSAlexander Lobakin module_exit(qed_exit); 257fe56b9e6SYuval Mintz 258fe56b9e6SYuval Mintz /* Check if the DMA controller on the machine can properly handle the DMA 259fe56b9e6SYuval Mintz * addressing required by the device. 260fe56b9e6SYuval Mintz */ 261fe56b9e6SYuval Mintz static int qed_set_coherency_mask(struct qed_dev *cdev) 262fe56b9e6SYuval Mintz { 263fe56b9e6SYuval Mintz struct device *dev = &cdev->pdev->dev; 264fe56b9e6SYuval Mintz 265fe56b9e6SYuval Mintz if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { 266fe56b9e6SYuval Mintz if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { 267fe56b9e6SYuval Mintz DP_NOTICE(cdev, 268fe56b9e6SYuval Mintz "Can't request 64-bit consistent allocations\n"); 269fe56b9e6SYuval Mintz return -EIO; 270fe56b9e6SYuval Mintz } 271fe56b9e6SYuval Mintz } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { 272fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); 273fe56b9e6SYuval Mintz return -EIO; 274fe56b9e6SYuval Mintz } 275fe56b9e6SYuval Mintz 276fe56b9e6SYuval Mintz return 0; 277fe56b9e6SYuval Mintz } 278fe56b9e6SYuval Mintz 279fe56b9e6SYuval Mintz static void qed_free_pci(struct qed_dev *cdev) 280fe56b9e6SYuval Mintz { 281fe56b9e6SYuval Mintz struct pci_dev *pdev = cdev->pdev; 282fe56b9e6SYuval Mintz 2832196d831SSudarsana Reddy Kalluru pci_disable_pcie_error_reporting(pdev); 2842196d831SSudarsana Reddy Kalluru 2851a850bfcSMintz, Yuval if (cdev->doorbells && cdev->db_size) 286fe56b9e6SYuval Mintz iounmap(cdev->doorbells); 287fe56b9e6SYuval Mintz if (cdev->regview) 288fe56b9e6SYuval Mintz iounmap(cdev->regview); 289fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) 290fe56b9e6SYuval Mintz pci_release_regions(pdev); 291fe56b9e6SYuval Mintz 292fe56b9e6SYuval Mintz pci_disable_device(pdev); 293fe56b9e6SYuval Mintz } 294fe56b9e6SYuval Mintz 2950dfaba6dSYuval Mintz #define PCI_REVISION_ID_ERROR_VAL 0xff 2960dfaba6dSYuval Mintz 297fe56b9e6SYuval Mintz /* Performs PCI initializations as well as initializing PCI-related parameters 298fe56b9e6SYuval Mintz * in the device structrue. Returns 0 in case of success. 299fe56b9e6SYuval Mintz */ 3001a635e48SYuval Mintz static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) 301fe56b9e6SYuval Mintz { 3020dfaba6dSYuval Mintz u8 rev_id; 303fe56b9e6SYuval Mintz int rc; 304fe56b9e6SYuval Mintz 305fe56b9e6SYuval Mintz cdev->pdev = pdev; 306fe56b9e6SYuval Mintz 307fe56b9e6SYuval Mintz rc = pci_enable_device(pdev); 308fe56b9e6SYuval Mintz if (rc) { 309fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot enable PCI device\n"); 310fe56b9e6SYuval Mintz goto err0; 311fe56b9e6SYuval Mintz } 312fe56b9e6SYuval Mintz 313fe56b9e6SYuval Mintz if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 314fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #0\n"); 315fe56b9e6SYuval Mintz rc = -EIO; 316fe56b9e6SYuval Mintz goto err1; 317fe56b9e6SYuval Mintz } 318fe56b9e6SYuval Mintz 3191408cc1fSYuval Mintz if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 320fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #2\n"); 321fe56b9e6SYuval Mintz rc = -EIO; 322fe56b9e6SYuval Mintz goto err1; 323fe56b9e6SYuval Mintz } 324fe56b9e6SYuval Mintz 325fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) { 326fe56b9e6SYuval Mintz rc = pci_request_regions(pdev, "qed"); 327fe56b9e6SYuval Mintz if (rc) { 328fe56b9e6SYuval Mintz DP_NOTICE(cdev, 329fe56b9e6SYuval Mintz "Failed to request PCI memory resources\n"); 330fe56b9e6SYuval Mintz goto err1; 331fe56b9e6SYuval Mintz } 332fe56b9e6SYuval Mintz pci_set_master(pdev); 333fe56b9e6SYuval Mintz pci_save_state(pdev); 334fe56b9e6SYuval Mintz } 335fe56b9e6SYuval Mintz 3360dfaba6dSYuval Mintz pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 3370dfaba6dSYuval Mintz if (rev_id == PCI_REVISION_ID_ERROR_VAL) { 3380dfaba6dSYuval Mintz DP_NOTICE(cdev, 3390dfaba6dSYuval Mintz "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", 3400dfaba6dSYuval Mintz rev_id); 3410dfaba6dSYuval Mintz rc = -ENODEV; 3420dfaba6dSYuval Mintz goto err2; 3430dfaba6dSYuval Mintz } 344fe56b9e6SYuval Mintz if (!pci_is_pcie(pdev)) { 345fe56b9e6SYuval Mintz DP_NOTICE(cdev, "The bus is not PCI Express\n"); 346fe56b9e6SYuval Mintz rc = -EIO; 347fe56b9e6SYuval Mintz goto err2; 348fe56b9e6SYuval Mintz } 349fe56b9e6SYuval Mintz 350fe56b9e6SYuval Mintz cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); 351416cdf06SYuval Mintz if (IS_PF(cdev) && !cdev->pci_params.pm_cap) 352fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot find power management capability\n"); 353fe56b9e6SYuval Mintz 354fe56b9e6SYuval Mintz rc = qed_set_coherency_mask(cdev); 355fe56b9e6SYuval Mintz if (rc) 356fe56b9e6SYuval Mintz goto err2; 357fe56b9e6SYuval Mintz 358fe56b9e6SYuval Mintz cdev->pci_params.mem_start = pci_resource_start(pdev, 0); 359fe56b9e6SYuval Mintz cdev->pci_params.mem_end = pci_resource_end(pdev, 0); 360fe56b9e6SYuval Mintz cdev->pci_params.irq = pdev->irq; 361fe56b9e6SYuval Mintz 362fe56b9e6SYuval Mintz cdev->regview = pci_ioremap_bar(pdev, 0); 363fe56b9e6SYuval Mintz if (!cdev->regview) { 364fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map register space, aborting\n"); 365fe56b9e6SYuval Mintz rc = -ENOMEM; 366fe56b9e6SYuval Mintz goto err2; 367fe56b9e6SYuval Mintz } 368fe56b9e6SYuval Mintz 369fe56b9e6SYuval Mintz cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); 370fe56b9e6SYuval Mintz cdev->db_size = pci_resource_len(cdev->pdev, 2); 3711a850bfcSMintz, Yuval if (!cdev->db_size) { 3721a850bfcSMintz, Yuval if (IS_PF(cdev)) { 3731a850bfcSMintz, Yuval DP_NOTICE(cdev, "No Doorbell bar available\n"); 3741a850bfcSMintz, Yuval return -EINVAL; 3751a850bfcSMintz, Yuval } else { 3761a850bfcSMintz, Yuval return 0; 3771a850bfcSMintz, Yuval } 3781a850bfcSMintz, Yuval } 3791a850bfcSMintz, Yuval 380fe56b9e6SYuval Mintz cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); 3811a850bfcSMintz, Yuval 382fe56b9e6SYuval Mintz if (!cdev->doorbells) { 383fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map doorbell space\n"); 384fe56b9e6SYuval Mintz return -ENOMEM; 385fe56b9e6SYuval Mintz } 386fe56b9e6SYuval Mintz 3872196d831SSudarsana Reddy Kalluru /* AER (Advanced Error reporting) configuration */ 3882196d831SSudarsana Reddy Kalluru rc = pci_enable_pcie_error_reporting(pdev); 3892196d831SSudarsana Reddy Kalluru if (rc) 3902196d831SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 3912196d831SSudarsana Reddy Kalluru "Failed to configure PCIe AER [%d]\n", rc); 3922196d831SSudarsana Reddy Kalluru 393fe56b9e6SYuval Mintz return 0; 394fe56b9e6SYuval Mintz 395fe56b9e6SYuval Mintz err2: 396fe56b9e6SYuval Mintz pci_release_regions(pdev); 397fe56b9e6SYuval Mintz err1: 398fe56b9e6SYuval Mintz pci_disable_device(pdev); 399fe56b9e6SYuval Mintz err0: 400fe56b9e6SYuval Mintz return rc; 401fe56b9e6SYuval Mintz } 402fe56b9e6SYuval Mintz 403fe56b9e6SYuval Mintz int qed_fill_dev_info(struct qed_dev *cdev, 404fe56b9e6SYuval Mintz struct qed_dev_info *dev_info) 405fe56b9e6SYuval Mintz { 406c851a9dcSKalderon, Michal struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 407c851a9dcSKalderon, Michal struct qed_hw_info *hw_info = &p_hwfn->hw_info; 40819489c7fSChopra, Manish struct qed_tunnel_info *tun = &cdev->tunnel; 409cee4d264SManish Chopra struct qed_ptt *ptt; 410cee4d264SManish Chopra 411fe56b9e6SYuval Mintz memset(dev_info, 0, sizeof(struct qed_dev_info)); 412fe56b9e6SYuval Mintz 41319489c7fSChopra, Manish if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 41419489c7fSChopra, Manish tun->vxlan.b_mode_enabled) 41519489c7fSChopra, Manish dev_info->vxlan_enable = true; 41619489c7fSChopra, Manish 41719489c7fSChopra, Manish if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && 41819489c7fSChopra, Manish tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 41919489c7fSChopra, Manish tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 42019489c7fSChopra, Manish dev_info->gre_enable = true; 42119489c7fSChopra, Manish 42219489c7fSChopra, Manish if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && 42319489c7fSChopra, Manish tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 42419489c7fSChopra, Manish tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 42519489c7fSChopra, Manish dev_info->geneve_enable = true; 42619489c7fSChopra, Manish 427fe56b9e6SYuval Mintz dev_info->num_hwfns = cdev->num_hwfns; 428fe56b9e6SYuval Mintz dev_info->pci_mem_start = cdev->pci_params.mem_start; 429fe56b9e6SYuval Mintz dev_info->pci_mem_end = cdev->pci_params.mem_end; 430fe56b9e6SYuval Mintz dev_info->pci_irq = cdev->pci_params.irq; 431c851a9dcSKalderon, Michal dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn); 4329c79ddaaSMintz, Yuval dev_info->dev_type = cdev->type; 433c851a9dcSKalderon, Michal ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr); 434fe56b9e6SYuval Mintz 4351408cc1fSYuval Mintz if (IS_PF(cdev)) { 436fe56b9e6SYuval Mintz dev_info->fw_major = FW_MAJOR_VERSION; 437fe56b9e6SYuval Mintz dev_info->fw_minor = FW_MINOR_VERSION; 438fe56b9e6SYuval Mintz dev_info->fw_rev = FW_REVISION_VERSION; 439fe56b9e6SYuval Mintz dev_info->fw_eng = FW_ENGINEERING_VERSION; 4400bc5fe85SSudarsana Reddy Kalluru dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH, 4410bc5fe85SSudarsana Reddy Kalluru &cdev->mf_bits); 4422d2fe843SDmitry Bogdanov if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits)) 4432d2fe843SDmitry Bogdanov dev_info->b_arfs_capable = true; 444831bfb0eSYuval Mintz dev_info->tx_switching = true; 44514d39648SMintz, Yuval 446c851a9dcSKalderon, Michal if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME) 44714d39648SMintz, Yuval dev_info->wol_support = true; 4483c5da942SMintz, Yuval 449df9c716dSSudarsana Reddy Kalluru dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn); 450df9c716dSSudarsana Reddy Kalluru 4513c5da942SMintz, Yuval dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; 4521408cc1fSYuval Mintz } else { 4531408cc1fSYuval Mintz qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, 4541408cc1fSYuval Mintz &dev_info->fw_minor, &dev_info->fw_rev, 4551408cc1fSYuval Mintz &dev_info->fw_eng); 4561408cc1fSYuval Mintz } 457fe56b9e6SYuval Mintz 4581408cc1fSYuval Mintz if (IS_PF(cdev)) { 459cee4d264SManish Chopra ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 460cee4d264SManish Chopra if (ptt) { 4611408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, 4621408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 4631408cc1fSYuval Mintz 464ae33666aSTomer Tayar qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, 465ae33666aSTomer Tayar &dev_info->mbi_version); 466ae33666aSTomer Tayar 467cee4d264SManish Chopra qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, 468cee4d264SManish Chopra &dev_info->flash_size); 469cee4d264SManish Chopra 470cee4d264SManish Chopra qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); 471cee4d264SManish Chopra } 4721408cc1fSYuval Mintz } else { 4731408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, 4741408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 4751408cc1fSYuval Mintz } 476cee4d264SManish Chopra 477c851a9dcSKalderon, Michal dev_info->mtu = hw_info->mtu; 47853916a67SIgor Russkikh cdev->common_dev_info = *dev_info; 4790fefbfbaSSudarsana Kalluru 480fe56b9e6SYuval Mintz return 0; 481fe56b9e6SYuval Mintz } 482fe56b9e6SYuval Mintz 483fe56b9e6SYuval Mintz static void qed_free_cdev(struct qed_dev *cdev) 484fe56b9e6SYuval Mintz { 485fe56b9e6SYuval Mintz kfree((void *)cdev); 486fe56b9e6SYuval Mintz } 487fe56b9e6SYuval Mintz 488fe56b9e6SYuval Mintz static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) 489fe56b9e6SYuval Mintz { 490fe56b9e6SYuval Mintz struct qed_dev *cdev; 491fe56b9e6SYuval Mintz 492fe56b9e6SYuval Mintz cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 493fe56b9e6SYuval Mintz if (!cdev) 494fe56b9e6SYuval Mintz return cdev; 495fe56b9e6SYuval Mintz 496fe56b9e6SYuval Mintz qed_init_struct(cdev); 497fe56b9e6SYuval Mintz 498fe56b9e6SYuval Mintz return cdev; 499fe56b9e6SYuval Mintz } 500fe56b9e6SYuval Mintz 501fe56b9e6SYuval Mintz /* Sets the requested power state */ 5021a635e48SYuval Mintz static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) 503fe56b9e6SYuval Mintz { 504fe56b9e6SYuval Mintz if (!cdev) 505fe56b9e6SYuval Mintz return -ENODEV; 506fe56b9e6SYuval Mintz 507fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); 508fe56b9e6SYuval Mintz return 0; 509fe56b9e6SYuval Mintz } 510fe56b9e6SYuval Mintz 511fe56b9e6SYuval Mintz /* probing */ 512fe56b9e6SYuval Mintz static struct qed_dev *qed_probe(struct pci_dev *pdev, 5131408cc1fSYuval Mintz struct qed_probe_params *params) 514fe56b9e6SYuval Mintz { 515fe56b9e6SYuval Mintz struct qed_dev *cdev; 516fe56b9e6SYuval Mintz int rc; 517fe56b9e6SYuval Mintz 518fe56b9e6SYuval Mintz cdev = qed_alloc_cdev(pdev); 519fe56b9e6SYuval Mintz if (!cdev) 520fe56b9e6SYuval Mintz goto err0; 521fe56b9e6SYuval Mintz 522712c3cbfSMintz, Yuval cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; 5231408cc1fSYuval Mintz cdev->protocol = params->protocol; 524fe56b9e6SYuval Mintz 5251408cc1fSYuval Mintz if (params->is_vf) 5261408cc1fSYuval Mintz cdev->b_is_vf = true; 5271408cc1fSYuval Mintz 5281408cc1fSYuval Mintz qed_init_dp(cdev, params->dp_module, params->dp_level); 529fe56b9e6SYuval Mintz 53064515dc8STomer Tayar cdev->recov_in_prog = params->recov_in_prog; 53164515dc8STomer Tayar 532fe56b9e6SYuval Mintz rc = qed_init_pci(cdev, pdev); 533fe56b9e6SYuval Mintz if (rc) { 534fe56b9e6SYuval Mintz DP_ERR(cdev, "init pci failed\n"); 535fe56b9e6SYuval Mintz goto err1; 536fe56b9e6SYuval Mintz } 537fe56b9e6SYuval Mintz DP_INFO(cdev, "PCI init completed successfully\n"); 538fe56b9e6SYuval Mintz 539fe56b9e6SYuval Mintz rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); 540fe56b9e6SYuval Mintz if (rc) { 541fe56b9e6SYuval Mintz DP_ERR(cdev, "hw prepare failed\n"); 542fe56b9e6SYuval Mintz goto err2; 543fe56b9e6SYuval Mintz } 544fe56b9e6SYuval Mintz 545f2a74107SPrabhakar Kushwaha DP_INFO(cdev, "%s completed successfully\n", __func__); 546fe56b9e6SYuval Mintz 547fe56b9e6SYuval Mintz return cdev; 548fe56b9e6SYuval Mintz 549fe56b9e6SYuval Mintz err2: 550fe56b9e6SYuval Mintz qed_free_pci(cdev); 551fe56b9e6SYuval Mintz err1: 552fe56b9e6SYuval Mintz qed_free_cdev(cdev); 553fe56b9e6SYuval Mintz err0: 554fe56b9e6SYuval Mintz return NULL; 555fe56b9e6SYuval Mintz } 556fe56b9e6SYuval Mintz 557fe56b9e6SYuval Mintz static void qed_remove(struct qed_dev *cdev) 558fe56b9e6SYuval Mintz { 559fe56b9e6SYuval Mintz if (!cdev) 560fe56b9e6SYuval Mintz return; 561fe56b9e6SYuval Mintz 562fe56b9e6SYuval Mintz qed_hw_remove(cdev); 563fe56b9e6SYuval Mintz 564fe56b9e6SYuval Mintz qed_free_pci(cdev); 565fe56b9e6SYuval Mintz 566fe56b9e6SYuval Mintz qed_set_power_state(cdev, PCI_D3hot); 567fe56b9e6SYuval Mintz 568fe56b9e6SYuval Mintz qed_free_cdev(cdev); 569fe56b9e6SYuval Mintz } 570fe56b9e6SYuval Mintz 571fe56b9e6SYuval Mintz static void qed_disable_msix(struct qed_dev *cdev) 572fe56b9e6SYuval Mintz { 573fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 574fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 575fe56b9e6SYuval Mintz kfree(cdev->int_params.msix_table); 576fe56b9e6SYuval Mintz } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { 577fe56b9e6SYuval Mintz pci_disable_msi(cdev->pdev); 578fe56b9e6SYuval Mintz } 579fe56b9e6SYuval Mintz 580fe56b9e6SYuval Mintz memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); 581fe56b9e6SYuval Mintz } 582fe56b9e6SYuval Mintz 583fe56b9e6SYuval Mintz static int qed_enable_msix(struct qed_dev *cdev, 584fe56b9e6SYuval Mintz struct qed_int_params *int_params) 585fe56b9e6SYuval Mintz { 586fe56b9e6SYuval Mintz int i, rc, cnt; 587fe56b9e6SYuval Mintz 588fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 589fe56b9e6SYuval Mintz 590fe56b9e6SYuval Mintz for (i = 0; i < cnt; i++) 591fe56b9e6SYuval Mintz int_params->msix_table[i].entry = i; 592fe56b9e6SYuval Mintz 593fe56b9e6SYuval Mintz rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, 594fe56b9e6SYuval Mintz int_params->in.min_msix_cnt, cnt); 595fe56b9e6SYuval Mintz if (rc < cnt && rc >= int_params->in.min_msix_cnt && 596fe56b9e6SYuval Mintz (rc % cdev->num_hwfns)) { 597fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 598fe56b9e6SYuval Mintz 599fe56b9e6SYuval Mintz /* If fastpath is initialized, we need at least one interrupt 600fe56b9e6SYuval Mintz * per hwfn [and the slow path interrupts]. New requested number 601fe56b9e6SYuval Mintz * should be a multiple of the number of hwfns. 602fe56b9e6SYuval Mintz */ 603fe56b9e6SYuval Mintz cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; 604fe56b9e6SYuval Mintz DP_NOTICE(cdev, 605fe56b9e6SYuval Mintz "Trying to enable MSI-X with less vectors (%d out of %d)\n", 606fe56b9e6SYuval Mintz cnt, int_params->in.num_vectors); 6071a635e48SYuval Mintz rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, 6081a635e48SYuval Mintz cnt); 609fe56b9e6SYuval Mintz if (!rc) 610fe56b9e6SYuval Mintz rc = cnt; 611fe56b9e6SYuval Mintz } 612fe56b9e6SYuval Mintz 613b0cd0853SShai Malin /* For VFs, we should return with an error in case we didn't get the 614b0cd0853SShai Malin * exact number of msix vectors as we requested. 615b0cd0853SShai Malin * Not doing that will lead to a crash when starting queues for 616b0cd0853SShai Malin * this VF. 617b0cd0853SShai Malin */ 618b0cd0853SShai Malin if ((IS_PF(cdev) && rc > 0) || (IS_VF(cdev) && rc == cnt)) { 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) { 978f2a74107SPrabhakar Kushwaha DP_ERR(cdev, "%s ERR\n", __func__); 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); 1159f2a74107SPrabhakar Kushwaha /* Memory barrier after setting atomic bit */ 1160a1b469b8SAriel Elior smp_mb__after_atomic(); 1161a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay); 1162a1b469b8SAriel Elior 1163a1b469b8SAriel Elior return 0; 1164a1b469b8SAriel Elior } 1165a1b469b8SAriel Elior 1166a1b469b8SAriel Elior void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn) 1167a1b469b8SAriel Elior { 1168a1b469b8SAriel Elior /* Reset periodic Doorbell Recovery counter */ 1169a1b469b8SAriel Elior p_hwfn->periodic_db_rec_count = QED_PERIODIC_DB_REC_COUNT; 1170a1b469b8SAriel Elior 1171a1b469b8SAriel Elior /* Don't schedule periodic Doorbell Recovery if already scheduled */ 1172a1b469b8SAriel Elior if (test_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1173a1b469b8SAriel Elior &p_hwfn->slowpath_task_flags)) 1174a1b469b8SAriel Elior return; 1175a1b469b8SAriel Elior 1176a1b469b8SAriel Elior qed_slowpath_delayed_work(p_hwfn, QED_SLOWPATH_PERIODIC_DB_REC, 1177a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1178a1b469b8SAriel Elior } 1179a1b469b8SAriel Elior 118059ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_wq_stop(struct qed_dev *cdev) 118159ccf86fSSudarsana Reddy Kalluru { 11823b85720dSYuval Basson int i; 118359ccf86fSSudarsana Reddy Kalluru 118459ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 118559ccf86fSSudarsana Reddy Kalluru return; 118659ccf86fSSudarsana Reddy Kalluru 118759ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 118859ccf86fSSudarsana Reddy Kalluru if (!cdev->hwfns[i].slowpath_wq) 118959ccf86fSSudarsana Reddy Kalluru continue; 119059ccf86fSSudarsana Reddy Kalluru 1191a1b469b8SAriel Elior /* Stop queuing new delayed works */ 1192a1b469b8SAriel Elior cdev->hwfns[i].slowpath_wq_active = false; 1193a1b469b8SAriel Elior 11943b85720dSYuval Basson cancel_delayed_work(&cdev->hwfns[i].slowpath_task); 119559ccf86fSSudarsana Reddy Kalluru destroy_workqueue(cdev->hwfns[i].slowpath_wq); 119659ccf86fSSudarsana Reddy Kalluru } 119759ccf86fSSudarsana Reddy Kalluru } 119859ccf86fSSudarsana Reddy Kalluru 119959ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_task(struct work_struct *work) 120059ccf86fSSudarsana Reddy Kalluru { 120159ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 120259ccf86fSSudarsana Reddy Kalluru slowpath_task.work); 120359ccf86fSSudarsana Reddy Kalluru struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 120459ccf86fSSudarsana Reddy Kalluru 120559ccf86fSSudarsana Reddy Kalluru if (!ptt) { 1206a1b469b8SAriel Elior if (hwfn->slowpath_wq_active) 1207a1b469b8SAriel Elior queue_delayed_work(hwfn->slowpath_wq, 1208a1b469b8SAriel Elior &hwfn->slowpath_task, 0); 1209a1b469b8SAriel Elior 121059ccf86fSSudarsana Reddy Kalluru return; 121159ccf86fSSudarsana Reddy Kalluru } 121259ccf86fSSudarsana Reddy Kalluru 121359ccf86fSSudarsana Reddy Kalluru if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ, 121459ccf86fSSudarsana Reddy Kalluru &hwfn->slowpath_task_flags)) 121559ccf86fSSudarsana Reddy Kalluru qed_mfw_process_tlv_req(hwfn, ptt); 121659ccf86fSSudarsana Reddy Kalluru 1217a1b469b8SAriel Elior if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC, 1218a1b469b8SAriel Elior &hwfn->slowpath_task_flags)) { 1219995c3d49SShai Malin /* skip qed_db_rec_handler during recovery/unload */ 1220995c3d49SShai Malin if (hwfn->cdev->recov_in_prog || !hwfn->slowpath_wq_active) 1221995c3d49SShai Malin goto out; 1222995c3d49SShai Malin 1223a1b469b8SAriel Elior qed_db_rec_handler(hwfn, ptt); 1224a1b469b8SAriel Elior if (hwfn->periodic_db_rec_count--) 1225a1b469b8SAriel Elior qed_slowpath_delayed_work(hwfn, 1226a1b469b8SAriel Elior QED_SLOWPATH_PERIODIC_DB_REC, 1227a1b469b8SAriel Elior QED_PERIODIC_DB_REC_INTERVAL); 1228a1b469b8SAriel Elior } 1229a1b469b8SAriel Elior 1230995c3d49SShai Malin out: 123159ccf86fSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 123259ccf86fSSudarsana Reddy Kalluru } 123359ccf86fSSudarsana Reddy Kalluru 123459ccf86fSSudarsana Reddy Kalluru static int qed_slowpath_wq_start(struct qed_dev *cdev) 123559ccf86fSSudarsana Reddy Kalluru { 123659ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn; 123759ccf86fSSudarsana Reddy Kalluru char name[NAME_SIZE]; 123859ccf86fSSudarsana Reddy Kalluru int i; 123959ccf86fSSudarsana Reddy Kalluru 124059ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 124159ccf86fSSudarsana Reddy Kalluru return 0; 124259ccf86fSSudarsana Reddy Kalluru 124359ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 124459ccf86fSSudarsana Reddy Kalluru hwfn = &cdev->hwfns[i]; 124559ccf86fSSudarsana Reddy Kalluru 124659ccf86fSSudarsana Reddy Kalluru snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", 124759ccf86fSSudarsana Reddy Kalluru cdev->pdev->bus->number, 124859ccf86fSSudarsana Reddy Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 124959ccf86fSSudarsana Reddy Kalluru 125059ccf86fSSudarsana Reddy Kalluru hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); 125159ccf86fSSudarsana Reddy Kalluru if (!hwfn->slowpath_wq) { 125259ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); 125359ccf86fSSudarsana Reddy Kalluru return -ENOMEM; 125459ccf86fSSudarsana Reddy Kalluru } 125559ccf86fSSudarsana Reddy Kalluru 125659ccf86fSSudarsana Reddy Kalluru INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task); 1257a1b469b8SAriel Elior hwfn->slowpath_wq_active = true; 125859ccf86fSSudarsana Reddy Kalluru } 125959ccf86fSSudarsana Reddy Kalluru 126059ccf86fSSudarsana Reddy Kalluru return 0; 126159ccf86fSSudarsana Reddy Kalluru } 126259ccf86fSSudarsana Reddy Kalluru 1263fe56b9e6SYuval Mintz static int qed_slowpath_start(struct qed_dev *cdev, 1264fe56b9e6SYuval Mintz struct qed_slowpath_params *params) 1265fe56b9e6SYuval Mintz { 12665d24bcf1STomer Tayar struct qed_drv_load_params drv_load_params; 1267c0c2d0b4SMintz, Yuval struct qed_hw_init_params hw_init_params; 1268fe56b9e6SYuval Mintz struct qed_mcp_drv_version drv_version; 126919968430SChopra, Manish struct qed_tunnel_info tunn_info; 1270fe56b9e6SYuval Mintz const u8 *data = NULL; 1271fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 1272c78c70faSSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 127337bff2b9SYuval Mintz int rc = -EINVAL; 127437bff2b9SYuval Mintz 127537bff2b9SYuval Mintz if (qed_iov_wq_start(cdev)) 127637bff2b9SYuval Mintz goto err; 1277fe56b9e6SYuval Mintz 127859ccf86fSSudarsana Reddy Kalluru if (qed_slowpath_wq_start(cdev)) 127959ccf86fSSudarsana Reddy Kalluru goto err; 128059ccf86fSSudarsana Reddy Kalluru 12811408cc1fSYuval Mintz if (IS_PF(cdev)) { 1282fe56b9e6SYuval Mintz rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, 1283fe56b9e6SYuval Mintz &cdev->pdev->dev); 1284fe56b9e6SYuval Mintz if (rc) { 1285fe56b9e6SYuval Mintz DP_NOTICE(cdev, 1286fe56b9e6SYuval Mintz "Failed to find fw file - /lib/firmware/%s\n", 1287fe56b9e6SYuval Mintz QED_FW_FILE_NAME); 1288fe56b9e6SYuval Mintz goto err; 1289fe56b9e6SYuval Mintz } 1290c78c70faSSudarsana Reddy Kalluru 1291d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) { 1292d51e4af5SChopra, Manish p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 1293d51e4af5SChopra, Manish if (p_ptt) { 1294d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; 1295d51e4af5SChopra, Manish } else { 1296d51e4af5SChopra, Manish DP_NOTICE(cdev, 1297d51e4af5SChopra, Manish "Failed to acquire PTT for aRFS\n"); 1298d51e4af5SChopra, Manish goto err; 1299d51e4af5SChopra, Manish } 1300d51e4af5SChopra, Manish } 13011408cc1fSYuval Mintz } 1302fe56b9e6SYuval Mintz 13030e191827SSudarsana Reddy Kalluru cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 1304fe56b9e6SYuval Mintz rc = qed_nic_setup(cdev); 1305fe56b9e6SYuval Mintz if (rc) 1306fe56b9e6SYuval Mintz goto err; 1307fe56b9e6SYuval Mintz 13081408cc1fSYuval Mintz if (IS_PF(cdev)) 1309fe56b9e6SYuval Mintz rc = qed_slowpath_setup_int(cdev, params->int_mode); 13101408cc1fSYuval Mintz else 13111408cc1fSYuval Mintz rc = qed_slowpath_vf_setup_int(cdev); 1312fe56b9e6SYuval Mintz if (rc) 1313fe56b9e6SYuval Mintz goto err1; 1314fe56b9e6SYuval Mintz 13151408cc1fSYuval Mintz if (IS_PF(cdev)) { 1316fe56b9e6SYuval Mintz /* Allocate stream for unzipping */ 1317fe56b9e6SYuval Mintz rc = qed_alloc_stream_mem(cdev); 13182591c280SJoe Perches if (rc) 13198f16bc97SSudarsana Kalluru goto err2; 1320fe56b9e6SYuval Mintz 13218ac1ed79SJoe Perches /* First Dword used to differentiate between various sources */ 1322351a4dedSYuval Mintz data = cdev->firmware->data + sizeof(u32); 1323c965db44STomer Tayar 1324c965db44STomer Tayar qed_dbg_pf_init(cdev); 13251408cc1fSYuval Mintz } 1326fe56b9e6SYuval Mintz 13271408cc1fSYuval Mintz /* Start the slowpath */ 1328c0c2d0b4SMintz, Yuval memset(&hw_init_params, 0, sizeof(hw_init_params)); 132919968430SChopra, Manish memset(&tunn_info, 0, sizeof(tunn_info)); 133019968430SChopra, Manish tunn_info.vxlan.b_mode_enabled = true; 133119968430SChopra, Manish tunn_info.l2_gre.b_mode_enabled = true; 133219968430SChopra, Manish tunn_info.ip_gre.b_mode_enabled = true; 133319968430SChopra, Manish tunn_info.l2_geneve.b_mode_enabled = true; 133419968430SChopra, Manish tunn_info.ip_geneve.b_mode_enabled = true; 133519968430SChopra, Manish tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133619968430SChopra, Manish tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133719968430SChopra, Manish tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133819968430SChopra, Manish tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 133919968430SChopra, Manish tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 1340c0c2d0b4SMintz, Yuval hw_init_params.p_tunn = &tunn_info; 1341c0c2d0b4SMintz, Yuval hw_init_params.b_hw_start = true; 1342c0c2d0b4SMintz, Yuval hw_init_params.int_mode = cdev->int_params.out.int_mode; 1343c0c2d0b4SMintz, Yuval hw_init_params.allow_npar_tx_switch = true; 1344c0c2d0b4SMintz, Yuval hw_init_params.bin_fw_data = data; 1345c0c2d0b4SMintz, Yuval 13465d24bcf1STomer Tayar memset(&drv_load_params, 0, sizeof(drv_load_params)); 13475d24bcf1STomer Tayar drv_load_params.is_crash_kernel = is_kdump_kernel(); 13485d24bcf1STomer Tayar drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; 13495d24bcf1STomer Tayar drv_load_params.avoid_eng_reset = false; 13505d24bcf1STomer Tayar drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; 13515d24bcf1STomer Tayar hw_init_params.p_drv_load_params = &drv_load_params; 13525d24bcf1STomer Tayar 1353c0c2d0b4SMintz, Yuval rc = qed_hw_init(cdev, &hw_init_params); 1354fe56b9e6SYuval Mintz if (rc) 13558c925c44SYuval Mintz goto err2; 1356fe56b9e6SYuval Mintz 1357fe56b9e6SYuval Mintz DP_INFO(cdev, 1358fe56b9e6SYuval Mintz "HW initialization and function start completed successfully\n"); 1359fe56b9e6SYuval Mintz 1360eaf3c0c6SChopra, Manish if (IS_PF(cdev)) { 1361eaf3c0c6SChopra, Manish cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | 1362eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GENEVE_TUNN) | 1363eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGENEVE_TUNN) | 1364eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GRE_TUNN) | 1365eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGRE_TUNN)); 1366eaf3c0c6SChopra, Manish } 1367eaf3c0c6SChopra, Manish 13680a7fb11cSYuval Mintz /* Allocate LL2 interface if needed */ 13690a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->using_ll2) { 13700a7fb11cSYuval Mintz rc = qed_ll2_alloc_if(cdev); 13710a7fb11cSYuval Mintz if (rc) 13720a7fb11cSYuval Mintz goto err3; 13730a7fb11cSYuval Mintz } 13741408cc1fSYuval Mintz if (IS_PF(cdev)) { 1375fe56b9e6SYuval Mintz hwfn = QED_LEADING_HWFN(cdev); 1376fe56b9e6SYuval Mintz drv_version.version = (params->drv_major << 24) | 1377fe56b9e6SYuval Mintz (params->drv_minor << 16) | 1378fe56b9e6SYuval Mintz (params->drv_rev << 8) | 1379fe56b9e6SYuval Mintz (params->drv_eng); 1380f2a74107SPrabhakar Kushwaha strscpy(drv_version.name, params->name, 1381fe56b9e6SYuval Mintz MCP_DRV_VER_STR_SIZE - 4); 1382fe56b9e6SYuval Mintz rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, 1383fe56b9e6SYuval Mintz &drv_version); 1384fe56b9e6SYuval Mintz if (rc) { 1385fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed sending drv version command\n"); 1386de0e4fd2SWenwen Wang goto err4; 1387fe56b9e6SYuval Mintz } 13881408cc1fSYuval Mintz } 1389fe56b9e6SYuval Mintz 13908c925c44SYuval Mintz qed_reset_vport_stats(cdev); 13918c925c44SYuval Mintz 1392fe56b9e6SYuval Mintz return 0; 1393fe56b9e6SYuval Mintz 1394de0e4fd2SWenwen Wang err4: 1395de0e4fd2SWenwen Wang qed_ll2_dealloc_if(cdev); 13960a7fb11cSYuval Mintz err3: 13970a7fb11cSYuval Mintz qed_hw_stop(cdev); 1398fe56b9e6SYuval Mintz err2: 13998c925c44SYuval Mintz qed_hw_timers_stop_all(cdev); 14001408cc1fSYuval Mintz if (IS_PF(cdev)) 14018c925c44SYuval Mintz qed_slowpath_irq_free(cdev); 14028c925c44SYuval Mintz qed_free_stream_mem(cdev); 1403fe56b9e6SYuval Mintz qed_disable_msix(cdev); 1404fe56b9e6SYuval Mintz err1: 1405fe56b9e6SYuval Mintz qed_resc_free(cdev); 1406fe56b9e6SYuval Mintz err: 14071408cc1fSYuval Mintz if (IS_PF(cdev)) 1408fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1409fe56b9e6SYuval Mintz 1410d51e4af5SChopra, Manish if (IS_PF(cdev) && (cdev->num_hwfns == 1) && 1411d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt) 1412d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1413d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1414c78c70faSSudarsana Reddy Kalluru 141537bff2b9SYuval Mintz qed_iov_wq_stop(cdev, false); 141637bff2b9SYuval Mintz 141759ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 141859ccf86fSSudarsana Reddy Kalluru 1419fe56b9e6SYuval Mintz return rc; 1420fe56b9e6SYuval Mintz } 1421fe56b9e6SYuval Mintz 1422fe56b9e6SYuval Mintz static int qed_slowpath_stop(struct qed_dev *cdev) 1423fe56b9e6SYuval Mintz { 1424fe56b9e6SYuval Mintz if (!cdev) 1425fe56b9e6SYuval Mintz return -ENODEV; 1426fe56b9e6SYuval Mintz 142759ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 142859ccf86fSSudarsana Reddy Kalluru 14290a7fb11cSYuval Mintz qed_ll2_dealloc_if(cdev); 14300a7fb11cSYuval Mintz 14311408cc1fSYuval Mintz if (IS_PF(cdev)) { 1432d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) 1433d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1434d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1435fe56b9e6SYuval Mintz qed_free_stream_mem(cdev); 1436c5ac9319SYuval Mintz if (IS_QED_ETH_IF(cdev)) 14370b55e27dSYuval Mintz qed_sriov_disable(cdev, true); 14385f027d7aSMintz, Yuval } 1439fe56b9e6SYuval Mintz 1440fe56b9e6SYuval Mintz qed_nic_stop(cdev); 14415f027d7aSMintz, Yuval 14425f027d7aSMintz, Yuval if (IS_PF(cdev)) 1443fe56b9e6SYuval Mintz qed_slowpath_irq_free(cdev); 1444fe56b9e6SYuval Mintz 1445fe56b9e6SYuval Mintz qed_disable_msix(cdev); 14461226337aSTomer Tayar 14471226337aSTomer Tayar qed_resc_free(cdev); 1448fe56b9e6SYuval Mintz 144937bff2b9SYuval Mintz qed_iov_wq_stop(cdev, true); 145037bff2b9SYuval Mintz 14511408cc1fSYuval Mintz if (IS_PF(cdev)) 1452fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1453fe56b9e6SYuval Mintz 1454fe56b9e6SYuval Mintz return 0; 1455fe56b9e6SYuval Mintz } 1456fe56b9e6SYuval Mintz 1457712c3cbfSMintz, Yuval static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) 1458fe56b9e6SYuval Mintz { 1459fe56b9e6SYuval Mintz int i; 1460fe56b9e6SYuval Mintz 1461fe56b9e6SYuval Mintz memcpy(cdev->name, name, NAME_SIZE); 1462fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) 1463fe56b9e6SYuval Mintz snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); 1464fe56b9e6SYuval Mintz } 1465fe56b9e6SYuval Mintz 1466fe56b9e6SYuval Mintz static u32 qed_sb_init(struct qed_dev *cdev, 1467fe56b9e6SYuval Mintz struct qed_sb_info *sb_info, 1468fe56b9e6SYuval Mintz void *sb_virt_addr, 1469fe56b9e6SYuval Mintz dma_addr_t sb_phy_addr, u16 sb_id, 1470fe56b9e6SYuval Mintz enum qed_sb_type type) 1471fe56b9e6SYuval Mintz { 1472fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 147385750d74SMintz, Yuval struct qed_ptt *p_ptt; 1474fe56b9e6SYuval Mintz u16 rel_sb_id; 1475fe56b9e6SYuval Mintz u32 rc; 1476fe56b9e6SYuval Mintz 147708eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 147808eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 147908eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 148008eb1fb0SMichal Kalderon rel_sb_id = sb_id / cdev->num_hwfns; 148108eb1fb0SMichal Kalderon } else { 148208eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 148308eb1fb0SMichal Kalderon rel_sb_id = sb_id; 148408eb1fb0SMichal Kalderon } 1485fe56b9e6SYuval Mintz 1486fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1487fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 148808eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1489fe56b9e6SYuval Mintz 149085750d74SMintz, Yuval if (IS_PF(p_hwfn->cdev)) { 149185750d74SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 149285750d74SMintz, Yuval if (!p_ptt) 149385750d74SMintz, Yuval return -EBUSY; 149485750d74SMintz, Yuval 149585750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, 149685750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 149785750d74SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 149885750d74SMintz, Yuval } else { 149985750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, 150085750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 150185750d74SMintz, Yuval } 1502fe56b9e6SYuval Mintz 1503fe56b9e6SYuval Mintz return rc; 1504fe56b9e6SYuval Mintz } 1505fe56b9e6SYuval Mintz 1506fe56b9e6SYuval Mintz static u32 qed_sb_release(struct qed_dev *cdev, 150708eb1fb0SMichal Kalderon struct qed_sb_info *sb_info, 150808eb1fb0SMichal Kalderon u16 sb_id, 150908eb1fb0SMichal Kalderon enum qed_sb_type type) 1510fe56b9e6SYuval Mintz { 1511fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 1512fe56b9e6SYuval Mintz u16 rel_sb_id; 1513fe56b9e6SYuval Mintz u32 rc; 1514fe56b9e6SYuval Mintz 151508eb1fb0SMichal Kalderon /* RoCE/Storage use a single engine in CMT mode while L2 uses both */ 151608eb1fb0SMichal Kalderon if (type == QED_SB_TYPE_L2_QUEUE) { 151708eb1fb0SMichal Kalderon p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns]; 1518fe56b9e6SYuval Mintz rel_sb_id = sb_id / cdev->num_hwfns; 151908eb1fb0SMichal Kalderon } else { 152008eb1fb0SMichal Kalderon p_hwfn = QED_AFFIN_HWFN(cdev); 152108eb1fb0SMichal Kalderon rel_sb_id = sb_id; 152208eb1fb0SMichal Kalderon } 1523fe56b9e6SYuval Mintz 1524fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1525fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 152608eb1fb0SMichal Kalderon IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id); 1527fe56b9e6SYuval Mintz 1528fe56b9e6SYuval Mintz rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); 1529fe56b9e6SYuval Mintz 1530fe56b9e6SYuval Mintz return rc; 1531fe56b9e6SYuval Mintz } 1532fe56b9e6SYuval Mintz 1533fe7cd2bfSYuval Mintz static bool qed_can_link_change(struct qed_dev *cdev) 1534fe7cd2bfSYuval Mintz { 1535fe7cd2bfSYuval Mintz return true; 1536fe7cd2bfSYuval Mintz } 1537fe7cd2bfSYuval Mintz 153899785a87SAlexander Lobakin static void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params, 153999785a87SAlexander Lobakin const struct qed_link_params *params) 154099785a87SAlexander Lobakin { 154199785a87SAlexander Lobakin struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed; 154299785a87SAlexander Lobakin const struct qed_mfw_speed_map *map; 154399785a87SAlexander Lobakin u32 i; 154499785a87SAlexander Lobakin 154599785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 154699785a87SAlexander Lobakin ext_speed->autoneg = !!params->autoneg; 154799785a87SAlexander Lobakin 154899785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 154999785a87SAlexander Lobakin ext_speed->advertised_speeds = 0; 155099785a87SAlexander Lobakin 155199785a87SAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) { 155299785a87SAlexander Lobakin map = qed_mfw_ext_maps + i; 155399785a87SAlexander Lobakin 155499785a87SAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 155599785a87SAlexander Lobakin ext_speed->advertised_speeds |= map->mfw_val; 155699785a87SAlexander Lobakin } 155799785a87SAlexander Lobakin } 155899785a87SAlexander Lobakin 155999785a87SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) { 156099785a87SAlexander Lobakin switch (params->forced_speed) { 156199785a87SAlexander Lobakin case SPEED_1000: 156299785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_1G; 156399785a87SAlexander Lobakin break; 156499785a87SAlexander Lobakin case SPEED_10000: 156599785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_10G; 156699785a87SAlexander Lobakin break; 156799785a87SAlexander Lobakin case SPEED_20000: 156899785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_20G; 156999785a87SAlexander Lobakin break; 157099785a87SAlexander Lobakin case SPEED_25000: 157199785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_25G; 157299785a87SAlexander Lobakin break; 157399785a87SAlexander Lobakin case SPEED_40000: 157499785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_40G; 157599785a87SAlexander Lobakin break; 157699785a87SAlexander Lobakin case SPEED_50000: 157799785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_50G_R | 157899785a87SAlexander Lobakin QED_EXT_SPEED_50G_R2; 157999785a87SAlexander Lobakin break; 158099785a87SAlexander Lobakin case SPEED_100000: 158199785a87SAlexander Lobakin ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 | 158299785a87SAlexander Lobakin QED_EXT_SPEED_100G_R4 | 158399785a87SAlexander Lobakin QED_EXT_SPEED_100G_P4; 158499785a87SAlexander Lobakin break; 158599785a87SAlexander Lobakin default: 158699785a87SAlexander Lobakin break; 158799785a87SAlexander Lobakin } 158899785a87SAlexander Lobakin } 158999785a87SAlexander Lobakin 159099785a87SAlexander Lobakin if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)) 159199785a87SAlexander Lobakin return; 159299785a87SAlexander Lobakin 159399785a87SAlexander Lobakin switch (params->forced_speed) { 159499785a87SAlexander Lobakin case SPEED_25000: 159599785a87SAlexander Lobakin switch (params->fec) { 159699785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 159799785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE; 159899785a87SAlexander Lobakin break; 159999785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 160099785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R; 160199785a87SAlexander Lobakin break; 160299785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 160399785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528; 160499785a87SAlexander Lobakin break; 160599785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 160699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 | 160799785a87SAlexander Lobakin ETH_EXT_FEC_25G_BASE_R | 160899785a87SAlexander Lobakin ETH_EXT_FEC_25G_NONE; 160999785a87SAlexander Lobakin break; 161099785a87SAlexander Lobakin default: 161199785a87SAlexander Lobakin break; 161299785a87SAlexander Lobakin } 161399785a87SAlexander Lobakin 161499785a87SAlexander Lobakin break; 161599785a87SAlexander Lobakin case SPEED_40000: 161699785a87SAlexander Lobakin switch (params->fec) { 161799785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 161899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE; 161999785a87SAlexander Lobakin break; 162099785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 162199785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R; 162299785a87SAlexander Lobakin break; 162399785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 162499785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R | 162599785a87SAlexander Lobakin ETH_EXT_FEC_40G_NONE; 162699785a87SAlexander Lobakin break; 162799785a87SAlexander Lobakin default: 162899785a87SAlexander Lobakin break; 162999785a87SAlexander Lobakin } 163099785a87SAlexander Lobakin 163199785a87SAlexander Lobakin break; 163299785a87SAlexander Lobakin case SPEED_50000: 163399785a87SAlexander Lobakin switch (params->fec) { 163499785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 163599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE; 163699785a87SAlexander Lobakin break; 163799785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 163899785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R; 163999785a87SAlexander Lobakin break; 164099785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 164199785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528; 164299785a87SAlexander Lobakin break; 164399785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 164499785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 | 164599785a87SAlexander Lobakin ETH_EXT_FEC_50G_BASE_R | 164699785a87SAlexander Lobakin ETH_EXT_FEC_50G_NONE; 164799785a87SAlexander Lobakin break; 164899785a87SAlexander Lobakin default: 164999785a87SAlexander Lobakin break; 165099785a87SAlexander Lobakin } 165199785a87SAlexander Lobakin 165299785a87SAlexander Lobakin break; 165399785a87SAlexander Lobakin case SPEED_100000: 165499785a87SAlexander Lobakin switch (params->fec) { 165599785a87SAlexander Lobakin case FEC_FORCE_MODE_NONE: 165699785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE; 165799785a87SAlexander Lobakin break; 165899785a87SAlexander Lobakin case FEC_FORCE_MODE_FIRECODE: 165999785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R; 166099785a87SAlexander Lobakin break; 166199785a87SAlexander Lobakin case FEC_FORCE_MODE_RS: 166299785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528; 166399785a87SAlexander Lobakin break; 166499785a87SAlexander Lobakin case FEC_FORCE_MODE_AUTO: 166599785a87SAlexander Lobakin link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 | 166699785a87SAlexander Lobakin ETH_EXT_FEC_100G_BASE_R | 166799785a87SAlexander Lobakin ETH_EXT_FEC_100G_NONE; 166899785a87SAlexander Lobakin break; 166999785a87SAlexander Lobakin default: 167099785a87SAlexander Lobakin break; 167199785a87SAlexander Lobakin } 167299785a87SAlexander Lobakin 167399785a87SAlexander Lobakin break; 167499785a87SAlexander Lobakin default: 167599785a87SAlexander Lobakin break; 167699785a87SAlexander Lobakin } 167799785a87SAlexander Lobakin } 167899785a87SAlexander Lobakin 1679351a4dedSYuval Mintz static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) 1680cc875c2eSYuval Mintz { 1681cc875c2eSYuval Mintz struct qed_mcp_link_params *link_params; 1682097818fcSAlexander Lobakin struct qed_mcp_link_speed_params *speed; 1683097818fcSAlexander Lobakin const struct qed_mfw_speed_map *map; 1684bdb5d8ecSAlexander Lobakin struct qed_hwfn *hwfn; 1685cc875c2eSYuval Mintz struct qed_ptt *ptt; 1686cc875c2eSYuval Mintz int rc; 1687097818fcSAlexander Lobakin u32 i; 1688cc875c2eSYuval Mintz 1689cc875c2eSYuval Mintz if (!cdev) 1690cc875c2eSYuval Mintz return -ENODEV; 1691cc875c2eSYuval Mintz 1692cc875c2eSYuval Mintz /* The link should be set only once per PF */ 1693cc875c2eSYuval Mintz hwfn = &cdev->hwfns[0]; 1694cc875c2eSYuval Mintz 169565ed2ffdSMintz, Yuval /* When VF wants to set link, force it to read the bulletin instead. 169665ed2ffdSMintz, Yuval * This mimics the PF behavior, where a noitification [both immediate 169765ed2ffdSMintz, Yuval * and possible later] would be generated when changing properties. 169865ed2ffdSMintz, Yuval */ 169965ed2ffdSMintz, Yuval if (IS_VF(cdev)) { 170065ed2ffdSMintz, Yuval qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); 170165ed2ffdSMintz, Yuval return 0; 170265ed2ffdSMintz, Yuval } 170365ed2ffdSMintz, Yuval 1704cc875c2eSYuval Mintz ptt = qed_ptt_acquire(hwfn); 1705cc875c2eSYuval Mintz if (!ptt) 1706cc875c2eSYuval Mintz return -EBUSY; 1707cc875c2eSYuval Mintz 1708cc875c2eSYuval Mintz link_params = qed_mcp_get_link_params(hwfn); 1709bdb5d8ecSAlexander Lobakin if (!link_params) 1710bdb5d8ecSAlexander Lobakin return -ENODATA; 1711bdb5d8ecSAlexander Lobakin 1712097818fcSAlexander Lobakin speed = &link_params->speed; 1713097818fcSAlexander Lobakin 1714cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 1715097818fcSAlexander Lobakin speed->autoneg = !!params->autoneg; 1716bdb5d8ecSAlexander Lobakin 1717cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 1718097818fcSAlexander Lobakin speed->advertised_speeds = 0; 1719bdb5d8ecSAlexander Lobakin 1720097818fcSAlexander Lobakin for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) { 1721097818fcSAlexander Lobakin map = qed_mfw_legacy_maps + i; 1722bdb5d8ecSAlexander Lobakin 1723097818fcSAlexander Lobakin if (linkmode_intersects(params->adv_speeds, map->caps)) 1724097818fcSAlexander Lobakin speed->advertised_speeds |= map->mfw_val; 1725097818fcSAlexander Lobakin } 1726cc875c2eSYuval Mintz } 1727bdb5d8ecSAlexander Lobakin 1728cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) 1729097818fcSAlexander Lobakin speed->forced_speed = params->forced_speed; 1730097818fcSAlexander Lobakin 173199785a87SAlexander Lobakin if (qed_mcp_is_ext_speed_supported(hwfn)) 173299785a87SAlexander Lobakin qed_set_ext_speed_params(link_params, params); 173399785a87SAlexander Lobakin 1734a43f235fSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { 1735a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 1736a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = true; 1737a43f235fSSudarsana Reddy Kalluru else 1738a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = false; 1739a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) 1740a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = true; 1741a43f235fSSudarsana Reddy Kalluru else 1742a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = false; 1743a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) 1744a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = true; 1745a43f235fSSudarsana Reddy Kalluru else 1746a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = false; 1747a43f235fSSudarsana Reddy Kalluru } 1748097818fcSAlexander Lobakin 174903dc76caSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { 175003dc76caSSudarsana Reddy Kalluru switch (params->loopback_mode) { 175103dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_INT_PHY: 1752351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; 175303dc76caSSudarsana Reddy Kalluru break; 175403dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT_PHY: 1755351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; 175603dc76caSSudarsana Reddy Kalluru break; 175703dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT: 1758351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT; 175903dc76caSSudarsana Reddy Kalluru break; 176003dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_MAC: 1761351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_MAC; 176203dc76caSSudarsana Reddy Kalluru break; 176398e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123: 176498e675ecSAlexander Lobakin link_params->loopback_mode = 176598e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_0123; 176698e675ecSAlexander Lobakin break; 176798e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301: 176898e675ecSAlexander Lobakin link_params->loopback_mode = 176998e675ecSAlexander Lobakin ETH_LOOPBACK_CNIG_AH_ONLY_2301; 177098e675ecSAlexander Lobakin break; 177198e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_PCS_AH_ONLY: 177298e675ecSAlexander Lobakin link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY; 177398e675ecSAlexander Lobakin break; 177498e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY: 177598e675ecSAlexander Lobakin link_params->loopback_mode = 177698e675ecSAlexander Lobakin ETH_LOOPBACK_REVERSE_MAC_AH_ONLY; 177798e675ecSAlexander Lobakin break; 177898e675ecSAlexander Lobakin case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY: 177998e675ecSAlexander Lobakin link_params->loopback_mode = 178098e675ecSAlexander Lobakin ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY; 178198e675ecSAlexander Lobakin break; 178203dc76caSSudarsana Reddy Kalluru default: 1783351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_NONE; 178403dc76caSSudarsana Reddy Kalluru break; 178503dc76caSSudarsana Reddy Kalluru } 178603dc76caSSudarsana Reddy Kalluru } 1787cc875c2eSYuval Mintz 1788645874e5SSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) 1789645874e5SSudarsana Reddy Kalluru memcpy(&link_params->eee, ¶ms->eee, 1790645874e5SSudarsana Reddy Kalluru sizeof(link_params->eee)); 1791645874e5SSudarsana Reddy Kalluru 1792ae7e6937SAlexander Lobakin if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG) 1793ae7e6937SAlexander Lobakin link_params->fec = params->fec; 1794ae7e6937SAlexander Lobakin 1795cc875c2eSYuval Mintz rc = qed_mcp_set_link(hwfn, ptt, params->link_up); 1796cc875c2eSYuval Mintz 1797cc875c2eSYuval Mintz qed_ptt_release(hwfn, ptt); 1798cc875c2eSYuval Mintz 1799cc875c2eSYuval Mintz return rc; 1800cc875c2eSYuval Mintz } 1801cc875c2eSYuval Mintz 1802cc875c2eSYuval Mintz static int qed_get_port_type(u32 media_type) 1803cc875c2eSYuval Mintz { 1804cc875c2eSYuval Mintz int port_type; 1805cc875c2eSYuval Mintz 1806cc875c2eSYuval Mintz switch (media_type) { 1807cc875c2eSYuval Mintz case MEDIA_SFPP_10G_FIBER: 1808cc875c2eSYuval Mintz case MEDIA_SFP_1G_FIBER: 1809cc875c2eSYuval Mintz case MEDIA_XFP_FIBER: 1810b639f197SYuval Mintz case MEDIA_MODULE_FIBER: 1811cc875c2eSYuval Mintz port_type = PORT_FIBRE; 1812cc875c2eSYuval Mintz break; 1813cc875c2eSYuval Mintz case MEDIA_DA_TWINAX: 1814cc875c2eSYuval Mintz port_type = PORT_DA; 1815cc875c2eSYuval Mintz break; 1816cc875c2eSYuval Mintz case MEDIA_BASE_T: 1817cc875c2eSYuval Mintz port_type = PORT_TP; 1818cc875c2eSYuval Mintz break; 181999785a87SAlexander Lobakin case MEDIA_KR: 1820cc875c2eSYuval Mintz case MEDIA_NOT_PRESENT: 1821cc875c2eSYuval Mintz port_type = PORT_NONE; 1822cc875c2eSYuval Mintz break; 1823cc875c2eSYuval Mintz case MEDIA_UNSPECIFIED: 1824cc875c2eSYuval Mintz default: 1825cc875c2eSYuval Mintz port_type = PORT_OTHER; 1826cc875c2eSYuval Mintz break; 1827cc875c2eSYuval Mintz } 1828cc875c2eSYuval Mintz return port_type; 1829cc875c2eSYuval Mintz } 1830cc875c2eSYuval Mintz 183114b84e86SArnd Bergmann static int qed_get_link_data(struct qed_hwfn *hwfn, 183214b84e86SArnd Bergmann struct qed_mcp_link_params *params, 183314b84e86SArnd Bergmann struct qed_mcp_link_state *link, 183414b84e86SArnd Bergmann struct qed_mcp_link_capabilities *link_caps) 183514b84e86SArnd Bergmann { 183614b84e86SArnd Bergmann void *p; 183714b84e86SArnd Bergmann 183814b84e86SArnd Bergmann if (!IS_PF(hwfn->cdev)) { 183914b84e86SArnd Bergmann qed_vf_get_link_params(hwfn, params); 184014b84e86SArnd Bergmann qed_vf_get_link_state(hwfn, link); 184114b84e86SArnd Bergmann qed_vf_get_link_caps(hwfn, link_caps); 184214b84e86SArnd Bergmann 184314b84e86SArnd Bergmann return 0; 184414b84e86SArnd Bergmann } 184514b84e86SArnd Bergmann 184614b84e86SArnd Bergmann p = qed_mcp_get_link_params(hwfn); 184714b84e86SArnd Bergmann if (!p) 184814b84e86SArnd Bergmann return -ENXIO; 184914b84e86SArnd Bergmann memcpy(params, p, sizeof(*params)); 185014b84e86SArnd Bergmann 185114b84e86SArnd Bergmann p = qed_mcp_get_link_state(hwfn); 185214b84e86SArnd Bergmann if (!p) 185314b84e86SArnd Bergmann return -ENXIO; 185414b84e86SArnd Bergmann memcpy(link, p, sizeof(*link)); 185514b84e86SArnd Bergmann 185614b84e86SArnd Bergmann p = qed_mcp_get_link_capabilities(hwfn); 185714b84e86SArnd Bergmann if (!p) 185814b84e86SArnd Bergmann return -ENXIO; 185914b84e86SArnd Bergmann memcpy(link_caps, p, sizeof(*link_caps)); 186014b84e86SArnd Bergmann 186114b84e86SArnd Bergmann return 0; 186214b84e86SArnd Bergmann } 186314b84e86SArnd Bergmann 1864c56a8be7SRahul Verma static void qed_fill_link_capability(struct qed_hwfn *hwfn, 1865c56a8be7SRahul Verma struct qed_ptt *ptt, u32 capability, 1866bdb5d8ecSAlexander Lobakin unsigned long *if_caps) 1867c56a8be7SRahul Verma { 1868c56a8be7SRahul Verma u32 media_type, tcvr_state, tcvr_type; 1869c56a8be7SRahul Verma u32 speed_mask, board_cfg; 1870c56a8be7SRahul Verma 1871c56a8be7SRahul Verma if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) 1872c56a8be7SRahul Verma media_type = MEDIA_UNSPECIFIED; 1873c56a8be7SRahul Verma 1874c56a8be7SRahul Verma if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) 1875c56a8be7SRahul Verma tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; 1876c56a8be7SRahul Verma 1877c56a8be7SRahul Verma if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) 1878c56a8be7SRahul Verma speed_mask = 0xFFFFFFFF; 1879c56a8be7SRahul Verma 1880c56a8be7SRahul Verma if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) 1881c56a8be7SRahul Verma board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 1882c56a8be7SRahul Verma 1883c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 1884c56a8be7SRahul Verma "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", 1885c56a8be7SRahul Verma media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); 1886c56a8be7SRahul Verma 1887c56a8be7SRahul Verma switch (media_type) { 1888c56a8be7SRahul Verma case MEDIA_DA_TWINAX: 1889bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1890bdb5d8ecSAlexander Lobakin 1891c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1892bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 1893bdb5d8ecSAlexander Lobakin 1894c56a8be7SRahul Verma /* For DAC media multiple speed capabilities are supported */ 18959228b7c1SAlexander Lobakin capability |= speed_mask; 18969228b7c1SAlexander Lobakin 1897c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1898bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 1899c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1900bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseCR_Full); 19019228b7c1SAlexander Lobakin 1902c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 19039228b7c1SAlexander Lobakin switch (tcvr_type) { 19049228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_CR4: 19059228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 19069228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1907bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseCR4_Full); 19089228b7c1SAlexander Lobakin break; 19099228b7c1SAlexander Lobakin default: 19109228b7c1SAlexander Lobakin break; 19119228b7c1SAlexander Lobakin } 19129228b7c1SAlexander Lobakin 1913c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 1914bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseCR_Full); 1915c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1916bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseCR2_Full); 19179228b7c1SAlexander Lobakin 1918c56a8be7SRahul Verma if (capability & 1919c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 19209228b7c1SAlexander Lobakin switch (tcvr_type) { 19219228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_CR4: 19229228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 1923bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseCR4_Full); 19249228b7c1SAlexander Lobakin break; 19259228b7c1SAlexander Lobakin default: 19269228b7c1SAlexander Lobakin break; 19279228b7c1SAlexander Lobakin } 1928bdb5d8ecSAlexander Lobakin 1929c56a8be7SRahul Verma break; 1930c56a8be7SRahul Verma case MEDIA_BASE_T: 1931bdb5d8ecSAlexander Lobakin phylink_set(if_caps, TP); 1932bdb5d8ecSAlexander Lobakin 1933c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { 1934c56a8be7SRahul Verma if (capability & 1935bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1936bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 1937c56a8be7SRahul Verma if (capability & 1938bdb5d8ecSAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1939bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 1940c56a8be7SRahul Verma } 1941bdb5d8ecSAlexander Lobakin 1942c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { 1943bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 1944bdb5d8ecSAlexander Lobakin 19459228b7c1SAlexander Lobakin switch (tcvr_type) { 19469228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1000BASET: 1947bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseT_Full); 19489228b7c1SAlexander Lobakin break; 19499228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_BASET: 1950bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseT_Full); 19519228b7c1SAlexander Lobakin break; 19529228b7c1SAlexander Lobakin default: 19539228b7c1SAlexander Lobakin break; 19549228b7c1SAlexander Lobakin } 1955c56a8be7SRahul Verma } 1956bdb5d8ecSAlexander Lobakin 1957c56a8be7SRahul Verma break; 1958c56a8be7SRahul Verma case MEDIA_SFP_1G_FIBER: 1959c56a8be7SRahul Verma case MEDIA_SFPP_10G_FIBER: 1960c56a8be7SRahul Verma case MEDIA_XFP_FIBER: 1961c56a8be7SRahul Verma case MEDIA_MODULE_FIBER: 1962bdb5d8ecSAlexander Lobakin phylink_set(if_caps, FIBRE); 19639228b7c1SAlexander Lobakin capability |= speed_mask; 1964bdb5d8ecSAlexander Lobakin 19659228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 19669228b7c1SAlexander Lobakin switch (tcvr_type) { 19679228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_LX: 19689228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_1G_SX: 19699228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 19709228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1971bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 19729228b7c1SAlexander Lobakin break; 19739228b7c1SAlexander Lobakin default: 19749228b7c1SAlexander Lobakin break; 1975c56a8be7SRahul Verma } 1976bdb5d8ecSAlexander Lobakin 19779228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 19789228b7c1SAlexander Lobakin switch (tcvr_type) { 19799228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_SR: 19809228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 19819228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 19829228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 1983bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseSR_Full); 19849228b7c1SAlexander Lobakin break; 19859228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LR: 19869228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 19879228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 19889228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 1989bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLR_Full); 19909228b7c1SAlexander Lobakin break; 19919228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_LRM: 1992bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseLRM_Full); 19939228b7c1SAlexander Lobakin break; 19949228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_10G_ER: 1995bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseR_FEC); 19969228b7c1SAlexander Lobakin break; 19979228b7c1SAlexander Lobakin default: 19989228b7c1SAlexander Lobakin break; 1999c56a8be7SRahul Verma } 2000bdb5d8ecSAlexander Lobakin 2001c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 2002bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 2003bdb5d8ecSAlexander Lobakin 20049228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 20059228b7c1SAlexander Lobakin switch (tcvr_type) { 20069228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_25G_SR: 20079228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 2008bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseSR_Full); 20099228b7c1SAlexander Lobakin break; 20109228b7c1SAlexander Lobakin default: 20119228b7c1SAlexander Lobakin break; 2012c56a8be7SRahul Verma } 2013bdb5d8ecSAlexander Lobakin 20149228b7c1SAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 20159228b7c1SAlexander Lobakin switch (tcvr_type) { 20169228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_LR4: 20179228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 20189228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2019bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseLR4_Full); 20209228b7c1SAlexander Lobakin break; 20219228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_40G_SR4: 20229228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 20239228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2024bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseSR4_Full); 20259228b7c1SAlexander Lobakin break; 20269228b7c1SAlexander Lobakin default: 20279228b7c1SAlexander Lobakin break; 2028c56a8be7SRahul Verma } 2029bdb5d8ecSAlexander Lobakin 2030bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2031bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2032bdb5d8ecSAlexander Lobakin 2033c56a8be7SRahul Verma if (capability & 20349228b7c1SAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 20359228b7c1SAlexander Lobakin switch (tcvr_type) { 20369228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_100G_SR4: 20379228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2038bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseSR4_Full); 20399228b7c1SAlexander Lobakin break; 20409228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 20419228b7c1SAlexander Lobakin phylink_set(if_caps, 100000baseLR4_ER4_Full); 20429228b7c1SAlexander Lobakin break; 20439228b7c1SAlexander Lobakin default: 20449228b7c1SAlexander Lobakin break; 2045c56a8be7SRahul Verma } 2046c56a8be7SRahul Verma 2047c56a8be7SRahul Verma break; 2048c56a8be7SRahul Verma case MEDIA_KR: 2049bdb5d8ecSAlexander Lobakin phylink_set(if_caps, Backplane); 2050bdb5d8ecSAlexander Lobakin 2051c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 2052bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 20000baseKR2_Full); 2053bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 2054bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 1000baseKX_Full); 2055bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 2056bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 10000baseKR_Full); 2057bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 2058bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 25000baseKR_Full); 2059bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 2060bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 40000baseKR4_Full); 2061bdb5d8ecSAlexander Lobakin if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 2062bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 50000baseKR2_Full); 2063c56a8be7SRahul Verma if (capability & 2064c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 2065bdb5d8ecSAlexander Lobakin phylink_set(if_caps, 100000baseKR4_Full); 2066bdb5d8ecSAlexander Lobakin 2067c56a8be7SRahul Verma break; 2068c56a8be7SRahul Verma case MEDIA_UNSPECIFIED: 2069c56a8be7SRahul Verma case MEDIA_NOT_PRESENT: 20709228b7c1SAlexander Lobakin default: 2071c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, 2072c56a8be7SRahul Verma "Unknown media and transceiver type;\n"); 2073c56a8be7SRahul Verma break; 2074c56a8be7SRahul Verma } 2075c56a8be7SRahul Verma } 2076c56a8be7SRahul Verma 20773c41486eSAlexander Lobakin static void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask) 20783c41486eSAlexander Lobakin { 20793c41486eSAlexander Lobakin *speed_mask = 0; 20803c41486eSAlexander Lobakin 20813c41486eSAlexander Lobakin if (caps & 20823c41486eSAlexander Lobakin (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD)) 20833c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 20843c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_10G) 20853c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 20863c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_20G) 20873c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; 20883c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_25G) 20893c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 20903c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_40G) 20913c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 20923c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_50G) 20933c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; 20943c41486eSAlexander Lobakin if (caps & QED_LINK_PARTNER_SPEED_100G) 20953c41486eSAlexander Lobakin *speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; 20963c41486eSAlexander Lobakin } 20973c41486eSAlexander Lobakin 2098cc875c2eSYuval Mintz static void qed_fill_link(struct qed_hwfn *hwfn, 2099706d0891SRahul Verma struct qed_ptt *ptt, 2100cc875c2eSYuval Mintz struct qed_link_output *if_link) 2101cc875c2eSYuval Mintz { 2102c56a8be7SRahul Verma struct qed_mcp_link_capabilities link_caps; 2103cc875c2eSYuval Mintz struct qed_mcp_link_params params; 2104cc875c2eSYuval Mintz struct qed_mcp_link_state link; 21053c41486eSAlexander Lobakin u32 media_type, speed_mask; 2106cc875c2eSYuval Mintz 2107cc875c2eSYuval Mintz memset(if_link, 0, sizeof(*if_link)); 2108cc875c2eSYuval Mintz 2109cc875c2eSYuval Mintz /* Prepare source inputs */ 211014b84e86SArnd Bergmann if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { 211114b84e86SArnd Bergmann dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); 211214b84e86SArnd Bergmann return; 21131408cc1fSYuval Mintz } 2114cc875c2eSYuval Mintz 2115cc875c2eSYuval Mintz /* Set the link parameters to pass to protocol driver */ 2116cc875c2eSYuval Mintz if (link.link_up) 2117cc875c2eSYuval Mintz if_link->link_up = true; 2118cc875c2eSYuval Mintz 211999785a87SAlexander Lobakin if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) { 212099785a87SAlexander Lobakin if (link_caps.default_ext_autoneg) 212199785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 212299785a87SAlexander Lobakin 212399785a87SAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 212499785a87SAlexander Lobakin 212599785a87SAlexander Lobakin if (params.ext_speed.autoneg) 212699785a87SAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 212799785a87SAlexander Lobakin else 212899785a87SAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 212999785a87SAlexander Lobakin 213099785a87SAlexander Lobakin qed_fill_link_capability(hwfn, ptt, 213199785a87SAlexander Lobakin params.ext_speed.advertised_speeds, 213299785a87SAlexander Lobakin if_link->advertised_caps); 213399785a87SAlexander Lobakin } else { 213434f9199cSsudarsana.kalluru@cavium.com if (link_caps.default_speed_autoneg) 2135bdb5d8ecSAlexander Lobakin phylink_set(if_link->supported_caps, Autoneg); 2136cc875c2eSYuval Mintz 2137bdb5d8ecSAlexander Lobakin linkmode_copy(if_link->advertised_caps, if_link->supported_caps); 2138bdb5d8ecSAlexander Lobakin 213934f9199cSsudarsana.kalluru@cavium.com if (params.speed.autoneg) 2140bdb5d8ecSAlexander Lobakin phylink_set(if_link->advertised_caps, Autoneg); 214134f9199cSsudarsana.kalluru@cavium.com else 2142bdb5d8ecSAlexander Lobakin phylink_clear(if_link->advertised_caps, Autoneg); 214399785a87SAlexander Lobakin } 214499785a87SAlexander Lobakin 214599785a87SAlexander Lobakin if (params.pause.autoneg || 214699785a87SAlexander Lobakin (params.pause.forced_rx && params.pause.forced_tx)) 214799785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Asym_Pause); 214899785a87SAlexander Lobakin if (params.pause.autoneg || params.pause.forced_rx || 214999785a87SAlexander Lobakin params.pause.forced_tx) 215099785a87SAlexander Lobakin phylink_set(if_link->supported_caps, Pause); 2151cc875c2eSYuval Mintz 2152ae7e6937SAlexander Lobakin if_link->sup_fec = link_caps.fec_default; 2153ae7e6937SAlexander Lobakin if_link->active_fec = params.fec; 2154ae7e6937SAlexander Lobakin 2155c56a8be7SRahul Verma /* Fill link advertised capability */ 2156c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, 2157bdb5d8ecSAlexander Lobakin if_link->advertised_caps); 21583c41486eSAlexander Lobakin 2159c56a8be7SRahul Verma /* Fill link supported capability */ 2160c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, 2161bdb5d8ecSAlexander Lobakin if_link->supported_caps); 2162cc875c2eSYuval Mintz 21633c41486eSAlexander Lobakin /* Fill partner advertised capability */ 21643c41486eSAlexander Lobakin qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask); 21653c41486eSAlexander Lobakin qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps); 21663c41486eSAlexander Lobakin 2167cc875c2eSYuval Mintz if (link.link_up) 2168cc875c2eSYuval Mintz if_link->speed = link.speed; 2169cc875c2eSYuval Mintz 2170cc875c2eSYuval Mintz /* TODO - fill duplex properly */ 2171cc875c2eSYuval Mintz if_link->duplex = DUPLEX_FULL; 2172706d0891SRahul Verma qed_mcp_get_media_type(hwfn, ptt, &media_type); 2173cc875c2eSYuval Mintz if_link->port = qed_get_port_type(media_type); 2174cc875c2eSYuval Mintz 2175cc875c2eSYuval Mintz if_link->autoneg = params.speed.autoneg; 2176cc875c2eSYuval Mintz 2177cc875c2eSYuval Mintz if (params.pause.autoneg) 2178cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 2179cc875c2eSYuval Mintz if (params.pause.forced_rx) 2180cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; 2181cc875c2eSYuval Mintz if (params.pause.forced_tx) 2182cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; 2183cc875c2eSYuval Mintz 2184cc875c2eSYuval Mintz if (link.an_complete) 2185bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Autoneg); 2186cc875c2eSYuval Mintz if (link.partner_adv_pause) 2187bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Pause); 2188cc875c2eSYuval Mintz if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || 2189cc875c2eSYuval Mintz link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) 2190bdb5d8ecSAlexander Lobakin phylink_set(if_link->lp_caps, Asym_Pause); 2191645874e5SSudarsana Reddy Kalluru 2192645874e5SSudarsana Reddy Kalluru if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) { 2193645874e5SSudarsana Reddy Kalluru if_link->eee_supported = false; 2194645874e5SSudarsana Reddy Kalluru } else { 2195645874e5SSudarsana Reddy Kalluru if_link->eee_supported = true; 2196645874e5SSudarsana Reddy Kalluru if_link->eee_active = link.eee_active; 2197645874e5SSudarsana Reddy Kalluru if_link->sup_caps = link_caps.eee_speed_caps; 2198645874e5SSudarsana Reddy Kalluru /* MFW clears adv_caps on eee disable; use configured value */ 2199645874e5SSudarsana Reddy Kalluru if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : 2200645874e5SSudarsana Reddy Kalluru params.eee.adv_caps; 2201645874e5SSudarsana Reddy Kalluru if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; 2202645874e5SSudarsana Reddy Kalluru if_link->eee.enable = params.eee.enable; 2203645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; 2204645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; 2205645874e5SSudarsana Reddy Kalluru } 2206cc875c2eSYuval Mintz } 2207cc875c2eSYuval Mintz 2208cc875c2eSYuval Mintz static void qed_get_current_link(struct qed_dev *cdev, 2209cc875c2eSYuval Mintz struct qed_link_output *if_link) 2210cc875c2eSYuval Mintz { 2211706d0891SRahul Verma struct qed_hwfn *hwfn; 2212706d0891SRahul Verma struct qed_ptt *ptt; 221336558c3dSYuval Mintz int i; 221436558c3dSYuval Mintz 2215706d0891SRahul Verma hwfn = &cdev->hwfns[0]; 2216706d0891SRahul Verma if (IS_PF(cdev)) { 2217706d0891SRahul Verma ptt = qed_ptt_acquire(hwfn); 2218706d0891SRahul Verma if (ptt) { 2219706d0891SRahul Verma qed_fill_link(hwfn, ptt, if_link); 2220706d0891SRahul Verma qed_ptt_release(hwfn, ptt); 2221706d0891SRahul Verma } else { 2222706d0891SRahul Verma DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); 2223706d0891SRahul Verma } 2224706d0891SRahul Verma } else { 2225706d0891SRahul Verma qed_fill_link(hwfn, NULL, if_link); 2226706d0891SRahul Verma } 222736558c3dSYuval Mintz 222836558c3dSYuval Mintz for_each_hwfn(cdev, i) 222936558c3dSYuval Mintz qed_inform_vf_link_state(&cdev->hwfns[i]); 2230cc875c2eSYuval Mintz } 2231cc875c2eSYuval Mintz 2232706d0891SRahul Verma void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2233cc875c2eSYuval Mintz { 2234cc875c2eSYuval Mintz void *cookie = hwfn->cdev->ops_cookie; 2235cc875c2eSYuval Mintz struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2236cc875c2eSYuval Mintz struct qed_link_output if_link; 2237cc875c2eSYuval Mintz 2238706d0891SRahul Verma qed_fill_link(hwfn, ptt, &if_link); 223936558c3dSYuval Mintz qed_inform_vf_link_state(hwfn); 2240cc875c2eSYuval Mintz 2241cc875c2eSYuval Mintz if (IS_LEAD_HWFN(hwfn) && cookie) 2242cc875c2eSYuval Mintz op->link_update(cookie, &if_link); 2243cc875c2eSYuval Mintz } 2244cc875c2eSYuval Mintz 2245699fed4aSSudarsana Reddy Kalluru void qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 2246699fed4aSSudarsana Reddy Kalluru { 2247699fed4aSSudarsana Reddy Kalluru void *cookie = hwfn->cdev->ops_cookie; 2248699fed4aSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 2249699fed4aSSudarsana Reddy Kalluru 2250699fed4aSSudarsana Reddy Kalluru if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update) 2251699fed4aSSudarsana Reddy Kalluru op->bw_update(cookie); 2252699fed4aSSudarsana Reddy Kalluru } 2253699fed4aSSudarsana Reddy Kalluru 2254fe56b9e6SYuval Mintz static int qed_drain(struct qed_dev *cdev) 2255fe56b9e6SYuval Mintz { 2256fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 2257fe56b9e6SYuval Mintz struct qed_ptt *ptt; 2258fe56b9e6SYuval Mintz int i, rc; 2259fe56b9e6SYuval Mintz 22601408cc1fSYuval Mintz if (IS_VF(cdev)) 22611408cc1fSYuval Mintz return 0; 22621408cc1fSYuval Mintz 2263fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 2264fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 2265fe56b9e6SYuval Mintz ptt = qed_ptt_acquire(hwfn); 2266fe56b9e6SYuval Mintz if (!ptt) { 2267fe56b9e6SYuval Mintz DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); 2268fe56b9e6SYuval Mintz return -EBUSY; 2269fe56b9e6SYuval Mintz } 2270fe56b9e6SYuval Mintz rc = qed_mcp_drain(hwfn, ptt); 22719aaa4e8bSDenis Bolotin qed_ptt_release(hwfn, ptt); 2272fe56b9e6SYuval Mintz if (rc) 2273fe56b9e6SYuval Mintz return rc; 2274fe56b9e6SYuval Mintz } 2275fe56b9e6SYuval Mintz 2276fe56b9e6SYuval Mintz return 0; 2277fe56b9e6SYuval Mintz } 2278fe56b9e6SYuval Mintz 22793a69cae8SSudarsana Reddy Kalluru static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev, 22803a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att *nvm_image, 22813a69cae8SSudarsana Reddy Kalluru u32 *crc) 22823a69cae8SSudarsana Reddy Kalluru { 22833a69cae8SSudarsana Reddy Kalluru u8 *buf = NULL; 22845ab90341SAlexander Lobakin int rc; 22853a69cae8SSudarsana Reddy Kalluru 22863a69cae8SSudarsana Reddy Kalluru /* Allocate a buffer for holding the nvram image */ 22873a69cae8SSudarsana Reddy Kalluru buf = kzalloc(nvm_image->length, GFP_KERNEL); 22883a69cae8SSudarsana Reddy Kalluru if (!buf) 22893a69cae8SSudarsana Reddy Kalluru return -ENOMEM; 22903a69cae8SSudarsana Reddy Kalluru 22913a69cae8SSudarsana Reddy Kalluru /* Read image into buffer */ 22923a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr, 22933a69cae8SSudarsana Reddy Kalluru buf, nvm_image->length); 22943a69cae8SSudarsana Reddy Kalluru if (rc) { 22953a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading image from nvm\n"); 22963a69cae8SSudarsana Reddy Kalluru goto out; 22973a69cae8SSudarsana Reddy Kalluru } 22983a69cae8SSudarsana Reddy Kalluru 22993a69cae8SSudarsana Reddy Kalluru /* Convert the buffer into big-endian format (excluding the 23003a69cae8SSudarsana Reddy Kalluru * closing 4 bytes of CRC). 23013a69cae8SSudarsana Reddy Kalluru */ 23025ab90341SAlexander Lobakin cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf, 23035ab90341SAlexander Lobakin DIV_ROUND_UP(nvm_image->length - 4, 4)); 23043a69cae8SSudarsana Reddy Kalluru 23053a69cae8SSudarsana Reddy Kalluru /* Calc CRC for the "actual" image buffer, i.e. not including 23063a69cae8SSudarsana Reddy Kalluru * the last 4 CRC bytes. 23073a69cae8SSudarsana Reddy Kalluru */ 23085ab90341SAlexander Lobakin *crc = ~crc32(~0U, buf, nvm_image->length - 4); 23095ab90341SAlexander Lobakin *crc = (__force u32)cpu_to_be32p(crc); 23103a69cae8SSudarsana Reddy Kalluru 23113a69cae8SSudarsana Reddy Kalluru out: 23123a69cae8SSudarsana Reddy Kalluru kfree(buf); 23133a69cae8SSudarsana Reddy Kalluru 23143a69cae8SSudarsana Reddy Kalluru return rc; 23153a69cae8SSudarsana Reddy Kalluru } 23163a69cae8SSudarsana Reddy Kalluru 23173a69cae8SSudarsana Reddy Kalluru /* Binary file format - 23183a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 23193a69cae8SSudarsana Reddy Kalluru * 0B | 0x4 [command index] | 23203a69cae8SSudarsana Reddy Kalluru * 4B | image_type | Options | Number of register settings | 23213a69cae8SSudarsana Reddy Kalluru * 8B | Value | 23223a69cae8SSudarsana Reddy Kalluru * 12B | Mask | 23233a69cae8SSudarsana Reddy Kalluru * 16B | Offset | 23243a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 23253a69cae8SSudarsana Reddy Kalluru * There can be several Value-Mask-Offset sets as specified by 'Number of...'. 23263a69cae8SSudarsana Reddy Kalluru * Options - 0'b - Calculate & Update CRC for image 23273a69cae8SSudarsana Reddy Kalluru */ 23283a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data, 23293a69cae8SSudarsana Reddy Kalluru bool *check_resp) 23303a69cae8SSudarsana Reddy Kalluru { 23313a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att nvm_image; 23323a69cae8SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn; 23333a69cae8SSudarsana Reddy Kalluru bool is_crc = false; 23343a69cae8SSudarsana Reddy Kalluru u32 image_type; 23353a69cae8SSudarsana Reddy Kalluru int rc = 0, i; 23363a69cae8SSudarsana Reddy Kalluru u16 len; 23373a69cae8SSudarsana Reddy Kalluru 23383a69cae8SSudarsana Reddy Kalluru *data += 4; 23393a69cae8SSudarsana Reddy Kalluru image_type = **data; 23403a69cae8SSudarsana Reddy Kalluru p_hwfn = QED_LEADING_HWFN(cdev); 23413a69cae8SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 23423a69cae8SSudarsana Reddy Kalluru if (image_type == p_hwfn->nvm_info.image_att[i].image_type) 23433a69cae8SSudarsana Reddy Kalluru break; 23443a69cae8SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 23453a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find nvram image of type %08x\n", 23463a69cae8SSudarsana Reddy Kalluru image_type); 23473a69cae8SSudarsana Reddy Kalluru return -ENOENT; 23483a69cae8SSudarsana Reddy Kalluru } 23493a69cae8SSudarsana Reddy Kalluru 23503a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 23513a69cae8SSudarsana Reddy Kalluru nvm_image.length = p_hwfn->nvm_info.image_att[i].len; 23523a69cae8SSudarsana Reddy Kalluru 23533a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 23543a69cae8SSudarsana Reddy Kalluru "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n", 23553a69cae8SSudarsana Reddy Kalluru **data, image_type, nvm_image.start_addr, 23563a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 1); 23573a69cae8SSudarsana Reddy Kalluru (*data)++; 23583a69cae8SSudarsana Reddy Kalluru is_crc = !!(**data & BIT(0)); 23593a69cae8SSudarsana Reddy Kalluru (*data)++; 23603a69cae8SSudarsana Reddy Kalluru len = *((u16 *)*data); 23613a69cae8SSudarsana Reddy Kalluru *data += 2; 23623a69cae8SSudarsana Reddy Kalluru if (is_crc) { 23633a69cae8SSudarsana Reddy Kalluru u32 crc = 0; 23643a69cae8SSudarsana Reddy Kalluru 23653a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc); 23663a69cae8SSudarsana Reddy Kalluru if (rc) { 23673a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc); 23683a69cae8SSudarsana Reddy Kalluru goto exit; 23693a69cae8SSudarsana Reddy Kalluru } 23703a69cae8SSudarsana Reddy Kalluru 23713a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 23723a69cae8SSudarsana Reddy Kalluru (nvm_image.start_addr + 23733a69cae8SSudarsana Reddy Kalluru nvm_image.length - 4), (u8 *)&crc, 4); 23743a69cae8SSudarsana Reddy Kalluru if (rc) 23753a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x, rc = %d\n", 23763a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 4, rc); 23773a69cae8SSudarsana Reddy Kalluru goto exit; 23783a69cae8SSudarsana Reddy Kalluru } 23793a69cae8SSudarsana Reddy Kalluru 23803a69cae8SSudarsana Reddy Kalluru /* Iterate over the values for setting */ 23813a69cae8SSudarsana Reddy Kalluru while (len) { 23823a69cae8SSudarsana Reddy Kalluru u32 offset, mask, value, cur_value; 23833a69cae8SSudarsana Reddy Kalluru u8 buf[4]; 23843a69cae8SSudarsana Reddy Kalluru 23853a69cae8SSudarsana Reddy Kalluru value = *((u32 *)*data); 23863a69cae8SSudarsana Reddy Kalluru *data += 4; 23873a69cae8SSudarsana Reddy Kalluru mask = *((u32 *)*data); 23883a69cae8SSudarsana Reddy Kalluru *data += 4; 23893a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)*data); 23903a69cae8SSudarsana Reddy Kalluru *data += 4; 23913a69cae8SSudarsana Reddy Kalluru 23923a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf, 23933a69cae8SSudarsana Reddy Kalluru 4); 23943a69cae8SSudarsana Reddy Kalluru if (rc) { 23953a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading from %08x\n", 23963a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 23973a69cae8SSudarsana Reddy Kalluru goto exit; 23983a69cae8SSudarsana Reddy Kalluru } 23993a69cae8SSudarsana Reddy Kalluru 24003a69cae8SSudarsana Reddy Kalluru cur_value = le32_to_cpu(*((__le32 *)buf)); 24013a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 24023a69cae8SSudarsana Reddy Kalluru "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n", 24033a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, cur_value, 24043a69cae8SSudarsana Reddy Kalluru (cur_value & ~mask) | (value & mask), value, mask); 24053a69cae8SSudarsana Reddy Kalluru value = (value & mask) | (cur_value & ~mask); 24063a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 24073a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, 24083a69cae8SSudarsana Reddy Kalluru (u8 *)&value, 4); 24093a69cae8SSudarsana Reddy Kalluru if (rc) { 24103a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x\n", 24113a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 24123a69cae8SSudarsana Reddy Kalluru goto exit; 24133a69cae8SSudarsana Reddy Kalluru } 24143a69cae8SSudarsana Reddy Kalluru 24153a69cae8SSudarsana Reddy Kalluru len--; 24163a69cae8SSudarsana Reddy Kalluru } 24173a69cae8SSudarsana Reddy Kalluru exit: 24183a69cae8SSudarsana Reddy Kalluru return rc; 24193a69cae8SSudarsana Reddy Kalluru } 24203a69cae8SSudarsana Reddy Kalluru 24213a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24223a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24233a69cae8SSudarsana Reddy Kalluru * 0B | 0x3 [command index] | 24243a69cae8SSudarsana Reddy Kalluru * 4B | b'0: check_response? | b'1-31 reserved | 24253a69cae8SSudarsana Reddy Kalluru * 8B | File-type | reserved | 2426057d2b19SSudarsana Reddy Kalluru * 12B | Image length in bytes | 24273a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24283a69cae8SSudarsana Reddy Kalluru * Start a new file of the provided type 24293a69cae8SSudarsana Reddy Kalluru */ 24303a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_start(struct qed_dev *cdev, 24313a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24323a69cae8SSudarsana Reddy Kalluru { 2433057d2b19SSudarsana Reddy Kalluru u32 file_type, file_size = 0; 24343a69cae8SSudarsana Reddy Kalluru int rc; 24353a69cae8SSudarsana Reddy Kalluru 24363a69cae8SSudarsana Reddy Kalluru *data += 4; 24373a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24383a69cae8SSudarsana Reddy Kalluru *data += 4; 2439057d2b19SSudarsana Reddy Kalluru file_type = **data; 24403a69cae8SSudarsana Reddy Kalluru 24413a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 2442057d2b19SSudarsana Reddy Kalluru "About to start a new file of type %02x\n", file_type); 2443057d2b19SSudarsana Reddy Kalluru if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) { 2444057d2b19SSudarsana Reddy Kalluru *data += 4; 2445057d2b19SSudarsana Reddy Kalluru file_size = *((u32 *)(*data)); 2446057d2b19SSudarsana Reddy Kalluru } 2447057d2b19SSudarsana Reddy Kalluru 2448057d2b19SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type, 2449057d2b19SSudarsana Reddy Kalluru (u8 *)(&file_size), 4); 24503a69cae8SSudarsana Reddy Kalluru *data += 4; 24513a69cae8SSudarsana Reddy Kalluru 24523a69cae8SSudarsana Reddy Kalluru return rc; 24533a69cae8SSudarsana Reddy Kalluru } 24543a69cae8SSudarsana Reddy Kalluru 24553a69cae8SSudarsana Reddy Kalluru /* Binary file format - 24563a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24573a69cae8SSudarsana Reddy Kalluru * 0B | 0x2 [command index] | 24583a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24593a69cae8SSudarsana Reddy Kalluru * 8B | b'0: check_response? | b'1-31 reserved | 24603a69cae8SSudarsana Reddy Kalluru * 12B | Offset in bytes | 24613a69cae8SSudarsana Reddy Kalluru * 16B | Data ... | 24623a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24633a69cae8SSudarsana Reddy Kalluru * Write data as part of a file that was previously started. Data should be 24643a69cae8SSudarsana Reddy Kalluru * of length equal to that provided in the message 24653a69cae8SSudarsana Reddy Kalluru */ 24663a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_data(struct qed_dev *cdev, 24673a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 24683a69cae8SSudarsana Reddy Kalluru { 24693a69cae8SSudarsana Reddy Kalluru u32 offset, len; 24703a69cae8SSudarsana Reddy Kalluru int rc; 24713a69cae8SSudarsana Reddy Kalluru 24723a69cae8SSudarsana Reddy Kalluru *data += 4; 24733a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 24743a69cae8SSudarsana Reddy Kalluru *data += 4; 24753a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 24763a69cae8SSudarsana Reddy Kalluru *data += 4; 24773a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)(*data)); 24783a69cae8SSudarsana Reddy Kalluru *data += 4; 24793a69cae8SSudarsana Reddy Kalluru 24803a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 24813a69cae8SSudarsana Reddy Kalluru "About to write File-data: %08x bytes to offset %08x\n", 24823a69cae8SSudarsana Reddy Kalluru len, offset); 24833a69cae8SSudarsana Reddy Kalluru 24843a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset, 24853a69cae8SSudarsana Reddy Kalluru (char *)(*data), len); 24863a69cae8SSudarsana Reddy Kalluru *data += len; 24873a69cae8SSudarsana Reddy Kalluru 24883a69cae8SSudarsana Reddy Kalluru return rc; 24893a69cae8SSudarsana Reddy Kalluru } 24903a69cae8SSudarsana Reddy Kalluru 24913a69cae8SSudarsana Reddy Kalluru /* Binary file format [General header] - 24923a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 24933a69cae8SSudarsana Reddy Kalluru * 0B | QED_NVM_SIGNATURE | 24943a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 24953a69cae8SSudarsana Reddy Kalluru * 8B | Highest command in this batchfile | Reserved | 24963a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 24973a69cae8SSudarsana Reddy Kalluru */ 24983a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_validate(struct qed_dev *cdev, 24993a69cae8SSudarsana Reddy Kalluru const struct firmware *image, 25003a69cae8SSudarsana Reddy Kalluru const u8 **data) 25013a69cae8SSudarsana Reddy Kalluru { 25023a69cae8SSudarsana Reddy Kalluru u32 signature, len; 25033a69cae8SSudarsana Reddy Kalluru 25043a69cae8SSudarsana Reddy Kalluru /* Check minimum size */ 25053a69cae8SSudarsana Reddy Kalluru if (image->size < 12) { 25063a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size); 25073a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25083a69cae8SSudarsana Reddy Kalluru } 25093a69cae8SSudarsana Reddy Kalluru 25103a69cae8SSudarsana Reddy Kalluru /* Check signature */ 25113a69cae8SSudarsana Reddy Kalluru signature = *((u32 *)(*data)); 25123a69cae8SSudarsana Reddy Kalluru if (signature != QED_NVM_SIGNATURE) { 25133a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Wrong signature '%08x'\n", signature); 25143a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25153a69cae8SSudarsana Reddy Kalluru } 25163a69cae8SSudarsana Reddy Kalluru 25173a69cae8SSudarsana Reddy Kalluru *data += 4; 25183a69cae8SSudarsana Reddy Kalluru /* Validate internal size equals the image-size */ 25193a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 25203a69cae8SSudarsana Reddy Kalluru if (len != image->size) { 25213a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n", 25223a69cae8SSudarsana Reddy Kalluru len, (u32)image->size); 25233a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25243a69cae8SSudarsana Reddy Kalluru } 25253a69cae8SSudarsana Reddy Kalluru 25263a69cae8SSudarsana Reddy Kalluru *data += 4; 25273a69cae8SSudarsana Reddy Kalluru /* Make sure driver familiar with all commands necessary for this */ 25283a69cae8SSudarsana Reddy Kalluru if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) { 25293a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n", 25303a69cae8SSudarsana Reddy Kalluru *((u16 *)(*data))); 25313a69cae8SSudarsana Reddy Kalluru return -EINVAL; 25323a69cae8SSudarsana Reddy Kalluru } 25333a69cae8SSudarsana Reddy Kalluru 25343a69cae8SSudarsana Reddy Kalluru *data += 4; 25353a69cae8SSudarsana Reddy Kalluru 25363a69cae8SSudarsana Reddy Kalluru return 0; 25373a69cae8SSudarsana Reddy Kalluru } 25383a69cae8SSudarsana Reddy Kalluru 25390dabbe1bSSudarsana Reddy Kalluru /* Binary file format - 25400dabbe1bSSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 25410dabbe1bSSudarsana Reddy Kalluru * 0B | 0x5 [command index] | 25422da244a5SSudarsana Reddy Kalluru * 4B | Number of config attributes | Reserved | 25432da244a5SSudarsana Reddy Kalluru * 4B | Config ID | Entity ID | Length | 25442da244a5SSudarsana Reddy Kalluru * 4B | Value | 25450dabbe1bSSudarsana Reddy Kalluru * | | 25460dabbe1bSSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 25472da244a5SSudarsana Reddy Kalluru * There can be several cfg_id-entity_id-Length-Value sets as specified by 25482da244a5SSudarsana Reddy Kalluru * 'Number of config attributes'. 25490dabbe1bSSudarsana Reddy Kalluru * 25500dabbe1bSSudarsana Reddy Kalluru * The API parses config attributes from the user provided buffer and flashes 25510dabbe1bSSudarsana Reddy Kalluru * them to the respective NVM path using Management FW inerface. 25520dabbe1bSSudarsana Reddy Kalluru */ 25530dabbe1bSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data) 25540dabbe1bSSudarsana Reddy Kalluru { 25550dabbe1bSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 25560dabbe1bSSudarsana Reddy Kalluru u8 entity_id, len, buf[32]; 2557c63b0968SSudarsana Reddy Kalluru bool need_nvm_init = true; 25580dabbe1bSSudarsana Reddy Kalluru struct qed_ptt *ptt; 25590dabbe1bSSudarsana Reddy Kalluru u16 cfg_id, count; 25600dabbe1bSSudarsana Reddy Kalluru int rc = 0, i; 25610dabbe1bSSudarsana Reddy Kalluru u32 flags; 25620dabbe1bSSudarsana Reddy Kalluru 25630dabbe1bSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 25640dabbe1bSSudarsana Reddy Kalluru if (!ptt) 25650dabbe1bSSudarsana Reddy Kalluru return -EAGAIN; 25660dabbe1bSSudarsana Reddy Kalluru 25670dabbe1bSSudarsana Reddy Kalluru /* NVM CFG ID attribute header */ 25680dabbe1bSSudarsana Reddy Kalluru *data += 4; 25690dabbe1bSSudarsana Reddy Kalluru count = *((u16 *)*data); 25702da244a5SSudarsana Reddy Kalluru *data += 4; 25710dabbe1bSSudarsana Reddy Kalluru 25720dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 25732da244a5SSudarsana Reddy Kalluru "Read config ids: num_attrs = %0d\n", count); 2574c63b0968SSudarsana Reddy Kalluru /* NVM CFG ID attributes. Start loop index from 1 to avoid additional 2575c63b0968SSudarsana Reddy Kalluru * arithmetic operations in the implementation. 2576c63b0968SSudarsana Reddy Kalluru */ 2577c63b0968SSudarsana Reddy Kalluru for (i = 1; i <= count; i++) { 25780dabbe1bSSudarsana Reddy Kalluru cfg_id = *((u16 *)*data); 25790dabbe1bSSudarsana Reddy Kalluru *data += 2; 25802da244a5SSudarsana Reddy Kalluru entity_id = **data; 25812da244a5SSudarsana Reddy Kalluru (*data)++; 25820dabbe1bSSudarsana Reddy Kalluru len = **data; 25830dabbe1bSSudarsana Reddy Kalluru (*data)++; 25840dabbe1bSSudarsana Reddy Kalluru memcpy(buf, *data, len); 25850dabbe1bSSudarsana Reddy Kalluru *data += len; 25860dabbe1bSSudarsana Reddy Kalluru 2587c63b0968SSudarsana Reddy Kalluru flags = 0; 2588c63b0968SSudarsana Reddy Kalluru if (need_nvm_init) { 2589c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_INIT; 2590c63b0968SSudarsana Reddy Kalluru need_nvm_init = false; 2591c63b0968SSudarsana Reddy Kalluru } 2592c63b0968SSudarsana Reddy Kalluru 2593c63b0968SSudarsana Reddy Kalluru /* Commit to flash and free the resources */ 2594c63b0968SSudarsana Reddy Kalluru if (!(i % QED_NVM_CFG_MAX_ATTRS) || i == count) { 2595c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_COMMIT | 2596c63b0968SSudarsana Reddy Kalluru QED_NVM_CFG_OPTION_FREE; 2597c63b0968SSudarsana Reddy Kalluru need_nvm_init = true; 2598c63b0968SSudarsana Reddy Kalluru } 2599c63b0968SSudarsana Reddy Kalluru 2600c63b0968SSudarsana Reddy Kalluru if (entity_id) 2601c63b0968SSudarsana Reddy Kalluru flags |= QED_NVM_CFG_OPTION_ENTITY_SEL; 26020dabbe1bSSudarsana Reddy Kalluru 26030dabbe1bSSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26042da244a5SSudarsana Reddy Kalluru "cfg_id = %d entity = %d len = %d\n", cfg_id, 26052da244a5SSudarsana Reddy Kalluru entity_id, len); 26060dabbe1bSSudarsana Reddy Kalluru rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags, 26070dabbe1bSSudarsana Reddy Kalluru buf, len); 26080dabbe1bSSudarsana Reddy Kalluru if (rc) { 26090dabbe1bSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id); 26100dabbe1bSSudarsana Reddy Kalluru break; 26110dabbe1bSSudarsana Reddy Kalluru } 26120dabbe1bSSudarsana Reddy Kalluru } 26130dabbe1bSSudarsana Reddy Kalluru 26140dabbe1bSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26150dabbe1bSSudarsana Reddy Kalluru 26160dabbe1bSSudarsana Reddy Kalluru return rc; 26170dabbe1bSSudarsana Reddy Kalluru } 26180dabbe1bSSudarsana Reddy Kalluru 26199e54ba7cSSudarsana Reddy Kalluru #define QED_MAX_NVM_BUF_LEN 32 26209e54ba7cSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_len(struct qed_dev *cdev, u32 cmd) 26219e54ba7cSSudarsana Reddy Kalluru { 26229e54ba7cSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26239e54ba7cSSudarsana Reddy Kalluru u8 buf[QED_MAX_NVM_BUF_LEN]; 26249e54ba7cSSudarsana Reddy Kalluru struct qed_ptt *ptt; 26259e54ba7cSSudarsana Reddy Kalluru u32 len; 26269e54ba7cSSudarsana Reddy Kalluru int rc; 26279e54ba7cSSudarsana Reddy Kalluru 26289e54ba7cSSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26299e54ba7cSSudarsana Reddy Kalluru if (!ptt) 26309e54ba7cSSudarsana Reddy Kalluru return QED_MAX_NVM_BUF_LEN; 26319e54ba7cSSudarsana Reddy Kalluru 26329e54ba7cSSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, 0, QED_NVM_CFG_GET_FLAGS, buf, 26339e54ba7cSSudarsana Reddy Kalluru &len); 26349e54ba7cSSudarsana Reddy Kalluru if (rc || !len) { 26359e54ba7cSSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26369e54ba7cSSudarsana Reddy Kalluru len = QED_MAX_NVM_BUF_LEN; 26379e54ba7cSSudarsana Reddy Kalluru } 26389e54ba7cSSudarsana Reddy Kalluru 26399e54ba7cSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26409e54ba7cSSudarsana Reddy Kalluru 26419e54ba7cSSudarsana Reddy Kalluru return len; 26429e54ba7cSSudarsana Reddy Kalluru } 26439e54ba7cSSudarsana Reddy Kalluru 26442d4c8495SSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_read(struct qed_dev *cdev, u8 **data, 26452d4c8495SSudarsana Reddy Kalluru u32 cmd, u32 entity_id) 26462d4c8495SSudarsana Reddy Kalluru { 26472d4c8495SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 26482d4c8495SSudarsana Reddy Kalluru struct qed_ptt *ptt; 26492d4c8495SSudarsana Reddy Kalluru u32 flags, len; 26502d4c8495SSudarsana Reddy Kalluru int rc = 0; 26512d4c8495SSudarsana Reddy Kalluru 26522d4c8495SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 26532d4c8495SSudarsana Reddy Kalluru if (!ptt) 26542d4c8495SSudarsana Reddy Kalluru return -EAGAIN; 26552d4c8495SSudarsana Reddy Kalluru 26562d4c8495SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26572d4c8495SSudarsana Reddy Kalluru "Read config cmd = %d entity id %d\n", cmd, entity_id); 26582d4c8495SSudarsana Reddy Kalluru flags = entity_id ? QED_NVM_CFG_GET_PF_FLAGS : QED_NVM_CFG_GET_FLAGS; 26592d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, entity_id, flags, *data, &len); 26602d4c8495SSudarsana Reddy Kalluru if (rc) 26612d4c8495SSudarsana Reddy Kalluru DP_ERR(cdev, "Error %d reading %d\n", rc, cmd); 26622d4c8495SSudarsana Reddy Kalluru 26632d4c8495SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 26642d4c8495SSudarsana Reddy Kalluru 26652d4c8495SSudarsana Reddy Kalluru return rc; 26662d4c8495SSudarsana Reddy Kalluru } 26672d4c8495SSudarsana Reddy Kalluru 26683a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash(struct qed_dev *cdev, const char *name) 26693a69cae8SSudarsana Reddy Kalluru { 26703a69cae8SSudarsana Reddy Kalluru const struct firmware *image; 26713a69cae8SSudarsana Reddy Kalluru const u8 *data, *data_end; 26723a69cae8SSudarsana Reddy Kalluru u32 cmd_type; 26733a69cae8SSudarsana Reddy Kalluru int rc; 26743a69cae8SSudarsana Reddy Kalluru 26753a69cae8SSudarsana Reddy Kalluru rc = request_firmware(&image, name, &cdev->pdev->dev); 26763a69cae8SSudarsana Reddy Kalluru if (rc) { 26773a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find '%s'\n", name); 26783a69cae8SSudarsana Reddy Kalluru return rc; 26793a69cae8SSudarsana Reddy Kalluru } 26803a69cae8SSudarsana Reddy Kalluru 26813a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 26823a69cae8SSudarsana Reddy Kalluru "Flashing '%s' - firmware's data at %p, size is %08x\n", 26833a69cae8SSudarsana Reddy Kalluru name, image->data, (u32)image->size); 26843a69cae8SSudarsana Reddy Kalluru data = image->data; 26853a69cae8SSudarsana Reddy Kalluru data_end = data + image->size; 26863a69cae8SSudarsana Reddy Kalluru 26873a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_validate(cdev, image, &data); 26883a69cae8SSudarsana Reddy Kalluru if (rc) 26893a69cae8SSudarsana Reddy Kalluru goto exit; 26903a69cae8SSudarsana Reddy Kalluru 26913a69cae8SSudarsana Reddy Kalluru while (data < data_end) { 26923a69cae8SSudarsana Reddy Kalluru bool check_resp = false; 26933a69cae8SSudarsana Reddy Kalluru 26943a69cae8SSudarsana Reddy Kalluru /* Parse the actual command */ 26953a69cae8SSudarsana Reddy Kalluru cmd_type = *((u32 *)data); 26963a69cae8SSudarsana Reddy Kalluru switch (cmd_type) { 26973a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_DATA: 26983a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_data(cdev, &data, 26993a69cae8SSudarsana Reddy Kalluru &check_resp); 27003a69cae8SSudarsana Reddy Kalluru break; 27013a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_START: 27023a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_start(cdev, &data, 27033a69cae8SSudarsana Reddy Kalluru &check_resp); 27043a69cae8SSudarsana Reddy Kalluru break; 27053a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CHANGE: 27063a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access(cdev, &data, 27073a69cae8SSudarsana Reddy Kalluru &check_resp); 27083a69cae8SSudarsana Reddy Kalluru break; 27090dabbe1bSSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CFG_ID: 27100dabbe1bSSudarsana Reddy Kalluru rc = qed_nvm_flash_cfg_write(cdev, &data); 27110dabbe1bSSudarsana Reddy Kalluru break; 27123a69cae8SSudarsana Reddy Kalluru default: 27133a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Unknown command %08x\n", cmd_type); 27143a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27153a69cae8SSudarsana Reddy Kalluru goto exit; 27163a69cae8SSudarsana Reddy Kalluru } 27173a69cae8SSudarsana Reddy Kalluru 27183a69cae8SSudarsana Reddy Kalluru if (rc) { 27193a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Command %08x failed\n", cmd_type); 27203a69cae8SSudarsana Reddy Kalluru goto exit; 27213a69cae8SSudarsana Reddy Kalluru } 27223a69cae8SSudarsana Reddy Kalluru 27233a69cae8SSudarsana Reddy Kalluru /* Check response if needed */ 27243a69cae8SSudarsana Reddy Kalluru if (check_resp) { 27253a69cae8SSudarsana Reddy Kalluru u32 mcp_response = 0; 27263a69cae8SSudarsana Reddy Kalluru 27273a69cae8SSudarsana Reddy Kalluru if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) { 27283a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed getting MCP response\n"); 27293a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27303a69cae8SSudarsana Reddy Kalluru goto exit; 27313a69cae8SSudarsana Reddy Kalluru } 27323a69cae8SSudarsana Reddy Kalluru 27333a69cae8SSudarsana Reddy Kalluru switch (mcp_response & FW_MSG_CODE_MASK) { 27343a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_OK: 27353a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_OK: 27363a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK: 27373a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_PHY_OK: 27383a69cae8SSudarsana Reddy Kalluru break; 27393a69cae8SSudarsana Reddy Kalluru default: 27403a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "MFW returns error: %08x\n", 27413a69cae8SSudarsana Reddy Kalluru mcp_response); 27423a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 27433a69cae8SSudarsana Reddy Kalluru goto exit; 27443a69cae8SSudarsana Reddy Kalluru } 27453a69cae8SSudarsana Reddy Kalluru } 27463a69cae8SSudarsana Reddy Kalluru } 27473a69cae8SSudarsana Reddy Kalluru 27483a69cae8SSudarsana Reddy Kalluru exit: 27493a69cae8SSudarsana Reddy Kalluru release_firmware(image); 27503a69cae8SSudarsana Reddy Kalluru 27513a69cae8SSudarsana Reddy Kalluru return rc; 27523a69cae8SSudarsana Reddy Kalluru } 27533a69cae8SSudarsana Reddy Kalluru 275420675b37SMintz, Yuval static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, 275520675b37SMintz, Yuval u8 *buf, u16 len) 275620675b37SMintz, Yuval { 275720675b37SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 275820675b37SMintz, Yuval 2759b60bfdfeSDenis Bolotin return qed_mcp_get_nvm_image(hwfn, type, buf, len); 276020675b37SMintz, Yuval } 276120675b37SMintz, Yuval 276264515dc8STomer Tayar void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) 276364515dc8STomer Tayar { 276464515dc8STomer Tayar struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 276564515dc8STomer Tayar void *cookie = p_hwfn->cdev->ops_cookie; 276664515dc8STomer Tayar 276764515dc8STomer Tayar if (ops && ops->schedule_recovery_handler) 276864515dc8STomer Tayar ops->schedule_recovery_handler(cookie); 276964515dc8STomer Tayar } 277064515dc8STomer Tayar 2771c6b7314dSAlexander Lobakin static const char * const qed_hw_err_type_descr[] = { 2772d639836aSIgor Russkikh [QED_HW_ERR_FAN_FAIL] = "Fan Failure", 2773d639836aSIgor Russkikh [QED_HW_ERR_MFW_RESP_FAIL] = "MFW Response Failure", 2774d639836aSIgor Russkikh [QED_HW_ERR_HW_ATTN] = "HW Attention", 2775d639836aSIgor Russkikh [QED_HW_ERR_DMAE_FAIL] = "DMAE Failure", 2776d639836aSIgor Russkikh [QED_HW_ERR_RAMROD_FAIL] = "Ramrod Failure", 2777d639836aSIgor Russkikh [QED_HW_ERR_FW_ASSERT] = "FW Assertion", 2778d639836aSIgor Russkikh [QED_HW_ERR_LAST] = "Unknown", 2779d639836aSIgor Russkikh }; 2780d639836aSIgor Russkikh 2781d639836aSIgor Russkikh void qed_hw_error_occurred(struct qed_hwfn *p_hwfn, 2782d639836aSIgor Russkikh enum qed_hw_err_type err_type) 2783d639836aSIgor Russkikh { 2784d639836aSIgor Russkikh struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; 2785d639836aSIgor Russkikh void *cookie = p_hwfn->cdev->ops_cookie; 2786c6b7314dSAlexander Lobakin const char *err_str; 2787d639836aSIgor Russkikh 2788d639836aSIgor Russkikh if (err_type > QED_HW_ERR_LAST) 2789d639836aSIgor Russkikh err_type = QED_HW_ERR_LAST; 2790d639836aSIgor Russkikh err_str = qed_hw_err_type_descr[err_type]; 2791d639836aSIgor Russkikh 2792d639836aSIgor Russkikh DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str); 2793d639836aSIgor Russkikh 2794936c7ba4SIgor Russkikh /* Call the HW error handler of the protocol driver. 2795936c7ba4SIgor Russkikh * If it is not available - perform a minimal handling of preventing 2796936c7ba4SIgor Russkikh * HW attentions from being reasserted. 2797d639836aSIgor Russkikh */ 2798d639836aSIgor Russkikh if (ops && ops->schedule_hw_err_handler) 2799d639836aSIgor Russkikh ops->schedule_hw_err_handler(cookie, err_type); 2800936c7ba4SIgor Russkikh else 2801936c7ba4SIgor Russkikh qed_int_attn_clr_enable(p_hwfn->cdev, true); 2802d639836aSIgor Russkikh } 2803d639836aSIgor Russkikh 2804722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, 2805477f2d14SRahul Verma void *handle) 2806722003acSSudarsana Reddy Kalluru { 2807477f2d14SRahul Verma return qed_set_queue_coalesce(rx_coal, tx_coal, handle); 2808722003acSSudarsana Reddy Kalluru } 2809722003acSSudarsana Reddy Kalluru 281091420b83SSudarsana Kalluru static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) 281191420b83SSudarsana Kalluru { 281291420b83SSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 281391420b83SSudarsana Kalluru struct qed_ptt *ptt; 281491420b83SSudarsana Kalluru int status = 0; 281591420b83SSudarsana Kalluru 281691420b83SSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 281791420b83SSudarsana Kalluru if (!ptt) 281891420b83SSudarsana Kalluru return -EAGAIN; 281991420b83SSudarsana Kalluru 282091420b83SSudarsana Kalluru status = qed_mcp_set_led(hwfn, ptt, mode); 282191420b83SSudarsana Kalluru 282291420b83SSudarsana Kalluru qed_ptt_release(hwfn, ptt); 282391420b83SSudarsana Kalluru 282491420b83SSudarsana Kalluru return status; 282591420b83SSudarsana Kalluru } 282691420b83SSudarsana Kalluru 2827b228cb16SIgor Russkikh int qed_recovery_process(struct qed_dev *cdev) 282864515dc8STomer Tayar { 282964515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 283064515dc8STomer Tayar struct qed_ptt *p_ptt; 283164515dc8STomer Tayar int rc = 0; 283264515dc8STomer Tayar 283364515dc8STomer Tayar p_ptt = qed_ptt_acquire(p_hwfn); 283464515dc8STomer Tayar if (!p_ptt) 283564515dc8STomer Tayar return -EAGAIN; 283664515dc8STomer Tayar 283764515dc8STomer Tayar rc = qed_start_recovery_process(p_hwfn, p_ptt); 283864515dc8STomer Tayar 283964515dc8STomer Tayar qed_ptt_release(p_hwfn, p_ptt); 284064515dc8STomer Tayar 284164515dc8STomer Tayar return rc; 284264515dc8STomer Tayar } 284364515dc8STomer Tayar 284414d39648SMintz, Yuval static int qed_update_wol(struct qed_dev *cdev, bool enabled) 284514d39648SMintz, Yuval { 284614d39648SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 284714d39648SMintz, Yuval struct qed_ptt *ptt; 284814d39648SMintz, Yuval int rc = 0; 284914d39648SMintz, Yuval 285014d39648SMintz, Yuval if (IS_VF(cdev)) 285114d39648SMintz, Yuval return 0; 285214d39648SMintz, Yuval 285314d39648SMintz, Yuval ptt = qed_ptt_acquire(hwfn); 285414d39648SMintz, Yuval if (!ptt) 285514d39648SMintz, Yuval return -EAGAIN; 285614d39648SMintz, Yuval 285714d39648SMintz, Yuval rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED 285814d39648SMintz, Yuval : QED_OV_WOL_DISABLED); 285914d39648SMintz, Yuval if (rc) 286014d39648SMintz, Yuval goto out; 286114d39648SMintz, Yuval rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 286214d39648SMintz, Yuval 286314d39648SMintz, Yuval out: 286414d39648SMintz, Yuval qed_ptt_release(hwfn, ptt); 286514d39648SMintz, Yuval return rc; 286614d39648SMintz, Yuval } 286714d39648SMintz, Yuval 28680fefbfbaSSudarsana Kalluru static int qed_update_drv_state(struct qed_dev *cdev, bool active) 28690fefbfbaSSudarsana Kalluru { 28700fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28710fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28720fefbfbaSSudarsana Kalluru int status = 0; 28730fefbfbaSSudarsana Kalluru 28740fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28750fefbfbaSSudarsana Kalluru return 0; 28760fefbfbaSSudarsana Kalluru 28770fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 28780fefbfbaSSudarsana Kalluru if (!ptt) 28790fefbfbaSSudarsana Kalluru return -EAGAIN; 28800fefbfbaSSudarsana Kalluru 28810fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? 28820fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_ACTIVE : 28830fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_DISABLED); 28840fefbfbaSSudarsana Kalluru 28850fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 28860fefbfbaSSudarsana Kalluru 28870fefbfbaSSudarsana Kalluru return status; 28880fefbfbaSSudarsana Kalluru } 28890fefbfbaSSudarsana Kalluru 2890*76660757SJakub Kicinski static int qed_update_mac(struct qed_dev *cdev, const u8 *mac) 28910fefbfbaSSudarsana Kalluru { 28920fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 28930fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 28940fefbfbaSSudarsana Kalluru int status = 0; 28950fefbfbaSSudarsana Kalluru 28960fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 28970fefbfbaSSudarsana Kalluru return 0; 28980fefbfbaSSudarsana Kalluru 28990fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 29000fefbfbaSSudarsana Kalluru if (!ptt) 29010fefbfbaSSudarsana Kalluru return -EAGAIN; 29020fefbfbaSSudarsana Kalluru 29030fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mac(hwfn, ptt, mac); 29040fefbfbaSSudarsana Kalluru if (status) 29050fefbfbaSSudarsana Kalluru goto out; 29060fefbfbaSSudarsana Kalluru 29070fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29080fefbfbaSSudarsana Kalluru 29090fefbfbaSSudarsana Kalluru out: 29100fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29110fefbfbaSSudarsana Kalluru return status; 29120fefbfbaSSudarsana Kalluru } 29130fefbfbaSSudarsana Kalluru 29140fefbfbaSSudarsana Kalluru static int qed_update_mtu(struct qed_dev *cdev, u16 mtu) 29150fefbfbaSSudarsana Kalluru { 29160fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29170fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 29180fefbfbaSSudarsana Kalluru int status = 0; 29190fefbfbaSSudarsana Kalluru 29200fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 29210fefbfbaSSudarsana Kalluru return 0; 29220fefbfbaSSudarsana Kalluru 29230fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 29240fefbfbaSSudarsana Kalluru if (!ptt) 29250fefbfbaSSudarsana Kalluru return -EAGAIN; 29260fefbfbaSSudarsana Kalluru 29270fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); 29280fefbfbaSSudarsana Kalluru if (status) 29290fefbfbaSSudarsana Kalluru goto out; 29300fefbfbaSSudarsana Kalluru 29310fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 29320fefbfbaSSudarsana Kalluru 29330fefbfbaSSudarsana Kalluru out: 29340fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 29350fefbfbaSSudarsana Kalluru return status; 29360fefbfbaSSudarsana Kalluru } 29370fefbfbaSSudarsana Kalluru 2938b51dab46SSudarsana Reddy Kalluru static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 2939b51dab46SSudarsana Reddy Kalluru u8 dev_addr, u32 offset, u32 len) 2940b51dab46SSudarsana Reddy Kalluru { 2941b51dab46SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 2942b51dab46SSudarsana Reddy Kalluru struct qed_ptt *ptt; 2943b51dab46SSudarsana Reddy Kalluru int rc = 0; 2944b51dab46SSudarsana Reddy Kalluru 2945b51dab46SSudarsana Reddy Kalluru if (IS_VF(cdev)) 2946b51dab46SSudarsana Reddy Kalluru return 0; 2947b51dab46SSudarsana Reddy Kalluru 2948b51dab46SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 2949b51dab46SSudarsana Reddy Kalluru if (!ptt) 2950b51dab46SSudarsana Reddy Kalluru return -EAGAIN; 2951b51dab46SSudarsana Reddy Kalluru 2952b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr, 2953b51dab46SSudarsana Reddy Kalluru offset, len, buf); 2954b51dab46SSudarsana Reddy Kalluru 2955b51dab46SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 2956b51dab46SSudarsana Reddy Kalluru 2957b51dab46SSudarsana Reddy Kalluru return rc; 2958b51dab46SSudarsana Reddy Kalluru } 2959b51dab46SSudarsana Reddy Kalluru 29603b86bd07SSudarsana Reddy Kalluru static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val) 29613b86bd07SSudarsana Reddy Kalluru { 29623b86bd07SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 29633b86bd07SSudarsana Reddy Kalluru struct qed_ptt *ptt; 29643b86bd07SSudarsana Reddy Kalluru int rc = 0; 29653b86bd07SSudarsana Reddy Kalluru 29663b86bd07SSudarsana Reddy Kalluru if (IS_VF(cdev)) 29673b86bd07SSudarsana Reddy Kalluru return 0; 29683b86bd07SSudarsana Reddy Kalluru 29693b86bd07SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 29703b86bd07SSudarsana Reddy Kalluru if (!ptt) 29713b86bd07SSudarsana Reddy Kalluru return -EAGAIN; 29723b86bd07SSudarsana Reddy Kalluru 29732d22bc83SMichal Kalderon rc = qed_dbg_grc_config(hwfn, cfg_id, val); 29743b86bd07SSudarsana Reddy Kalluru 29753b86bd07SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 29763b86bd07SSudarsana Reddy Kalluru 29773b86bd07SSudarsana Reddy Kalluru return rc; 29783b86bd07SSudarsana Reddy Kalluru } 29793b86bd07SSudarsana Reddy Kalluru 298008eb1fb0SMichal Kalderon static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev) 298108eb1fb0SMichal Kalderon { 298208eb1fb0SMichal Kalderon return QED_AFFIN_HWFN_IDX(cdev); 298308eb1fb0SMichal Kalderon } 298408eb1fb0SMichal Kalderon 29858c93beafSYuval Mintz static struct qed_selftest_ops qed_selftest_ops_pass = { 298603dc76caSSudarsana Reddy Kalluru .selftest_memory = &qed_selftest_memory, 298703dc76caSSudarsana Reddy Kalluru .selftest_interrupt = &qed_selftest_interrupt, 298803dc76caSSudarsana Reddy Kalluru .selftest_register = &qed_selftest_register, 298903dc76caSSudarsana Reddy Kalluru .selftest_clock = &qed_selftest_clock, 29907a4b21b7SMintz, Yuval .selftest_nvram = &qed_selftest_nvram, 299103dc76caSSudarsana Reddy Kalluru }; 299203dc76caSSudarsana Reddy Kalluru 2993fe56b9e6SYuval Mintz const struct qed_common_ops qed_common_ops_pass = { 299403dc76caSSudarsana Reddy Kalluru .selftest = &qed_selftest_ops_pass, 2995fe56b9e6SYuval Mintz .probe = &qed_probe, 2996fe56b9e6SYuval Mintz .remove = &qed_remove, 2997fe56b9e6SYuval Mintz .set_power_state = &qed_set_power_state, 2998712c3cbfSMintz, Yuval .set_name = &qed_set_name, 2999fe56b9e6SYuval Mintz .update_pf_params = &qed_update_pf_params, 3000fe56b9e6SYuval Mintz .slowpath_start = &qed_slowpath_start, 3001fe56b9e6SYuval Mintz .slowpath_stop = &qed_slowpath_stop, 3002fe56b9e6SYuval Mintz .set_fp_int = &qed_set_int_fp, 3003fe56b9e6SYuval Mintz .get_fp_int = &qed_get_int_fp, 3004fe56b9e6SYuval Mintz .sb_init = &qed_sb_init, 3005fe56b9e6SYuval Mintz .sb_release = &qed_sb_release, 3006fe56b9e6SYuval Mintz .simd_handler_config = &qed_simd_handler_config, 3007fe56b9e6SYuval Mintz .simd_handler_clean = &qed_simd_handler_clean, 30081e128c81SArun Easi .dbg_grc = &qed_dbg_grc, 30091e128c81SArun Easi .dbg_grc_size = &qed_dbg_grc_size, 3010fe7cd2bfSYuval Mintz .can_link_change = &qed_can_link_change, 3011cc875c2eSYuval Mintz .set_link = &qed_set_link, 3012cc875c2eSYuval Mintz .get_link = &qed_get_current_link, 3013fe56b9e6SYuval Mintz .drain = &qed_drain, 3014fe56b9e6SYuval Mintz .update_msglvl = &qed_init_dp, 3015755f982bSIgor Russkikh .devlink_register = qed_devlink_register, 3016755f982bSIgor Russkikh .devlink_unregister = qed_devlink_unregister, 30174f5a8db2SIgor Russkikh .report_fatal_error = qed_report_fatal_error, 3018e0971c83STomer Tayar .dbg_all_data = &qed_dbg_all_data, 3019e0971c83STomer Tayar .dbg_all_data_size = &qed_dbg_all_data_size, 3020fe56b9e6SYuval Mintz .chain_alloc = &qed_chain_alloc, 3021fe56b9e6SYuval Mintz .chain_free = &qed_chain_free, 30223a69cae8SSudarsana Reddy Kalluru .nvm_flash = &qed_nvm_flash, 302320675b37SMintz, Yuval .nvm_get_image = &qed_nvm_get_image, 3024722003acSSudarsana Reddy Kalluru .set_coalesce = &qed_set_coalesce, 302591420b83SSudarsana Kalluru .set_led = &qed_set_led, 302664515dc8STomer Tayar .recovery_process = &qed_recovery_process, 302764515dc8STomer Tayar .recovery_prolog = &qed_recovery_prolog, 3028936c7ba4SIgor Russkikh .attn_clr_enable = &qed_int_attn_clr_enable, 30290fefbfbaSSudarsana Kalluru .update_drv_state = &qed_update_drv_state, 30300fefbfbaSSudarsana Kalluru .update_mac = &qed_update_mac, 30310fefbfbaSSudarsana Kalluru .update_mtu = &qed_update_mtu, 303214d39648SMintz, Yuval .update_wol = &qed_update_wol, 30330e1f1044SAriel Elior .db_recovery_add = &qed_db_recovery_add, 30340e1f1044SAriel Elior .db_recovery_del = &qed_db_recovery_del, 3035b51dab46SSudarsana Reddy Kalluru .read_module_eeprom = &qed_read_module_eeprom, 303608eb1fb0SMichal Kalderon .get_affin_hwfn_idx = &qed_get_affin_hwfn_idx, 30372d4c8495SSudarsana Reddy Kalluru .read_nvm_cfg = &qed_nvm_flash_cfg_read, 30389e54ba7cSSudarsana Reddy Kalluru .read_nvm_cfg_len = &qed_nvm_flash_cfg_len, 30393b86bd07SSudarsana Reddy Kalluru .set_grc_config = &qed_set_grc_config, 3040fe56b9e6SYuval Mintz }; 30416c754246SSudarsana Reddy Kalluru 30426c754246SSudarsana Reddy Kalluru void qed_get_protocol_stats(struct qed_dev *cdev, 30436c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type type, 30446c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats *stats) 30456c754246SSudarsana Reddy Kalluru { 30466c754246SSudarsana Reddy Kalluru struct qed_eth_stats eth_stats; 30476c754246SSudarsana Reddy Kalluru 30486c754246SSudarsana Reddy Kalluru memset(stats, 0, sizeof(*stats)); 30496c754246SSudarsana Reddy Kalluru 30506c754246SSudarsana Reddy Kalluru switch (type) { 30516c754246SSudarsana Reddy Kalluru case QED_MCP_LAN_STATS: 30526c754246SSudarsana Reddy Kalluru qed_get_vport_stats(cdev, ð_stats); 30539c79ddaaSMintz, Yuval stats->lan_stats.ucast_rx_pkts = 30549c79ddaaSMintz, Yuval eth_stats.common.rx_ucast_pkts; 30559c79ddaaSMintz, Yuval stats->lan_stats.ucast_tx_pkts = 30569c79ddaaSMintz, Yuval eth_stats.common.tx_ucast_pkts; 30576c754246SSudarsana Reddy Kalluru stats->lan_stats.fcs_err = -1; 30586c754246SSudarsana Reddy Kalluru break; 30591e128c81SArun Easi case QED_MCP_FCOE_STATS: 30601e128c81SArun Easi qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); 30611e128c81SArun Easi break; 30622f2b2614SMintz, Yuval case QED_MCP_ISCSI_STATS: 30632f2b2614SMintz, Yuval qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); 30642f2b2614SMintz, Yuval break; 30656c754246SSudarsana Reddy Kalluru default: 3066512c7840SMintz, Yuval DP_VERBOSE(cdev, QED_MSG_SP, 3067512c7840SMintz, Yuval "Invalid protocol type = %d\n", type); 30686c754246SSudarsana Reddy Kalluru return; 30696c754246SSudarsana Reddy Kalluru } 30706c754246SSudarsana Reddy Kalluru } 30712528c389SSudarsana Reddy Kalluru 307259ccf86fSSudarsana Reddy Kalluru int qed_mfw_tlv_req(struct qed_hwfn *hwfn) 307359ccf86fSSudarsana Reddy Kalluru { 307459ccf86fSSudarsana Reddy Kalluru DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 307559ccf86fSSudarsana Reddy Kalluru "Scheduling slowpath task [Flag: %d]\n", 307659ccf86fSSudarsana Reddy Kalluru QED_SLOWPATH_MFW_TLV_REQ); 3077f2a74107SPrabhakar Kushwaha /* Memory barrier for setting atomic bit */ 307859ccf86fSSudarsana Reddy Kalluru smp_mb__before_atomic(); 307959ccf86fSSudarsana Reddy Kalluru set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags); 3080f2a74107SPrabhakar Kushwaha /* Memory barrier after setting atomic bit */ 308159ccf86fSSudarsana Reddy Kalluru smp_mb__after_atomic(); 308259ccf86fSSudarsana Reddy Kalluru queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 308359ccf86fSSudarsana Reddy Kalluru 308459ccf86fSSudarsana Reddy Kalluru return 0; 308559ccf86fSSudarsana Reddy Kalluru } 308659ccf86fSSudarsana Reddy Kalluru 308759ccf86fSSudarsana Reddy Kalluru static void 308859ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv) 308959ccf86fSSudarsana Reddy Kalluru { 309059ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = cdev->protocol_ops.common; 309159ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats_common *p_common; 309259ccf86fSSudarsana Reddy Kalluru struct qed_generic_tlvs gen_tlvs; 309359ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats stats; 309459ccf86fSSudarsana Reddy Kalluru int i; 309559ccf86fSSudarsana Reddy Kalluru 309659ccf86fSSudarsana Reddy Kalluru memset(&gen_tlvs, 0, sizeof(gen_tlvs)); 309759ccf86fSSudarsana Reddy Kalluru op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs); 309859ccf86fSSudarsana Reddy Kalluru 309959ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM) 310059ccf86fSSudarsana Reddy Kalluru tlv->flags.ipv4_csum_offload = true; 310159ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_LSO) 310259ccf86fSSudarsana Reddy Kalluru tlv->flags.lso_supported = true; 310359ccf86fSSudarsana Reddy Kalluru tlv->flags.b_set = true; 310459ccf86fSSudarsana Reddy Kalluru 310559ccf86fSSudarsana Reddy Kalluru for (i = 0; i < QED_TLV_MAC_COUNT; i++) { 310659ccf86fSSudarsana Reddy Kalluru if (is_valid_ether_addr(gen_tlvs.mac[i])) { 310759ccf86fSSudarsana Reddy Kalluru ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]); 310859ccf86fSSudarsana Reddy Kalluru tlv->mac_set[i] = true; 310959ccf86fSSudarsana Reddy Kalluru } 311059ccf86fSSudarsana Reddy Kalluru } 311159ccf86fSSudarsana Reddy Kalluru 311259ccf86fSSudarsana Reddy Kalluru qed_get_vport_stats(cdev, &stats); 311359ccf86fSSudarsana Reddy Kalluru p_common = &stats.common; 311459ccf86fSSudarsana Reddy Kalluru tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 311559ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_pkts; 311659ccf86fSSudarsana Reddy Kalluru tlv->rx_frames_set = true; 311759ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 311859ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_bytes; 311959ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 312059ccf86fSSudarsana Reddy Kalluru tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 312159ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_pkts; 312259ccf86fSSudarsana Reddy Kalluru tlv->tx_frames_set = true; 312359ccf86fSSudarsana Reddy Kalluru tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 312459ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_bytes; 312559ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 312659ccf86fSSudarsana Reddy Kalluru } 312759ccf86fSSudarsana Reddy Kalluru 31282528c389SSudarsana Reddy Kalluru int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type, 31292528c389SSudarsana Reddy Kalluru union qed_mfw_tlv_data *tlv_buf) 31302528c389SSudarsana Reddy Kalluru { 313159ccf86fSSudarsana Reddy Kalluru struct qed_dev *cdev = hwfn->cdev; 313259ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *ops; 313359ccf86fSSudarsana Reddy Kalluru 313459ccf86fSSudarsana Reddy Kalluru ops = cdev->protocol_ops.common; 313559ccf86fSSudarsana Reddy Kalluru if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) { 313659ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Can't collect TLV management info\n"); 31372528c389SSudarsana Reddy Kalluru return -EINVAL; 31382528c389SSudarsana Reddy Kalluru } 313959ccf86fSSudarsana Reddy Kalluru 314059ccf86fSSudarsana Reddy Kalluru switch (type) { 314159ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_GENERIC: 314259ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic); 314359ccf86fSSudarsana Reddy Kalluru break; 314459ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ETH: 314559ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth); 314659ccf86fSSudarsana Reddy Kalluru break; 314759ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_FCOE: 314859ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe); 314959ccf86fSSudarsana Reddy Kalluru break; 315059ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ISCSI: 315159ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi); 315259ccf86fSSudarsana Reddy Kalluru break; 315359ccf86fSSudarsana Reddy Kalluru default: 315459ccf86fSSudarsana Reddy Kalluru break; 315559ccf86fSSudarsana Reddy Kalluru } 315659ccf86fSSudarsana Reddy Kalluru 315759ccf86fSSudarsana Reddy Kalluru return 0; 315859ccf86fSSudarsana Reddy Kalluru } 31596c95dd8fSPrabhakar Kushwaha 31606c95dd8fSPrabhakar Kushwaha unsigned long qed_get_epoch_time(void) 31616c95dd8fSPrabhakar Kushwaha { 31626c95dd8fSPrabhakar Kushwaha return ktime_get_real_seconds(); 31636c95dd8fSPrabhakar Kushwaha } 3164