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