1fe56b9e6SYuval Mintz /* QLogic qed NIC Driver 2e8f1cb50SMintz, Yuval * Copyright (c) 2015-2017 QLogic Corporation 3fe56b9e6SYuval Mintz * 4e8f1cb50SMintz, Yuval * This software is available to you under a choice of one of two 5e8f1cb50SMintz, Yuval * licenses. You may choose to be licensed under the terms of the GNU 6e8f1cb50SMintz, Yuval * General Public License (GPL) Version 2, available from the file 7e8f1cb50SMintz, Yuval * COPYING in the main directory of this source tree, or the 8e8f1cb50SMintz, Yuval * OpenIB.org BSD license below: 9e8f1cb50SMintz, Yuval * 10e8f1cb50SMintz, Yuval * Redistribution and use in source and binary forms, with or 11e8f1cb50SMintz, Yuval * without modification, are permitted provided that the following 12e8f1cb50SMintz, Yuval * conditions are met: 13e8f1cb50SMintz, Yuval * 14e8f1cb50SMintz, Yuval * - Redistributions of source code must retain the above 15e8f1cb50SMintz, Yuval * copyright notice, this list of conditions and the following 16e8f1cb50SMintz, Yuval * disclaimer. 17e8f1cb50SMintz, Yuval * 18e8f1cb50SMintz, Yuval * - Redistributions in binary form must reproduce the above 19e8f1cb50SMintz, Yuval * copyright notice, this list of conditions and the following 20e8f1cb50SMintz, Yuval * disclaimer in the documentation and /or other materials 21e8f1cb50SMintz, Yuval * provided with the distribution. 22e8f1cb50SMintz, Yuval * 23e8f1cb50SMintz, Yuval * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24e8f1cb50SMintz, Yuval * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25e8f1cb50SMintz, Yuval * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26e8f1cb50SMintz, Yuval * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27e8f1cb50SMintz, Yuval * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28e8f1cb50SMintz, Yuval * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29e8f1cb50SMintz, Yuval * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30e8f1cb50SMintz, Yuval * SOFTWARE. 31fe56b9e6SYuval Mintz */ 32fe56b9e6SYuval Mintz 33fe56b9e6SYuval Mintz #include <linux/stddef.h> 34fe56b9e6SYuval Mintz #include <linux/pci.h> 35fe56b9e6SYuval Mintz #include <linux/kernel.h> 36fe56b9e6SYuval Mintz #include <linux/slab.h> 37fe56b9e6SYuval Mintz #include <linux/delay.h> 38fe56b9e6SYuval Mintz #include <asm/byteorder.h> 39fe56b9e6SYuval Mintz #include <linux/dma-mapping.h> 40fe56b9e6SYuval Mintz #include <linux/string.h> 41fe56b9e6SYuval Mintz #include <linux/module.h> 42fe56b9e6SYuval Mintz #include <linux/interrupt.h> 43fe56b9e6SYuval Mintz #include <linux/workqueue.h> 44fe56b9e6SYuval Mintz #include <linux/ethtool.h> 45fe56b9e6SYuval Mintz #include <linux/etherdevice.h> 46fe56b9e6SYuval Mintz #include <linux/vmalloc.h> 475d24bcf1STomer Tayar #include <linux/crash_dump.h> 483a69cae8SSudarsana Reddy Kalluru #include <linux/crc32.h> 49fe56b9e6SYuval Mintz #include <linux/qed/qed_if.h> 500a7fb11cSYuval Mintz #include <linux/qed/qed_ll2_if.h> 51fe56b9e6SYuval Mintz 52fe56b9e6SYuval Mintz #include "qed.h" 5337bff2b9SYuval Mintz #include "qed_sriov.h" 54fe56b9e6SYuval Mintz #include "qed_sp.h" 55fe56b9e6SYuval Mintz #include "qed_dev_api.h" 560a7fb11cSYuval Mintz #include "qed_ll2.h" 571e128c81SArun Easi #include "qed_fcoe.h" 582f2b2614SMintz, Yuval #include "qed_iscsi.h" 592f2b2614SMintz, Yuval 60fe56b9e6SYuval Mintz #include "qed_mcp.h" 61c56a8be7SRahul Verma #include "qed_reg_addr.h" 62fe56b9e6SYuval Mintz #include "qed_hw.h" 6303dc76caSSudarsana Reddy Kalluru #include "qed_selftest.h" 641e128c81SArun Easi #include "qed_debug.h" 65fe56b9e6SYuval Mintz 6651ff1725SRam Amrani #define QED_ROCE_QPS (8192) 6751ff1725SRam Amrani #define QED_ROCE_DPIS (8) 6839dbc646SYuval Bason #define QED_RDMA_SRQS QED_ROCE_QPS 6951ff1725SRam Amrani 705abd7e92SYuval Mintz static char version[] = 715abd7e92SYuval Mintz "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; 72fe56b9e6SYuval Mintz 735abd7e92SYuval Mintz MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module"); 74fe56b9e6SYuval Mintz MODULE_LICENSE("GPL"); 75fe56b9e6SYuval Mintz MODULE_VERSION(DRV_MODULE_VERSION); 76fe56b9e6SYuval Mintz 77fe56b9e6SYuval Mintz #define FW_FILE_VERSION \ 78fe56b9e6SYuval Mintz __stringify(FW_MAJOR_VERSION) "." \ 79fe56b9e6SYuval Mintz __stringify(FW_MINOR_VERSION) "." \ 80fe56b9e6SYuval Mintz __stringify(FW_REVISION_VERSION) "." \ 81fe56b9e6SYuval Mintz __stringify(FW_ENGINEERING_VERSION) 82fe56b9e6SYuval Mintz 83fe56b9e6SYuval Mintz #define QED_FW_FILE_NAME \ 84fe56b9e6SYuval Mintz "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" 85fe56b9e6SYuval Mintz 86d43d3f0fSYuval Mintz MODULE_FIRMWARE(QED_FW_FILE_NAME); 87d43d3f0fSYuval Mintz 88fe56b9e6SYuval Mintz static int __init qed_init(void) 89fe56b9e6SYuval Mintz { 90fe56b9e6SYuval Mintz pr_info("%s", version); 91fe56b9e6SYuval Mintz 92fe56b9e6SYuval Mintz return 0; 93fe56b9e6SYuval Mintz } 94fe56b9e6SYuval Mintz 95fe56b9e6SYuval Mintz static void __exit qed_cleanup(void) 96fe56b9e6SYuval Mintz { 97fe56b9e6SYuval Mintz pr_notice("qed_cleanup called\n"); 98fe56b9e6SYuval Mintz } 99fe56b9e6SYuval Mintz 100fe56b9e6SYuval Mintz module_init(qed_init); 101fe56b9e6SYuval Mintz module_exit(qed_cleanup); 102fe56b9e6SYuval Mintz 103fe56b9e6SYuval Mintz /* Check if the DMA controller on the machine can properly handle the DMA 104fe56b9e6SYuval Mintz * addressing required by the device. 105fe56b9e6SYuval Mintz */ 106fe56b9e6SYuval Mintz static int qed_set_coherency_mask(struct qed_dev *cdev) 107fe56b9e6SYuval Mintz { 108fe56b9e6SYuval Mintz struct device *dev = &cdev->pdev->dev; 109fe56b9e6SYuval Mintz 110fe56b9e6SYuval Mintz if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { 111fe56b9e6SYuval Mintz if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { 112fe56b9e6SYuval Mintz DP_NOTICE(cdev, 113fe56b9e6SYuval Mintz "Can't request 64-bit consistent allocations\n"); 114fe56b9e6SYuval Mintz return -EIO; 115fe56b9e6SYuval Mintz } 116fe56b9e6SYuval Mintz } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { 117fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); 118fe56b9e6SYuval Mintz return -EIO; 119fe56b9e6SYuval Mintz } 120fe56b9e6SYuval Mintz 121fe56b9e6SYuval Mintz return 0; 122fe56b9e6SYuval Mintz } 123fe56b9e6SYuval Mintz 124fe56b9e6SYuval Mintz static void qed_free_pci(struct qed_dev *cdev) 125fe56b9e6SYuval Mintz { 126fe56b9e6SYuval Mintz struct pci_dev *pdev = cdev->pdev; 127fe56b9e6SYuval Mintz 1281a850bfcSMintz, Yuval if (cdev->doorbells && cdev->db_size) 129fe56b9e6SYuval Mintz iounmap(cdev->doorbells); 130fe56b9e6SYuval Mintz if (cdev->regview) 131fe56b9e6SYuval Mintz iounmap(cdev->regview); 132fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) 133fe56b9e6SYuval Mintz pci_release_regions(pdev); 134fe56b9e6SYuval Mintz 135fe56b9e6SYuval Mintz pci_disable_device(pdev); 136fe56b9e6SYuval Mintz } 137fe56b9e6SYuval Mintz 1380dfaba6dSYuval Mintz #define PCI_REVISION_ID_ERROR_VAL 0xff 1390dfaba6dSYuval Mintz 140fe56b9e6SYuval Mintz /* Performs PCI initializations as well as initializing PCI-related parameters 141fe56b9e6SYuval Mintz * in the device structrue. Returns 0 in case of success. 142fe56b9e6SYuval Mintz */ 1431a635e48SYuval Mintz static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) 144fe56b9e6SYuval Mintz { 1450dfaba6dSYuval Mintz u8 rev_id; 146fe56b9e6SYuval Mintz int rc; 147fe56b9e6SYuval Mintz 148fe56b9e6SYuval Mintz cdev->pdev = pdev; 149fe56b9e6SYuval Mintz 150fe56b9e6SYuval Mintz rc = pci_enable_device(pdev); 151fe56b9e6SYuval Mintz if (rc) { 152fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot enable PCI device\n"); 153fe56b9e6SYuval Mintz goto err0; 154fe56b9e6SYuval Mintz } 155fe56b9e6SYuval Mintz 156fe56b9e6SYuval Mintz if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 157fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #0\n"); 158fe56b9e6SYuval Mintz rc = -EIO; 159fe56b9e6SYuval Mintz goto err1; 160fe56b9e6SYuval Mintz } 161fe56b9e6SYuval Mintz 1621408cc1fSYuval Mintz if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 163fe56b9e6SYuval Mintz DP_NOTICE(cdev, "No memory region found in bar #2\n"); 164fe56b9e6SYuval Mintz rc = -EIO; 165fe56b9e6SYuval Mintz goto err1; 166fe56b9e6SYuval Mintz } 167fe56b9e6SYuval Mintz 168fe56b9e6SYuval Mintz if (atomic_read(&pdev->enable_cnt) == 1) { 169fe56b9e6SYuval Mintz rc = pci_request_regions(pdev, "qed"); 170fe56b9e6SYuval Mintz if (rc) { 171fe56b9e6SYuval Mintz DP_NOTICE(cdev, 172fe56b9e6SYuval Mintz "Failed to request PCI memory resources\n"); 173fe56b9e6SYuval Mintz goto err1; 174fe56b9e6SYuval Mintz } 175fe56b9e6SYuval Mintz pci_set_master(pdev); 176fe56b9e6SYuval Mintz pci_save_state(pdev); 177fe56b9e6SYuval Mintz } 178fe56b9e6SYuval Mintz 1790dfaba6dSYuval Mintz pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 1800dfaba6dSYuval Mintz if (rev_id == PCI_REVISION_ID_ERROR_VAL) { 1810dfaba6dSYuval Mintz DP_NOTICE(cdev, 1820dfaba6dSYuval Mintz "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", 1830dfaba6dSYuval Mintz rev_id); 1840dfaba6dSYuval Mintz rc = -ENODEV; 1850dfaba6dSYuval Mintz goto err2; 1860dfaba6dSYuval Mintz } 187fe56b9e6SYuval Mintz if (!pci_is_pcie(pdev)) { 188fe56b9e6SYuval Mintz DP_NOTICE(cdev, "The bus is not PCI Express\n"); 189fe56b9e6SYuval Mintz rc = -EIO; 190fe56b9e6SYuval Mintz goto err2; 191fe56b9e6SYuval Mintz } 192fe56b9e6SYuval Mintz 193fe56b9e6SYuval Mintz cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); 194416cdf06SYuval Mintz if (IS_PF(cdev) && !cdev->pci_params.pm_cap) 195fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot find power management capability\n"); 196fe56b9e6SYuval Mintz 197fe56b9e6SYuval Mintz rc = qed_set_coherency_mask(cdev); 198fe56b9e6SYuval Mintz if (rc) 199fe56b9e6SYuval Mintz goto err2; 200fe56b9e6SYuval Mintz 201fe56b9e6SYuval Mintz cdev->pci_params.mem_start = pci_resource_start(pdev, 0); 202fe56b9e6SYuval Mintz cdev->pci_params.mem_end = pci_resource_end(pdev, 0); 203fe56b9e6SYuval Mintz cdev->pci_params.irq = pdev->irq; 204fe56b9e6SYuval Mintz 205fe56b9e6SYuval Mintz cdev->regview = pci_ioremap_bar(pdev, 0); 206fe56b9e6SYuval Mintz if (!cdev->regview) { 207fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map register space, aborting\n"); 208fe56b9e6SYuval Mintz rc = -ENOMEM; 209fe56b9e6SYuval Mintz goto err2; 210fe56b9e6SYuval Mintz } 211fe56b9e6SYuval Mintz 212fe56b9e6SYuval Mintz cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); 213fe56b9e6SYuval Mintz cdev->db_size = pci_resource_len(cdev->pdev, 2); 2141a850bfcSMintz, Yuval if (!cdev->db_size) { 2151a850bfcSMintz, Yuval if (IS_PF(cdev)) { 2161a850bfcSMintz, Yuval DP_NOTICE(cdev, "No Doorbell bar available\n"); 2171a850bfcSMintz, Yuval return -EINVAL; 2181a850bfcSMintz, Yuval } else { 2191a850bfcSMintz, Yuval return 0; 2201a850bfcSMintz, Yuval } 2211a850bfcSMintz, Yuval } 2221a850bfcSMintz, Yuval 223fe56b9e6SYuval Mintz cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); 2241a850bfcSMintz, Yuval 225fe56b9e6SYuval Mintz if (!cdev->doorbells) { 226fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Cannot map doorbell space\n"); 227fe56b9e6SYuval Mintz return -ENOMEM; 228fe56b9e6SYuval Mintz } 229fe56b9e6SYuval Mintz 230fe56b9e6SYuval Mintz return 0; 231fe56b9e6SYuval Mintz 232fe56b9e6SYuval Mintz err2: 233fe56b9e6SYuval Mintz pci_release_regions(pdev); 234fe56b9e6SYuval Mintz err1: 235fe56b9e6SYuval Mintz pci_disable_device(pdev); 236fe56b9e6SYuval Mintz err0: 237fe56b9e6SYuval Mintz return rc; 238fe56b9e6SYuval Mintz } 239fe56b9e6SYuval Mintz 240fe56b9e6SYuval Mintz int qed_fill_dev_info(struct qed_dev *cdev, 241fe56b9e6SYuval Mintz struct qed_dev_info *dev_info) 242fe56b9e6SYuval Mintz { 243c851a9dcSKalderon, Michal struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 244c851a9dcSKalderon, Michal struct qed_hw_info *hw_info = &p_hwfn->hw_info; 24519489c7fSChopra, Manish struct qed_tunnel_info *tun = &cdev->tunnel; 246cee4d264SManish Chopra struct qed_ptt *ptt; 247cee4d264SManish Chopra 248fe56b9e6SYuval Mintz memset(dev_info, 0, sizeof(struct qed_dev_info)); 249fe56b9e6SYuval Mintz 25019489c7fSChopra, Manish if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 25119489c7fSChopra, Manish tun->vxlan.b_mode_enabled) 25219489c7fSChopra, Manish dev_info->vxlan_enable = true; 25319489c7fSChopra, Manish 25419489c7fSChopra, Manish if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && 25519489c7fSChopra, Manish tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 25619489c7fSChopra, Manish tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 25719489c7fSChopra, Manish dev_info->gre_enable = true; 25819489c7fSChopra, Manish 25919489c7fSChopra, Manish if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && 26019489c7fSChopra, Manish tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN && 26119489c7fSChopra, Manish tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN) 26219489c7fSChopra, Manish dev_info->geneve_enable = true; 26319489c7fSChopra, Manish 264fe56b9e6SYuval Mintz dev_info->num_hwfns = cdev->num_hwfns; 265fe56b9e6SYuval Mintz dev_info->pci_mem_start = cdev->pci_params.mem_start; 266fe56b9e6SYuval Mintz dev_info->pci_mem_end = cdev->pci_params.mem_end; 267fe56b9e6SYuval Mintz dev_info->pci_irq = cdev->pci_params.irq; 268c851a9dcSKalderon, Michal dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn); 2699c79ddaaSMintz, Yuval dev_info->dev_type = cdev->type; 270c851a9dcSKalderon, Michal ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr); 271fe56b9e6SYuval Mintz 2721408cc1fSYuval Mintz if (IS_PF(cdev)) { 273fe56b9e6SYuval Mintz dev_info->fw_major = FW_MAJOR_VERSION; 274fe56b9e6SYuval Mintz dev_info->fw_minor = FW_MINOR_VERSION; 275fe56b9e6SYuval Mintz dev_info->fw_rev = FW_REVISION_VERSION; 276fe56b9e6SYuval Mintz dev_info->fw_eng = FW_ENGINEERING_VERSION; 2770bc5fe85SSudarsana Reddy Kalluru dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH, 2780bc5fe85SSudarsana Reddy Kalluru &cdev->mf_bits); 279831bfb0eSYuval Mintz dev_info->tx_switching = true; 28014d39648SMintz, Yuval 281c851a9dcSKalderon, Michal if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME) 28214d39648SMintz, Yuval dev_info->wol_support = true; 2833c5da942SMintz, Yuval 2843c5da942SMintz, Yuval dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; 2851408cc1fSYuval Mintz } else { 2861408cc1fSYuval Mintz qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, 2871408cc1fSYuval Mintz &dev_info->fw_minor, &dev_info->fw_rev, 2881408cc1fSYuval Mintz &dev_info->fw_eng); 2891408cc1fSYuval Mintz } 290fe56b9e6SYuval Mintz 2911408cc1fSYuval Mintz if (IS_PF(cdev)) { 292cee4d264SManish Chopra ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 293cee4d264SManish Chopra if (ptt) { 2941408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, 2951408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 2961408cc1fSYuval Mintz 297ae33666aSTomer Tayar qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, 298ae33666aSTomer Tayar &dev_info->mbi_version); 299ae33666aSTomer Tayar 300cee4d264SManish Chopra qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, 301cee4d264SManish Chopra &dev_info->flash_size); 302cee4d264SManish Chopra 303cee4d264SManish Chopra qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); 304cee4d264SManish Chopra } 3051408cc1fSYuval Mintz } else { 3061408cc1fSYuval Mintz qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, 3071408cc1fSYuval Mintz &dev_info->mfw_rev, NULL); 3081408cc1fSYuval Mintz } 309cee4d264SManish Chopra 310c851a9dcSKalderon, Michal dev_info->mtu = hw_info->mtu; 3110fefbfbaSSudarsana Kalluru 312fe56b9e6SYuval Mintz return 0; 313fe56b9e6SYuval Mintz } 314fe56b9e6SYuval Mintz 315fe56b9e6SYuval Mintz static void qed_free_cdev(struct qed_dev *cdev) 316fe56b9e6SYuval Mintz { 317fe56b9e6SYuval Mintz kfree((void *)cdev); 318fe56b9e6SYuval Mintz } 319fe56b9e6SYuval Mintz 320fe56b9e6SYuval Mintz static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) 321fe56b9e6SYuval Mintz { 322fe56b9e6SYuval Mintz struct qed_dev *cdev; 323fe56b9e6SYuval Mintz 324fe56b9e6SYuval Mintz cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 325fe56b9e6SYuval Mintz if (!cdev) 326fe56b9e6SYuval Mintz return cdev; 327fe56b9e6SYuval Mintz 328fe56b9e6SYuval Mintz qed_init_struct(cdev); 329fe56b9e6SYuval Mintz 330fe56b9e6SYuval Mintz return cdev; 331fe56b9e6SYuval Mintz } 332fe56b9e6SYuval Mintz 333fe56b9e6SYuval Mintz /* Sets the requested power state */ 3341a635e48SYuval Mintz static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) 335fe56b9e6SYuval Mintz { 336fe56b9e6SYuval Mintz if (!cdev) 337fe56b9e6SYuval Mintz return -ENODEV; 338fe56b9e6SYuval Mintz 339fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); 340fe56b9e6SYuval Mintz return 0; 341fe56b9e6SYuval Mintz } 342fe56b9e6SYuval Mintz 343fe56b9e6SYuval Mintz /* probing */ 344fe56b9e6SYuval Mintz static struct qed_dev *qed_probe(struct pci_dev *pdev, 3451408cc1fSYuval Mintz struct qed_probe_params *params) 346fe56b9e6SYuval Mintz { 347fe56b9e6SYuval Mintz struct qed_dev *cdev; 348fe56b9e6SYuval Mintz int rc; 349fe56b9e6SYuval Mintz 350fe56b9e6SYuval Mintz cdev = qed_alloc_cdev(pdev); 351fe56b9e6SYuval Mintz if (!cdev) 352fe56b9e6SYuval Mintz goto err0; 353fe56b9e6SYuval Mintz 354712c3cbfSMintz, Yuval cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; 3551408cc1fSYuval Mintz cdev->protocol = params->protocol; 356fe56b9e6SYuval Mintz 3571408cc1fSYuval Mintz if (params->is_vf) 3581408cc1fSYuval Mintz cdev->b_is_vf = true; 3591408cc1fSYuval Mintz 3601408cc1fSYuval Mintz qed_init_dp(cdev, params->dp_module, params->dp_level); 361fe56b9e6SYuval Mintz 362fe56b9e6SYuval Mintz rc = qed_init_pci(cdev, pdev); 363fe56b9e6SYuval Mintz if (rc) { 364fe56b9e6SYuval Mintz DP_ERR(cdev, "init pci failed\n"); 365fe56b9e6SYuval Mintz goto err1; 366fe56b9e6SYuval Mintz } 367fe56b9e6SYuval Mintz DP_INFO(cdev, "PCI init completed successfully\n"); 368fe56b9e6SYuval Mintz 369fe56b9e6SYuval Mintz rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); 370fe56b9e6SYuval Mintz if (rc) { 371fe56b9e6SYuval Mintz DP_ERR(cdev, "hw prepare failed\n"); 372fe56b9e6SYuval Mintz goto err2; 373fe56b9e6SYuval Mintz } 374fe56b9e6SYuval Mintz 37520c4515aSEwan D. Milne DP_INFO(cdev, "qed_probe completed successfully\n"); 376fe56b9e6SYuval Mintz 377fe56b9e6SYuval Mintz return cdev; 378fe56b9e6SYuval Mintz 379fe56b9e6SYuval Mintz err2: 380fe56b9e6SYuval Mintz qed_free_pci(cdev); 381fe56b9e6SYuval Mintz err1: 382fe56b9e6SYuval Mintz qed_free_cdev(cdev); 383fe56b9e6SYuval Mintz err0: 384fe56b9e6SYuval Mintz return NULL; 385fe56b9e6SYuval Mintz } 386fe56b9e6SYuval Mintz 387fe56b9e6SYuval Mintz static void qed_remove(struct qed_dev *cdev) 388fe56b9e6SYuval Mintz { 389fe56b9e6SYuval Mintz if (!cdev) 390fe56b9e6SYuval Mintz return; 391fe56b9e6SYuval Mintz 392fe56b9e6SYuval Mintz qed_hw_remove(cdev); 393fe56b9e6SYuval Mintz 394fe56b9e6SYuval Mintz qed_free_pci(cdev); 395fe56b9e6SYuval Mintz 396fe56b9e6SYuval Mintz qed_set_power_state(cdev, PCI_D3hot); 397fe56b9e6SYuval Mintz 398fe56b9e6SYuval Mintz qed_free_cdev(cdev); 399fe56b9e6SYuval Mintz } 400fe56b9e6SYuval Mintz 401fe56b9e6SYuval Mintz static void qed_disable_msix(struct qed_dev *cdev) 402fe56b9e6SYuval Mintz { 403fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 404fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 405fe56b9e6SYuval Mintz kfree(cdev->int_params.msix_table); 406fe56b9e6SYuval Mintz } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { 407fe56b9e6SYuval Mintz pci_disable_msi(cdev->pdev); 408fe56b9e6SYuval Mintz } 409fe56b9e6SYuval Mintz 410fe56b9e6SYuval Mintz memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); 411fe56b9e6SYuval Mintz } 412fe56b9e6SYuval Mintz 413fe56b9e6SYuval Mintz static int qed_enable_msix(struct qed_dev *cdev, 414fe56b9e6SYuval Mintz struct qed_int_params *int_params) 415fe56b9e6SYuval Mintz { 416fe56b9e6SYuval Mintz int i, rc, cnt; 417fe56b9e6SYuval Mintz 418fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 419fe56b9e6SYuval Mintz 420fe56b9e6SYuval Mintz for (i = 0; i < cnt; i++) 421fe56b9e6SYuval Mintz int_params->msix_table[i].entry = i; 422fe56b9e6SYuval Mintz 423fe56b9e6SYuval Mintz rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, 424fe56b9e6SYuval Mintz int_params->in.min_msix_cnt, cnt); 425fe56b9e6SYuval Mintz if (rc < cnt && rc >= int_params->in.min_msix_cnt && 426fe56b9e6SYuval Mintz (rc % cdev->num_hwfns)) { 427fe56b9e6SYuval Mintz pci_disable_msix(cdev->pdev); 428fe56b9e6SYuval Mintz 429fe56b9e6SYuval Mintz /* If fastpath is initialized, we need at least one interrupt 430fe56b9e6SYuval Mintz * per hwfn [and the slow path interrupts]. New requested number 431fe56b9e6SYuval Mintz * should be a multiple of the number of hwfns. 432fe56b9e6SYuval Mintz */ 433fe56b9e6SYuval Mintz cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; 434fe56b9e6SYuval Mintz DP_NOTICE(cdev, 435fe56b9e6SYuval Mintz "Trying to enable MSI-X with less vectors (%d out of %d)\n", 436fe56b9e6SYuval Mintz cnt, int_params->in.num_vectors); 4371a635e48SYuval Mintz rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, 4381a635e48SYuval Mintz cnt); 439fe56b9e6SYuval Mintz if (!rc) 440fe56b9e6SYuval Mintz rc = cnt; 441fe56b9e6SYuval Mintz } 442fe56b9e6SYuval Mintz 443fe56b9e6SYuval Mintz if (rc > 0) { 444fe56b9e6SYuval Mintz /* MSI-x configuration was achieved */ 445fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSIX; 446fe56b9e6SYuval Mintz int_params->out.num_vectors = rc; 447fe56b9e6SYuval Mintz rc = 0; 448fe56b9e6SYuval Mintz } else { 449fe56b9e6SYuval Mintz DP_NOTICE(cdev, 450fe56b9e6SYuval Mintz "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", 451fe56b9e6SYuval Mintz cnt, rc); 452fe56b9e6SYuval Mintz } 453fe56b9e6SYuval Mintz 454fe56b9e6SYuval Mintz return rc; 455fe56b9e6SYuval Mintz } 456fe56b9e6SYuval Mintz 457fe56b9e6SYuval Mintz /* This function outputs the int mode and the number of enabled msix vector */ 458fe56b9e6SYuval Mintz static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) 459fe56b9e6SYuval Mintz { 460fe56b9e6SYuval Mintz struct qed_int_params *int_params = &cdev->int_params; 461fe56b9e6SYuval Mintz struct msix_entry *tbl; 462fe56b9e6SYuval Mintz int rc = 0, cnt; 463fe56b9e6SYuval Mintz 464fe56b9e6SYuval Mintz switch (int_params->in.int_mode) { 465fe56b9e6SYuval Mintz case QED_INT_MODE_MSIX: 466fe56b9e6SYuval Mintz /* Allocate MSIX table */ 467fe56b9e6SYuval Mintz cnt = int_params->in.num_vectors; 468fe56b9e6SYuval Mintz int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); 469fe56b9e6SYuval Mintz if (!int_params->msix_table) { 470fe56b9e6SYuval Mintz rc = -ENOMEM; 471fe56b9e6SYuval Mintz goto out; 472fe56b9e6SYuval Mintz } 473fe56b9e6SYuval Mintz 474fe56b9e6SYuval Mintz /* Enable MSIX */ 475fe56b9e6SYuval Mintz rc = qed_enable_msix(cdev, int_params); 476fe56b9e6SYuval Mintz if (!rc) 477fe56b9e6SYuval Mintz goto out; 478fe56b9e6SYuval Mintz 479fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI-X\n"); 480fe56b9e6SYuval Mintz kfree(int_params->msix_table); 481fe56b9e6SYuval Mintz if (force_mode) 482fe56b9e6SYuval Mintz goto out; 483fe56b9e6SYuval Mintz /* Fallthrough */ 484fe56b9e6SYuval Mintz 485fe56b9e6SYuval Mintz case QED_INT_MODE_MSI: 486bb13ace7SSudarsana Reddy Kalluru if (cdev->num_hwfns == 1) { 487fe56b9e6SYuval Mintz rc = pci_enable_msi(cdev->pdev); 488fe56b9e6SYuval Mintz if (!rc) { 489fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_MSI; 490fe56b9e6SYuval Mintz goto out; 491fe56b9e6SYuval Mintz } 492fe56b9e6SYuval Mintz 493fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed to enable MSI\n"); 494fe56b9e6SYuval Mintz if (force_mode) 495fe56b9e6SYuval Mintz goto out; 496bb13ace7SSudarsana Reddy Kalluru } 497fe56b9e6SYuval Mintz /* Fallthrough */ 498fe56b9e6SYuval Mintz 499fe56b9e6SYuval Mintz case QED_INT_MODE_INTA: 500fe56b9e6SYuval Mintz int_params->out.int_mode = QED_INT_MODE_INTA; 501fe56b9e6SYuval Mintz rc = 0; 502fe56b9e6SYuval Mintz goto out; 503fe56b9e6SYuval Mintz default: 504fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Unknown int_mode value %d\n", 505fe56b9e6SYuval Mintz int_params->in.int_mode); 506fe56b9e6SYuval Mintz rc = -EINVAL; 507fe56b9e6SYuval Mintz } 508fe56b9e6SYuval Mintz 509fe56b9e6SYuval Mintz out: 510525ef5c0SYuval Mintz if (!rc) 511525ef5c0SYuval Mintz DP_INFO(cdev, "Using %s interrupts\n", 512525ef5c0SYuval Mintz int_params->out.int_mode == QED_INT_MODE_INTA ? 513525ef5c0SYuval Mintz "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? 514525ef5c0SYuval Mintz "MSI" : "MSIX"); 515fe56b9e6SYuval Mintz cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; 516fe56b9e6SYuval Mintz 517fe56b9e6SYuval Mintz return rc; 518fe56b9e6SYuval Mintz } 519fe56b9e6SYuval Mintz 520fe56b9e6SYuval Mintz static void qed_simd_handler_config(struct qed_dev *cdev, void *token, 521fe56b9e6SYuval Mintz int index, void(*handler)(void *)) 522fe56b9e6SYuval Mintz { 523fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 524fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 525fe56b9e6SYuval Mintz 526fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].func = handler; 527fe56b9e6SYuval Mintz hwfn->simd_proto_handler[relative_idx].token = token; 528fe56b9e6SYuval Mintz } 529fe56b9e6SYuval Mintz 530fe56b9e6SYuval Mintz static void qed_simd_handler_clean(struct qed_dev *cdev, int index) 531fe56b9e6SYuval Mintz { 532fe56b9e6SYuval Mintz struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; 533fe56b9e6SYuval Mintz int relative_idx = index / cdev->num_hwfns; 534fe56b9e6SYuval Mintz 535fe56b9e6SYuval Mintz memset(&hwfn->simd_proto_handler[relative_idx], 0, 536fe56b9e6SYuval Mintz sizeof(struct qed_simd_fp_handler)); 537fe56b9e6SYuval Mintz } 538fe56b9e6SYuval Mintz 539fe56b9e6SYuval Mintz static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) 540fe56b9e6SYuval Mintz { 541fe56b9e6SYuval Mintz tasklet_schedule((struct tasklet_struct *)tasklet); 542fe56b9e6SYuval Mintz return IRQ_HANDLED; 543fe56b9e6SYuval Mintz } 544fe56b9e6SYuval Mintz 545fe56b9e6SYuval Mintz static irqreturn_t qed_single_int(int irq, void *dev_instance) 546fe56b9e6SYuval Mintz { 547fe56b9e6SYuval Mintz struct qed_dev *cdev = (struct qed_dev *)dev_instance; 548fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 549fe56b9e6SYuval Mintz irqreturn_t rc = IRQ_NONE; 550fe56b9e6SYuval Mintz u64 status; 551fe56b9e6SYuval Mintz int i, j; 552fe56b9e6SYuval Mintz 553fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 554fe56b9e6SYuval Mintz status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); 555fe56b9e6SYuval Mintz 556fe56b9e6SYuval Mintz if (!status) 557fe56b9e6SYuval Mintz continue; 558fe56b9e6SYuval Mintz 559fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 560fe56b9e6SYuval Mintz 561fe56b9e6SYuval Mintz /* Slowpath interrupt */ 562fe56b9e6SYuval Mintz if (unlikely(status & 0x1)) { 563fe56b9e6SYuval Mintz tasklet_schedule(hwfn->sp_dpc); 564fe56b9e6SYuval Mintz status &= ~0x1; 565fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 566fe56b9e6SYuval Mintz } 567fe56b9e6SYuval Mintz 568fe56b9e6SYuval Mintz /* Fastpath interrupts */ 569fe56b9e6SYuval Mintz for (j = 0; j < 64; j++) { 570fe56b9e6SYuval Mintz if ((0x2ULL << j) & status) { 5713935a709SSudarsana Reddy Kalluru struct qed_simd_fp_handler *p_handler = 5723935a709SSudarsana Reddy Kalluru &hwfn->simd_proto_handler[j]; 5733935a709SSudarsana Reddy Kalluru 5743935a709SSudarsana Reddy Kalluru if (p_handler->func) 5753935a709SSudarsana Reddy Kalluru p_handler->func(p_handler->token); 5763935a709SSudarsana Reddy Kalluru else 5773935a709SSudarsana Reddy Kalluru DP_NOTICE(hwfn, 5783935a709SSudarsana Reddy Kalluru "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n", 5793935a709SSudarsana Reddy Kalluru j, status); 5803935a709SSudarsana Reddy Kalluru 581fe56b9e6SYuval Mintz status &= ~(0x2ULL << j); 582fe56b9e6SYuval Mintz rc = IRQ_HANDLED; 583fe56b9e6SYuval Mintz } 584fe56b9e6SYuval Mintz } 585fe56b9e6SYuval Mintz 586fe56b9e6SYuval Mintz if (unlikely(status)) 587fe56b9e6SYuval Mintz DP_VERBOSE(hwfn, NETIF_MSG_INTR, 588fe56b9e6SYuval Mintz "got an unknown interrupt status 0x%llx\n", 589fe56b9e6SYuval Mintz status); 590fe56b9e6SYuval Mintz } 591fe56b9e6SYuval Mintz 592fe56b9e6SYuval Mintz return rc; 593fe56b9e6SYuval Mintz } 594fe56b9e6SYuval Mintz 5958f16bc97SSudarsana Kalluru int qed_slowpath_irq_req(struct qed_hwfn *hwfn) 596fe56b9e6SYuval Mintz { 5978f16bc97SSudarsana Kalluru struct qed_dev *cdev = hwfn->cdev; 598525ef5c0SYuval Mintz u32 int_mode; 5998f16bc97SSudarsana Kalluru int rc = 0; 6008f16bc97SSudarsana Kalluru u8 id; 601fe56b9e6SYuval Mintz 602525ef5c0SYuval Mintz int_mode = cdev->int_params.out.int_mode; 603525ef5c0SYuval Mintz if (int_mode == QED_INT_MODE_MSIX) { 6048f16bc97SSudarsana Kalluru id = hwfn->my_id; 6058f16bc97SSudarsana Kalluru snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", 6068f16bc97SSudarsana Kalluru id, cdev->pdev->bus->number, 6078f16bc97SSudarsana Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 6088f16bc97SSudarsana Kalluru rc = request_irq(cdev->int_params.msix_table[id].vector, 6098f16bc97SSudarsana Kalluru qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc); 610fe56b9e6SYuval Mintz } else { 611fe56b9e6SYuval Mintz unsigned long flags = 0; 612fe56b9e6SYuval Mintz 613fe56b9e6SYuval Mintz snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", 614fe56b9e6SYuval Mintz cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), 615fe56b9e6SYuval Mintz PCI_FUNC(cdev->pdev->devfn)); 616fe56b9e6SYuval Mintz 617fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) 618fe56b9e6SYuval Mintz flags |= IRQF_SHARED; 619fe56b9e6SYuval Mintz 620fe56b9e6SYuval Mintz rc = request_irq(cdev->pdev->irq, qed_single_int, 621fe56b9e6SYuval Mintz flags, cdev->name, cdev); 622fe56b9e6SYuval Mintz } 623fe56b9e6SYuval Mintz 624525ef5c0SYuval Mintz if (rc) 625525ef5c0SYuval Mintz DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); 626525ef5c0SYuval Mintz else 627525ef5c0SYuval Mintz DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), 628525ef5c0SYuval Mintz "Requested slowpath %s\n", 629525ef5c0SYuval Mintz (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); 630525ef5c0SYuval Mintz 631fe56b9e6SYuval Mintz return rc; 632fe56b9e6SYuval Mintz } 633fe56b9e6SYuval Mintz 63406892f2eSTomer Tayar static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) 63506892f2eSTomer Tayar { 63606892f2eSTomer Tayar /* Calling the disable function will make sure that any 63706892f2eSTomer Tayar * currently-running function is completed. The following call to the 63806892f2eSTomer Tayar * enable function makes this sequence a flush-like operation. 63906892f2eSTomer Tayar */ 64006892f2eSTomer Tayar if (p_hwfn->b_sp_dpc_enabled) { 64106892f2eSTomer Tayar tasklet_disable(p_hwfn->sp_dpc); 64206892f2eSTomer Tayar tasklet_enable(p_hwfn->sp_dpc); 64306892f2eSTomer Tayar } 64406892f2eSTomer Tayar } 64506892f2eSTomer Tayar 6461226337aSTomer Tayar void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) 6471226337aSTomer Tayar { 6481226337aSTomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 6491226337aSTomer Tayar u8 id = p_hwfn->my_id; 6501226337aSTomer Tayar u32 int_mode; 6511226337aSTomer Tayar 6521226337aSTomer Tayar int_mode = cdev->int_params.out.int_mode; 6531226337aSTomer Tayar if (int_mode == QED_INT_MODE_MSIX) 6541226337aSTomer Tayar synchronize_irq(cdev->int_params.msix_table[id].vector); 6551226337aSTomer Tayar else 6561226337aSTomer Tayar synchronize_irq(cdev->pdev->irq); 65706892f2eSTomer Tayar 65806892f2eSTomer Tayar qed_slowpath_tasklet_flush(p_hwfn); 6591226337aSTomer Tayar } 6601226337aSTomer Tayar 661fe56b9e6SYuval Mintz static void qed_slowpath_irq_free(struct qed_dev *cdev) 662fe56b9e6SYuval Mintz { 663fe56b9e6SYuval Mintz int i; 664fe56b9e6SYuval Mintz 665fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 666fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 6678f16bc97SSudarsana Kalluru if (!cdev->hwfns[i].b_int_requested) 6688f16bc97SSudarsana Kalluru break; 669fe56b9e6SYuval Mintz synchronize_irq(cdev->int_params.msix_table[i].vector); 670fe56b9e6SYuval Mintz free_irq(cdev->int_params.msix_table[i].vector, 671fe56b9e6SYuval Mintz cdev->hwfns[i].sp_dpc); 672fe56b9e6SYuval Mintz } 673fe56b9e6SYuval Mintz } else { 6748f16bc97SSudarsana Kalluru if (QED_LEADING_HWFN(cdev)->b_int_requested) 675fe56b9e6SYuval Mintz free_irq(cdev->pdev->irq, cdev); 676fe56b9e6SYuval Mintz } 6778f16bc97SSudarsana Kalluru qed_int_disable_post_isr_release(cdev); 678fe56b9e6SYuval Mintz } 679fe56b9e6SYuval Mintz 680fe56b9e6SYuval Mintz static int qed_nic_stop(struct qed_dev *cdev) 681fe56b9e6SYuval Mintz { 682fe56b9e6SYuval Mintz int i, rc; 683fe56b9e6SYuval Mintz 684fe56b9e6SYuval Mintz rc = qed_hw_stop(cdev); 685fe56b9e6SYuval Mintz 686fe56b9e6SYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 687fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 688fe56b9e6SYuval Mintz 689fe56b9e6SYuval Mintz if (p_hwfn->b_sp_dpc_enabled) { 690fe56b9e6SYuval Mintz tasklet_disable(p_hwfn->sp_dpc); 691fe56b9e6SYuval Mintz p_hwfn->b_sp_dpc_enabled = false; 692fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, 6932fdae034SColin Ian King "Disabled sp tasklet [hwfn %d] at %p\n", 694fe56b9e6SYuval Mintz i, p_hwfn->sp_dpc); 695fe56b9e6SYuval Mintz } 696fe56b9e6SYuval Mintz } 697fe56b9e6SYuval Mintz 698c965db44STomer Tayar qed_dbg_pf_exit(cdev); 699c965db44STomer Tayar 700fe56b9e6SYuval Mintz return rc; 701fe56b9e6SYuval Mintz } 702fe56b9e6SYuval Mintz 703fe56b9e6SYuval Mintz static int qed_nic_setup(struct qed_dev *cdev) 704fe56b9e6SYuval Mintz { 7050a7fb11cSYuval Mintz int rc, i; 7060a7fb11cSYuval Mintz 7070a7fb11cSYuval Mintz /* Determine if interface is going to require LL2 */ 7080a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) { 7090a7fb11cSYuval Mintz for (i = 0; i < cdev->num_hwfns; i++) { 7100a7fb11cSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 7110a7fb11cSYuval Mintz 7120a7fb11cSYuval Mintz p_hwfn->using_ll2 = true; 7130a7fb11cSYuval Mintz } 7140a7fb11cSYuval Mintz } 715fe56b9e6SYuval Mintz 716fe56b9e6SYuval Mintz rc = qed_resc_alloc(cdev); 717fe56b9e6SYuval Mintz if (rc) 718fe56b9e6SYuval Mintz return rc; 719fe56b9e6SYuval Mintz 720fe56b9e6SYuval Mintz DP_INFO(cdev, "Allocated qed resources\n"); 721fe56b9e6SYuval Mintz 722fe56b9e6SYuval Mintz qed_resc_setup(cdev); 723fe56b9e6SYuval Mintz 724fe56b9e6SYuval Mintz return rc; 725fe56b9e6SYuval Mintz } 726fe56b9e6SYuval Mintz 727fe56b9e6SYuval Mintz static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) 728fe56b9e6SYuval Mintz { 729fe56b9e6SYuval Mintz int limit = 0; 730fe56b9e6SYuval Mintz 731fe56b9e6SYuval Mintz /* Mark the fastpath as free/used */ 732fe56b9e6SYuval Mintz cdev->int_params.fp_initialized = cnt ? true : false; 733fe56b9e6SYuval Mintz 734fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) 735fe56b9e6SYuval Mintz limit = cdev->num_hwfns * 63; 736fe56b9e6SYuval Mintz else if (cdev->int_params.fp_msix_cnt) 737fe56b9e6SYuval Mintz limit = cdev->int_params.fp_msix_cnt; 738fe56b9e6SYuval Mintz 739fe56b9e6SYuval Mintz if (!limit) 740fe56b9e6SYuval Mintz return -ENOMEM; 741fe56b9e6SYuval Mintz 742fe56b9e6SYuval Mintz return min_t(int, cnt, limit); 743fe56b9e6SYuval Mintz } 744fe56b9e6SYuval Mintz 745fe56b9e6SYuval Mintz static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) 746fe56b9e6SYuval Mintz { 747fe56b9e6SYuval Mintz memset(info, 0, sizeof(struct qed_int_info)); 748fe56b9e6SYuval Mintz 749fe56b9e6SYuval Mintz if (!cdev->int_params.fp_initialized) { 750fe56b9e6SYuval Mintz DP_INFO(cdev, 751fe56b9e6SYuval Mintz "Protocol driver requested interrupt information, but its support is not yet configured\n"); 752fe56b9e6SYuval Mintz return -EINVAL; 753fe56b9e6SYuval Mintz } 754fe56b9e6SYuval Mintz 755fe56b9e6SYuval Mintz /* Need to expose only MSI-X information; Single IRQ is handled solely 756fe56b9e6SYuval Mintz * by qed. 757fe56b9e6SYuval Mintz */ 758fe56b9e6SYuval Mintz if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { 759fe56b9e6SYuval Mintz int msix_base = cdev->int_params.fp_msix_base; 760fe56b9e6SYuval Mintz 761fe56b9e6SYuval Mintz info->msix_cnt = cdev->int_params.fp_msix_cnt; 762fe56b9e6SYuval Mintz info->msix = &cdev->int_params.msix_table[msix_base]; 763fe56b9e6SYuval Mintz } 764fe56b9e6SYuval Mintz 765fe56b9e6SYuval Mintz return 0; 766fe56b9e6SYuval Mintz } 767fe56b9e6SYuval Mintz 768fe56b9e6SYuval Mintz static int qed_slowpath_setup_int(struct qed_dev *cdev, 769fe56b9e6SYuval Mintz enum qed_int_mode int_mode) 770fe56b9e6SYuval Mintz { 7714ac801b7SYuval Mintz struct qed_sb_cnt_info sb_cnt_info; 7720189efb8SYuval Mintz int num_l2_queues = 0; 7734ac801b7SYuval Mintz int rc; 7744ac801b7SYuval Mintz int i; 775fe56b9e6SYuval Mintz 7761d2c2024SSudarsana Reddy Kalluru if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { 7771d2c2024SSudarsana Reddy Kalluru DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); 7781d2c2024SSudarsana Reddy Kalluru return -EINVAL; 7791d2c2024SSudarsana Reddy Kalluru } 7801d2c2024SSudarsana Reddy Kalluru 7811d2c2024SSudarsana Reddy Kalluru memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 782fe56b9e6SYuval Mintz cdev->int_params.in.int_mode = int_mode; 7834ac801b7SYuval Mintz for_each_hwfn(cdev, i) { 7844ac801b7SYuval Mintz memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); 7854ac801b7SYuval Mintz qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); 786726fdbe9SMintz, Yuval cdev->int_params.in.num_vectors += sb_cnt_info.cnt; 7874ac801b7SYuval Mintz cdev->int_params.in.num_vectors++; /* slowpath */ 7884ac801b7SYuval Mintz } 789fe56b9e6SYuval Mintz 790fe56b9e6SYuval Mintz /* We want a minimum of one slowpath and one fastpath vector per hwfn */ 791fe56b9e6SYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; 792fe56b9e6SYuval Mintz 793bb7858baSSudarsana Reddy Kalluru if (is_kdump_kernel()) { 794bb7858baSSudarsana Reddy Kalluru DP_INFO(cdev, 795bb7858baSSudarsana Reddy Kalluru "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", 796bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt); 797bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.num_vectors = 798bb7858baSSudarsana Reddy Kalluru cdev->int_params.in.min_msix_cnt; 799bb7858baSSudarsana Reddy Kalluru } 800bb7858baSSudarsana Reddy Kalluru 801fe56b9e6SYuval Mintz rc = qed_set_int_mode(cdev, false); 802fe56b9e6SYuval Mintz if (rc) { 803fe56b9e6SYuval Mintz DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); 804fe56b9e6SYuval Mintz return rc; 805fe56b9e6SYuval Mintz } 806fe56b9e6SYuval Mintz 807fe56b9e6SYuval Mintz cdev->int_params.fp_msix_base = cdev->num_hwfns; 808fe56b9e6SYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - 809fe56b9e6SYuval Mintz cdev->num_hwfns; 810fe56b9e6SYuval Mintz 8112f782278SMintz, Yuval if (!IS_ENABLED(CONFIG_QED_RDMA) || 812c851a9dcSKalderon, Michal !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) 8130189efb8SYuval Mintz return 0; 8140189efb8SYuval Mintz 81551ff1725SRam Amrani for_each_hwfn(cdev, i) 81651ff1725SRam Amrani num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); 81751ff1725SRam Amrani 81851ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, 81951ff1725SRam Amrani "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n", 82051ff1725SRam Amrani cdev->int_params.fp_msix_cnt, num_l2_queues); 82151ff1725SRam Amrani 82251ff1725SRam Amrani if (cdev->int_params.fp_msix_cnt > num_l2_queues) { 82351ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 82451ff1725SRam Amrani (cdev->int_params.fp_msix_cnt - num_l2_queues) 82551ff1725SRam Amrani / cdev->num_hwfns; 82651ff1725SRam Amrani cdev->int_params.rdma_msix_base = 82751ff1725SRam Amrani cdev->int_params.fp_msix_base + num_l2_queues; 82851ff1725SRam Amrani cdev->int_params.fp_msix_cnt = num_l2_queues; 82951ff1725SRam Amrani } else { 83051ff1725SRam Amrani cdev->int_params.rdma_msix_cnt = 0; 83151ff1725SRam Amrani } 83251ff1725SRam Amrani 83351ff1725SRam Amrani DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", 83451ff1725SRam Amrani cdev->int_params.rdma_msix_cnt, 83551ff1725SRam Amrani cdev->int_params.rdma_msix_base); 83651ff1725SRam Amrani 837fe56b9e6SYuval Mintz return 0; 838fe56b9e6SYuval Mintz } 839fe56b9e6SYuval Mintz 8401408cc1fSYuval Mintz static int qed_slowpath_vf_setup_int(struct qed_dev *cdev) 8411408cc1fSYuval Mintz { 8421408cc1fSYuval Mintz int rc; 8431408cc1fSYuval Mintz 8441408cc1fSYuval Mintz memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); 8451408cc1fSYuval Mintz cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; 8461408cc1fSYuval Mintz 8471408cc1fSYuval Mintz qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), 8481408cc1fSYuval Mintz &cdev->int_params.in.num_vectors); 8491408cc1fSYuval Mintz if (cdev->num_hwfns > 1) { 8501408cc1fSYuval Mintz u8 vectors = 0; 8511408cc1fSYuval Mintz 8521408cc1fSYuval Mintz qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); 8531408cc1fSYuval Mintz cdev->int_params.in.num_vectors += vectors; 8541408cc1fSYuval Mintz } 8551408cc1fSYuval Mintz 8561408cc1fSYuval Mintz /* We want a minimum of one fastpath vector per vf hwfn */ 8571408cc1fSYuval Mintz cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; 8581408cc1fSYuval Mintz 8591408cc1fSYuval Mintz rc = qed_set_int_mode(cdev, true); 8601408cc1fSYuval Mintz if (rc) 8611408cc1fSYuval Mintz return rc; 8621408cc1fSYuval Mintz 8631408cc1fSYuval Mintz cdev->int_params.fp_msix_base = 0; 8641408cc1fSYuval Mintz cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; 8651408cc1fSYuval Mintz 8661408cc1fSYuval Mintz return 0; 8671408cc1fSYuval Mintz } 8681408cc1fSYuval Mintz 869fe56b9e6SYuval Mintz u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, 870fe56b9e6SYuval Mintz u8 *input_buf, u32 max_size, u8 *unzip_buf) 871fe56b9e6SYuval Mintz { 872fe56b9e6SYuval Mintz int rc; 873fe56b9e6SYuval Mintz 874fe56b9e6SYuval Mintz p_hwfn->stream->next_in = input_buf; 875fe56b9e6SYuval Mintz p_hwfn->stream->avail_in = input_len; 876fe56b9e6SYuval Mintz p_hwfn->stream->next_out = unzip_buf; 877fe56b9e6SYuval Mintz p_hwfn->stream->avail_out = max_size; 878fe56b9e6SYuval Mintz 879fe56b9e6SYuval Mintz rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); 880fe56b9e6SYuval Mintz 881fe56b9e6SYuval Mintz if (rc != Z_OK) { 882fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", 883fe56b9e6SYuval Mintz rc); 884fe56b9e6SYuval Mintz return 0; 885fe56b9e6SYuval Mintz } 886fe56b9e6SYuval Mintz 887fe56b9e6SYuval Mintz rc = zlib_inflate(p_hwfn->stream, Z_FINISH); 888fe56b9e6SYuval Mintz zlib_inflateEnd(p_hwfn->stream); 889fe56b9e6SYuval Mintz 890fe56b9e6SYuval Mintz if (rc != Z_OK && rc != Z_STREAM_END) { 891fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", 892fe56b9e6SYuval Mintz p_hwfn->stream->msg, rc); 893fe56b9e6SYuval Mintz return 0; 894fe56b9e6SYuval Mintz } 895fe56b9e6SYuval Mintz 896fe56b9e6SYuval Mintz return p_hwfn->stream->total_out / 4; 897fe56b9e6SYuval Mintz } 898fe56b9e6SYuval Mintz 899fe56b9e6SYuval Mintz static int qed_alloc_stream_mem(struct qed_dev *cdev) 900fe56b9e6SYuval Mintz { 901fe56b9e6SYuval Mintz int i; 902fe56b9e6SYuval Mintz void *workspace; 903fe56b9e6SYuval Mintz 904fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 905fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 906fe56b9e6SYuval Mintz 907fe56b9e6SYuval Mintz p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); 908fe56b9e6SYuval Mintz if (!p_hwfn->stream) 909fe56b9e6SYuval Mintz return -ENOMEM; 910fe56b9e6SYuval Mintz 911fe56b9e6SYuval Mintz workspace = vzalloc(zlib_inflate_workspacesize()); 912fe56b9e6SYuval Mintz if (!workspace) 913fe56b9e6SYuval Mintz return -ENOMEM; 914fe56b9e6SYuval Mintz p_hwfn->stream->workspace = workspace; 915fe56b9e6SYuval Mintz } 916fe56b9e6SYuval Mintz 917fe56b9e6SYuval Mintz return 0; 918fe56b9e6SYuval Mintz } 919fe56b9e6SYuval Mintz 920fe56b9e6SYuval Mintz static void qed_free_stream_mem(struct qed_dev *cdev) 921fe56b9e6SYuval Mintz { 922fe56b9e6SYuval Mintz int i; 923fe56b9e6SYuval Mintz 924fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 925fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 926fe56b9e6SYuval Mintz 927fe56b9e6SYuval Mintz if (!p_hwfn->stream) 928fe56b9e6SYuval Mintz return; 929fe56b9e6SYuval Mintz 930fe56b9e6SYuval Mintz vfree(p_hwfn->stream->workspace); 931fe56b9e6SYuval Mintz kfree(p_hwfn->stream); 932fe56b9e6SYuval Mintz } 933fe56b9e6SYuval Mintz } 934fe56b9e6SYuval Mintz 935fe56b9e6SYuval Mintz static void qed_update_pf_params(struct qed_dev *cdev, 936fe56b9e6SYuval Mintz struct qed_pf_params *params) 937fe56b9e6SYuval Mintz { 938fe56b9e6SYuval Mintz int i; 939fe56b9e6SYuval Mintz 9405c5f2609SRam Amrani if (IS_ENABLED(CONFIG_QED_RDMA)) { 9410189efb8SYuval Mintz params->rdma_pf_params.num_qps = QED_ROCE_QPS; 9420189efb8SYuval Mintz params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; 94339dbc646SYuval Bason params->rdma_pf_params.num_srqs = QED_RDMA_SRQS; 9440189efb8SYuval Mintz /* divide by 3 the MRs to avoid MF ILT overflow */ 9450189efb8SYuval Mintz params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; 946fe56b9e6SYuval Mintz } 947fe56b9e6SYuval Mintz 948d51e4af5SChopra, Manish if (cdev->num_hwfns > 1 || IS_VF(cdev)) 949d51e4af5SChopra, Manish params->eth_pf_params.num_arfs_filters = 0; 950d51e4af5SChopra, Manish 951e1d32acbSMintz, Yuval /* In case we might support RDMA, don't allow qede to be greedy 9525e7baf0fSManish Chopra * with the L2 contexts. Allow for 64 queues [rx, tx cos, xdp] 9535e7baf0fSManish Chopra * per hwfn. 954e1d32acbSMintz, Yuval */ 955c851a9dcSKalderon, Michal if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) { 956e1d32acbSMintz, Yuval u16 *num_cons; 957e1d32acbSMintz, Yuval 958e1d32acbSMintz, Yuval num_cons = ¶ms->eth_pf_params.num_cons; 9595e7baf0fSManish Chopra *num_cons = min_t(u16, *num_cons, QED_MAX_L2_CONS); 960e1d32acbSMintz, Yuval } 961e1d32acbSMintz, Yuval 9625c5f2609SRam Amrani for (i = 0; i < cdev->num_hwfns; i++) { 9635c5f2609SRam Amrani struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 9645c5f2609SRam Amrani 9655c5f2609SRam Amrani p_hwfn->pf_params = *params; 9665c5f2609SRam Amrani } 9675c5f2609SRam Amrani } 9685c5f2609SRam Amrani 96959ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_wq_stop(struct qed_dev *cdev) 97059ccf86fSSudarsana Reddy Kalluru { 97159ccf86fSSudarsana Reddy Kalluru int i; 97259ccf86fSSudarsana Reddy Kalluru 97359ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 97459ccf86fSSudarsana Reddy Kalluru return; 97559ccf86fSSudarsana Reddy Kalluru 97659ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 97759ccf86fSSudarsana Reddy Kalluru if (!cdev->hwfns[i].slowpath_wq) 97859ccf86fSSudarsana Reddy Kalluru continue; 97959ccf86fSSudarsana Reddy Kalluru 98059ccf86fSSudarsana Reddy Kalluru flush_workqueue(cdev->hwfns[i].slowpath_wq); 98159ccf86fSSudarsana Reddy Kalluru destroy_workqueue(cdev->hwfns[i].slowpath_wq); 98259ccf86fSSudarsana Reddy Kalluru } 98359ccf86fSSudarsana Reddy Kalluru } 98459ccf86fSSudarsana Reddy Kalluru 98559ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_task(struct work_struct *work) 98659ccf86fSSudarsana Reddy Kalluru { 98759ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn, 98859ccf86fSSudarsana Reddy Kalluru slowpath_task.work); 98959ccf86fSSudarsana Reddy Kalluru struct qed_ptt *ptt = qed_ptt_acquire(hwfn); 99059ccf86fSSudarsana Reddy Kalluru 99159ccf86fSSudarsana Reddy Kalluru if (!ptt) { 99259ccf86fSSudarsana Reddy Kalluru queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 99359ccf86fSSudarsana Reddy Kalluru return; 99459ccf86fSSudarsana Reddy Kalluru } 99559ccf86fSSudarsana Reddy Kalluru 99659ccf86fSSudarsana Reddy Kalluru if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ, 99759ccf86fSSudarsana Reddy Kalluru &hwfn->slowpath_task_flags)) 99859ccf86fSSudarsana Reddy Kalluru qed_mfw_process_tlv_req(hwfn, ptt); 99959ccf86fSSudarsana Reddy Kalluru 100059ccf86fSSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 100159ccf86fSSudarsana Reddy Kalluru } 100259ccf86fSSudarsana Reddy Kalluru 100359ccf86fSSudarsana Reddy Kalluru static int qed_slowpath_wq_start(struct qed_dev *cdev) 100459ccf86fSSudarsana Reddy Kalluru { 100559ccf86fSSudarsana Reddy Kalluru struct qed_hwfn *hwfn; 100659ccf86fSSudarsana Reddy Kalluru char name[NAME_SIZE]; 100759ccf86fSSudarsana Reddy Kalluru int i; 100859ccf86fSSudarsana Reddy Kalluru 100959ccf86fSSudarsana Reddy Kalluru if (IS_VF(cdev)) 101059ccf86fSSudarsana Reddy Kalluru return 0; 101159ccf86fSSudarsana Reddy Kalluru 101259ccf86fSSudarsana Reddy Kalluru for_each_hwfn(cdev, i) { 101359ccf86fSSudarsana Reddy Kalluru hwfn = &cdev->hwfns[i]; 101459ccf86fSSudarsana Reddy Kalluru 101559ccf86fSSudarsana Reddy Kalluru snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x", 101659ccf86fSSudarsana Reddy Kalluru cdev->pdev->bus->number, 101759ccf86fSSudarsana Reddy Kalluru PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); 101859ccf86fSSudarsana Reddy Kalluru 101959ccf86fSSudarsana Reddy Kalluru hwfn->slowpath_wq = alloc_workqueue(name, 0, 0); 102059ccf86fSSudarsana Reddy Kalluru if (!hwfn->slowpath_wq) { 102159ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n"); 102259ccf86fSSudarsana Reddy Kalluru return -ENOMEM; 102359ccf86fSSudarsana Reddy Kalluru } 102459ccf86fSSudarsana Reddy Kalluru 102559ccf86fSSudarsana Reddy Kalluru INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task); 102659ccf86fSSudarsana Reddy Kalluru } 102759ccf86fSSudarsana Reddy Kalluru 102859ccf86fSSudarsana Reddy Kalluru return 0; 102959ccf86fSSudarsana Reddy Kalluru } 103059ccf86fSSudarsana Reddy Kalluru 1031fe56b9e6SYuval Mintz static int qed_slowpath_start(struct qed_dev *cdev, 1032fe56b9e6SYuval Mintz struct qed_slowpath_params *params) 1033fe56b9e6SYuval Mintz { 10345d24bcf1STomer Tayar struct qed_drv_load_params drv_load_params; 1035c0c2d0b4SMintz, Yuval struct qed_hw_init_params hw_init_params; 1036fe56b9e6SYuval Mintz struct qed_mcp_drv_version drv_version; 103719968430SChopra, Manish struct qed_tunnel_info tunn_info; 1038fe56b9e6SYuval Mintz const u8 *data = NULL; 1039fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 1040c78c70faSSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 104137bff2b9SYuval Mintz int rc = -EINVAL; 104237bff2b9SYuval Mintz 104337bff2b9SYuval Mintz if (qed_iov_wq_start(cdev)) 104437bff2b9SYuval Mintz goto err; 1045fe56b9e6SYuval Mintz 104659ccf86fSSudarsana Reddy Kalluru if (qed_slowpath_wq_start(cdev)) 104759ccf86fSSudarsana Reddy Kalluru goto err; 104859ccf86fSSudarsana Reddy Kalluru 10491408cc1fSYuval Mintz if (IS_PF(cdev)) { 1050fe56b9e6SYuval Mintz rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, 1051fe56b9e6SYuval Mintz &cdev->pdev->dev); 1052fe56b9e6SYuval Mintz if (rc) { 1053fe56b9e6SYuval Mintz DP_NOTICE(cdev, 1054fe56b9e6SYuval Mintz "Failed to find fw file - /lib/firmware/%s\n", 1055fe56b9e6SYuval Mintz QED_FW_FILE_NAME); 1056fe56b9e6SYuval Mintz goto err; 1057fe56b9e6SYuval Mintz } 1058c78c70faSSudarsana Reddy Kalluru 1059d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) { 1060d51e4af5SChopra, Manish p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 1061d51e4af5SChopra, Manish if (p_ptt) { 1062d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; 1063d51e4af5SChopra, Manish } else { 1064d51e4af5SChopra, Manish DP_NOTICE(cdev, 1065d51e4af5SChopra, Manish "Failed to acquire PTT for aRFS\n"); 1066d51e4af5SChopra, Manish goto err; 1067d51e4af5SChopra, Manish } 1068d51e4af5SChopra, Manish } 10691408cc1fSYuval Mintz } 1070fe56b9e6SYuval Mintz 10710e191827SSudarsana Reddy Kalluru cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 1072fe56b9e6SYuval Mintz rc = qed_nic_setup(cdev); 1073fe56b9e6SYuval Mintz if (rc) 1074fe56b9e6SYuval Mintz goto err; 1075fe56b9e6SYuval Mintz 10761408cc1fSYuval Mintz if (IS_PF(cdev)) 1077fe56b9e6SYuval Mintz rc = qed_slowpath_setup_int(cdev, params->int_mode); 10781408cc1fSYuval Mintz else 10791408cc1fSYuval Mintz rc = qed_slowpath_vf_setup_int(cdev); 1080fe56b9e6SYuval Mintz if (rc) 1081fe56b9e6SYuval Mintz goto err1; 1082fe56b9e6SYuval Mintz 10831408cc1fSYuval Mintz if (IS_PF(cdev)) { 1084fe56b9e6SYuval Mintz /* Allocate stream for unzipping */ 1085fe56b9e6SYuval Mintz rc = qed_alloc_stream_mem(cdev); 10862591c280SJoe Perches if (rc) 10878f16bc97SSudarsana Kalluru goto err2; 1088fe56b9e6SYuval Mintz 10898ac1ed79SJoe Perches /* First Dword used to differentiate between various sources */ 1090351a4dedSYuval Mintz data = cdev->firmware->data + sizeof(u32); 1091c965db44STomer Tayar 1092c965db44STomer Tayar qed_dbg_pf_init(cdev); 10931408cc1fSYuval Mintz } 1094fe56b9e6SYuval Mintz 10951408cc1fSYuval Mintz /* Start the slowpath */ 1096c0c2d0b4SMintz, Yuval memset(&hw_init_params, 0, sizeof(hw_init_params)); 109719968430SChopra, Manish memset(&tunn_info, 0, sizeof(tunn_info)); 109819968430SChopra, Manish tunn_info.vxlan.b_mode_enabled = true; 109919968430SChopra, Manish tunn_info.l2_gre.b_mode_enabled = true; 110019968430SChopra, Manish tunn_info.ip_gre.b_mode_enabled = true; 110119968430SChopra, Manish tunn_info.l2_geneve.b_mode_enabled = true; 110219968430SChopra, Manish tunn_info.ip_geneve.b_mode_enabled = true; 110319968430SChopra, Manish tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 110419968430SChopra, Manish tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 110519968430SChopra, Manish tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 110619968430SChopra, Manish tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 110719968430SChopra, Manish tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; 1108c0c2d0b4SMintz, Yuval hw_init_params.p_tunn = &tunn_info; 1109c0c2d0b4SMintz, Yuval hw_init_params.b_hw_start = true; 1110c0c2d0b4SMintz, Yuval hw_init_params.int_mode = cdev->int_params.out.int_mode; 1111c0c2d0b4SMintz, Yuval hw_init_params.allow_npar_tx_switch = true; 1112c0c2d0b4SMintz, Yuval hw_init_params.bin_fw_data = data; 1113c0c2d0b4SMintz, Yuval 11145d24bcf1STomer Tayar memset(&drv_load_params, 0, sizeof(drv_load_params)); 11155d24bcf1STomer Tayar drv_load_params.is_crash_kernel = is_kdump_kernel(); 11165d24bcf1STomer Tayar drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; 11175d24bcf1STomer Tayar drv_load_params.avoid_eng_reset = false; 11185d24bcf1STomer Tayar drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; 11195d24bcf1STomer Tayar hw_init_params.p_drv_load_params = &drv_load_params; 11205d24bcf1STomer Tayar 1121c0c2d0b4SMintz, Yuval rc = qed_hw_init(cdev, &hw_init_params); 1122fe56b9e6SYuval Mintz if (rc) 11238c925c44SYuval Mintz goto err2; 1124fe56b9e6SYuval Mintz 1125fe56b9e6SYuval Mintz DP_INFO(cdev, 1126fe56b9e6SYuval Mintz "HW initialization and function start completed successfully\n"); 1127fe56b9e6SYuval Mintz 1128eaf3c0c6SChopra, Manish if (IS_PF(cdev)) { 1129eaf3c0c6SChopra, Manish cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | 1130eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GENEVE_TUNN) | 1131eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGENEVE_TUNN) | 1132eaf3c0c6SChopra, Manish BIT(QED_MODE_L2GRE_TUNN) | 1133eaf3c0c6SChopra, Manish BIT(QED_MODE_IPGRE_TUNN)); 1134eaf3c0c6SChopra, Manish } 1135eaf3c0c6SChopra, Manish 11360a7fb11cSYuval Mintz /* Allocate LL2 interface if needed */ 11370a7fb11cSYuval Mintz if (QED_LEADING_HWFN(cdev)->using_ll2) { 11380a7fb11cSYuval Mintz rc = qed_ll2_alloc_if(cdev); 11390a7fb11cSYuval Mintz if (rc) 11400a7fb11cSYuval Mintz goto err3; 11410a7fb11cSYuval Mintz } 11421408cc1fSYuval Mintz if (IS_PF(cdev)) { 1143fe56b9e6SYuval Mintz hwfn = QED_LEADING_HWFN(cdev); 1144fe56b9e6SYuval Mintz drv_version.version = (params->drv_major << 24) | 1145fe56b9e6SYuval Mintz (params->drv_minor << 16) | 1146fe56b9e6SYuval Mintz (params->drv_rev << 8) | 1147fe56b9e6SYuval Mintz (params->drv_eng); 1148fe56b9e6SYuval Mintz strlcpy(drv_version.name, params->name, 1149fe56b9e6SYuval Mintz MCP_DRV_VER_STR_SIZE - 4); 1150fe56b9e6SYuval Mintz rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, 1151fe56b9e6SYuval Mintz &drv_version); 1152fe56b9e6SYuval Mintz if (rc) { 1153fe56b9e6SYuval Mintz DP_NOTICE(cdev, "Failed sending drv version command\n"); 1154fe56b9e6SYuval Mintz return rc; 1155fe56b9e6SYuval Mintz } 11561408cc1fSYuval Mintz } 1157fe56b9e6SYuval Mintz 11588c925c44SYuval Mintz qed_reset_vport_stats(cdev); 11598c925c44SYuval Mintz 1160fe56b9e6SYuval Mintz return 0; 1161fe56b9e6SYuval Mintz 11620a7fb11cSYuval Mintz err3: 11630a7fb11cSYuval Mintz qed_hw_stop(cdev); 1164fe56b9e6SYuval Mintz err2: 11658c925c44SYuval Mintz qed_hw_timers_stop_all(cdev); 11661408cc1fSYuval Mintz if (IS_PF(cdev)) 11678c925c44SYuval Mintz qed_slowpath_irq_free(cdev); 11688c925c44SYuval Mintz qed_free_stream_mem(cdev); 1169fe56b9e6SYuval Mintz qed_disable_msix(cdev); 1170fe56b9e6SYuval Mintz err1: 1171fe56b9e6SYuval Mintz qed_resc_free(cdev); 1172fe56b9e6SYuval Mintz err: 11731408cc1fSYuval Mintz if (IS_PF(cdev)) 1174fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1175fe56b9e6SYuval Mintz 1176d51e4af5SChopra, Manish if (IS_PF(cdev) && (cdev->num_hwfns == 1) && 1177d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt) 1178d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1179d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1180c78c70faSSudarsana Reddy Kalluru 118137bff2b9SYuval Mintz qed_iov_wq_stop(cdev, false); 118237bff2b9SYuval Mintz 118359ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 118459ccf86fSSudarsana Reddy Kalluru 1185fe56b9e6SYuval Mintz return rc; 1186fe56b9e6SYuval Mintz } 1187fe56b9e6SYuval Mintz 1188fe56b9e6SYuval Mintz static int qed_slowpath_stop(struct qed_dev *cdev) 1189fe56b9e6SYuval Mintz { 1190fe56b9e6SYuval Mintz if (!cdev) 1191fe56b9e6SYuval Mintz return -ENODEV; 1192fe56b9e6SYuval Mintz 119359ccf86fSSudarsana Reddy Kalluru qed_slowpath_wq_stop(cdev); 119459ccf86fSSudarsana Reddy Kalluru 11950a7fb11cSYuval Mintz qed_ll2_dealloc_if(cdev); 11960a7fb11cSYuval Mintz 11971408cc1fSYuval Mintz if (IS_PF(cdev)) { 1198d51e4af5SChopra, Manish if (cdev->num_hwfns == 1) 1199d51e4af5SChopra, Manish qed_ptt_release(QED_LEADING_HWFN(cdev), 1200d51e4af5SChopra, Manish QED_LEADING_HWFN(cdev)->p_arfs_ptt); 1201fe56b9e6SYuval Mintz qed_free_stream_mem(cdev); 1202c5ac9319SYuval Mintz if (IS_QED_ETH_IF(cdev)) 12030b55e27dSYuval Mintz qed_sriov_disable(cdev, true); 12045f027d7aSMintz, Yuval } 1205fe56b9e6SYuval Mintz 1206fe56b9e6SYuval Mintz qed_nic_stop(cdev); 12075f027d7aSMintz, Yuval 12085f027d7aSMintz, Yuval if (IS_PF(cdev)) 1209fe56b9e6SYuval Mintz qed_slowpath_irq_free(cdev); 1210fe56b9e6SYuval Mintz 1211fe56b9e6SYuval Mintz qed_disable_msix(cdev); 12121226337aSTomer Tayar 12131226337aSTomer Tayar qed_resc_free(cdev); 1214fe56b9e6SYuval Mintz 121537bff2b9SYuval Mintz qed_iov_wq_stop(cdev, true); 121637bff2b9SYuval Mintz 12171408cc1fSYuval Mintz if (IS_PF(cdev)) 1218fe56b9e6SYuval Mintz release_firmware(cdev->firmware); 1219fe56b9e6SYuval Mintz 1220fe56b9e6SYuval Mintz return 0; 1221fe56b9e6SYuval Mintz } 1222fe56b9e6SYuval Mintz 1223712c3cbfSMintz, Yuval static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) 1224fe56b9e6SYuval Mintz { 1225fe56b9e6SYuval Mintz int i; 1226fe56b9e6SYuval Mintz 1227fe56b9e6SYuval Mintz memcpy(cdev->name, name, NAME_SIZE); 1228fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) 1229fe56b9e6SYuval Mintz snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); 1230fe56b9e6SYuval Mintz } 1231fe56b9e6SYuval Mintz 1232fe56b9e6SYuval Mintz static u32 qed_sb_init(struct qed_dev *cdev, 1233fe56b9e6SYuval Mintz struct qed_sb_info *sb_info, 1234fe56b9e6SYuval Mintz void *sb_virt_addr, 1235fe56b9e6SYuval Mintz dma_addr_t sb_phy_addr, u16 sb_id, 1236fe56b9e6SYuval Mintz enum qed_sb_type type) 1237fe56b9e6SYuval Mintz { 1238fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 123985750d74SMintz, Yuval struct qed_ptt *p_ptt; 1240fe56b9e6SYuval Mintz int hwfn_index; 1241fe56b9e6SYuval Mintz u16 rel_sb_id; 1242fe56b9e6SYuval Mintz u8 n_hwfns; 1243fe56b9e6SYuval Mintz u32 rc; 1244fe56b9e6SYuval Mintz 1245fe56b9e6SYuval Mintz /* RoCE uses single engine and CMT uses two engines. When using both 1246fe56b9e6SYuval Mintz * we force only a single engine. Storage uses only engine 0 too. 1247fe56b9e6SYuval Mintz */ 1248fe56b9e6SYuval Mintz if (type == QED_SB_TYPE_L2_QUEUE) 1249fe56b9e6SYuval Mintz n_hwfns = cdev->num_hwfns; 1250fe56b9e6SYuval Mintz else 1251fe56b9e6SYuval Mintz n_hwfns = 1; 1252fe56b9e6SYuval Mintz 1253fe56b9e6SYuval Mintz hwfn_index = sb_id % n_hwfns; 1254fe56b9e6SYuval Mintz p_hwfn = &cdev->hwfns[hwfn_index]; 1255fe56b9e6SYuval Mintz rel_sb_id = sb_id / n_hwfns; 1256fe56b9e6SYuval Mintz 1257fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1258fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 1259fe56b9e6SYuval Mintz hwfn_index, rel_sb_id, sb_id); 1260fe56b9e6SYuval Mintz 126185750d74SMintz, Yuval if (IS_PF(p_hwfn->cdev)) { 126285750d74SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 126385750d74SMintz, Yuval if (!p_ptt) 126485750d74SMintz, Yuval return -EBUSY; 126585750d74SMintz, Yuval 126685750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, 126785750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 126885750d74SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 126985750d74SMintz, Yuval } else { 127085750d74SMintz, Yuval rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, 127185750d74SMintz, Yuval sb_phy_addr, rel_sb_id); 127285750d74SMintz, Yuval } 1273fe56b9e6SYuval Mintz 1274fe56b9e6SYuval Mintz return rc; 1275fe56b9e6SYuval Mintz } 1276fe56b9e6SYuval Mintz 1277fe56b9e6SYuval Mintz static u32 qed_sb_release(struct qed_dev *cdev, 12781a635e48SYuval Mintz struct qed_sb_info *sb_info, u16 sb_id) 1279fe56b9e6SYuval Mintz { 1280fe56b9e6SYuval Mintz struct qed_hwfn *p_hwfn; 1281fe56b9e6SYuval Mintz int hwfn_index; 1282fe56b9e6SYuval Mintz u16 rel_sb_id; 1283fe56b9e6SYuval Mintz u32 rc; 1284fe56b9e6SYuval Mintz 1285fe56b9e6SYuval Mintz hwfn_index = sb_id % cdev->num_hwfns; 1286fe56b9e6SYuval Mintz p_hwfn = &cdev->hwfns[hwfn_index]; 1287fe56b9e6SYuval Mintz rel_sb_id = sb_id / cdev->num_hwfns; 1288fe56b9e6SYuval Mintz 1289fe56b9e6SYuval Mintz DP_VERBOSE(cdev, NETIF_MSG_INTR, 1290fe56b9e6SYuval Mintz "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", 1291fe56b9e6SYuval Mintz hwfn_index, rel_sb_id, sb_id); 1292fe56b9e6SYuval Mintz 1293fe56b9e6SYuval Mintz rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); 1294fe56b9e6SYuval Mintz 1295fe56b9e6SYuval Mintz return rc; 1296fe56b9e6SYuval Mintz } 1297fe56b9e6SYuval Mintz 1298fe7cd2bfSYuval Mintz static bool qed_can_link_change(struct qed_dev *cdev) 1299fe7cd2bfSYuval Mintz { 1300fe7cd2bfSYuval Mintz return true; 1301fe7cd2bfSYuval Mintz } 1302fe7cd2bfSYuval Mintz 1303351a4dedSYuval Mintz static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) 1304cc875c2eSYuval Mintz { 1305cc875c2eSYuval Mintz struct qed_hwfn *hwfn; 1306cc875c2eSYuval Mintz struct qed_mcp_link_params *link_params; 1307cc875c2eSYuval Mintz struct qed_ptt *ptt; 13081c90eabcSRahul Verma u32 sup_caps; 1309cc875c2eSYuval Mintz int rc; 1310cc875c2eSYuval Mintz 1311cc875c2eSYuval Mintz if (!cdev) 1312cc875c2eSYuval Mintz return -ENODEV; 1313cc875c2eSYuval Mintz 1314cc875c2eSYuval Mintz /* The link should be set only once per PF */ 1315cc875c2eSYuval Mintz hwfn = &cdev->hwfns[0]; 1316cc875c2eSYuval Mintz 131765ed2ffdSMintz, Yuval /* When VF wants to set link, force it to read the bulletin instead. 131865ed2ffdSMintz, Yuval * This mimics the PF behavior, where a noitification [both immediate 131965ed2ffdSMintz, Yuval * and possible later] would be generated when changing properties. 132065ed2ffdSMintz, Yuval */ 132165ed2ffdSMintz, Yuval if (IS_VF(cdev)) { 132265ed2ffdSMintz, Yuval qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); 132365ed2ffdSMintz, Yuval return 0; 132465ed2ffdSMintz, Yuval } 132565ed2ffdSMintz, Yuval 1326cc875c2eSYuval Mintz ptt = qed_ptt_acquire(hwfn); 1327cc875c2eSYuval Mintz if (!ptt) 1328cc875c2eSYuval Mintz return -EBUSY; 1329cc875c2eSYuval Mintz 1330cc875c2eSYuval Mintz link_params = qed_mcp_get_link_params(hwfn); 1331cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) 1332cc875c2eSYuval Mintz link_params->speed.autoneg = params->autoneg; 1333cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { 1334cc875c2eSYuval Mintz link_params->speed.advertised_speeds = 0; 13351c90eabcSRahul Verma sup_caps = QED_LM_1000baseT_Full_BIT | 13361c90eabcSRahul Verma QED_LM_1000baseKX_Full_BIT | 13371c90eabcSRahul Verma QED_LM_1000baseX_Full_BIT; 13381c90eabcSRahul Verma if (params->adv_speeds & sup_caps) 1339cc875c2eSYuval Mintz link_params->speed.advertised_speeds |= 1340cc875c2eSYuval Mintz NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 13411c90eabcSRahul Verma sup_caps = QED_LM_10000baseT_Full_BIT | 13421c90eabcSRahul Verma QED_LM_10000baseKR_Full_BIT | 13431c90eabcSRahul Verma QED_LM_10000baseKX4_Full_BIT | 13441c90eabcSRahul Verma QED_LM_10000baseR_FEC_BIT | 13451c90eabcSRahul Verma QED_LM_10000baseCR_Full_BIT | 13461c90eabcSRahul Verma QED_LM_10000baseSR_Full_BIT | 13471c90eabcSRahul Verma QED_LM_10000baseLR_Full_BIT | 13481c90eabcSRahul Verma QED_LM_10000baseLRM_Full_BIT; 13491c90eabcSRahul Verma if (params->adv_speeds & sup_caps) 1350cc875c2eSYuval Mintz link_params->speed.advertised_speeds |= 1351cc875c2eSYuval Mintz NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 13525bf0961cSSudarsana Reddy Kalluru if (params->adv_speeds & QED_LM_20000baseKR2_Full_BIT) 13535bf0961cSSudarsana Reddy Kalluru link_params->speed.advertised_speeds |= 13545bf0961cSSudarsana Reddy Kalluru NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; 13551c90eabcSRahul Verma sup_caps = QED_LM_25000baseKR_Full_BIT | 13561c90eabcSRahul Verma QED_LM_25000baseCR_Full_BIT | 13571c90eabcSRahul Verma QED_LM_25000baseSR_Full_BIT; 13581c90eabcSRahul Verma if (params->adv_speeds & sup_caps) 1359054c67d1SSudarsana Reddy Kalluru link_params->speed.advertised_speeds |= 1360054c67d1SSudarsana Reddy Kalluru NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 13611c90eabcSRahul Verma sup_caps = QED_LM_40000baseLR4_Full_BIT | 13621c90eabcSRahul Verma QED_LM_40000baseKR4_Full_BIT | 13631c90eabcSRahul Verma QED_LM_40000baseCR4_Full_BIT | 13641c90eabcSRahul Verma QED_LM_40000baseSR4_Full_BIT; 13651c90eabcSRahul Verma if (params->adv_speeds & sup_caps) 1366cc875c2eSYuval Mintz link_params->speed.advertised_speeds |= 1367cc875c2eSYuval Mintz NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 13681c90eabcSRahul Verma sup_caps = QED_LM_50000baseKR2_Full_BIT | 13691c90eabcSRahul Verma QED_LM_50000baseCR2_Full_BIT | 13701c90eabcSRahul Verma QED_LM_50000baseSR2_Full_BIT; 13711c90eabcSRahul Verma if (params->adv_speeds & sup_caps) 1372cc875c2eSYuval Mintz link_params->speed.advertised_speeds |= 1373cc875c2eSYuval Mintz NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; 13741c90eabcSRahul Verma sup_caps = QED_LM_100000baseKR4_Full_BIT | 13751c90eabcSRahul Verma QED_LM_100000baseSR4_Full_BIT | 13761c90eabcSRahul Verma QED_LM_100000baseCR4_Full_BIT | 13771c90eabcSRahul Verma QED_LM_100000baseLR4_ER4_Full_BIT; 13781c90eabcSRahul Verma if (params->adv_speeds & sup_caps) 1379cc875c2eSYuval Mintz link_params->speed.advertised_speeds |= 1380351a4dedSYuval Mintz NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; 1381cc875c2eSYuval Mintz } 1382cc875c2eSYuval Mintz if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) 1383cc875c2eSYuval Mintz link_params->speed.forced_speed = params->forced_speed; 1384a43f235fSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { 1385a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 1386a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = true; 1387a43f235fSSudarsana Reddy Kalluru else 1388a43f235fSSudarsana Reddy Kalluru link_params->pause.autoneg = false; 1389a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) 1390a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = true; 1391a43f235fSSudarsana Reddy Kalluru else 1392a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_rx = false; 1393a43f235fSSudarsana Reddy Kalluru if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) 1394a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = true; 1395a43f235fSSudarsana Reddy Kalluru else 1396a43f235fSSudarsana Reddy Kalluru link_params->pause.forced_tx = false; 1397a43f235fSSudarsana Reddy Kalluru } 139803dc76caSSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { 139903dc76caSSudarsana Reddy Kalluru switch (params->loopback_mode) { 140003dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_INT_PHY: 1401351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; 140203dc76caSSudarsana Reddy Kalluru break; 140303dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT_PHY: 1404351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; 140503dc76caSSudarsana Reddy Kalluru break; 140603dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_EXT: 1407351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_EXT; 140803dc76caSSudarsana Reddy Kalluru break; 140903dc76caSSudarsana Reddy Kalluru case QED_LINK_LOOPBACK_MAC: 1410351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_MAC; 141103dc76caSSudarsana Reddy Kalluru break; 141203dc76caSSudarsana Reddy Kalluru default: 1413351a4dedSYuval Mintz link_params->loopback_mode = ETH_LOOPBACK_NONE; 141403dc76caSSudarsana Reddy Kalluru break; 141503dc76caSSudarsana Reddy Kalluru } 141603dc76caSSudarsana Reddy Kalluru } 1417cc875c2eSYuval Mintz 1418645874e5SSudarsana Reddy Kalluru if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG) 1419645874e5SSudarsana Reddy Kalluru memcpy(&link_params->eee, ¶ms->eee, 1420645874e5SSudarsana Reddy Kalluru sizeof(link_params->eee)); 1421645874e5SSudarsana Reddy Kalluru 1422cc875c2eSYuval Mintz rc = qed_mcp_set_link(hwfn, ptt, params->link_up); 1423cc875c2eSYuval Mintz 1424cc875c2eSYuval Mintz qed_ptt_release(hwfn, ptt); 1425cc875c2eSYuval Mintz 1426cc875c2eSYuval Mintz return rc; 1427cc875c2eSYuval Mintz } 1428cc875c2eSYuval Mintz 1429cc875c2eSYuval Mintz static int qed_get_port_type(u32 media_type) 1430cc875c2eSYuval Mintz { 1431cc875c2eSYuval Mintz int port_type; 1432cc875c2eSYuval Mintz 1433cc875c2eSYuval Mintz switch (media_type) { 1434cc875c2eSYuval Mintz case MEDIA_SFPP_10G_FIBER: 1435cc875c2eSYuval Mintz case MEDIA_SFP_1G_FIBER: 1436cc875c2eSYuval Mintz case MEDIA_XFP_FIBER: 1437b639f197SYuval Mintz case MEDIA_MODULE_FIBER: 1438cc875c2eSYuval Mintz case MEDIA_KR: 1439cc875c2eSYuval Mintz port_type = PORT_FIBRE; 1440cc875c2eSYuval Mintz break; 1441cc875c2eSYuval Mintz case MEDIA_DA_TWINAX: 1442cc875c2eSYuval Mintz port_type = PORT_DA; 1443cc875c2eSYuval Mintz break; 1444cc875c2eSYuval Mintz case MEDIA_BASE_T: 1445cc875c2eSYuval Mintz port_type = PORT_TP; 1446cc875c2eSYuval Mintz break; 1447cc875c2eSYuval Mintz case MEDIA_NOT_PRESENT: 1448cc875c2eSYuval Mintz port_type = PORT_NONE; 1449cc875c2eSYuval Mintz break; 1450cc875c2eSYuval Mintz case MEDIA_UNSPECIFIED: 1451cc875c2eSYuval Mintz default: 1452cc875c2eSYuval Mintz port_type = PORT_OTHER; 1453cc875c2eSYuval Mintz break; 1454cc875c2eSYuval Mintz } 1455cc875c2eSYuval Mintz return port_type; 1456cc875c2eSYuval Mintz } 1457cc875c2eSYuval Mintz 145814b84e86SArnd Bergmann static int qed_get_link_data(struct qed_hwfn *hwfn, 145914b84e86SArnd Bergmann struct qed_mcp_link_params *params, 146014b84e86SArnd Bergmann struct qed_mcp_link_state *link, 146114b84e86SArnd Bergmann struct qed_mcp_link_capabilities *link_caps) 146214b84e86SArnd Bergmann { 146314b84e86SArnd Bergmann void *p; 146414b84e86SArnd Bergmann 146514b84e86SArnd Bergmann if (!IS_PF(hwfn->cdev)) { 146614b84e86SArnd Bergmann qed_vf_get_link_params(hwfn, params); 146714b84e86SArnd Bergmann qed_vf_get_link_state(hwfn, link); 146814b84e86SArnd Bergmann qed_vf_get_link_caps(hwfn, link_caps); 146914b84e86SArnd Bergmann 147014b84e86SArnd Bergmann return 0; 147114b84e86SArnd Bergmann } 147214b84e86SArnd Bergmann 147314b84e86SArnd Bergmann p = qed_mcp_get_link_params(hwfn); 147414b84e86SArnd Bergmann if (!p) 147514b84e86SArnd Bergmann return -ENXIO; 147614b84e86SArnd Bergmann memcpy(params, p, sizeof(*params)); 147714b84e86SArnd Bergmann 147814b84e86SArnd Bergmann p = qed_mcp_get_link_state(hwfn); 147914b84e86SArnd Bergmann if (!p) 148014b84e86SArnd Bergmann return -ENXIO; 148114b84e86SArnd Bergmann memcpy(link, p, sizeof(*link)); 148214b84e86SArnd Bergmann 148314b84e86SArnd Bergmann p = qed_mcp_get_link_capabilities(hwfn); 148414b84e86SArnd Bergmann if (!p) 148514b84e86SArnd Bergmann return -ENXIO; 148614b84e86SArnd Bergmann memcpy(link_caps, p, sizeof(*link_caps)); 148714b84e86SArnd Bergmann 148814b84e86SArnd Bergmann return 0; 148914b84e86SArnd Bergmann } 149014b84e86SArnd Bergmann 1491c56a8be7SRahul Verma static void qed_fill_link_capability(struct qed_hwfn *hwfn, 1492c56a8be7SRahul Verma struct qed_ptt *ptt, u32 capability, 1493c56a8be7SRahul Verma u32 *if_capability) 1494c56a8be7SRahul Verma { 1495c56a8be7SRahul Verma u32 media_type, tcvr_state, tcvr_type; 1496c56a8be7SRahul Verma u32 speed_mask, board_cfg; 1497c56a8be7SRahul Verma 1498c56a8be7SRahul Verma if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) 1499c56a8be7SRahul Verma media_type = MEDIA_UNSPECIFIED; 1500c56a8be7SRahul Verma 1501c56a8be7SRahul Verma if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) 1502c56a8be7SRahul Verma tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; 1503c56a8be7SRahul Verma 1504c56a8be7SRahul Verma if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) 1505c56a8be7SRahul Verma speed_mask = 0xFFFFFFFF; 1506c56a8be7SRahul Verma 1507c56a8be7SRahul Verma if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) 1508c56a8be7SRahul Verma board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 1509c56a8be7SRahul Verma 1510c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 1511c56a8be7SRahul Verma "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", 1512c56a8be7SRahul Verma media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); 1513c56a8be7SRahul Verma 1514c56a8be7SRahul Verma switch (media_type) { 1515c56a8be7SRahul Verma case MEDIA_DA_TWINAX: 1516c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1517c56a8be7SRahul Verma *if_capability |= QED_LM_20000baseKR2_Full_BIT; 1518c56a8be7SRahul Verma /* For DAC media multiple speed capabilities are supported*/ 1519c56a8be7SRahul Verma capability = capability & speed_mask; 1520c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1521c56a8be7SRahul Verma *if_capability |= QED_LM_1000baseKX_Full_BIT; 1522c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1523c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseCR_Full_BIT; 1524c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 1525c56a8be7SRahul Verma *if_capability |= QED_LM_40000baseCR4_Full_BIT; 1526c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 1527c56a8be7SRahul Verma *if_capability |= QED_LM_25000baseCR_Full_BIT; 1528c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1529c56a8be7SRahul Verma *if_capability |= QED_LM_50000baseCR2_Full_BIT; 1530c56a8be7SRahul Verma if (capability & 1531c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 1532c56a8be7SRahul Verma *if_capability |= QED_LM_100000baseCR4_Full_BIT; 1533c56a8be7SRahul Verma break; 1534c56a8be7SRahul Verma case MEDIA_BASE_T: 1535c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { 1536c56a8be7SRahul Verma if (capability & 1537c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) { 1538c56a8be7SRahul Verma *if_capability |= QED_LM_1000baseT_Full_BIT; 1539c56a8be7SRahul Verma } 1540c56a8be7SRahul Verma if (capability & 1541c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) { 1542c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseT_Full_BIT; 1543c56a8be7SRahul Verma } 1544c56a8be7SRahul Verma } 1545c56a8be7SRahul Verma if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { 1546c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_1000BASET) 1547c56a8be7SRahul Verma *if_capability |= QED_LM_1000baseT_Full_BIT; 1548c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_BASET) 1549c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseT_Full_BIT; 1550c56a8be7SRahul Verma } 1551c56a8be7SRahul Verma break; 1552c56a8be7SRahul Verma case MEDIA_SFP_1G_FIBER: 1553c56a8be7SRahul Verma case MEDIA_SFPP_10G_FIBER: 1554c56a8be7SRahul Verma case MEDIA_XFP_FIBER: 1555c56a8be7SRahul Verma case MEDIA_MODULE_FIBER: 1556c56a8be7SRahul Verma if (capability & 1557c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) { 1558c56a8be7SRahul Verma if ((tcvr_type == ETH_TRANSCEIVER_TYPE_1G_LX) || 1559c56a8be7SRahul Verma (tcvr_type == ETH_TRANSCEIVER_TYPE_1G_SX)) 1560c56a8be7SRahul Verma *if_capability |= QED_LM_1000baseKX_Full_BIT; 1561c56a8be7SRahul Verma } 1562c56a8be7SRahul Verma if (capability & 1563c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) { 1564c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_SR) 1565c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseSR_Full_BIT; 1566c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LR) 1567c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseLR_Full_BIT; 1568c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LRM) 1569c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseLRM_Full_BIT; 1570c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_ER) 1571c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseR_FEC_BIT; 1572c56a8be7SRahul Verma } 1573c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1574c56a8be7SRahul Verma *if_capability |= QED_LM_20000baseKR2_Full_BIT; 1575c56a8be7SRahul Verma if (capability & 1576c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) { 1577c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_25G_SR) 1578c56a8be7SRahul Verma *if_capability |= QED_LM_25000baseSR_Full_BIT; 1579c56a8be7SRahul Verma } 1580c56a8be7SRahul Verma if (capability & 1581c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) { 1582c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_LR4) 1583c56a8be7SRahul Verma *if_capability |= QED_LM_40000baseLR4_Full_BIT; 1584c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_SR4) 1585c56a8be7SRahul Verma *if_capability |= QED_LM_40000baseSR4_Full_BIT; 1586c56a8be7SRahul Verma } 1587c56a8be7SRahul Verma if (capability & 1588c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1589c56a8be7SRahul Verma *if_capability |= QED_LM_50000baseKR2_Full_BIT; 1590c56a8be7SRahul Verma if (capability & 1591c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) { 1592c56a8be7SRahul Verma if (tcvr_type == ETH_TRANSCEIVER_TYPE_100G_SR4) 1593c56a8be7SRahul Verma *if_capability |= QED_LM_100000baseSR4_Full_BIT; 1594c56a8be7SRahul Verma } 1595c56a8be7SRahul Verma 1596c56a8be7SRahul Verma break; 1597c56a8be7SRahul Verma case MEDIA_KR: 1598c56a8be7SRahul Verma if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) 1599c56a8be7SRahul Verma *if_capability |= QED_LM_20000baseKR2_Full_BIT; 1600c56a8be7SRahul Verma if (capability & 1601c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) 1602c56a8be7SRahul Verma *if_capability |= QED_LM_1000baseKX_Full_BIT; 1603c56a8be7SRahul Verma if (capability & 1604c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) 1605c56a8be7SRahul Verma *if_capability |= QED_LM_10000baseKR_Full_BIT; 1606c56a8be7SRahul Verma if (capability & 1607c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) 1608c56a8be7SRahul Verma *if_capability |= QED_LM_25000baseKR_Full_BIT; 1609c56a8be7SRahul Verma if (capability & 1610c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) 1611c56a8be7SRahul Verma *if_capability |= QED_LM_40000baseKR4_Full_BIT; 1612c56a8be7SRahul Verma if (capability & 1613c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) 1614c56a8be7SRahul Verma *if_capability |= QED_LM_50000baseKR2_Full_BIT; 1615c56a8be7SRahul Verma if (capability & 1616c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) 1617c56a8be7SRahul Verma *if_capability |= QED_LM_100000baseKR4_Full_BIT; 1618c56a8be7SRahul Verma break; 1619c56a8be7SRahul Verma case MEDIA_UNSPECIFIED: 1620c56a8be7SRahul Verma case MEDIA_NOT_PRESENT: 1621c56a8be7SRahul Verma DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, 1622c56a8be7SRahul Verma "Unknown media and transceiver type;\n"); 1623c56a8be7SRahul Verma break; 1624c56a8be7SRahul Verma } 1625c56a8be7SRahul Verma } 1626c56a8be7SRahul Verma 1627cc875c2eSYuval Mintz static void qed_fill_link(struct qed_hwfn *hwfn, 1628706d0891SRahul Verma struct qed_ptt *ptt, 1629cc875c2eSYuval Mintz struct qed_link_output *if_link) 1630cc875c2eSYuval Mintz { 1631c56a8be7SRahul Verma struct qed_mcp_link_capabilities link_caps; 1632cc875c2eSYuval Mintz struct qed_mcp_link_params params; 1633cc875c2eSYuval Mintz struct qed_mcp_link_state link; 1634cc875c2eSYuval Mintz u32 media_type; 1635cc875c2eSYuval Mintz 1636cc875c2eSYuval Mintz memset(if_link, 0, sizeof(*if_link)); 1637cc875c2eSYuval Mintz 1638cc875c2eSYuval Mintz /* Prepare source inputs */ 163914b84e86SArnd Bergmann if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { 164014b84e86SArnd Bergmann dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); 164114b84e86SArnd Bergmann return; 16421408cc1fSYuval Mintz } 1643cc875c2eSYuval Mintz 1644cc875c2eSYuval Mintz /* Set the link parameters to pass to protocol driver */ 1645cc875c2eSYuval Mintz if (link.link_up) 1646cc875c2eSYuval Mintz if_link->link_up = true; 1647cc875c2eSYuval Mintz 1648cc875c2eSYuval Mintz /* TODO - at the moment assume supported and advertised speed equal */ 1649054c67d1SSudarsana Reddy Kalluru if_link->supported_caps = QED_LM_FIBRE_BIT; 165034f9199cSsudarsana.kalluru@cavium.com if (link_caps.default_speed_autoneg) 1651054c67d1SSudarsana Reddy Kalluru if_link->supported_caps |= QED_LM_Autoneg_BIT; 1652cc875c2eSYuval Mintz if (params.pause.autoneg || 1653cc875c2eSYuval Mintz (params.pause.forced_rx && params.pause.forced_tx)) 1654054c67d1SSudarsana Reddy Kalluru if_link->supported_caps |= QED_LM_Asym_Pause_BIT; 1655cc875c2eSYuval Mintz if (params.pause.autoneg || params.pause.forced_rx || 1656cc875c2eSYuval Mintz params.pause.forced_tx) 1657054c67d1SSudarsana Reddy Kalluru if_link->supported_caps |= QED_LM_Pause_BIT; 1658cc875c2eSYuval Mintz 1659cc875c2eSYuval Mintz if_link->advertised_caps = if_link->supported_caps; 166034f9199cSsudarsana.kalluru@cavium.com if (params.speed.autoneg) 166134f9199cSsudarsana.kalluru@cavium.com if_link->advertised_caps |= QED_LM_Autoneg_BIT; 166234f9199cSsudarsana.kalluru@cavium.com else 166334f9199cSsudarsana.kalluru@cavium.com if_link->advertised_caps &= ~QED_LM_Autoneg_BIT; 1664cc875c2eSYuval Mintz 1665c56a8be7SRahul Verma /* Fill link advertised capability*/ 1666c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, 1667c56a8be7SRahul Verma &if_link->advertised_caps); 1668c56a8be7SRahul Verma /* Fill link supported capability*/ 1669c56a8be7SRahul Verma qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, 1670c56a8be7SRahul Verma &if_link->supported_caps); 1671cc875c2eSYuval Mintz 1672cc875c2eSYuval Mintz if (link.link_up) 1673cc875c2eSYuval Mintz if_link->speed = link.speed; 1674cc875c2eSYuval Mintz 1675cc875c2eSYuval Mintz /* TODO - fill duplex properly */ 1676cc875c2eSYuval Mintz if_link->duplex = DUPLEX_FULL; 1677706d0891SRahul Verma qed_mcp_get_media_type(hwfn, ptt, &media_type); 1678cc875c2eSYuval Mintz if_link->port = qed_get_port_type(media_type); 1679cc875c2eSYuval Mintz 1680cc875c2eSYuval Mintz if_link->autoneg = params.speed.autoneg; 1681cc875c2eSYuval Mintz 1682cc875c2eSYuval Mintz if (params.pause.autoneg) 1683cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 1684cc875c2eSYuval Mintz if (params.pause.forced_rx) 1685cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; 1686cc875c2eSYuval Mintz if (params.pause.forced_tx) 1687cc875c2eSYuval Mintz if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; 1688cc875c2eSYuval Mintz 1689cc875c2eSYuval Mintz /* Link partner capabilities */ 1690c56a8be7SRahul Verma if (link.partner_adv_speed & 1691c56a8be7SRahul Verma QED_LINK_PARTNER_SPEED_1G_FD) 1692054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_1000baseT_Full_BIT; 1693054c67d1SSudarsana Reddy Kalluru if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G) 1694054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT; 16955bf0961cSSudarsana Reddy Kalluru if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_20G) 16965bf0961cSSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_20000baseKR2_Full_BIT; 1697054c67d1SSudarsana Reddy Kalluru if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G) 1698054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT; 1699054c67d1SSudarsana Reddy Kalluru if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G) 1700054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_40000baseLR4_Full_BIT; 1701054c67d1SSudarsana Reddy Kalluru if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_50G) 1702054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_50000baseKR2_Full_BIT; 1703054c67d1SSudarsana Reddy Kalluru if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_100G) 1704054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_100000baseKR4_Full_BIT; 1705cc875c2eSYuval Mintz 1706cc875c2eSYuval Mintz if (link.an_complete) 1707054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_Autoneg_BIT; 1708cc875c2eSYuval Mintz 1709cc875c2eSYuval Mintz if (link.partner_adv_pause) 1710054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_Pause_BIT; 1711cc875c2eSYuval Mintz if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || 1712cc875c2eSYuval Mintz link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) 1713054c67d1SSudarsana Reddy Kalluru if_link->lp_caps |= QED_LM_Asym_Pause_BIT; 1714645874e5SSudarsana Reddy Kalluru 1715645874e5SSudarsana Reddy Kalluru if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) { 1716645874e5SSudarsana Reddy Kalluru if_link->eee_supported = false; 1717645874e5SSudarsana Reddy Kalluru } else { 1718645874e5SSudarsana Reddy Kalluru if_link->eee_supported = true; 1719645874e5SSudarsana Reddy Kalluru if_link->eee_active = link.eee_active; 1720645874e5SSudarsana Reddy Kalluru if_link->sup_caps = link_caps.eee_speed_caps; 1721645874e5SSudarsana Reddy Kalluru /* MFW clears adv_caps on eee disable; use configured value */ 1722645874e5SSudarsana Reddy Kalluru if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps : 1723645874e5SSudarsana Reddy Kalluru params.eee.adv_caps; 1724645874e5SSudarsana Reddy Kalluru if_link->eee.lp_adv_caps = link.eee_lp_adv_caps; 1725645874e5SSudarsana Reddy Kalluru if_link->eee.enable = params.eee.enable; 1726645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable; 1727645874e5SSudarsana Reddy Kalluru if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer; 1728645874e5SSudarsana Reddy Kalluru } 1729cc875c2eSYuval Mintz } 1730cc875c2eSYuval Mintz 1731cc875c2eSYuval Mintz static void qed_get_current_link(struct qed_dev *cdev, 1732cc875c2eSYuval Mintz struct qed_link_output *if_link) 1733cc875c2eSYuval Mintz { 1734706d0891SRahul Verma struct qed_hwfn *hwfn; 1735706d0891SRahul Verma struct qed_ptt *ptt; 173636558c3dSYuval Mintz int i; 173736558c3dSYuval Mintz 1738706d0891SRahul Verma hwfn = &cdev->hwfns[0]; 1739706d0891SRahul Verma if (IS_PF(cdev)) { 1740706d0891SRahul Verma ptt = qed_ptt_acquire(hwfn); 1741706d0891SRahul Verma if (ptt) { 1742706d0891SRahul Verma qed_fill_link(hwfn, ptt, if_link); 1743706d0891SRahul Verma qed_ptt_release(hwfn, ptt); 1744706d0891SRahul Verma } else { 1745706d0891SRahul Verma DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); 1746706d0891SRahul Verma } 1747706d0891SRahul Verma } else { 1748706d0891SRahul Verma qed_fill_link(hwfn, NULL, if_link); 1749706d0891SRahul Verma } 175036558c3dSYuval Mintz 175136558c3dSYuval Mintz for_each_hwfn(cdev, i) 175236558c3dSYuval Mintz qed_inform_vf_link_state(&cdev->hwfns[i]); 1753cc875c2eSYuval Mintz } 1754cc875c2eSYuval Mintz 1755706d0891SRahul Verma void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) 1756cc875c2eSYuval Mintz { 1757cc875c2eSYuval Mintz void *cookie = hwfn->cdev->ops_cookie; 1758cc875c2eSYuval Mintz struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; 1759cc875c2eSYuval Mintz struct qed_link_output if_link; 1760cc875c2eSYuval Mintz 1761706d0891SRahul Verma qed_fill_link(hwfn, ptt, &if_link); 176236558c3dSYuval Mintz qed_inform_vf_link_state(hwfn); 1763cc875c2eSYuval Mintz 1764cc875c2eSYuval Mintz if (IS_LEAD_HWFN(hwfn) && cookie) 1765cc875c2eSYuval Mintz op->link_update(cookie, &if_link); 1766cc875c2eSYuval Mintz } 1767cc875c2eSYuval Mintz 1768fe56b9e6SYuval Mintz static int qed_drain(struct qed_dev *cdev) 1769fe56b9e6SYuval Mintz { 1770fe56b9e6SYuval Mintz struct qed_hwfn *hwfn; 1771fe56b9e6SYuval Mintz struct qed_ptt *ptt; 1772fe56b9e6SYuval Mintz int i, rc; 1773fe56b9e6SYuval Mintz 17741408cc1fSYuval Mintz if (IS_VF(cdev)) 17751408cc1fSYuval Mintz return 0; 17761408cc1fSYuval Mintz 1777fe56b9e6SYuval Mintz for_each_hwfn(cdev, i) { 1778fe56b9e6SYuval Mintz hwfn = &cdev->hwfns[i]; 1779fe56b9e6SYuval Mintz ptt = qed_ptt_acquire(hwfn); 1780fe56b9e6SYuval Mintz if (!ptt) { 1781fe56b9e6SYuval Mintz DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); 1782fe56b9e6SYuval Mintz return -EBUSY; 1783fe56b9e6SYuval Mintz } 1784fe56b9e6SYuval Mintz rc = qed_mcp_drain(hwfn, ptt); 17859aaa4e8bSDenis Bolotin qed_ptt_release(hwfn, ptt); 1786fe56b9e6SYuval Mintz if (rc) 1787fe56b9e6SYuval Mintz return rc; 1788fe56b9e6SYuval Mintz } 1789fe56b9e6SYuval Mintz 1790fe56b9e6SYuval Mintz return 0; 1791fe56b9e6SYuval Mintz } 1792fe56b9e6SYuval Mintz 17933a69cae8SSudarsana Reddy Kalluru static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev, 17943a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att *nvm_image, 17953a69cae8SSudarsana Reddy Kalluru u32 *crc) 17963a69cae8SSudarsana Reddy Kalluru { 17973a69cae8SSudarsana Reddy Kalluru u8 *buf = NULL; 17983a69cae8SSudarsana Reddy Kalluru int rc, j; 17993a69cae8SSudarsana Reddy Kalluru u32 val; 18003a69cae8SSudarsana Reddy Kalluru 18013a69cae8SSudarsana Reddy Kalluru /* Allocate a buffer for holding the nvram image */ 18023a69cae8SSudarsana Reddy Kalluru buf = kzalloc(nvm_image->length, GFP_KERNEL); 18033a69cae8SSudarsana Reddy Kalluru if (!buf) 18043a69cae8SSudarsana Reddy Kalluru return -ENOMEM; 18053a69cae8SSudarsana Reddy Kalluru 18063a69cae8SSudarsana Reddy Kalluru /* Read image into buffer */ 18073a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr, 18083a69cae8SSudarsana Reddy Kalluru buf, nvm_image->length); 18093a69cae8SSudarsana Reddy Kalluru if (rc) { 18103a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading image from nvm\n"); 18113a69cae8SSudarsana Reddy Kalluru goto out; 18123a69cae8SSudarsana Reddy Kalluru } 18133a69cae8SSudarsana Reddy Kalluru 18143a69cae8SSudarsana Reddy Kalluru /* Convert the buffer into big-endian format (excluding the 18153a69cae8SSudarsana Reddy Kalluru * closing 4 bytes of CRC). 18163a69cae8SSudarsana Reddy Kalluru */ 18173a69cae8SSudarsana Reddy Kalluru for (j = 0; j < nvm_image->length - 4; j += 4) { 18183a69cae8SSudarsana Reddy Kalluru val = cpu_to_be32(*(u32 *)&buf[j]); 18193a69cae8SSudarsana Reddy Kalluru *(u32 *)&buf[j] = val; 18203a69cae8SSudarsana Reddy Kalluru } 18213a69cae8SSudarsana Reddy Kalluru 18223a69cae8SSudarsana Reddy Kalluru /* Calc CRC for the "actual" image buffer, i.e. not including 18233a69cae8SSudarsana Reddy Kalluru * the last 4 CRC bytes. 18243a69cae8SSudarsana Reddy Kalluru */ 18253a69cae8SSudarsana Reddy Kalluru *crc = (~cpu_to_be32(crc32(0xffffffff, buf, nvm_image->length - 4))); 18263a69cae8SSudarsana Reddy Kalluru 18273a69cae8SSudarsana Reddy Kalluru out: 18283a69cae8SSudarsana Reddy Kalluru kfree(buf); 18293a69cae8SSudarsana Reddy Kalluru 18303a69cae8SSudarsana Reddy Kalluru return rc; 18313a69cae8SSudarsana Reddy Kalluru } 18323a69cae8SSudarsana Reddy Kalluru 18333a69cae8SSudarsana Reddy Kalluru /* Binary file format - 18343a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 18353a69cae8SSudarsana Reddy Kalluru * 0B | 0x4 [command index] | 18363a69cae8SSudarsana Reddy Kalluru * 4B | image_type | Options | Number of register settings | 18373a69cae8SSudarsana Reddy Kalluru * 8B | Value | 18383a69cae8SSudarsana Reddy Kalluru * 12B | Mask | 18393a69cae8SSudarsana Reddy Kalluru * 16B | Offset | 18403a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 18413a69cae8SSudarsana Reddy Kalluru * There can be several Value-Mask-Offset sets as specified by 'Number of...'. 18423a69cae8SSudarsana Reddy Kalluru * Options - 0'b - Calculate & Update CRC for image 18433a69cae8SSudarsana Reddy Kalluru */ 18443a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data, 18453a69cae8SSudarsana Reddy Kalluru bool *check_resp) 18463a69cae8SSudarsana Reddy Kalluru { 18473a69cae8SSudarsana Reddy Kalluru struct qed_nvm_image_att nvm_image; 18483a69cae8SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn; 18493a69cae8SSudarsana Reddy Kalluru bool is_crc = false; 18503a69cae8SSudarsana Reddy Kalluru u32 image_type; 18513a69cae8SSudarsana Reddy Kalluru int rc = 0, i; 18523a69cae8SSudarsana Reddy Kalluru u16 len; 18533a69cae8SSudarsana Reddy Kalluru 18543a69cae8SSudarsana Reddy Kalluru *data += 4; 18553a69cae8SSudarsana Reddy Kalluru image_type = **data; 18563a69cae8SSudarsana Reddy Kalluru p_hwfn = QED_LEADING_HWFN(cdev); 18573a69cae8SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 18583a69cae8SSudarsana Reddy Kalluru if (image_type == p_hwfn->nvm_info.image_att[i].image_type) 18593a69cae8SSudarsana Reddy Kalluru break; 18603a69cae8SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 18613a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find nvram image of type %08x\n", 18623a69cae8SSudarsana Reddy Kalluru image_type); 18633a69cae8SSudarsana Reddy Kalluru return -ENOENT; 18643a69cae8SSudarsana Reddy Kalluru } 18653a69cae8SSudarsana Reddy Kalluru 18663a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 18673a69cae8SSudarsana Reddy Kalluru nvm_image.length = p_hwfn->nvm_info.image_att[i].len; 18683a69cae8SSudarsana Reddy Kalluru 18693a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 18703a69cae8SSudarsana Reddy Kalluru "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n", 18713a69cae8SSudarsana Reddy Kalluru **data, image_type, nvm_image.start_addr, 18723a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 1); 18733a69cae8SSudarsana Reddy Kalluru (*data)++; 18743a69cae8SSudarsana Reddy Kalluru is_crc = !!(**data & BIT(0)); 18753a69cae8SSudarsana Reddy Kalluru (*data)++; 18763a69cae8SSudarsana Reddy Kalluru len = *((u16 *)*data); 18773a69cae8SSudarsana Reddy Kalluru *data += 2; 18783a69cae8SSudarsana Reddy Kalluru if (is_crc) { 18793a69cae8SSudarsana Reddy Kalluru u32 crc = 0; 18803a69cae8SSudarsana Reddy Kalluru 18813a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc); 18823a69cae8SSudarsana Reddy Kalluru if (rc) { 18833a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc); 18843a69cae8SSudarsana Reddy Kalluru goto exit; 18853a69cae8SSudarsana Reddy Kalluru } 18863a69cae8SSudarsana Reddy Kalluru 18873a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 18883a69cae8SSudarsana Reddy Kalluru (nvm_image.start_addr + 18893a69cae8SSudarsana Reddy Kalluru nvm_image.length - 4), (u8 *)&crc, 4); 18903a69cae8SSudarsana Reddy Kalluru if (rc) 18913a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x, rc = %d\n", 18923a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + nvm_image.length - 4, rc); 18933a69cae8SSudarsana Reddy Kalluru goto exit; 18943a69cae8SSudarsana Reddy Kalluru } 18953a69cae8SSudarsana Reddy Kalluru 18963a69cae8SSudarsana Reddy Kalluru /* Iterate over the values for setting */ 18973a69cae8SSudarsana Reddy Kalluru while (len) { 18983a69cae8SSudarsana Reddy Kalluru u32 offset, mask, value, cur_value; 18993a69cae8SSudarsana Reddy Kalluru u8 buf[4]; 19003a69cae8SSudarsana Reddy Kalluru 19013a69cae8SSudarsana Reddy Kalluru value = *((u32 *)*data); 19023a69cae8SSudarsana Reddy Kalluru *data += 4; 19033a69cae8SSudarsana Reddy Kalluru mask = *((u32 *)*data); 19043a69cae8SSudarsana Reddy Kalluru *data += 4; 19053a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)*data); 19063a69cae8SSudarsana Reddy Kalluru *data += 4; 19073a69cae8SSudarsana Reddy Kalluru 19083a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf, 19093a69cae8SSudarsana Reddy Kalluru 4); 19103a69cae8SSudarsana Reddy Kalluru if (rc) { 19113a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed reading from %08x\n", 19123a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 19133a69cae8SSudarsana Reddy Kalluru goto exit; 19143a69cae8SSudarsana Reddy Kalluru } 19153a69cae8SSudarsana Reddy Kalluru 19163a69cae8SSudarsana Reddy Kalluru cur_value = le32_to_cpu(*((__le32 *)buf)); 19173a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 19183a69cae8SSudarsana Reddy Kalluru "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n", 19193a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, cur_value, 19203a69cae8SSudarsana Reddy Kalluru (cur_value & ~mask) | (value & mask), value, mask); 19213a69cae8SSudarsana Reddy Kalluru value = (value & mask) | (cur_value & ~mask); 19223a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM, 19233a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset, 19243a69cae8SSudarsana Reddy Kalluru (u8 *)&value, 4); 19253a69cae8SSudarsana Reddy Kalluru if (rc) { 19263a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed writing to %08x\n", 19273a69cae8SSudarsana Reddy Kalluru nvm_image.start_addr + offset); 19283a69cae8SSudarsana Reddy Kalluru goto exit; 19293a69cae8SSudarsana Reddy Kalluru } 19303a69cae8SSudarsana Reddy Kalluru 19313a69cae8SSudarsana Reddy Kalluru len--; 19323a69cae8SSudarsana Reddy Kalluru } 19333a69cae8SSudarsana Reddy Kalluru exit: 19343a69cae8SSudarsana Reddy Kalluru return rc; 19353a69cae8SSudarsana Reddy Kalluru } 19363a69cae8SSudarsana Reddy Kalluru 19373a69cae8SSudarsana Reddy Kalluru /* Binary file format - 19383a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 19393a69cae8SSudarsana Reddy Kalluru * 0B | 0x3 [command index] | 19403a69cae8SSudarsana Reddy Kalluru * 4B | b'0: check_response? | b'1-31 reserved | 19413a69cae8SSudarsana Reddy Kalluru * 8B | File-type | reserved | 1942057d2b19SSudarsana Reddy Kalluru * 12B | Image length in bytes | 19433a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 19443a69cae8SSudarsana Reddy Kalluru * Start a new file of the provided type 19453a69cae8SSudarsana Reddy Kalluru */ 19463a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_start(struct qed_dev *cdev, 19473a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 19483a69cae8SSudarsana Reddy Kalluru { 1949057d2b19SSudarsana Reddy Kalluru u32 file_type, file_size = 0; 19503a69cae8SSudarsana Reddy Kalluru int rc; 19513a69cae8SSudarsana Reddy Kalluru 19523a69cae8SSudarsana Reddy Kalluru *data += 4; 19533a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 19543a69cae8SSudarsana Reddy Kalluru *data += 4; 1955057d2b19SSudarsana Reddy Kalluru file_type = **data; 19563a69cae8SSudarsana Reddy Kalluru 19573a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 1958057d2b19SSudarsana Reddy Kalluru "About to start a new file of type %02x\n", file_type); 1959057d2b19SSudarsana Reddy Kalluru if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) { 1960057d2b19SSudarsana Reddy Kalluru *data += 4; 1961057d2b19SSudarsana Reddy Kalluru file_size = *((u32 *)(*data)); 1962057d2b19SSudarsana Reddy Kalluru } 1963057d2b19SSudarsana Reddy Kalluru 1964057d2b19SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type, 1965057d2b19SSudarsana Reddy Kalluru (u8 *)(&file_size), 4); 19663a69cae8SSudarsana Reddy Kalluru *data += 4; 19673a69cae8SSudarsana Reddy Kalluru 19683a69cae8SSudarsana Reddy Kalluru return rc; 19693a69cae8SSudarsana Reddy Kalluru } 19703a69cae8SSudarsana Reddy Kalluru 19713a69cae8SSudarsana Reddy Kalluru /* Binary file format - 19723a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 19733a69cae8SSudarsana Reddy Kalluru * 0B | 0x2 [command index] | 19743a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 19753a69cae8SSudarsana Reddy Kalluru * 8B | b'0: check_response? | b'1-31 reserved | 19763a69cae8SSudarsana Reddy Kalluru * 12B | Offset in bytes | 19773a69cae8SSudarsana Reddy Kalluru * 16B | Data ... | 19783a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 19793a69cae8SSudarsana Reddy Kalluru * Write data as part of a file that was previously started. Data should be 19803a69cae8SSudarsana Reddy Kalluru * of length equal to that provided in the message 19813a69cae8SSudarsana Reddy Kalluru */ 19823a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_data(struct qed_dev *cdev, 19833a69cae8SSudarsana Reddy Kalluru const u8 **data, bool *check_resp) 19843a69cae8SSudarsana Reddy Kalluru { 19853a69cae8SSudarsana Reddy Kalluru u32 offset, len; 19863a69cae8SSudarsana Reddy Kalluru int rc; 19873a69cae8SSudarsana Reddy Kalluru 19883a69cae8SSudarsana Reddy Kalluru *data += 4; 19893a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 19903a69cae8SSudarsana Reddy Kalluru *data += 4; 19913a69cae8SSudarsana Reddy Kalluru *check_resp = !!(**data & BIT(0)); 19923a69cae8SSudarsana Reddy Kalluru *data += 4; 19933a69cae8SSudarsana Reddy Kalluru offset = *((u32 *)(*data)); 19943a69cae8SSudarsana Reddy Kalluru *data += 4; 19953a69cae8SSudarsana Reddy Kalluru 19963a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 19973a69cae8SSudarsana Reddy Kalluru "About to write File-data: %08x bytes to offset %08x\n", 19983a69cae8SSudarsana Reddy Kalluru len, offset); 19993a69cae8SSudarsana Reddy Kalluru 20003a69cae8SSudarsana Reddy Kalluru rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset, 20013a69cae8SSudarsana Reddy Kalluru (char *)(*data), len); 20023a69cae8SSudarsana Reddy Kalluru *data += len; 20033a69cae8SSudarsana Reddy Kalluru 20043a69cae8SSudarsana Reddy Kalluru return rc; 20053a69cae8SSudarsana Reddy Kalluru } 20063a69cae8SSudarsana Reddy Kalluru 20073a69cae8SSudarsana Reddy Kalluru /* Binary file format [General header] - 20083a69cae8SSudarsana Reddy Kalluru * /----------------------------------------------------------------------\ 20093a69cae8SSudarsana Reddy Kalluru * 0B | QED_NVM_SIGNATURE | 20103a69cae8SSudarsana Reddy Kalluru * 4B | Length in bytes | 20113a69cae8SSudarsana Reddy Kalluru * 8B | Highest command in this batchfile | Reserved | 20123a69cae8SSudarsana Reddy Kalluru * \----------------------------------------------------------------------/ 20133a69cae8SSudarsana Reddy Kalluru */ 20143a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_validate(struct qed_dev *cdev, 20153a69cae8SSudarsana Reddy Kalluru const struct firmware *image, 20163a69cae8SSudarsana Reddy Kalluru const u8 **data) 20173a69cae8SSudarsana Reddy Kalluru { 20183a69cae8SSudarsana Reddy Kalluru u32 signature, len; 20193a69cae8SSudarsana Reddy Kalluru 20203a69cae8SSudarsana Reddy Kalluru /* Check minimum size */ 20213a69cae8SSudarsana Reddy Kalluru if (image->size < 12) { 20223a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size); 20233a69cae8SSudarsana Reddy Kalluru return -EINVAL; 20243a69cae8SSudarsana Reddy Kalluru } 20253a69cae8SSudarsana Reddy Kalluru 20263a69cae8SSudarsana Reddy Kalluru /* Check signature */ 20273a69cae8SSudarsana Reddy Kalluru signature = *((u32 *)(*data)); 20283a69cae8SSudarsana Reddy Kalluru if (signature != QED_NVM_SIGNATURE) { 20293a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Wrong signature '%08x'\n", signature); 20303a69cae8SSudarsana Reddy Kalluru return -EINVAL; 20313a69cae8SSudarsana Reddy Kalluru } 20323a69cae8SSudarsana Reddy Kalluru 20333a69cae8SSudarsana Reddy Kalluru *data += 4; 20343a69cae8SSudarsana Reddy Kalluru /* Validate internal size equals the image-size */ 20353a69cae8SSudarsana Reddy Kalluru len = *((u32 *)(*data)); 20363a69cae8SSudarsana Reddy Kalluru if (len != image->size) { 20373a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n", 20383a69cae8SSudarsana Reddy Kalluru len, (u32)image->size); 20393a69cae8SSudarsana Reddy Kalluru return -EINVAL; 20403a69cae8SSudarsana Reddy Kalluru } 20413a69cae8SSudarsana Reddy Kalluru 20423a69cae8SSudarsana Reddy Kalluru *data += 4; 20433a69cae8SSudarsana Reddy Kalluru /* Make sure driver familiar with all commands necessary for this */ 20443a69cae8SSudarsana Reddy Kalluru if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) { 20453a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n", 20463a69cae8SSudarsana Reddy Kalluru *((u16 *)(*data))); 20473a69cae8SSudarsana Reddy Kalluru return -EINVAL; 20483a69cae8SSudarsana Reddy Kalluru } 20493a69cae8SSudarsana Reddy Kalluru 20503a69cae8SSudarsana Reddy Kalluru *data += 4; 20513a69cae8SSudarsana Reddy Kalluru 20523a69cae8SSudarsana Reddy Kalluru return 0; 20533a69cae8SSudarsana Reddy Kalluru } 20543a69cae8SSudarsana Reddy Kalluru 20553a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash(struct qed_dev *cdev, const char *name) 20563a69cae8SSudarsana Reddy Kalluru { 20573a69cae8SSudarsana Reddy Kalluru const struct firmware *image; 20583a69cae8SSudarsana Reddy Kalluru const u8 *data, *data_end; 20593a69cae8SSudarsana Reddy Kalluru u32 cmd_type; 20603a69cae8SSudarsana Reddy Kalluru int rc; 20613a69cae8SSudarsana Reddy Kalluru 20623a69cae8SSudarsana Reddy Kalluru rc = request_firmware(&image, name, &cdev->pdev->dev); 20633a69cae8SSudarsana Reddy Kalluru if (rc) { 20643a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed to find '%s'\n", name); 20653a69cae8SSudarsana Reddy Kalluru return rc; 20663a69cae8SSudarsana Reddy Kalluru } 20673a69cae8SSudarsana Reddy Kalluru 20683a69cae8SSudarsana Reddy Kalluru DP_VERBOSE(cdev, NETIF_MSG_DRV, 20693a69cae8SSudarsana Reddy Kalluru "Flashing '%s' - firmware's data at %p, size is %08x\n", 20703a69cae8SSudarsana Reddy Kalluru name, image->data, (u32)image->size); 20713a69cae8SSudarsana Reddy Kalluru data = image->data; 20723a69cae8SSudarsana Reddy Kalluru data_end = data + image->size; 20733a69cae8SSudarsana Reddy Kalluru 20743a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_validate(cdev, image, &data); 20753a69cae8SSudarsana Reddy Kalluru if (rc) 20763a69cae8SSudarsana Reddy Kalluru goto exit; 20773a69cae8SSudarsana Reddy Kalluru 20783a69cae8SSudarsana Reddy Kalluru while (data < data_end) { 20793a69cae8SSudarsana Reddy Kalluru bool check_resp = false; 20803a69cae8SSudarsana Reddy Kalluru 20813a69cae8SSudarsana Reddy Kalluru /* Parse the actual command */ 20823a69cae8SSudarsana Reddy Kalluru cmd_type = *((u32 *)data); 20833a69cae8SSudarsana Reddy Kalluru switch (cmd_type) { 20843a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_DATA: 20853a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_data(cdev, &data, 20863a69cae8SSudarsana Reddy Kalluru &check_resp); 20873a69cae8SSudarsana Reddy Kalluru break; 20883a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_FILE_START: 20893a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_file_start(cdev, &data, 20903a69cae8SSudarsana Reddy Kalluru &check_resp); 20913a69cae8SSudarsana Reddy Kalluru break; 20923a69cae8SSudarsana Reddy Kalluru case QED_NVM_FLASH_CMD_NVM_CHANGE: 20933a69cae8SSudarsana Reddy Kalluru rc = qed_nvm_flash_image_access(cdev, &data, 20943a69cae8SSudarsana Reddy Kalluru &check_resp); 20953a69cae8SSudarsana Reddy Kalluru break; 20963a69cae8SSudarsana Reddy Kalluru default: 20973a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Unknown command %08x\n", cmd_type); 20983a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 20993a69cae8SSudarsana Reddy Kalluru goto exit; 21003a69cae8SSudarsana Reddy Kalluru } 21013a69cae8SSudarsana Reddy Kalluru 21023a69cae8SSudarsana Reddy Kalluru if (rc) { 21033a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Command %08x failed\n", cmd_type); 21043a69cae8SSudarsana Reddy Kalluru goto exit; 21053a69cae8SSudarsana Reddy Kalluru } 21063a69cae8SSudarsana Reddy Kalluru 21073a69cae8SSudarsana Reddy Kalluru /* Check response if needed */ 21083a69cae8SSudarsana Reddy Kalluru if (check_resp) { 21093a69cae8SSudarsana Reddy Kalluru u32 mcp_response = 0; 21103a69cae8SSudarsana Reddy Kalluru 21113a69cae8SSudarsana Reddy Kalluru if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) { 21123a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "Failed getting MCP response\n"); 21133a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 21143a69cae8SSudarsana Reddy Kalluru goto exit; 21153a69cae8SSudarsana Reddy Kalluru } 21163a69cae8SSudarsana Reddy Kalluru 21173a69cae8SSudarsana Reddy Kalluru switch (mcp_response & FW_MSG_CODE_MASK) { 21183a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_OK: 21193a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_OK: 21203a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK: 21213a69cae8SSudarsana Reddy Kalluru case FW_MSG_CODE_PHY_OK: 21223a69cae8SSudarsana Reddy Kalluru break; 21233a69cae8SSudarsana Reddy Kalluru default: 21243a69cae8SSudarsana Reddy Kalluru DP_ERR(cdev, "MFW returns error: %08x\n", 21253a69cae8SSudarsana Reddy Kalluru mcp_response); 21263a69cae8SSudarsana Reddy Kalluru rc = -EINVAL; 21273a69cae8SSudarsana Reddy Kalluru goto exit; 21283a69cae8SSudarsana Reddy Kalluru } 21293a69cae8SSudarsana Reddy Kalluru } 21303a69cae8SSudarsana Reddy Kalluru } 21313a69cae8SSudarsana Reddy Kalluru 21323a69cae8SSudarsana Reddy Kalluru exit: 21333a69cae8SSudarsana Reddy Kalluru release_firmware(image); 21343a69cae8SSudarsana Reddy Kalluru 21353a69cae8SSudarsana Reddy Kalluru return rc; 21363a69cae8SSudarsana Reddy Kalluru } 21373a69cae8SSudarsana Reddy Kalluru 213820675b37SMintz, Yuval static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, 213920675b37SMintz, Yuval u8 *buf, u16 len) 214020675b37SMintz, Yuval { 214120675b37SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 214220675b37SMintz, Yuval 2143b60bfdfeSDenis Bolotin return qed_mcp_get_nvm_image(hwfn, type, buf, len); 214420675b37SMintz, Yuval } 214520675b37SMintz, Yuval 2146722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, 2147477f2d14SRahul Verma void *handle) 2148722003acSSudarsana Reddy Kalluru { 2149477f2d14SRahul Verma return qed_set_queue_coalesce(rx_coal, tx_coal, handle); 2150722003acSSudarsana Reddy Kalluru } 2151722003acSSudarsana Reddy Kalluru 215291420b83SSudarsana Kalluru static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) 215391420b83SSudarsana Kalluru { 215491420b83SSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 215591420b83SSudarsana Kalluru struct qed_ptt *ptt; 215691420b83SSudarsana Kalluru int status = 0; 215791420b83SSudarsana Kalluru 215891420b83SSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 215991420b83SSudarsana Kalluru if (!ptt) 216091420b83SSudarsana Kalluru return -EAGAIN; 216191420b83SSudarsana Kalluru 216291420b83SSudarsana Kalluru status = qed_mcp_set_led(hwfn, ptt, mode); 216391420b83SSudarsana Kalluru 216491420b83SSudarsana Kalluru qed_ptt_release(hwfn, ptt); 216591420b83SSudarsana Kalluru 216691420b83SSudarsana Kalluru return status; 216791420b83SSudarsana Kalluru } 216891420b83SSudarsana Kalluru 216914d39648SMintz, Yuval static int qed_update_wol(struct qed_dev *cdev, bool enabled) 217014d39648SMintz, Yuval { 217114d39648SMintz, Yuval struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 217214d39648SMintz, Yuval struct qed_ptt *ptt; 217314d39648SMintz, Yuval int rc = 0; 217414d39648SMintz, Yuval 217514d39648SMintz, Yuval if (IS_VF(cdev)) 217614d39648SMintz, Yuval return 0; 217714d39648SMintz, Yuval 217814d39648SMintz, Yuval ptt = qed_ptt_acquire(hwfn); 217914d39648SMintz, Yuval if (!ptt) 218014d39648SMintz, Yuval return -EAGAIN; 218114d39648SMintz, Yuval 218214d39648SMintz, Yuval rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED 218314d39648SMintz, Yuval : QED_OV_WOL_DISABLED); 218414d39648SMintz, Yuval if (rc) 218514d39648SMintz, Yuval goto out; 218614d39648SMintz, Yuval rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 218714d39648SMintz, Yuval 218814d39648SMintz, Yuval out: 218914d39648SMintz, Yuval qed_ptt_release(hwfn, ptt); 219014d39648SMintz, Yuval return rc; 219114d39648SMintz, Yuval } 219214d39648SMintz, Yuval 21930fefbfbaSSudarsana Kalluru static int qed_update_drv_state(struct qed_dev *cdev, bool active) 21940fefbfbaSSudarsana Kalluru { 21950fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 21960fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 21970fefbfbaSSudarsana Kalluru int status = 0; 21980fefbfbaSSudarsana Kalluru 21990fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 22000fefbfbaSSudarsana Kalluru return 0; 22010fefbfbaSSudarsana Kalluru 22020fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 22030fefbfbaSSudarsana Kalluru if (!ptt) 22040fefbfbaSSudarsana Kalluru return -EAGAIN; 22050fefbfbaSSudarsana Kalluru 22060fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? 22070fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_ACTIVE : 22080fefbfbaSSudarsana Kalluru QED_OV_DRIVER_STATE_DISABLED); 22090fefbfbaSSudarsana Kalluru 22100fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 22110fefbfbaSSudarsana Kalluru 22120fefbfbaSSudarsana Kalluru return status; 22130fefbfbaSSudarsana Kalluru } 22140fefbfbaSSudarsana Kalluru 22150fefbfbaSSudarsana Kalluru static int qed_update_mac(struct qed_dev *cdev, u8 *mac) 22160fefbfbaSSudarsana Kalluru { 22170fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 22180fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 22190fefbfbaSSudarsana Kalluru int status = 0; 22200fefbfbaSSudarsana Kalluru 22210fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 22220fefbfbaSSudarsana Kalluru return 0; 22230fefbfbaSSudarsana Kalluru 22240fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 22250fefbfbaSSudarsana Kalluru if (!ptt) 22260fefbfbaSSudarsana Kalluru return -EAGAIN; 22270fefbfbaSSudarsana Kalluru 22280fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mac(hwfn, ptt, mac); 22290fefbfbaSSudarsana Kalluru if (status) 22300fefbfbaSSudarsana Kalluru goto out; 22310fefbfbaSSudarsana Kalluru 22320fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 22330fefbfbaSSudarsana Kalluru 22340fefbfbaSSudarsana Kalluru out: 22350fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 22360fefbfbaSSudarsana Kalluru return status; 22370fefbfbaSSudarsana Kalluru } 22380fefbfbaSSudarsana Kalluru 22390fefbfbaSSudarsana Kalluru static int qed_update_mtu(struct qed_dev *cdev, u16 mtu) 22400fefbfbaSSudarsana Kalluru { 22410fefbfbaSSudarsana Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 22420fefbfbaSSudarsana Kalluru struct qed_ptt *ptt; 22430fefbfbaSSudarsana Kalluru int status = 0; 22440fefbfbaSSudarsana Kalluru 22450fefbfbaSSudarsana Kalluru if (IS_VF(cdev)) 22460fefbfbaSSudarsana Kalluru return 0; 22470fefbfbaSSudarsana Kalluru 22480fefbfbaSSudarsana Kalluru ptt = qed_ptt_acquire(hwfn); 22490fefbfbaSSudarsana Kalluru if (!ptt) 22500fefbfbaSSudarsana Kalluru return -EAGAIN; 22510fefbfbaSSudarsana Kalluru 22520fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); 22530fefbfbaSSudarsana Kalluru if (status) 22540fefbfbaSSudarsana Kalluru goto out; 22550fefbfbaSSudarsana Kalluru 22560fefbfbaSSudarsana Kalluru status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); 22570fefbfbaSSudarsana Kalluru 22580fefbfbaSSudarsana Kalluru out: 22590fefbfbaSSudarsana Kalluru qed_ptt_release(hwfn, ptt); 22600fefbfbaSSudarsana Kalluru return status; 22610fefbfbaSSudarsana Kalluru } 22620fefbfbaSSudarsana Kalluru 2263b51dab46SSudarsana Reddy Kalluru static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 2264b51dab46SSudarsana Reddy Kalluru u8 dev_addr, u32 offset, u32 len) 2265b51dab46SSudarsana Reddy Kalluru { 2266b51dab46SSudarsana Reddy Kalluru struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 2267b51dab46SSudarsana Reddy Kalluru struct qed_ptt *ptt; 2268b51dab46SSudarsana Reddy Kalluru int rc = 0; 2269b51dab46SSudarsana Reddy Kalluru 2270b51dab46SSudarsana Reddy Kalluru if (IS_VF(cdev)) 2271b51dab46SSudarsana Reddy Kalluru return 0; 2272b51dab46SSudarsana Reddy Kalluru 2273b51dab46SSudarsana Reddy Kalluru ptt = qed_ptt_acquire(hwfn); 2274b51dab46SSudarsana Reddy Kalluru if (!ptt) 2275b51dab46SSudarsana Reddy Kalluru return -EAGAIN; 2276b51dab46SSudarsana Reddy Kalluru 2277b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr, 2278b51dab46SSudarsana Reddy Kalluru offset, len, buf); 2279b51dab46SSudarsana Reddy Kalluru 2280b51dab46SSudarsana Reddy Kalluru qed_ptt_release(hwfn, ptt); 2281b51dab46SSudarsana Reddy Kalluru 2282b51dab46SSudarsana Reddy Kalluru return rc; 2283b51dab46SSudarsana Reddy Kalluru } 2284b51dab46SSudarsana Reddy Kalluru 22858c93beafSYuval Mintz static struct qed_selftest_ops qed_selftest_ops_pass = { 228603dc76caSSudarsana Reddy Kalluru .selftest_memory = &qed_selftest_memory, 228703dc76caSSudarsana Reddy Kalluru .selftest_interrupt = &qed_selftest_interrupt, 228803dc76caSSudarsana Reddy Kalluru .selftest_register = &qed_selftest_register, 228903dc76caSSudarsana Reddy Kalluru .selftest_clock = &qed_selftest_clock, 22907a4b21b7SMintz, Yuval .selftest_nvram = &qed_selftest_nvram, 229103dc76caSSudarsana Reddy Kalluru }; 229203dc76caSSudarsana Reddy Kalluru 2293fe56b9e6SYuval Mintz const struct qed_common_ops qed_common_ops_pass = { 229403dc76caSSudarsana Reddy Kalluru .selftest = &qed_selftest_ops_pass, 2295fe56b9e6SYuval Mintz .probe = &qed_probe, 2296fe56b9e6SYuval Mintz .remove = &qed_remove, 2297fe56b9e6SYuval Mintz .set_power_state = &qed_set_power_state, 2298712c3cbfSMintz, Yuval .set_name = &qed_set_name, 2299fe56b9e6SYuval Mintz .update_pf_params = &qed_update_pf_params, 2300fe56b9e6SYuval Mintz .slowpath_start = &qed_slowpath_start, 2301fe56b9e6SYuval Mintz .slowpath_stop = &qed_slowpath_stop, 2302fe56b9e6SYuval Mintz .set_fp_int = &qed_set_int_fp, 2303fe56b9e6SYuval Mintz .get_fp_int = &qed_get_int_fp, 2304fe56b9e6SYuval Mintz .sb_init = &qed_sb_init, 2305fe56b9e6SYuval Mintz .sb_release = &qed_sb_release, 2306fe56b9e6SYuval Mintz .simd_handler_config = &qed_simd_handler_config, 2307fe56b9e6SYuval Mintz .simd_handler_clean = &qed_simd_handler_clean, 23081e128c81SArun Easi .dbg_grc = &qed_dbg_grc, 23091e128c81SArun Easi .dbg_grc_size = &qed_dbg_grc_size, 2310fe7cd2bfSYuval Mintz .can_link_change = &qed_can_link_change, 2311cc875c2eSYuval Mintz .set_link = &qed_set_link, 2312cc875c2eSYuval Mintz .get_link = &qed_get_current_link, 2313fe56b9e6SYuval Mintz .drain = &qed_drain, 2314fe56b9e6SYuval Mintz .update_msglvl = &qed_init_dp, 2315e0971c83STomer Tayar .dbg_all_data = &qed_dbg_all_data, 2316e0971c83STomer Tayar .dbg_all_data_size = &qed_dbg_all_data_size, 2317fe56b9e6SYuval Mintz .chain_alloc = &qed_chain_alloc, 2318fe56b9e6SYuval Mintz .chain_free = &qed_chain_free, 23193a69cae8SSudarsana Reddy Kalluru .nvm_flash = &qed_nvm_flash, 232020675b37SMintz, Yuval .nvm_get_image = &qed_nvm_get_image, 2321722003acSSudarsana Reddy Kalluru .set_coalesce = &qed_set_coalesce, 232291420b83SSudarsana Kalluru .set_led = &qed_set_led, 23230fefbfbaSSudarsana Kalluru .update_drv_state = &qed_update_drv_state, 23240fefbfbaSSudarsana Kalluru .update_mac = &qed_update_mac, 23250fefbfbaSSudarsana Kalluru .update_mtu = &qed_update_mtu, 232614d39648SMintz, Yuval .update_wol = &qed_update_wol, 2327b51dab46SSudarsana Reddy Kalluru .read_module_eeprom = &qed_read_module_eeprom, 2328fe56b9e6SYuval Mintz }; 23296c754246SSudarsana Reddy Kalluru 23306c754246SSudarsana Reddy Kalluru void qed_get_protocol_stats(struct qed_dev *cdev, 23316c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type type, 23326c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats *stats) 23336c754246SSudarsana Reddy Kalluru { 23346c754246SSudarsana Reddy Kalluru struct qed_eth_stats eth_stats; 23356c754246SSudarsana Reddy Kalluru 23366c754246SSudarsana Reddy Kalluru memset(stats, 0, sizeof(*stats)); 23376c754246SSudarsana Reddy Kalluru 23386c754246SSudarsana Reddy Kalluru switch (type) { 23396c754246SSudarsana Reddy Kalluru case QED_MCP_LAN_STATS: 23406c754246SSudarsana Reddy Kalluru qed_get_vport_stats(cdev, ð_stats); 23419c79ddaaSMintz, Yuval stats->lan_stats.ucast_rx_pkts = 23429c79ddaaSMintz, Yuval eth_stats.common.rx_ucast_pkts; 23439c79ddaaSMintz, Yuval stats->lan_stats.ucast_tx_pkts = 23449c79ddaaSMintz, Yuval eth_stats.common.tx_ucast_pkts; 23456c754246SSudarsana Reddy Kalluru stats->lan_stats.fcs_err = -1; 23466c754246SSudarsana Reddy Kalluru break; 23471e128c81SArun Easi case QED_MCP_FCOE_STATS: 23481e128c81SArun Easi qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); 23491e128c81SArun Easi break; 23502f2b2614SMintz, Yuval case QED_MCP_ISCSI_STATS: 23512f2b2614SMintz, Yuval qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); 23522f2b2614SMintz, Yuval break; 23536c754246SSudarsana Reddy Kalluru default: 2354512c7840SMintz, Yuval DP_VERBOSE(cdev, QED_MSG_SP, 2355512c7840SMintz, Yuval "Invalid protocol type = %d\n", type); 23566c754246SSudarsana Reddy Kalluru return; 23576c754246SSudarsana Reddy Kalluru } 23586c754246SSudarsana Reddy Kalluru } 23592528c389SSudarsana Reddy Kalluru 236059ccf86fSSudarsana Reddy Kalluru int qed_mfw_tlv_req(struct qed_hwfn *hwfn) 236159ccf86fSSudarsana Reddy Kalluru { 236259ccf86fSSudarsana Reddy Kalluru DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, 236359ccf86fSSudarsana Reddy Kalluru "Scheduling slowpath task [Flag: %d]\n", 236459ccf86fSSudarsana Reddy Kalluru QED_SLOWPATH_MFW_TLV_REQ); 236559ccf86fSSudarsana Reddy Kalluru smp_mb__before_atomic(); 236659ccf86fSSudarsana Reddy Kalluru set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags); 236759ccf86fSSudarsana Reddy Kalluru smp_mb__after_atomic(); 236859ccf86fSSudarsana Reddy Kalluru queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0); 236959ccf86fSSudarsana Reddy Kalluru 237059ccf86fSSudarsana Reddy Kalluru return 0; 237159ccf86fSSudarsana Reddy Kalluru } 237259ccf86fSSudarsana Reddy Kalluru 237359ccf86fSSudarsana Reddy Kalluru static void 237459ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv) 237559ccf86fSSudarsana Reddy Kalluru { 237659ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *op = cdev->protocol_ops.common; 237759ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats_common *p_common; 237859ccf86fSSudarsana Reddy Kalluru struct qed_generic_tlvs gen_tlvs; 237959ccf86fSSudarsana Reddy Kalluru struct qed_eth_stats stats; 238059ccf86fSSudarsana Reddy Kalluru int i; 238159ccf86fSSudarsana Reddy Kalluru 238259ccf86fSSudarsana Reddy Kalluru memset(&gen_tlvs, 0, sizeof(gen_tlvs)); 238359ccf86fSSudarsana Reddy Kalluru op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs); 238459ccf86fSSudarsana Reddy Kalluru 238559ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM) 238659ccf86fSSudarsana Reddy Kalluru tlv->flags.ipv4_csum_offload = true; 238759ccf86fSSudarsana Reddy Kalluru if (gen_tlvs.feat_flags & QED_TLV_LSO) 238859ccf86fSSudarsana Reddy Kalluru tlv->flags.lso_supported = true; 238959ccf86fSSudarsana Reddy Kalluru tlv->flags.b_set = true; 239059ccf86fSSudarsana Reddy Kalluru 239159ccf86fSSudarsana Reddy Kalluru for (i = 0; i < QED_TLV_MAC_COUNT; i++) { 239259ccf86fSSudarsana Reddy Kalluru if (is_valid_ether_addr(gen_tlvs.mac[i])) { 239359ccf86fSSudarsana Reddy Kalluru ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]); 239459ccf86fSSudarsana Reddy Kalluru tlv->mac_set[i] = true; 239559ccf86fSSudarsana Reddy Kalluru } 239659ccf86fSSudarsana Reddy Kalluru } 239759ccf86fSSudarsana Reddy Kalluru 239859ccf86fSSudarsana Reddy Kalluru qed_get_vport_stats(cdev, &stats); 239959ccf86fSSudarsana Reddy Kalluru p_common = &stats.common; 240059ccf86fSSudarsana Reddy Kalluru tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 240159ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_pkts; 240259ccf86fSSudarsana Reddy Kalluru tlv->rx_frames_set = true; 240359ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 240459ccf86fSSudarsana Reddy Kalluru p_common->rx_bcast_bytes; 240559ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 240659ccf86fSSudarsana Reddy Kalluru tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 240759ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_pkts; 240859ccf86fSSudarsana Reddy Kalluru tlv->tx_frames_set = true; 240959ccf86fSSudarsana Reddy Kalluru tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 241059ccf86fSSudarsana Reddy Kalluru p_common->tx_bcast_bytes; 241159ccf86fSSudarsana Reddy Kalluru tlv->rx_bytes_set = true; 241259ccf86fSSudarsana Reddy Kalluru } 241359ccf86fSSudarsana Reddy Kalluru 24142528c389SSudarsana Reddy Kalluru int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type, 24152528c389SSudarsana Reddy Kalluru union qed_mfw_tlv_data *tlv_buf) 24162528c389SSudarsana Reddy Kalluru { 241759ccf86fSSudarsana Reddy Kalluru struct qed_dev *cdev = hwfn->cdev; 241859ccf86fSSudarsana Reddy Kalluru struct qed_common_cb_ops *ops; 241959ccf86fSSudarsana Reddy Kalluru 242059ccf86fSSudarsana Reddy Kalluru ops = cdev->protocol_ops.common; 242159ccf86fSSudarsana Reddy Kalluru if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) { 242259ccf86fSSudarsana Reddy Kalluru DP_NOTICE(hwfn, "Can't collect TLV management info\n"); 24232528c389SSudarsana Reddy Kalluru return -EINVAL; 24242528c389SSudarsana Reddy Kalluru } 242559ccf86fSSudarsana Reddy Kalluru 242659ccf86fSSudarsana Reddy Kalluru switch (type) { 242759ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_GENERIC: 242859ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic); 242959ccf86fSSudarsana Reddy Kalluru break; 243059ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ETH: 243159ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth); 243259ccf86fSSudarsana Reddy Kalluru break; 243359ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_FCOE: 243459ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe); 243559ccf86fSSudarsana Reddy Kalluru break; 243659ccf86fSSudarsana Reddy Kalluru case QED_MFW_TLV_ISCSI: 243759ccf86fSSudarsana Reddy Kalluru ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi); 243859ccf86fSSudarsana Reddy Kalluru break; 243959ccf86fSSudarsana Reddy Kalluru default: 244059ccf86fSSudarsana Reddy Kalluru break; 244159ccf86fSSudarsana Reddy Kalluru } 244259ccf86fSSudarsana Reddy Kalluru 244359ccf86fSSudarsana Reddy Kalluru return 0; 244459ccf86fSSudarsana Reddy Kalluru } 2445