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"
42fe56b9e6SYuval Mintz 
4351ff1725SRam Amrani #define QED_ROCE_QPS			(8192)
4451ff1725SRam Amrani #define QED_ROCE_DPIS			(8)
4539dbc646SYuval Bason #define QED_RDMA_SRQS                   QED_ROCE_QPS
462d4c8495SSudarsana Reddy Kalluru #define QED_NVM_CFG_GET_FLAGS		0xA
472d4c8495SSudarsana Reddy Kalluru #define QED_NVM_CFG_GET_PF_FLAGS	0x1A
48c63b0968SSudarsana Reddy Kalluru #define QED_NVM_CFG_MAX_ATTRS		50
4951ff1725SRam Amrani 
505abd7e92SYuval Mintz static char version[] =
515abd7e92SYuval Mintz 	"QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n";
52fe56b9e6SYuval Mintz 
535abd7e92SYuval Mintz MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module");
54fe56b9e6SYuval Mintz MODULE_LICENSE("GPL");
55fe56b9e6SYuval Mintz MODULE_VERSION(DRV_MODULE_VERSION);
56fe56b9e6SYuval Mintz 
57fe56b9e6SYuval Mintz #define FW_FILE_VERSION				\
58fe56b9e6SYuval Mintz 	__stringify(FW_MAJOR_VERSION) "."	\
59fe56b9e6SYuval Mintz 	__stringify(FW_MINOR_VERSION) "."	\
60fe56b9e6SYuval Mintz 	__stringify(FW_REVISION_VERSION) "."	\
61fe56b9e6SYuval Mintz 	__stringify(FW_ENGINEERING_VERSION)
62fe56b9e6SYuval Mintz 
63fe56b9e6SYuval Mintz #define QED_FW_FILE_NAME	\
64fe56b9e6SYuval Mintz 	"qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin"
65fe56b9e6SYuval Mintz 
66d43d3f0fSYuval Mintz MODULE_FIRMWARE(QED_FW_FILE_NAME);
67d43d3f0fSYuval Mintz 
68097818fcSAlexander Lobakin /* MFW speed capabilities maps */
69097818fcSAlexander Lobakin 
70097818fcSAlexander Lobakin struct qed_mfw_speed_map {
71097818fcSAlexander Lobakin 	u32		mfw_val;
72097818fcSAlexander Lobakin 	__ETHTOOL_DECLARE_LINK_MODE_MASK(caps);
73097818fcSAlexander Lobakin 
74097818fcSAlexander Lobakin 	const u32	*cap_arr;
75097818fcSAlexander Lobakin 	u32		arr_size;
76097818fcSAlexander Lobakin };
77097818fcSAlexander Lobakin 
78097818fcSAlexander Lobakin #define QED_MFW_SPEED_MAP(type, arr)		\
79097818fcSAlexander Lobakin {						\
80097818fcSAlexander Lobakin 	.mfw_val	= (type),		\
81097818fcSAlexander Lobakin 	.cap_arr	= (arr),		\
82097818fcSAlexander Lobakin 	.arr_size	= ARRAY_SIZE(arr),	\
83097818fcSAlexander Lobakin }
84097818fcSAlexander Lobakin 
8599785a87SAlexander Lobakin static const u32 qed_mfw_ext_1g[] __initconst = {
8699785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
8799785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
8899785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
8999785a87SAlexander Lobakin };
9099785a87SAlexander Lobakin 
9199785a87SAlexander Lobakin static const u32 qed_mfw_ext_10g[] __initconst = {
9299785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
9399785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
9499785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
9599785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
9699785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
9799785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
9899785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
9999785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
10099785a87SAlexander Lobakin };
10199785a87SAlexander Lobakin 
10299785a87SAlexander Lobakin static const u32 qed_mfw_ext_20g[] __initconst = {
10399785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
10499785a87SAlexander Lobakin };
10599785a87SAlexander Lobakin 
10699785a87SAlexander Lobakin static const u32 qed_mfw_ext_25g[] __initconst = {
10799785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
10899785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
10999785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
11099785a87SAlexander Lobakin };
11199785a87SAlexander Lobakin 
11299785a87SAlexander Lobakin static const u32 qed_mfw_ext_40g[] __initconst = {
11399785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
11499785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
11599785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
11699785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
11799785a87SAlexander Lobakin };
11899785a87SAlexander Lobakin 
11999785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r[] __initconst = {
12099785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
12199785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
12299785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
12399785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
12499785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
12599785a87SAlexander Lobakin };
12699785a87SAlexander Lobakin 
12799785a87SAlexander Lobakin static const u32 qed_mfw_ext_50g_base_r2[] __initconst = {
12899785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
12999785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
13099785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
13199785a87SAlexander Lobakin };
13299785a87SAlexander Lobakin 
13399785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r2[] __initconst = {
13499785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
13599785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
13699785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
13799785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
13899785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
13999785a87SAlexander Lobakin };
14099785a87SAlexander Lobakin 
14199785a87SAlexander Lobakin static const u32 qed_mfw_ext_100g_base_r4[] __initconst = {
14299785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
14399785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
14499785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
14599785a87SAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
14699785a87SAlexander Lobakin };
14799785a87SAlexander Lobakin 
14899785a87SAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_ext_maps[] __ro_after_init = {
14999785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_1G, qed_mfw_ext_1g),
15099785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_10G, qed_mfw_ext_10g),
15199785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_20G, qed_mfw_ext_20g),
15299785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_25G, qed_mfw_ext_25g),
15399785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_40G, qed_mfw_ext_40g),
15499785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R,
15599785a87SAlexander Lobakin 			  qed_mfw_ext_50g_base_r),
15699785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_50G_BASE_R2,
15799785a87SAlexander Lobakin 			  qed_mfw_ext_50g_base_r2),
15899785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R2,
15999785a87SAlexander Lobakin 			  qed_mfw_ext_100g_base_r2),
16099785a87SAlexander Lobakin 	QED_MFW_SPEED_MAP(ETH_EXT_ADV_SPEED_100G_BASE_R4,
16199785a87SAlexander Lobakin 			  qed_mfw_ext_100g_base_r4),
16299785a87SAlexander Lobakin };
16399785a87SAlexander Lobakin 
164097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_1g[] __initconst = {
165097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
166097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
167097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
168097818fcSAlexander Lobakin };
169097818fcSAlexander Lobakin 
170097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_10g[] __initconst = {
171097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
172097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
173097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
174097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
175097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
176097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
177097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
178097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
179097818fcSAlexander Lobakin };
180097818fcSAlexander Lobakin 
181097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_20g[] __initconst = {
182097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
183097818fcSAlexander Lobakin };
184097818fcSAlexander Lobakin 
185097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_25g[] __initconst = {
186097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
187097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
188097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
189097818fcSAlexander Lobakin };
190097818fcSAlexander Lobakin 
191097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_40g[] __initconst = {
192097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
193097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
194097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
195097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
196097818fcSAlexander Lobakin };
197097818fcSAlexander Lobakin 
198097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_50g[] __initconst = {
199097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
200097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
201097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
202097818fcSAlexander Lobakin };
203097818fcSAlexander Lobakin 
204097818fcSAlexander Lobakin static const u32 qed_mfw_legacy_bb_100g[] __initconst = {
205097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
206097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
207097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
208097818fcSAlexander Lobakin 	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
209097818fcSAlexander Lobakin };
210097818fcSAlexander Lobakin 
211097818fcSAlexander Lobakin static struct qed_mfw_speed_map qed_mfw_legacy_maps[] __ro_after_init = {
212097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G,
213097818fcSAlexander Lobakin 			  qed_mfw_legacy_1g),
214097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G,
215097818fcSAlexander Lobakin 			  qed_mfw_legacy_10g),
216097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G,
217097818fcSAlexander Lobakin 			  qed_mfw_legacy_20g),
218097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G,
219097818fcSAlexander Lobakin 			  qed_mfw_legacy_25g),
220097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G,
221097818fcSAlexander Lobakin 			  qed_mfw_legacy_40g),
222097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G,
223097818fcSAlexander Lobakin 			  qed_mfw_legacy_50g),
224097818fcSAlexander Lobakin 	QED_MFW_SPEED_MAP(NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G,
225097818fcSAlexander Lobakin 			  qed_mfw_legacy_bb_100g),
226097818fcSAlexander Lobakin };
227097818fcSAlexander Lobakin 
228097818fcSAlexander Lobakin static void __init qed_mfw_speed_map_populate(struct qed_mfw_speed_map *map)
229097818fcSAlexander Lobakin {
230097818fcSAlexander Lobakin 	linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps);
231097818fcSAlexander Lobakin 
232097818fcSAlexander Lobakin 	map->cap_arr = NULL;
233097818fcSAlexander Lobakin 	map->arr_size = 0;
234097818fcSAlexander Lobakin }
235097818fcSAlexander Lobakin 
236097818fcSAlexander Lobakin static void __init qed_mfw_speed_maps_init(void)
237097818fcSAlexander Lobakin {
238097818fcSAlexander Lobakin 	u32 i;
239097818fcSAlexander Lobakin 
24099785a87SAlexander Lobakin 	for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++)
24199785a87SAlexander Lobakin 		qed_mfw_speed_map_populate(qed_mfw_ext_maps + i);
24299785a87SAlexander Lobakin 
243097818fcSAlexander Lobakin 	for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++)
244097818fcSAlexander Lobakin 		qed_mfw_speed_map_populate(qed_mfw_legacy_maps + i);
245097818fcSAlexander Lobakin }
246097818fcSAlexander Lobakin 
247fe56b9e6SYuval Mintz static int __init qed_init(void)
248fe56b9e6SYuval Mintz {
249fe56b9e6SYuval Mintz 	pr_info("%s", version);
250fe56b9e6SYuval Mintz 
251097818fcSAlexander Lobakin 	qed_mfw_speed_maps_init();
252097818fcSAlexander Lobakin 
253fe56b9e6SYuval Mintz 	return 0;
254fe56b9e6SYuval Mintz }
255fe56b9e6SYuval Mintz module_init(qed_init);
256097818fcSAlexander Lobakin 
257097818fcSAlexander Lobakin static void __exit qed_exit(void)
258097818fcSAlexander Lobakin {
259097818fcSAlexander Lobakin 	/* To prevent marking this module as "permanent" */
260097818fcSAlexander Lobakin }
261097818fcSAlexander Lobakin module_exit(qed_exit);
262fe56b9e6SYuval Mintz 
263fe56b9e6SYuval Mintz /* Check if the DMA controller on the machine can properly handle the DMA
264fe56b9e6SYuval Mintz  * addressing required by the device.
265fe56b9e6SYuval Mintz */
266fe56b9e6SYuval Mintz static int qed_set_coherency_mask(struct qed_dev *cdev)
267fe56b9e6SYuval Mintz {
268fe56b9e6SYuval Mintz 	struct device *dev = &cdev->pdev->dev;
269fe56b9e6SYuval Mintz 
270fe56b9e6SYuval Mintz 	if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) {
271fe56b9e6SYuval Mintz 		if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) {
272fe56b9e6SYuval Mintz 			DP_NOTICE(cdev,
273fe56b9e6SYuval Mintz 				  "Can't request 64-bit consistent allocations\n");
274fe56b9e6SYuval Mintz 			return -EIO;
275fe56b9e6SYuval Mintz 		}
276fe56b9e6SYuval Mintz 	} else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) {
277fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n");
278fe56b9e6SYuval Mintz 		return -EIO;
279fe56b9e6SYuval Mintz 	}
280fe56b9e6SYuval Mintz 
281fe56b9e6SYuval Mintz 	return 0;
282fe56b9e6SYuval Mintz }
283fe56b9e6SYuval Mintz 
284fe56b9e6SYuval Mintz static void qed_free_pci(struct qed_dev *cdev)
285fe56b9e6SYuval Mintz {
286fe56b9e6SYuval Mintz 	struct pci_dev *pdev = cdev->pdev;
287fe56b9e6SYuval Mintz 
2882196d831SSudarsana Reddy Kalluru 	pci_disable_pcie_error_reporting(pdev);
2892196d831SSudarsana Reddy Kalluru 
2901a850bfcSMintz, Yuval 	if (cdev->doorbells && cdev->db_size)
291fe56b9e6SYuval Mintz 		iounmap(cdev->doorbells);
292fe56b9e6SYuval Mintz 	if (cdev->regview)
293fe56b9e6SYuval Mintz 		iounmap(cdev->regview);
294fe56b9e6SYuval Mintz 	if (atomic_read(&pdev->enable_cnt) == 1)
295fe56b9e6SYuval Mintz 		pci_release_regions(pdev);
296fe56b9e6SYuval Mintz 
297fe56b9e6SYuval Mintz 	pci_disable_device(pdev);
298fe56b9e6SYuval Mintz }
299fe56b9e6SYuval Mintz 
3000dfaba6dSYuval Mintz #define PCI_REVISION_ID_ERROR_VAL	0xff
3010dfaba6dSYuval Mintz 
302fe56b9e6SYuval Mintz /* Performs PCI initializations as well as initializing PCI-related parameters
303fe56b9e6SYuval Mintz  * in the device structrue. Returns 0 in case of success.
304fe56b9e6SYuval Mintz  */
3051a635e48SYuval Mintz static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev)
306fe56b9e6SYuval Mintz {
3070dfaba6dSYuval Mintz 	u8 rev_id;
308fe56b9e6SYuval Mintz 	int rc;
309fe56b9e6SYuval Mintz 
310fe56b9e6SYuval Mintz 	cdev->pdev = pdev;
311fe56b9e6SYuval Mintz 
312fe56b9e6SYuval Mintz 	rc = pci_enable_device(pdev);
313fe56b9e6SYuval Mintz 	if (rc) {
314fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Cannot enable PCI device\n");
315fe56b9e6SYuval Mintz 		goto err0;
316fe56b9e6SYuval Mintz 	}
317fe56b9e6SYuval Mintz 
318fe56b9e6SYuval Mintz 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
319fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "No memory region found in bar #0\n");
320fe56b9e6SYuval Mintz 		rc = -EIO;
321fe56b9e6SYuval Mintz 		goto err1;
322fe56b9e6SYuval Mintz 	}
323fe56b9e6SYuval Mintz 
3241408cc1fSYuval Mintz 	if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
325fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "No memory region found in bar #2\n");
326fe56b9e6SYuval Mintz 		rc = -EIO;
327fe56b9e6SYuval Mintz 		goto err1;
328fe56b9e6SYuval Mintz 	}
329fe56b9e6SYuval Mintz 
330fe56b9e6SYuval Mintz 	if (atomic_read(&pdev->enable_cnt) == 1) {
331fe56b9e6SYuval Mintz 		rc = pci_request_regions(pdev, "qed");
332fe56b9e6SYuval Mintz 		if (rc) {
333fe56b9e6SYuval Mintz 			DP_NOTICE(cdev,
334fe56b9e6SYuval Mintz 				  "Failed to request PCI memory resources\n");
335fe56b9e6SYuval Mintz 			goto err1;
336fe56b9e6SYuval Mintz 		}
337fe56b9e6SYuval Mintz 		pci_set_master(pdev);
338fe56b9e6SYuval Mintz 		pci_save_state(pdev);
339fe56b9e6SYuval Mintz 	}
340fe56b9e6SYuval Mintz 
3410dfaba6dSYuval Mintz 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
3420dfaba6dSYuval Mintz 	if (rev_id == PCI_REVISION_ID_ERROR_VAL) {
3430dfaba6dSYuval Mintz 		DP_NOTICE(cdev,
3440dfaba6dSYuval Mintz 			  "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n",
3450dfaba6dSYuval Mintz 			  rev_id);
3460dfaba6dSYuval Mintz 		rc = -ENODEV;
3470dfaba6dSYuval Mintz 		goto err2;
3480dfaba6dSYuval Mintz 	}
349fe56b9e6SYuval Mintz 	if (!pci_is_pcie(pdev)) {
350fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "The bus is not PCI Express\n");
351fe56b9e6SYuval Mintz 		rc = -EIO;
352fe56b9e6SYuval Mintz 		goto err2;
353fe56b9e6SYuval Mintz 	}
354fe56b9e6SYuval Mintz 
355fe56b9e6SYuval Mintz 	cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
356416cdf06SYuval Mintz 	if (IS_PF(cdev) && !cdev->pci_params.pm_cap)
357fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Cannot find power management capability\n");
358fe56b9e6SYuval Mintz 
359fe56b9e6SYuval Mintz 	rc = qed_set_coherency_mask(cdev);
360fe56b9e6SYuval Mintz 	if (rc)
361fe56b9e6SYuval Mintz 		goto err2;
362fe56b9e6SYuval Mintz 
363fe56b9e6SYuval Mintz 	cdev->pci_params.mem_start = pci_resource_start(pdev, 0);
364fe56b9e6SYuval Mintz 	cdev->pci_params.mem_end = pci_resource_end(pdev, 0);
365fe56b9e6SYuval Mintz 	cdev->pci_params.irq = pdev->irq;
366fe56b9e6SYuval Mintz 
367fe56b9e6SYuval Mintz 	cdev->regview = pci_ioremap_bar(pdev, 0);
368fe56b9e6SYuval Mintz 	if (!cdev->regview) {
369fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Cannot map register space, aborting\n");
370fe56b9e6SYuval Mintz 		rc = -ENOMEM;
371fe56b9e6SYuval Mintz 		goto err2;
372fe56b9e6SYuval Mintz 	}
373fe56b9e6SYuval Mintz 
374fe56b9e6SYuval Mintz 	cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2);
375fe56b9e6SYuval Mintz 	cdev->db_size = pci_resource_len(cdev->pdev, 2);
3761a850bfcSMintz, Yuval 	if (!cdev->db_size) {
3771a850bfcSMintz, Yuval 		if (IS_PF(cdev)) {
3781a850bfcSMintz, Yuval 			DP_NOTICE(cdev, "No Doorbell bar available\n");
3791a850bfcSMintz, Yuval 			return -EINVAL;
3801a850bfcSMintz, Yuval 		} else {
3811a850bfcSMintz, Yuval 			return 0;
3821a850bfcSMintz, Yuval 		}
3831a850bfcSMintz, Yuval 	}
3841a850bfcSMintz, Yuval 
385fe56b9e6SYuval Mintz 	cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size);
3861a850bfcSMintz, Yuval 
387fe56b9e6SYuval Mintz 	if (!cdev->doorbells) {
388fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Cannot map doorbell space\n");
389fe56b9e6SYuval Mintz 		return -ENOMEM;
390fe56b9e6SYuval Mintz 	}
391fe56b9e6SYuval Mintz 
3922196d831SSudarsana Reddy Kalluru 	/* AER (Advanced Error reporting) configuration */
3932196d831SSudarsana Reddy Kalluru 	rc = pci_enable_pcie_error_reporting(pdev);
3942196d831SSudarsana Reddy Kalluru 	if (rc)
3952196d831SSudarsana Reddy Kalluru 		DP_VERBOSE(cdev, NETIF_MSG_DRV,
3962196d831SSudarsana Reddy Kalluru 			   "Failed to configure PCIe AER [%d]\n", rc);
3972196d831SSudarsana Reddy Kalluru 
398fe56b9e6SYuval Mintz 	return 0;
399fe56b9e6SYuval Mintz 
400fe56b9e6SYuval Mintz err2:
401fe56b9e6SYuval Mintz 	pci_release_regions(pdev);
402fe56b9e6SYuval Mintz err1:
403fe56b9e6SYuval Mintz 	pci_disable_device(pdev);
404fe56b9e6SYuval Mintz err0:
405fe56b9e6SYuval Mintz 	return rc;
406fe56b9e6SYuval Mintz }
407fe56b9e6SYuval Mintz 
408fe56b9e6SYuval Mintz int qed_fill_dev_info(struct qed_dev *cdev,
409fe56b9e6SYuval Mintz 		      struct qed_dev_info *dev_info)
410fe56b9e6SYuval Mintz {
411c851a9dcSKalderon, Michal 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
412c851a9dcSKalderon, Michal 	struct qed_hw_info *hw_info = &p_hwfn->hw_info;
41319489c7fSChopra, Manish 	struct qed_tunnel_info *tun = &cdev->tunnel;
414cee4d264SManish Chopra 	struct qed_ptt  *ptt;
415cee4d264SManish Chopra 
416fe56b9e6SYuval Mintz 	memset(dev_info, 0, sizeof(struct qed_dev_info));
417fe56b9e6SYuval Mintz 
41819489c7fSChopra, Manish 	if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN &&
41919489c7fSChopra, Manish 	    tun->vxlan.b_mode_enabled)
42019489c7fSChopra, Manish 		dev_info->vxlan_enable = true;
42119489c7fSChopra, Manish 
42219489c7fSChopra, Manish 	if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled &&
42319489c7fSChopra, Manish 	    tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN &&
42419489c7fSChopra, Manish 	    tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN)
42519489c7fSChopra, Manish 		dev_info->gre_enable = true;
42619489c7fSChopra, Manish 
42719489c7fSChopra, Manish 	if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled &&
42819489c7fSChopra, Manish 	    tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN &&
42919489c7fSChopra, Manish 	    tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN)
43019489c7fSChopra, Manish 		dev_info->geneve_enable = true;
43119489c7fSChopra, Manish 
432fe56b9e6SYuval Mintz 	dev_info->num_hwfns = cdev->num_hwfns;
433fe56b9e6SYuval Mintz 	dev_info->pci_mem_start = cdev->pci_params.mem_start;
434fe56b9e6SYuval Mintz 	dev_info->pci_mem_end = cdev->pci_params.mem_end;
435fe56b9e6SYuval Mintz 	dev_info->pci_irq = cdev->pci_params.irq;
436c851a9dcSKalderon, Michal 	dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn);
4379c79ddaaSMintz, Yuval 	dev_info->dev_type = cdev->type;
438c851a9dcSKalderon, Michal 	ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr);
439fe56b9e6SYuval Mintz 
4401408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
441fe56b9e6SYuval Mintz 		dev_info->fw_major = FW_MAJOR_VERSION;
442fe56b9e6SYuval Mintz 		dev_info->fw_minor = FW_MINOR_VERSION;
443fe56b9e6SYuval Mintz 		dev_info->fw_rev = FW_REVISION_VERSION;
444fe56b9e6SYuval Mintz 		dev_info->fw_eng = FW_ENGINEERING_VERSION;
4450bc5fe85SSudarsana Reddy Kalluru 		dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH,
4460bc5fe85SSudarsana Reddy Kalluru 						       &cdev->mf_bits);
4472d2fe843SDmitry Bogdanov 		if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits))
4482d2fe843SDmitry Bogdanov 			dev_info->b_arfs_capable = true;
449831bfb0eSYuval Mintz 		dev_info->tx_switching = true;
45014d39648SMintz, Yuval 
451c851a9dcSKalderon, Michal 		if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME)
45214d39648SMintz, Yuval 			dev_info->wol_support = true;
4533c5da942SMintz, Yuval 
454df9c716dSSudarsana Reddy Kalluru 		dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn);
455df9c716dSSudarsana Reddy Kalluru 
4563c5da942SMintz, Yuval 		dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id;
4571408cc1fSYuval Mintz 	} else {
4581408cc1fSYuval Mintz 		qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major,
4591408cc1fSYuval Mintz 				      &dev_info->fw_minor, &dev_info->fw_rev,
4601408cc1fSYuval Mintz 				      &dev_info->fw_eng);
4611408cc1fSYuval Mintz 	}
462fe56b9e6SYuval Mintz 
4631408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
464cee4d264SManish Chopra 		ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
465cee4d264SManish Chopra 		if (ptt) {
4661408cc1fSYuval Mintz 			qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt,
4671408cc1fSYuval Mintz 					    &dev_info->mfw_rev, NULL);
4681408cc1fSYuval Mintz 
469ae33666aSTomer Tayar 			qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt,
470ae33666aSTomer Tayar 					    &dev_info->mbi_version);
471ae33666aSTomer Tayar 
472cee4d264SManish Chopra 			qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt,
473cee4d264SManish Chopra 					       &dev_info->flash_size);
474cee4d264SManish Chopra 
475cee4d264SManish Chopra 			qed_ptt_release(QED_LEADING_HWFN(cdev), ptt);
476cee4d264SManish Chopra 		}
4771408cc1fSYuval Mintz 	} else {
4781408cc1fSYuval Mintz 		qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL,
4791408cc1fSYuval Mintz 				    &dev_info->mfw_rev, NULL);
4801408cc1fSYuval Mintz 	}
481cee4d264SManish Chopra 
482c851a9dcSKalderon, Michal 	dev_info->mtu = hw_info->mtu;
4830fefbfbaSSudarsana Kalluru 
484fe56b9e6SYuval Mintz 	return 0;
485fe56b9e6SYuval Mintz }
486fe56b9e6SYuval Mintz 
487fe56b9e6SYuval Mintz static void qed_free_cdev(struct qed_dev *cdev)
488fe56b9e6SYuval Mintz {
489fe56b9e6SYuval Mintz 	kfree((void *)cdev);
490fe56b9e6SYuval Mintz }
491fe56b9e6SYuval Mintz 
492fe56b9e6SYuval Mintz static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev)
493fe56b9e6SYuval Mintz {
494fe56b9e6SYuval Mintz 	struct qed_dev *cdev;
495fe56b9e6SYuval Mintz 
496fe56b9e6SYuval Mintz 	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
497fe56b9e6SYuval Mintz 	if (!cdev)
498fe56b9e6SYuval Mintz 		return cdev;
499fe56b9e6SYuval Mintz 
500fe56b9e6SYuval Mintz 	qed_init_struct(cdev);
501fe56b9e6SYuval Mintz 
502fe56b9e6SYuval Mintz 	return cdev;
503fe56b9e6SYuval Mintz }
504fe56b9e6SYuval Mintz 
505fe56b9e6SYuval Mintz /* Sets the requested power state */
5061a635e48SYuval Mintz static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state)
507fe56b9e6SYuval Mintz {
508fe56b9e6SYuval Mintz 	if (!cdev)
509fe56b9e6SYuval Mintz 		return -ENODEV;
510fe56b9e6SYuval Mintz 
511fe56b9e6SYuval Mintz 	DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n");
512fe56b9e6SYuval Mintz 	return 0;
513fe56b9e6SYuval Mintz }
514fe56b9e6SYuval Mintz 
51524e04879SMichal Kalderon struct qed_devlink {
51624e04879SMichal Kalderon 	struct qed_dev *cdev;
51724e04879SMichal Kalderon };
51824e04879SMichal Kalderon 
51924e04879SMichal Kalderon enum qed_devlink_param_id {
52024e04879SMichal Kalderon 	QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
52124e04879SMichal Kalderon 	QED_DEVLINK_PARAM_ID_IWARP_CMT,
52224e04879SMichal Kalderon };
52324e04879SMichal Kalderon 
52424e04879SMichal Kalderon static int qed_dl_param_get(struct devlink *dl, u32 id,
52524e04879SMichal Kalderon 			    struct devlink_param_gset_ctx *ctx)
52624e04879SMichal Kalderon {
52724e04879SMichal Kalderon 	struct qed_devlink *qed_dl;
52824e04879SMichal Kalderon 	struct qed_dev *cdev;
52924e04879SMichal Kalderon 
53024e04879SMichal Kalderon 	qed_dl = devlink_priv(dl);
53124e04879SMichal Kalderon 	cdev = qed_dl->cdev;
53224e04879SMichal Kalderon 	ctx->val.vbool = cdev->iwarp_cmt;
53324e04879SMichal Kalderon 
53424e04879SMichal Kalderon 	return 0;
53524e04879SMichal Kalderon }
53624e04879SMichal Kalderon 
53724e04879SMichal Kalderon static int qed_dl_param_set(struct devlink *dl, u32 id,
53824e04879SMichal Kalderon 			    struct devlink_param_gset_ctx *ctx)
53924e04879SMichal Kalderon {
54024e04879SMichal Kalderon 	struct qed_devlink *qed_dl;
54124e04879SMichal Kalderon 	struct qed_dev *cdev;
54224e04879SMichal Kalderon 
54324e04879SMichal Kalderon 	qed_dl = devlink_priv(dl);
54424e04879SMichal Kalderon 	cdev = qed_dl->cdev;
54524e04879SMichal Kalderon 	cdev->iwarp_cmt = ctx->val.vbool;
54624e04879SMichal Kalderon 
54724e04879SMichal Kalderon 	return 0;
54824e04879SMichal Kalderon }
54924e04879SMichal Kalderon 
55024e04879SMichal Kalderon static const struct devlink_param qed_devlink_params[] = {
55124e04879SMichal Kalderon 	DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT,
55224e04879SMichal Kalderon 			     "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL,
55324e04879SMichal Kalderon 			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
55424e04879SMichal Kalderon 			     qed_dl_param_get, qed_dl_param_set, NULL),
55524e04879SMichal Kalderon };
55624e04879SMichal Kalderon 
55724e04879SMichal Kalderon static const struct devlink_ops qed_dl_ops;
55824e04879SMichal Kalderon 
55924e04879SMichal Kalderon static int qed_devlink_register(struct qed_dev *cdev)
56024e04879SMichal Kalderon {
56124e04879SMichal Kalderon 	union devlink_param_value value;
56224e04879SMichal Kalderon 	struct qed_devlink *qed_dl;
56324e04879SMichal Kalderon 	struct devlink *dl;
56424e04879SMichal Kalderon 	int rc;
56524e04879SMichal Kalderon 
56624e04879SMichal Kalderon 	dl = devlink_alloc(&qed_dl_ops, sizeof(*qed_dl));
56724e04879SMichal Kalderon 	if (!dl)
56824e04879SMichal Kalderon 		return -ENOMEM;
56924e04879SMichal Kalderon 
57024e04879SMichal Kalderon 	qed_dl = devlink_priv(dl);
57124e04879SMichal Kalderon 
57224e04879SMichal Kalderon 	cdev->dl = dl;
57324e04879SMichal Kalderon 	qed_dl->cdev = cdev;
57424e04879SMichal Kalderon 
57524e04879SMichal Kalderon 	rc = devlink_register(dl, &cdev->pdev->dev);
57624e04879SMichal Kalderon 	if (rc)
57724e04879SMichal Kalderon 		goto err_free;
57824e04879SMichal Kalderon 
57924e04879SMichal Kalderon 	rc = devlink_params_register(dl, qed_devlink_params,
58024e04879SMichal Kalderon 				     ARRAY_SIZE(qed_devlink_params));
58124e04879SMichal Kalderon 	if (rc)
58224e04879SMichal Kalderon 		goto err_unregister;
58324e04879SMichal Kalderon 
58424e04879SMichal Kalderon 	value.vbool = false;
58524e04879SMichal Kalderon 	devlink_param_driverinit_value_set(dl,
58624e04879SMichal Kalderon 					   QED_DEVLINK_PARAM_ID_IWARP_CMT,
58724e04879SMichal Kalderon 					   value);
58824e04879SMichal Kalderon 
58924e04879SMichal Kalderon 	devlink_params_publish(dl);
59024e04879SMichal Kalderon 	cdev->iwarp_cmt = false;
59124e04879SMichal Kalderon 
59224e04879SMichal Kalderon 	return 0;
59324e04879SMichal Kalderon 
59424e04879SMichal Kalderon err_unregister:
59524e04879SMichal Kalderon 	devlink_unregister(dl);
59624e04879SMichal Kalderon 
59724e04879SMichal Kalderon err_free:
59824e04879SMichal Kalderon 	cdev->dl = NULL;
59924e04879SMichal Kalderon 	devlink_free(dl);
60024e04879SMichal Kalderon 
60124e04879SMichal Kalderon 	return rc;
60224e04879SMichal Kalderon }
60324e04879SMichal Kalderon 
60424e04879SMichal Kalderon static void qed_devlink_unregister(struct qed_dev *cdev)
60524e04879SMichal Kalderon {
60624e04879SMichal Kalderon 	if (!cdev->dl)
60724e04879SMichal Kalderon 		return;
60824e04879SMichal Kalderon 
60924e04879SMichal Kalderon 	devlink_params_unregister(cdev->dl, qed_devlink_params,
61024e04879SMichal Kalderon 				  ARRAY_SIZE(qed_devlink_params));
61124e04879SMichal Kalderon 
61224e04879SMichal Kalderon 	devlink_unregister(cdev->dl);
61324e04879SMichal Kalderon 	devlink_free(cdev->dl);
61424e04879SMichal Kalderon }
61524e04879SMichal Kalderon 
616fe56b9e6SYuval Mintz /* probing */
617fe56b9e6SYuval Mintz static struct qed_dev *qed_probe(struct pci_dev *pdev,
6181408cc1fSYuval Mintz 				 struct qed_probe_params *params)
619fe56b9e6SYuval Mintz {
620fe56b9e6SYuval Mintz 	struct qed_dev *cdev;
621fe56b9e6SYuval Mintz 	int rc;
622fe56b9e6SYuval Mintz 
623fe56b9e6SYuval Mintz 	cdev = qed_alloc_cdev(pdev);
624fe56b9e6SYuval Mintz 	if (!cdev)
625fe56b9e6SYuval Mintz 		goto err0;
626fe56b9e6SYuval Mintz 
627712c3cbfSMintz, Yuval 	cdev->drv_type = DRV_ID_DRV_TYPE_LINUX;
6281408cc1fSYuval Mintz 	cdev->protocol = params->protocol;
629fe56b9e6SYuval Mintz 
6301408cc1fSYuval Mintz 	if (params->is_vf)
6311408cc1fSYuval Mintz 		cdev->b_is_vf = true;
6321408cc1fSYuval Mintz 
6331408cc1fSYuval Mintz 	qed_init_dp(cdev, params->dp_module, params->dp_level);
634fe56b9e6SYuval Mintz 
63564515dc8STomer Tayar 	cdev->recov_in_prog = params->recov_in_prog;
63664515dc8STomer Tayar 
637fe56b9e6SYuval Mintz 	rc = qed_init_pci(cdev, pdev);
638fe56b9e6SYuval Mintz 	if (rc) {
639fe56b9e6SYuval Mintz 		DP_ERR(cdev, "init pci failed\n");
640fe56b9e6SYuval Mintz 		goto err1;
641fe56b9e6SYuval Mintz 	}
642fe56b9e6SYuval Mintz 	DP_INFO(cdev, "PCI init completed successfully\n");
643fe56b9e6SYuval Mintz 
64424e04879SMichal Kalderon 	rc = qed_devlink_register(cdev);
64524e04879SMichal Kalderon 	if (rc) {
64624e04879SMichal Kalderon 		DP_INFO(cdev, "Failed to register devlink.\n");
64724e04879SMichal Kalderon 		goto err2;
64824e04879SMichal Kalderon 	}
64924e04879SMichal Kalderon 
650fe56b9e6SYuval Mintz 	rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT);
651fe56b9e6SYuval Mintz 	if (rc) {
652fe56b9e6SYuval Mintz 		DP_ERR(cdev, "hw prepare failed\n");
653fe56b9e6SYuval Mintz 		goto err2;
654fe56b9e6SYuval Mintz 	}
655fe56b9e6SYuval Mintz 
65620c4515aSEwan D. Milne 	DP_INFO(cdev, "qed_probe completed successfully\n");
657fe56b9e6SYuval Mintz 
658fe56b9e6SYuval Mintz 	return cdev;
659fe56b9e6SYuval Mintz 
660fe56b9e6SYuval Mintz err2:
661fe56b9e6SYuval Mintz 	qed_free_pci(cdev);
662fe56b9e6SYuval Mintz err1:
663fe56b9e6SYuval Mintz 	qed_free_cdev(cdev);
664fe56b9e6SYuval Mintz err0:
665fe56b9e6SYuval Mintz 	return NULL;
666fe56b9e6SYuval Mintz }
667fe56b9e6SYuval Mintz 
668fe56b9e6SYuval Mintz static void qed_remove(struct qed_dev *cdev)
669fe56b9e6SYuval Mintz {
670fe56b9e6SYuval Mintz 	if (!cdev)
671fe56b9e6SYuval Mintz 		return;
672fe56b9e6SYuval Mintz 
673fe56b9e6SYuval Mintz 	qed_hw_remove(cdev);
674fe56b9e6SYuval Mintz 
675fe56b9e6SYuval Mintz 	qed_free_pci(cdev);
676fe56b9e6SYuval Mintz 
677fe56b9e6SYuval Mintz 	qed_set_power_state(cdev, PCI_D3hot);
678fe56b9e6SYuval Mintz 
67924e04879SMichal Kalderon 	qed_devlink_unregister(cdev);
68024e04879SMichal Kalderon 
681fe56b9e6SYuval Mintz 	qed_free_cdev(cdev);
682fe56b9e6SYuval Mintz }
683fe56b9e6SYuval Mintz 
684fe56b9e6SYuval Mintz static void qed_disable_msix(struct qed_dev *cdev)
685fe56b9e6SYuval Mintz {
686fe56b9e6SYuval Mintz 	if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
687fe56b9e6SYuval Mintz 		pci_disable_msix(cdev->pdev);
688fe56b9e6SYuval Mintz 		kfree(cdev->int_params.msix_table);
689fe56b9e6SYuval Mintz 	} else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) {
690fe56b9e6SYuval Mintz 		pci_disable_msi(cdev->pdev);
691fe56b9e6SYuval Mintz 	}
692fe56b9e6SYuval Mintz 
693fe56b9e6SYuval Mintz 	memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param));
694fe56b9e6SYuval Mintz }
695fe56b9e6SYuval Mintz 
696fe56b9e6SYuval Mintz static int qed_enable_msix(struct qed_dev *cdev,
697fe56b9e6SYuval Mintz 			   struct qed_int_params *int_params)
698fe56b9e6SYuval Mintz {
699fe56b9e6SYuval Mintz 	int i, rc, cnt;
700fe56b9e6SYuval Mintz 
701fe56b9e6SYuval Mintz 	cnt = int_params->in.num_vectors;
702fe56b9e6SYuval Mintz 
703fe56b9e6SYuval Mintz 	for (i = 0; i < cnt; i++)
704fe56b9e6SYuval Mintz 		int_params->msix_table[i].entry = i;
705fe56b9e6SYuval Mintz 
706fe56b9e6SYuval Mintz 	rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table,
707fe56b9e6SYuval Mintz 				   int_params->in.min_msix_cnt, cnt);
708fe56b9e6SYuval Mintz 	if (rc < cnt && rc >= int_params->in.min_msix_cnt &&
709fe56b9e6SYuval Mintz 	    (rc % cdev->num_hwfns)) {
710fe56b9e6SYuval Mintz 		pci_disable_msix(cdev->pdev);
711fe56b9e6SYuval Mintz 
712fe56b9e6SYuval Mintz 		/* If fastpath is initialized, we need at least one interrupt
713fe56b9e6SYuval Mintz 		 * per hwfn [and the slow path interrupts]. New requested number
714fe56b9e6SYuval Mintz 		 * should be a multiple of the number of hwfns.
715fe56b9e6SYuval Mintz 		 */
716fe56b9e6SYuval Mintz 		cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns;
717fe56b9e6SYuval Mintz 		DP_NOTICE(cdev,
718fe56b9e6SYuval Mintz 			  "Trying to enable MSI-X with less vectors (%d out of %d)\n",
719fe56b9e6SYuval Mintz 			  cnt, int_params->in.num_vectors);
7201a635e48SYuval Mintz 		rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table,
7211a635e48SYuval Mintz 					   cnt);
722fe56b9e6SYuval Mintz 		if (!rc)
723fe56b9e6SYuval Mintz 			rc = cnt;
724fe56b9e6SYuval Mintz 	}
725fe56b9e6SYuval Mintz 
726fe56b9e6SYuval Mintz 	if (rc > 0) {
727fe56b9e6SYuval Mintz 		/* MSI-x configuration was achieved */
728fe56b9e6SYuval Mintz 		int_params->out.int_mode = QED_INT_MODE_MSIX;
729fe56b9e6SYuval Mintz 		int_params->out.num_vectors = rc;
730fe56b9e6SYuval Mintz 		rc = 0;
731fe56b9e6SYuval Mintz 	} else {
732fe56b9e6SYuval Mintz 		DP_NOTICE(cdev,
733fe56b9e6SYuval Mintz 			  "Failed to enable MSI-X [Requested %d vectors][rc %d]\n",
734fe56b9e6SYuval Mintz 			  cnt, rc);
735fe56b9e6SYuval Mintz 	}
736fe56b9e6SYuval Mintz 
737fe56b9e6SYuval Mintz 	return rc;
738fe56b9e6SYuval Mintz }
739fe56b9e6SYuval Mintz 
740fe56b9e6SYuval Mintz /* This function outputs the int mode and the number of enabled msix vector */
741fe56b9e6SYuval Mintz static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode)
742fe56b9e6SYuval Mintz {
743fe56b9e6SYuval Mintz 	struct qed_int_params *int_params = &cdev->int_params;
744fe56b9e6SYuval Mintz 	struct msix_entry *tbl;
745fe56b9e6SYuval Mintz 	int rc = 0, cnt;
746fe56b9e6SYuval Mintz 
747fe56b9e6SYuval Mintz 	switch (int_params->in.int_mode) {
748fe56b9e6SYuval Mintz 	case QED_INT_MODE_MSIX:
749fe56b9e6SYuval Mintz 		/* Allocate MSIX table */
750fe56b9e6SYuval Mintz 		cnt = int_params->in.num_vectors;
751fe56b9e6SYuval Mintz 		int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL);
752fe56b9e6SYuval Mintz 		if (!int_params->msix_table) {
753fe56b9e6SYuval Mintz 			rc = -ENOMEM;
754fe56b9e6SYuval Mintz 			goto out;
755fe56b9e6SYuval Mintz 		}
756fe56b9e6SYuval Mintz 
757fe56b9e6SYuval Mintz 		/* Enable MSIX */
758fe56b9e6SYuval Mintz 		rc = qed_enable_msix(cdev, int_params);
759fe56b9e6SYuval Mintz 		if (!rc)
760fe56b9e6SYuval Mintz 			goto out;
761fe56b9e6SYuval Mintz 
762fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Failed to enable MSI-X\n");
763fe56b9e6SYuval Mintz 		kfree(int_params->msix_table);
764fe56b9e6SYuval Mintz 		if (force_mode)
765fe56b9e6SYuval Mintz 			goto out;
766df561f66SGustavo A. R. Silva 		fallthrough;
767fe56b9e6SYuval Mintz 
768fe56b9e6SYuval Mintz 	case QED_INT_MODE_MSI:
769bb13ace7SSudarsana Reddy Kalluru 		if (cdev->num_hwfns == 1) {
770fe56b9e6SYuval Mintz 			rc = pci_enable_msi(cdev->pdev);
771fe56b9e6SYuval Mintz 			if (!rc) {
772fe56b9e6SYuval Mintz 				int_params->out.int_mode = QED_INT_MODE_MSI;
773fe56b9e6SYuval Mintz 				goto out;
774fe56b9e6SYuval Mintz 			}
775fe56b9e6SYuval Mintz 
776fe56b9e6SYuval Mintz 			DP_NOTICE(cdev, "Failed to enable MSI\n");
777fe56b9e6SYuval Mintz 			if (force_mode)
778fe56b9e6SYuval Mintz 				goto out;
779bb13ace7SSudarsana Reddy Kalluru 		}
780df561f66SGustavo A. R. Silva 		fallthrough;
781fe56b9e6SYuval Mintz 
782fe56b9e6SYuval Mintz 	case QED_INT_MODE_INTA:
783fe56b9e6SYuval Mintz 			int_params->out.int_mode = QED_INT_MODE_INTA;
784fe56b9e6SYuval Mintz 			rc = 0;
785fe56b9e6SYuval Mintz 			goto out;
786fe56b9e6SYuval Mintz 	default:
787fe56b9e6SYuval Mintz 		DP_NOTICE(cdev, "Unknown int_mode value %d\n",
788fe56b9e6SYuval Mintz 			  int_params->in.int_mode);
789fe56b9e6SYuval Mintz 		rc = -EINVAL;
790fe56b9e6SYuval Mintz 	}
791fe56b9e6SYuval Mintz 
792fe56b9e6SYuval Mintz out:
793525ef5c0SYuval Mintz 	if (!rc)
794525ef5c0SYuval Mintz 		DP_INFO(cdev, "Using %s interrupts\n",
795525ef5c0SYuval Mintz 			int_params->out.int_mode == QED_INT_MODE_INTA ?
796525ef5c0SYuval Mintz 			"INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ?
797525ef5c0SYuval Mintz 			"MSI" : "MSIX");
798fe56b9e6SYuval Mintz 	cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE;
799fe56b9e6SYuval Mintz 
800fe56b9e6SYuval Mintz 	return rc;
801fe56b9e6SYuval Mintz }
802fe56b9e6SYuval Mintz 
803fe56b9e6SYuval Mintz static void qed_simd_handler_config(struct qed_dev *cdev, void *token,
804fe56b9e6SYuval Mintz 				    int index, void(*handler)(void *))
805fe56b9e6SYuval Mintz {
806fe56b9e6SYuval Mintz 	struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns];
807fe56b9e6SYuval Mintz 	int relative_idx = index / cdev->num_hwfns;
808fe56b9e6SYuval Mintz 
809fe56b9e6SYuval Mintz 	hwfn->simd_proto_handler[relative_idx].func = handler;
810fe56b9e6SYuval Mintz 	hwfn->simd_proto_handler[relative_idx].token = token;
811fe56b9e6SYuval Mintz }
812fe56b9e6SYuval Mintz 
813fe56b9e6SYuval Mintz static void qed_simd_handler_clean(struct qed_dev *cdev, int index)
814fe56b9e6SYuval Mintz {
815fe56b9e6SYuval Mintz 	struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns];
816fe56b9e6SYuval Mintz 	int relative_idx = index / cdev->num_hwfns;
817fe56b9e6SYuval Mintz 
818fe56b9e6SYuval Mintz 	memset(&hwfn->simd_proto_handler[relative_idx], 0,
819fe56b9e6SYuval Mintz 	       sizeof(struct qed_simd_fp_handler));
820fe56b9e6SYuval Mintz }
821fe56b9e6SYuval Mintz 
822fe56b9e6SYuval Mintz static irqreturn_t qed_msix_sp_int(int irq, void *tasklet)
823fe56b9e6SYuval Mintz {
824fe56b9e6SYuval Mintz 	tasklet_schedule((struct tasklet_struct *)tasklet);
825fe56b9e6SYuval Mintz 	return IRQ_HANDLED;
826fe56b9e6SYuval Mintz }
827fe56b9e6SYuval Mintz 
828fe56b9e6SYuval Mintz static irqreturn_t qed_single_int(int irq, void *dev_instance)
829fe56b9e6SYuval Mintz {
830fe56b9e6SYuval Mintz 	struct qed_dev *cdev = (struct qed_dev *)dev_instance;
831fe56b9e6SYuval Mintz 	struct qed_hwfn *hwfn;
832fe56b9e6SYuval Mintz 	irqreturn_t rc = IRQ_NONE;
833fe56b9e6SYuval Mintz 	u64 status;
834fe56b9e6SYuval Mintz 	int i, j;
835fe56b9e6SYuval Mintz 
836fe56b9e6SYuval Mintz 	for (i = 0; i < cdev->num_hwfns; i++) {
837fe56b9e6SYuval Mintz 		status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]);
838fe56b9e6SYuval Mintz 
839fe56b9e6SYuval Mintz 		if (!status)
840fe56b9e6SYuval Mintz 			continue;
841fe56b9e6SYuval Mintz 
842fe56b9e6SYuval Mintz 		hwfn = &cdev->hwfns[i];
843fe56b9e6SYuval Mintz 
844fe56b9e6SYuval Mintz 		/* Slowpath interrupt */
845fe56b9e6SYuval Mintz 		if (unlikely(status & 0x1)) {
846fe56b9e6SYuval Mintz 			tasklet_schedule(hwfn->sp_dpc);
847fe56b9e6SYuval Mintz 			status &= ~0x1;
848fe56b9e6SYuval Mintz 			rc = IRQ_HANDLED;
849fe56b9e6SYuval Mintz 		}
850fe56b9e6SYuval Mintz 
851fe56b9e6SYuval Mintz 		/* Fastpath interrupts */
852fe56b9e6SYuval Mintz 		for (j = 0; j < 64; j++) {
853fe56b9e6SYuval Mintz 			if ((0x2ULL << j) & status) {
8543935a709SSudarsana Reddy Kalluru 				struct qed_simd_fp_handler *p_handler =
8553935a709SSudarsana Reddy Kalluru 					&hwfn->simd_proto_handler[j];
8563935a709SSudarsana Reddy Kalluru 
8573935a709SSudarsana Reddy Kalluru 				if (p_handler->func)
8583935a709SSudarsana Reddy Kalluru 					p_handler->func(p_handler->token);
8593935a709SSudarsana Reddy Kalluru 				else
8603935a709SSudarsana Reddy Kalluru 					DP_NOTICE(hwfn,
8613935a709SSudarsana Reddy Kalluru 						  "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n",
8623935a709SSudarsana Reddy Kalluru 						  j, status);
8633935a709SSudarsana Reddy Kalluru 
864fe56b9e6SYuval Mintz 				status &= ~(0x2ULL << j);
865fe56b9e6SYuval Mintz 				rc = IRQ_HANDLED;
866fe56b9e6SYuval Mintz 			}
867fe56b9e6SYuval Mintz 		}
868fe56b9e6SYuval Mintz 
869fe56b9e6SYuval Mintz 		if (unlikely(status))
870fe56b9e6SYuval Mintz 			DP_VERBOSE(hwfn, NETIF_MSG_INTR,
871fe56b9e6SYuval Mintz 				   "got an unknown interrupt status 0x%llx\n",
872fe56b9e6SYuval Mintz 				   status);
873fe56b9e6SYuval Mintz 	}
874fe56b9e6SYuval Mintz 
875fe56b9e6SYuval Mintz 	return rc;
876fe56b9e6SYuval Mintz }
877fe56b9e6SYuval Mintz 
8788f16bc97SSudarsana Kalluru int qed_slowpath_irq_req(struct qed_hwfn *hwfn)
879fe56b9e6SYuval Mintz {
8808f16bc97SSudarsana Kalluru 	struct qed_dev *cdev = hwfn->cdev;
881525ef5c0SYuval Mintz 	u32 int_mode;
8828f16bc97SSudarsana Kalluru 	int rc = 0;
8838f16bc97SSudarsana Kalluru 	u8 id;
884fe56b9e6SYuval Mintz 
885525ef5c0SYuval Mintz 	int_mode = cdev->int_params.out.int_mode;
886525ef5c0SYuval Mintz 	if (int_mode == QED_INT_MODE_MSIX) {
8878f16bc97SSudarsana Kalluru 		id = hwfn->my_id;
8888f16bc97SSudarsana Kalluru 		snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x",
8898f16bc97SSudarsana Kalluru 			 id, cdev->pdev->bus->number,
8908f16bc97SSudarsana Kalluru 			 PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id);
8918f16bc97SSudarsana Kalluru 		rc = request_irq(cdev->int_params.msix_table[id].vector,
8928f16bc97SSudarsana Kalluru 				 qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc);
893fe56b9e6SYuval Mintz 	} else {
894fe56b9e6SYuval Mintz 		unsigned long flags = 0;
895fe56b9e6SYuval Mintz 
896fe56b9e6SYuval Mintz 		snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x",
897fe56b9e6SYuval Mintz 			 cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn),
898fe56b9e6SYuval Mintz 			 PCI_FUNC(cdev->pdev->devfn));
899fe56b9e6SYuval Mintz 
900fe56b9e6SYuval Mintz 		if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA)
901fe56b9e6SYuval Mintz 			flags |= IRQF_SHARED;
902fe56b9e6SYuval Mintz 
903fe56b9e6SYuval Mintz 		rc = request_irq(cdev->pdev->irq, qed_single_int,
904fe56b9e6SYuval Mintz 				 flags, cdev->name, cdev);
905fe56b9e6SYuval Mintz 	}
906fe56b9e6SYuval Mintz 
907525ef5c0SYuval Mintz 	if (rc)
908525ef5c0SYuval Mintz 		DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc);
909525ef5c0SYuval Mintz 	else
910525ef5c0SYuval Mintz 		DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP),
911525ef5c0SYuval Mintz 			   "Requested slowpath %s\n",
912525ef5c0SYuval Mintz 			   (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ");
913525ef5c0SYuval Mintz 
914fe56b9e6SYuval Mintz 	return rc;
915fe56b9e6SYuval Mintz }
916fe56b9e6SYuval Mintz 
91706892f2eSTomer Tayar static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn)
91806892f2eSTomer Tayar {
91906892f2eSTomer Tayar 	/* Calling the disable function will make sure that any
92006892f2eSTomer Tayar 	 * currently-running function is completed. The following call to the
92106892f2eSTomer Tayar 	 * enable function makes this sequence a flush-like operation.
92206892f2eSTomer Tayar 	 */
92306892f2eSTomer Tayar 	if (p_hwfn->b_sp_dpc_enabled) {
92406892f2eSTomer Tayar 		tasklet_disable(p_hwfn->sp_dpc);
92506892f2eSTomer Tayar 		tasklet_enable(p_hwfn->sp_dpc);
92606892f2eSTomer Tayar 	}
92706892f2eSTomer Tayar }
92806892f2eSTomer Tayar 
9291226337aSTomer Tayar void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn)
9301226337aSTomer Tayar {
9311226337aSTomer Tayar 	struct qed_dev *cdev = p_hwfn->cdev;
9321226337aSTomer Tayar 	u8 id = p_hwfn->my_id;
9331226337aSTomer Tayar 	u32 int_mode;
9341226337aSTomer Tayar 
9351226337aSTomer Tayar 	int_mode = cdev->int_params.out.int_mode;
9361226337aSTomer Tayar 	if (int_mode == QED_INT_MODE_MSIX)
9371226337aSTomer Tayar 		synchronize_irq(cdev->int_params.msix_table[id].vector);
9381226337aSTomer Tayar 	else
9391226337aSTomer Tayar 		synchronize_irq(cdev->pdev->irq);
94006892f2eSTomer Tayar 
94106892f2eSTomer Tayar 	qed_slowpath_tasklet_flush(p_hwfn);
9421226337aSTomer Tayar }
9431226337aSTomer Tayar 
944fe56b9e6SYuval Mintz static void qed_slowpath_irq_free(struct qed_dev *cdev)
945fe56b9e6SYuval Mintz {
946fe56b9e6SYuval Mintz 	int i;
947fe56b9e6SYuval Mintz 
948fe56b9e6SYuval Mintz 	if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
949fe56b9e6SYuval Mintz 		for_each_hwfn(cdev, i) {
9508f16bc97SSudarsana Kalluru 			if (!cdev->hwfns[i].b_int_requested)
9518f16bc97SSudarsana Kalluru 				break;
952fe56b9e6SYuval Mintz 			synchronize_irq(cdev->int_params.msix_table[i].vector);
953fe56b9e6SYuval Mintz 			free_irq(cdev->int_params.msix_table[i].vector,
954fe56b9e6SYuval Mintz 				 cdev->hwfns[i].sp_dpc);
955fe56b9e6SYuval Mintz 		}
956fe56b9e6SYuval Mintz 	} else {
9578f16bc97SSudarsana Kalluru 		if (QED_LEADING_HWFN(cdev)->b_int_requested)
958fe56b9e6SYuval Mintz 			free_irq(cdev->pdev->irq, cdev);
959fe56b9e6SYuval Mintz 	}
9608f16bc97SSudarsana Kalluru 	qed_int_disable_post_isr_release(cdev);
961fe56b9e6SYuval Mintz }
962fe56b9e6SYuval Mintz 
963fe56b9e6SYuval Mintz static int qed_nic_stop(struct qed_dev *cdev)
964fe56b9e6SYuval Mintz {
965fe56b9e6SYuval Mintz 	int i, rc;
966fe56b9e6SYuval Mintz 
967fe56b9e6SYuval Mintz 	rc = qed_hw_stop(cdev);
968fe56b9e6SYuval Mintz 
969fe56b9e6SYuval Mintz 	for (i = 0; i < cdev->num_hwfns; i++) {
970fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
971fe56b9e6SYuval Mintz 
972fe56b9e6SYuval Mintz 		if (p_hwfn->b_sp_dpc_enabled) {
973fe56b9e6SYuval Mintz 			tasklet_disable(p_hwfn->sp_dpc);
974fe56b9e6SYuval Mintz 			p_hwfn->b_sp_dpc_enabled = false;
975fe56b9e6SYuval Mintz 			DP_VERBOSE(cdev, NETIF_MSG_IFDOWN,
9762fdae034SColin Ian King 				   "Disabled sp tasklet [hwfn %d] at %p\n",
977fe56b9e6SYuval Mintz 				   i, p_hwfn->sp_dpc);
978fe56b9e6SYuval Mintz 		}
979fe56b9e6SYuval Mintz 	}
980fe56b9e6SYuval Mintz 
981c965db44STomer Tayar 	qed_dbg_pf_exit(cdev);
982c965db44STomer Tayar 
983fe56b9e6SYuval Mintz 	return rc;
984fe56b9e6SYuval Mintz }
985fe56b9e6SYuval Mintz 
986fe56b9e6SYuval Mintz static int qed_nic_setup(struct qed_dev *cdev)
987fe56b9e6SYuval Mintz {
9880a7fb11cSYuval Mintz 	int rc, i;
9890a7fb11cSYuval Mintz 
9900a7fb11cSYuval Mintz 	/* Determine if interface is going to require LL2 */
9910a7fb11cSYuval Mintz 	if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) {
9920a7fb11cSYuval Mintz 		for (i = 0; i < cdev->num_hwfns; i++) {
9930a7fb11cSYuval Mintz 			struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
9940a7fb11cSYuval Mintz 
9950a7fb11cSYuval Mintz 			p_hwfn->using_ll2 = true;
9960a7fb11cSYuval Mintz 		}
9970a7fb11cSYuval Mintz 	}
998fe56b9e6SYuval Mintz 
999fe56b9e6SYuval Mintz 	rc = qed_resc_alloc(cdev);
1000fe56b9e6SYuval Mintz 	if (rc)
1001fe56b9e6SYuval Mintz 		return rc;
1002fe56b9e6SYuval Mintz 
1003fe56b9e6SYuval Mintz 	DP_INFO(cdev, "Allocated qed resources\n");
1004fe56b9e6SYuval Mintz 
1005fe56b9e6SYuval Mintz 	qed_resc_setup(cdev);
1006fe56b9e6SYuval Mintz 
1007fe56b9e6SYuval Mintz 	return rc;
1008fe56b9e6SYuval Mintz }
1009fe56b9e6SYuval Mintz 
1010fe56b9e6SYuval Mintz static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt)
1011fe56b9e6SYuval Mintz {
1012fe56b9e6SYuval Mintz 	int limit = 0;
1013fe56b9e6SYuval Mintz 
1014fe56b9e6SYuval Mintz 	/* Mark the fastpath as free/used */
1015fe56b9e6SYuval Mintz 	cdev->int_params.fp_initialized = cnt ? true : false;
1016fe56b9e6SYuval Mintz 
1017fe56b9e6SYuval Mintz 	if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX)
1018fe56b9e6SYuval Mintz 		limit = cdev->num_hwfns * 63;
1019fe56b9e6SYuval Mintz 	else if (cdev->int_params.fp_msix_cnt)
1020fe56b9e6SYuval Mintz 		limit = cdev->int_params.fp_msix_cnt;
1021fe56b9e6SYuval Mintz 
1022fe56b9e6SYuval Mintz 	if (!limit)
1023fe56b9e6SYuval Mintz 		return -ENOMEM;
1024fe56b9e6SYuval Mintz 
1025fe56b9e6SYuval Mintz 	return min_t(int, cnt, limit);
1026fe56b9e6SYuval Mintz }
1027fe56b9e6SYuval Mintz 
1028fe56b9e6SYuval Mintz static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info)
1029fe56b9e6SYuval Mintz {
1030fe56b9e6SYuval Mintz 	memset(info, 0, sizeof(struct qed_int_info));
1031fe56b9e6SYuval Mintz 
1032fe56b9e6SYuval Mintz 	if (!cdev->int_params.fp_initialized) {
1033fe56b9e6SYuval Mintz 		DP_INFO(cdev,
1034fe56b9e6SYuval Mintz 			"Protocol driver requested interrupt information, but its support is not yet configured\n");
1035fe56b9e6SYuval Mintz 		return -EINVAL;
1036fe56b9e6SYuval Mintz 	}
1037fe56b9e6SYuval Mintz 
1038fe56b9e6SYuval Mintz 	/* Need to expose only MSI-X information; Single IRQ is handled solely
1039fe56b9e6SYuval Mintz 	 * by qed.
1040fe56b9e6SYuval Mintz 	 */
1041fe56b9e6SYuval Mintz 	if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
1042fe56b9e6SYuval Mintz 		int msix_base = cdev->int_params.fp_msix_base;
1043fe56b9e6SYuval Mintz 
1044fe56b9e6SYuval Mintz 		info->msix_cnt = cdev->int_params.fp_msix_cnt;
1045fe56b9e6SYuval Mintz 		info->msix = &cdev->int_params.msix_table[msix_base];
1046fe56b9e6SYuval Mintz 	}
1047fe56b9e6SYuval Mintz 
1048fe56b9e6SYuval Mintz 	return 0;
1049fe56b9e6SYuval Mintz }
1050fe56b9e6SYuval Mintz 
1051fe56b9e6SYuval Mintz static int qed_slowpath_setup_int(struct qed_dev *cdev,
1052fe56b9e6SYuval Mintz 				  enum qed_int_mode int_mode)
1053fe56b9e6SYuval Mintz {
10544ac801b7SYuval Mintz 	struct qed_sb_cnt_info sb_cnt_info;
10550189efb8SYuval Mintz 	int num_l2_queues = 0;
10564ac801b7SYuval Mintz 	int rc;
10574ac801b7SYuval Mintz 	int i;
1058fe56b9e6SYuval Mintz 
10591d2c2024SSudarsana Reddy Kalluru 	if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) {
10601d2c2024SSudarsana Reddy Kalluru 		DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n");
10611d2c2024SSudarsana Reddy Kalluru 		return -EINVAL;
10621d2c2024SSudarsana Reddy Kalluru 	}
10631d2c2024SSudarsana Reddy Kalluru 
10641d2c2024SSudarsana Reddy Kalluru 	memset(&cdev->int_params, 0, sizeof(struct qed_int_params));
1065fe56b9e6SYuval Mintz 	cdev->int_params.in.int_mode = int_mode;
10664ac801b7SYuval Mintz 	for_each_hwfn(cdev, i) {
10674ac801b7SYuval Mintz 		memset(&sb_cnt_info, 0, sizeof(sb_cnt_info));
10684ac801b7SYuval Mintz 		qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info);
1069726fdbe9SMintz, Yuval 		cdev->int_params.in.num_vectors += sb_cnt_info.cnt;
10704ac801b7SYuval Mintz 		cdev->int_params.in.num_vectors++; /* slowpath */
10714ac801b7SYuval Mintz 	}
1072fe56b9e6SYuval Mintz 
1073fe56b9e6SYuval Mintz 	/* We want a minimum of one slowpath and one fastpath vector per hwfn */
1074fe56b9e6SYuval Mintz 	cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2;
1075fe56b9e6SYuval Mintz 
1076bb7858baSSudarsana Reddy Kalluru 	if (is_kdump_kernel()) {
1077bb7858baSSudarsana Reddy Kalluru 		DP_INFO(cdev,
1078bb7858baSSudarsana Reddy Kalluru 			"Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n",
1079bb7858baSSudarsana Reddy Kalluru 			cdev->int_params.in.min_msix_cnt);
1080bb7858baSSudarsana Reddy Kalluru 		cdev->int_params.in.num_vectors =
1081bb7858baSSudarsana Reddy Kalluru 			cdev->int_params.in.min_msix_cnt;
1082bb7858baSSudarsana Reddy Kalluru 	}
1083bb7858baSSudarsana Reddy Kalluru 
1084fe56b9e6SYuval Mintz 	rc = qed_set_int_mode(cdev, false);
1085fe56b9e6SYuval Mintz 	if (rc)  {
1086fe56b9e6SYuval Mintz 		DP_ERR(cdev, "qed_slowpath_setup_int ERR\n");
1087fe56b9e6SYuval Mintz 		return rc;
1088fe56b9e6SYuval Mintz 	}
1089fe56b9e6SYuval Mintz 
1090fe56b9e6SYuval Mintz 	cdev->int_params.fp_msix_base = cdev->num_hwfns;
1091fe56b9e6SYuval Mintz 	cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors -
1092fe56b9e6SYuval Mintz 				       cdev->num_hwfns;
1093fe56b9e6SYuval Mintz 
10942f782278SMintz, Yuval 	if (!IS_ENABLED(CONFIG_QED_RDMA) ||
1095c851a9dcSKalderon, Michal 	    !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev)))
10960189efb8SYuval Mintz 		return 0;
10970189efb8SYuval Mintz 
109851ff1725SRam Amrani 	for_each_hwfn(cdev, i)
109951ff1725SRam Amrani 		num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE);
110051ff1725SRam Amrani 
110151ff1725SRam Amrani 	DP_VERBOSE(cdev, QED_MSG_RDMA,
110251ff1725SRam Amrani 		   "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n",
110351ff1725SRam Amrani 		   cdev->int_params.fp_msix_cnt, num_l2_queues);
110451ff1725SRam Amrani 
110551ff1725SRam Amrani 	if (cdev->int_params.fp_msix_cnt > num_l2_queues) {
110651ff1725SRam Amrani 		cdev->int_params.rdma_msix_cnt =
110751ff1725SRam Amrani 			(cdev->int_params.fp_msix_cnt - num_l2_queues)
110851ff1725SRam Amrani 			/ cdev->num_hwfns;
110951ff1725SRam Amrani 		cdev->int_params.rdma_msix_base =
111051ff1725SRam Amrani 			cdev->int_params.fp_msix_base + num_l2_queues;
111151ff1725SRam Amrani 		cdev->int_params.fp_msix_cnt = num_l2_queues;
111251ff1725SRam Amrani 	} else {
111351ff1725SRam Amrani 		cdev->int_params.rdma_msix_cnt = 0;
111451ff1725SRam Amrani 	}
111551ff1725SRam Amrani 
111651ff1725SRam Amrani 	DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n",
111751ff1725SRam Amrani 		   cdev->int_params.rdma_msix_cnt,
111851ff1725SRam Amrani 		   cdev->int_params.rdma_msix_base);
111951ff1725SRam Amrani 
1120fe56b9e6SYuval Mintz 	return 0;
1121fe56b9e6SYuval Mintz }
1122fe56b9e6SYuval Mintz 
11231408cc1fSYuval Mintz static int qed_slowpath_vf_setup_int(struct qed_dev *cdev)
11241408cc1fSYuval Mintz {
11251408cc1fSYuval Mintz 	int rc;
11261408cc1fSYuval Mintz 
11271408cc1fSYuval Mintz 	memset(&cdev->int_params, 0, sizeof(struct qed_int_params));
11281408cc1fSYuval Mintz 	cdev->int_params.in.int_mode = QED_INT_MODE_MSIX;
11291408cc1fSYuval Mintz 
11301408cc1fSYuval Mintz 	qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev),
11311408cc1fSYuval Mintz 			    &cdev->int_params.in.num_vectors);
11321408cc1fSYuval Mintz 	if (cdev->num_hwfns > 1) {
11331408cc1fSYuval Mintz 		u8 vectors = 0;
11341408cc1fSYuval Mintz 
11351408cc1fSYuval Mintz 		qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors);
11361408cc1fSYuval Mintz 		cdev->int_params.in.num_vectors += vectors;
11371408cc1fSYuval Mintz 	}
11381408cc1fSYuval Mintz 
11391408cc1fSYuval Mintz 	/* We want a minimum of one fastpath vector per vf hwfn */
11401408cc1fSYuval Mintz 	cdev->int_params.in.min_msix_cnt = cdev->num_hwfns;
11411408cc1fSYuval Mintz 
11421408cc1fSYuval Mintz 	rc = qed_set_int_mode(cdev, true);
11431408cc1fSYuval Mintz 	if (rc)
11441408cc1fSYuval Mintz 		return rc;
11451408cc1fSYuval Mintz 
11461408cc1fSYuval Mintz 	cdev->int_params.fp_msix_base = 0;
11471408cc1fSYuval Mintz 	cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors;
11481408cc1fSYuval Mintz 
11491408cc1fSYuval Mintz 	return 0;
11501408cc1fSYuval Mintz }
11511408cc1fSYuval Mintz 
1152fe56b9e6SYuval Mintz u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len,
1153fe56b9e6SYuval Mintz 		   u8 *input_buf, u32 max_size, u8 *unzip_buf)
1154fe56b9e6SYuval Mintz {
1155fe56b9e6SYuval Mintz 	int rc;
1156fe56b9e6SYuval Mintz 
1157fe56b9e6SYuval Mintz 	p_hwfn->stream->next_in = input_buf;
1158fe56b9e6SYuval Mintz 	p_hwfn->stream->avail_in = input_len;
1159fe56b9e6SYuval Mintz 	p_hwfn->stream->next_out = unzip_buf;
1160fe56b9e6SYuval Mintz 	p_hwfn->stream->avail_out = max_size;
1161fe56b9e6SYuval Mintz 
1162fe56b9e6SYuval Mintz 	rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS);
1163fe56b9e6SYuval Mintz 
1164fe56b9e6SYuval Mintz 	if (rc != Z_OK) {
1165fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n",
1166fe56b9e6SYuval Mintz 			   rc);
1167fe56b9e6SYuval Mintz 		return 0;
1168fe56b9e6SYuval Mintz 	}
1169fe56b9e6SYuval Mintz 
1170fe56b9e6SYuval Mintz 	rc = zlib_inflate(p_hwfn->stream, Z_FINISH);
1171fe56b9e6SYuval Mintz 	zlib_inflateEnd(p_hwfn->stream);
1172fe56b9e6SYuval Mintz 
1173fe56b9e6SYuval Mintz 	if (rc != Z_OK && rc != Z_STREAM_END) {
1174fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n",
1175fe56b9e6SYuval Mintz 			   p_hwfn->stream->msg, rc);
1176fe56b9e6SYuval Mintz 		return 0;
1177fe56b9e6SYuval Mintz 	}
1178fe56b9e6SYuval Mintz 
1179fe56b9e6SYuval Mintz 	return p_hwfn->stream->total_out / 4;
1180fe56b9e6SYuval Mintz }
1181fe56b9e6SYuval Mintz 
1182fe56b9e6SYuval Mintz static int qed_alloc_stream_mem(struct qed_dev *cdev)
1183fe56b9e6SYuval Mintz {
1184fe56b9e6SYuval Mintz 	int i;
1185fe56b9e6SYuval Mintz 	void *workspace;
1186fe56b9e6SYuval Mintz 
1187fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
1188fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1189fe56b9e6SYuval Mintz 
1190fe56b9e6SYuval Mintz 		p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL);
1191fe56b9e6SYuval Mintz 		if (!p_hwfn->stream)
1192fe56b9e6SYuval Mintz 			return -ENOMEM;
1193fe56b9e6SYuval Mintz 
1194fe56b9e6SYuval Mintz 		workspace = vzalloc(zlib_inflate_workspacesize());
1195fe56b9e6SYuval Mintz 		if (!workspace)
1196fe56b9e6SYuval Mintz 			return -ENOMEM;
1197fe56b9e6SYuval Mintz 		p_hwfn->stream->workspace = workspace;
1198fe56b9e6SYuval Mintz 	}
1199fe56b9e6SYuval Mintz 
1200fe56b9e6SYuval Mintz 	return 0;
1201fe56b9e6SYuval Mintz }
1202fe56b9e6SYuval Mintz 
1203fe56b9e6SYuval Mintz static void qed_free_stream_mem(struct qed_dev *cdev)
1204fe56b9e6SYuval Mintz {
1205fe56b9e6SYuval Mintz 	int i;
1206fe56b9e6SYuval Mintz 
1207fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
1208fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1209fe56b9e6SYuval Mintz 
1210fe56b9e6SYuval Mintz 		if (!p_hwfn->stream)
1211fe56b9e6SYuval Mintz 			return;
1212fe56b9e6SYuval Mintz 
1213fe56b9e6SYuval Mintz 		vfree(p_hwfn->stream->workspace);
1214fe56b9e6SYuval Mintz 		kfree(p_hwfn->stream);
1215fe56b9e6SYuval Mintz 	}
1216fe56b9e6SYuval Mintz }
1217fe56b9e6SYuval Mintz 
1218fe56b9e6SYuval Mintz static void qed_update_pf_params(struct qed_dev *cdev,
1219fe56b9e6SYuval Mintz 				 struct qed_pf_params *params)
1220fe56b9e6SYuval Mintz {
1221fe56b9e6SYuval Mintz 	int i;
1222fe56b9e6SYuval Mintz 
12235c5f2609SRam Amrani 	if (IS_ENABLED(CONFIG_QED_RDMA)) {
12240189efb8SYuval Mintz 		params->rdma_pf_params.num_qps = QED_ROCE_QPS;
12250189efb8SYuval Mintz 		params->rdma_pf_params.min_dpis = QED_ROCE_DPIS;
122639dbc646SYuval Bason 		params->rdma_pf_params.num_srqs = QED_RDMA_SRQS;
12270189efb8SYuval Mintz 		/* divide by 3 the MRs to avoid MF ILT overflow */
12280189efb8SYuval Mintz 		params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX;
1229fe56b9e6SYuval Mintz 	}
1230fe56b9e6SYuval Mintz 
1231d51e4af5SChopra, Manish 	if (cdev->num_hwfns > 1 || IS_VF(cdev))
1232d51e4af5SChopra, Manish 		params->eth_pf_params.num_arfs_filters = 0;
1233d51e4af5SChopra, Manish 
1234e1d32acbSMintz, Yuval 	/* In case we might support RDMA, don't allow qede to be greedy
12355e7baf0fSManish Chopra 	 * with the L2 contexts. Allow for 64 queues [rx, tx cos, xdp]
12365e7baf0fSManish Chopra 	 * per hwfn.
1237e1d32acbSMintz, Yuval 	 */
1238c851a9dcSKalderon, Michal 	if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) {
1239e1d32acbSMintz, Yuval 		u16 *num_cons;
1240e1d32acbSMintz, Yuval 
1241e1d32acbSMintz, Yuval 		num_cons = &params->eth_pf_params.num_cons;
12425e7baf0fSManish Chopra 		*num_cons = min_t(u16, *num_cons, QED_MAX_L2_CONS);
1243e1d32acbSMintz, Yuval 	}
1244e1d32acbSMintz, Yuval 
12455c5f2609SRam Amrani 	for (i = 0; i < cdev->num_hwfns; i++) {
12465c5f2609SRam Amrani 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
12475c5f2609SRam Amrani 
12485c5f2609SRam Amrani 		p_hwfn->pf_params = *params;
12495c5f2609SRam Amrani 	}
12505c5f2609SRam Amrani }
12515c5f2609SRam Amrani 
1252d4476b8aSDenis Bolotin #define QED_PERIODIC_DB_REC_COUNT		10
1253a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL_MS		100
1254a1b469b8SAriel Elior #define QED_PERIODIC_DB_REC_INTERVAL \
1255a1b469b8SAriel Elior 	msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS)
1256a1b469b8SAriel Elior 
1257a1b469b8SAriel Elior static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn,
1258a1b469b8SAriel Elior 				     enum qed_slowpath_wq_flag wq_flag,
1259a1b469b8SAriel Elior 				     unsigned long delay)
1260a1b469b8SAriel Elior {
1261a1b469b8SAriel Elior 	if (!hwfn->slowpath_wq_active)
1262a1b469b8SAriel Elior 		return -EINVAL;
1263a1b469b8SAriel Elior 
1264a1b469b8SAriel Elior 	/* Memory barrier for setting atomic bit */
1265a1b469b8SAriel Elior 	smp_mb__before_atomic();
1266a1b469b8SAriel Elior 	set_bit(wq_flag, &hwfn->slowpath_task_flags);
1267a1b469b8SAriel Elior 	smp_mb__after_atomic();
1268a1b469b8SAriel Elior 	queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, delay);
1269a1b469b8SAriel Elior 
1270a1b469b8SAriel Elior 	return 0;
1271a1b469b8SAriel Elior }
1272a1b469b8SAriel Elior 
1273a1b469b8SAriel Elior void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn)
1274a1b469b8SAriel Elior {
1275a1b469b8SAriel Elior 	/* Reset periodic Doorbell Recovery counter */
1276a1b469b8SAriel Elior 	p_hwfn->periodic_db_rec_count = QED_PERIODIC_DB_REC_COUNT;
1277a1b469b8SAriel Elior 
1278a1b469b8SAriel Elior 	/* Don't schedule periodic Doorbell Recovery if already scheduled */
1279a1b469b8SAriel Elior 	if (test_bit(QED_SLOWPATH_PERIODIC_DB_REC,
1280a1b469b8SAriel Elior 		     &p_hwfn->slowpath_task_flags))
1281a1b469b8SAriel Elior 		return;
1282a1b469b8SAriel Elior 
1283a1b469b8SAriel Elior 	qed_slowpath_delayed_work(p_hwfn, QED_SLOWPATH_PERIODIC_DB_REC,
1284a1b469b8SAriel Elior 				  QED_PERIODIC_DB_REC_INTERVAL);
1285a1b469b8SAriel Elior }
1286a1b469b8SAriel Elior 
128759ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_wq_stop(struct qed_dev *cdev)
128859ccf86fSSudarsana Reddy Kalluru {
12893b85720dSYuval Basson 	int i;
129059ccf86fSSudarsana Reddy Kalluru 
129159ccf86fSSudarsana Reddy Kalluru 	if (IS_VF(cdev))
129259ccf86fSSudarsana Reddy Kalluru 		return;
129359ccf86fSSudarsana Reddy Kalluru 
129459ccf86fSSudarsana Reddy Kalluru 	for_each_hwfn(cdev, i) {
129559ccf86fSSudarsana Reddy Kalluru 		if (!cdev->hwfns[i].slowpath_wq)
129659ccf86fSSudarsana Reddy Kalluru 			continue;
129759ccf86fSSudarsana Reddy Kalluru 
1298a1b469b8SAriel Elior 		/* Stop queuing new delayed works */
1299a1b469b8SAriel Elior 		cdev->hwfns[i].slowpath_wq_active = false;
1300a1b469b8SAriel Elior 
13013b85720dSYuval Basson 		cancel_delayed_work(&cdev->hwfns[i].slowpath_task);
130259ccf86fSSudarsana Reddy Kalluru 		destroy_workqueue(cdev->hwfns[i].slowpath_wq);
130359ccf86fSSudarsana Reddy Kalluru 	}
130459ccf86fSSudarsana Reddy Kalluru }
130559ccf86fSSudarsana Reddy Kalluru 
130659ccf86fSSudarsana Reddy Kalluru static void qed_slowpath_task(struct work_struct *work)
130759ccf86fSSudarsana Reddy Kalluru {
130859ccf86fSSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn,
130959ccf86fSSudarsana Reddy Kalluru 					     slowpath_task.work);
131059ccf86fSSudarsana Reddy Kalluru 	struct qed_ptt *ptt = qed_ptt_acquire(hwfn);
131159ccf86fSSudarsana Reddy Kalluru 
131259ccf86fSSudarsana Reddy Kalluru 	if (!ptt) {
1313a1b469b8SAriel Elior 		if (hwfn->slowpath_wq_active)
1314a1b469b8SAriel Elior 			queue_delayed_work(hwfn->slowpath_wq,
1315a1b469b8SAriel Elior 					   &hwfn->slowpath_task, 0);
1316a1b469b8SAriel Elior 
131759ccf86fSSudarsana Reddy Kalluru 		return;
131859ccf86fSSudarsana Reddy Kalluru 	}
131959ccf86fSSudarsana Reddy Kalluru 
132059ccf86fSSudarsana Reddy Kalluru 	if (test_and_clear_bit(QED_SLOWPATH_MFW_TLV_REQ,
132159ccf86fSSudarsana Reddy Kalluru 			       &hwfn->slowpath_task_flags))
132259ccf86fSSudarsana Reddy Kalluru 		qed_mfw_process_tlv_req(hwfn, ptt);
132359ccf86fSSudarsana Reddy Kalluru 
1324a1b469b8SAriel Elior 	if (test_and_clear_bit(QED_SLOWPATH_PERIODIC_DB_REC,
1325a1b469b8SAriel Elior 			       &hwfn->slowpath_task_flags)) {
1326a1b469b8SAriel Elior 		qed_db_rec_handler(hwfn, ptt);
1327a1b469b8SAriel Elior 		if (hwfn->periodic_db_rec_count--)
1328a1b469b8SAriel Elior 			qed_slowpath_delayed_work(hwfn,
1329a1b469b8SAriel Elior 						  QED_SLOWPATH_PERIODIC_DB_REC,
1330a1b469b8SAriel Elior 						  QED_PERIODIC_DB_REC_INTERVAL);
1331a1b469b8SAriel Elior 	}
1332a1b469b8SAriel Elior 
133359ccf86fSSudarsana Reddy Kalluru 	qed_ptt_release(hwfn, ptt);
133459ccf86fSSudarsana Reddy Kalluru }
133559ccf86fSSudarsana Reddy Kalluru 
133659ccf86fSSudarsana Reddy Kalluru static int qed_slowpath_wq_start(struct qed_dev *cdev)
133759ccf86fSSudarsana Reddy Kalluru {
133859ccf86fSSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn;
133959ccf86fSSudarsana Reddy Kalluru 	char name[NAME_SIZE];
134059ccf86fSSudarsana Reddy Kalluru 	int i;
134159ccf86fSSudarsana Reddy Kalluru 
134259ccf86fSSudarsana Reddy Kalluru 	if (IS_VF(cdev))
134359ccf86fSSudarsana Reddy Kalluru 		return 0;
134459ccf86fSSudarsana Reddy Kalluru 
134559ccf86fSSudarsana Reddy Kalluru 	for_each_hwfn(cdev, i) {
134659ccf86fSSudarsana Reddy Kalluru 		hwfn = &cdev->hwfns[i];
134759ccf86fSSudarsana Reddy Kalluru 
134859ccf86fSSudarsana Reddy Kalluru 		snprintf(name, NAME_SIZE, "slowpath-%02x:%02x.%02x",
134959ccf86fSSudarsana Reddy Kalluru 			 cdev->pdev->bus->number,
135059ccf86fSSudarsana Reddy Kalluru 			 PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id);
135159ccf86fSSudarsana Reddy Kalluru 
135259ccf86fSSudarsana Reddy Kalluru 		hwfn->slowpath_wq = alloc_workqueue(name, 0, 0);
135359ccf86fSSudarsana Reddy Kalluru 		if (!hwfn->slowpath_wq) {
135459ccf86fSSudarsana Reddy Kalluru 			DP_NOTICE(hwfn, "Cannot create slowpath workqueue\n");
135559ccf86fSSudarsana Reddy Kalluru 			return -ENOMEM;
135659ccf86fSSudarsana Reddy Kalluru 		}
135759ccf86fSSudarsana Reddy Kalluru 
135859ccf86fSSudarsana Reddy Kalluru 		INIT_DELAYED_WORK(&hwfn->slowpath_task, qed_slowpath_task);
1359a1b469b8SAriel Elior 		hwfn->slowpath_wq_active = true;
136059ccf86fSSudarsana Reddy Kalluru 	}
136159ccf86fSSudarsana Reddy Kalluru 
136259ccf86fSSudarsana Reddy Kalluru 	return 0;
136359ccf86fSSudarsana Reddy Kalluru }
136459ccf86fSSudarsana Reddy Kalluru 
1365fe56b9e6SYuval Mintz static int qed_slowpath_start(struct qed_dev *cdev,
1366fe56b9e6SYuval Mintz 			      struct qed_slowpath_params *params)
1367fe56b9e6SYuval Mintz {
13685d24bcf1STomer Tayar 	struct qed_drv_load_params drv_load_params;
1369c0c2d0b4SMintz, Yuval 	struct qed_hw_init_params hw_init_params;
1370fe56b9e6SYuval Mintz 	struct qed_mcp_drv_version drv_version;
137119968430SChopra, Manish 	struct qed_tunnel_info tunn_info;
1372fe56b9e6SYuval Mintz 	const u8 *data = NULL;
1373fe56b9e6SYuval Mintz 	struct qed_hwfn *hwfn;
1374c78c70faSSudarsana Reddy Kalluru 	struct qed_ptt *p_ptt;
137537bff2b9SYuval Mintz 	int rc = -EINVAL;
137637bff2b9SYuval Mintz 
137737bff2b9SYuval Mintz 	if (qed_iov_wq_start(cdev))
137837bff2b9SYuval Mintz 		goto err;
1379fe56b9e6SYuval Mintz 
138059ccf86fSSudarsana Reddy Kalluru 	if (qed_slowpath_wq_start(cdev))
138159ccf86fSSudarsana Reddy Kalluru 		goto err;
138259ccf86fSSudarsana Reddy Kalluru 
13831408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
1384fe56b9e6SYuval Mintz 		rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME,
1385fe56b9e6SYuval Mintz 				      &cdev->pdev->dev);
1386fe56b9e6SYuval Mintz 		if (rc) {
1387fe56b9e6SYuval Mintz 			DP_NOTICE(cdev,
1388fe56b9e6SYuval Mintz 				  "Failed to find fw file - /lib/firmware/%s\n",
1389fe56b9e6SYuval Mintz 				  QED_FW_FILE_NAME);
1390fe56b9e6SYuval Mintz 			goto err;
1391fe56b9e6SYuval Mintz 		}
1392c78c70faSSudarsana Reddy Kalluru 
1393d51e4af5SChopra, Manish 		if (cdev->num_hwfns == 1) {
1394d51e4af5SChopra, Manish 			p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
1395d51e4af5SChopra, Manish 			if (p_ptt) {
1396d51e4af5SChopra, Manish 				QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt;
1397d51e4af5SChopra, Manish 			} else {
1398d51e4af5SChopra, Manish 				DP_NOTICE(cdev,
1399d51e4af5SChopra, Manish 					  "Failed to acquire PTT for aRFS\n");
1400d51e4af5SChopra, Manish 				goto err;
1401d51e4af5SChopra, Manish 			}
1402d51e4af5SChopra, Manish 		}
14031408cc1fSYuval Mintz 	}
1404fe56b9e6SYuval Mintz 
14050e191827SSudarsana Reddy Kalluru 	cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS;
1406fe56b9e6SYuval Mintz 	rc = qed_nic_setup(cdev);
1407fe56b9e6SYuval Mintz 	if (rc)
1408fe56b9e6SYuval Mintz 		goto err;
1409fe56b9e6SYuval Mintz 
14101408cc1fSYuval Mintz 	if (IS_PF(cdev))
1411fe56b9e6SYuval Mintz 		rc = qed_slowpath_setup_int(cdev, params->int_mode);
14121408cc1fSYuval Mintz 	else
14131408cc1fSYuval Mintz 		rc = qed_slowpath_vf_setup_int(cdev);
1414fe56b9e6SYuval Mintz 	if (rc)
1415fe56b9e6SYuval Mintz 		goto err1;
1416fe56b9e6SYuval Mintz 
14171408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
1418fe56b9e6SYuval Mintz 		/* Allocate stream for unzipping */
1419fe56b9e6SYuval Mintz 		rc = qed_alloc_stream_mem(cdev);
14202591c280SJoe Perches 		if (rc)
14218f16bc97SSudarsana Kalluru 			goto err2;
1422fe56b9e6SYuval Mintz 
14238ac1ed79SJoe Perches 		/* First Dword used to differentiate between various sources */
1424351a4dedSYuval Mintz 		data = cdev->firmware->data + sizeof(u32);
1425c965db44STomer Tayar 
1426c965db44STomer Tayar 		qed_dbg_pf_init(cdev);
14271408cc1fSYuval Mintz 	}
1428fe56b9e6SYuval Mintz 
14291408cc1fSYuval Mintz 	/* Start the slowpath */
1430c0c2d0b4SMintz, Yuval 	memset(&hw_init_params, 0, sizeof(hw_init_params));
143119968430SChopra, Manish 	memset(&tunn_info, 0, sizeof(tunn_info));
143219968430SChopra, Manish 	tunn_info.vxlan.b_mode_enabled = true;
143319968430SChopra, Manish 	tunn_info.l2_gre.b_mode_enabled = true;
143419968430SChopra, Manish 	tunn_info.ip_gre.b_mode_enabled = true;
143519968430SChopra, Manish 	tunn_info.l2_geneve.b_mode_enabled = true;
143619968430SChopra, Manish 	tunn_info.ip_geneve.b_mode_enabled = true;
143719968430SChopra, Manish 	tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
143819968430SChopra, Manish 	tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
143919968430SChopra, Manish 	tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
144019968430SChopra, Manish 	tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
144119968430SChopra, Manish 	tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
1442c0c2d0b4SMintz, Yuval 	hw_init_params.p_tunn = &tunn_info;
1443c0c2d0b4SMintz, Yuval 	hw_init_params.b_hw_start = true;
1444c0c2d0b4SMintz, Yuval 	hw_init_params.int_mode = cdev->int_params.out.int_mode;
1445c0c2d0b4SMintz, Yuval 	hw_init_params.allow_npar_tx_switch = true;
1446c0c2d0b4SMintz, Yuval 	hw_init_params.bin_fw_data = data;
1447c0c2d0b4SMintz, Yuval 
14485d24bcf1STomer Tayar 	memset(&drv_load_params, 0, sizeof(drv_load_params));
14495d24bcf1STomer Tayar 	drv_load_params.is_crash_kernel = is_kdump_kernel();
14505d24bcf1STomer Tayar 	drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT;
14515d24bcf1STomer Tayar 	drv_load_params.avoid_eng_reset = false;
14525d24bcf1STomer Tayar 	drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE;
14535d24bcf1STomer Tayar 	hw_init_params.p_drv_load_params = &drv_load_params;
14545d24bcf1STomer Tayar 
1455c0c2d0b4SMintz, Yuval 	rc = qed_hw_init(cdev, &hw_init_params);
1456fe56b9e6SYuval Mintz 	if (rc)
14578c925c44SYuval Mintz 		goto err2;
1458fe56b9e6SYuval Mintz 
1459fe56b9e6SYuval Mintz 	DP_INFO(cdev,
1460fe56b9e6SYuval Mintz 		"HW initialization and function start completed successfully\n");
1461fe56b9e6SYuval Mintz 
1462eaf3c0c6SChopra, Manish 	if (IS_PF(cdev)) {
1463eaf3c0c6SChopra, Manish 		cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) |
1464eaf3c0c6SChopra, Manish 					   BIT(QED_MODE_L2GENEVE_TUNN) |
1465eaf3c0c6SChopra, Manish 					   BIT(QED_MODE_IPGENEVE_TUNN) |
1466eaf3c0c6SChopra, Manish 					   BIT(QED_MODE_L2GRE_TUNN) |
1467eaf3c0c6SChopra, Manish 					   BIT(QED_MODE_IPGRE_TUNN));
1468eaf3c0c6SChopra, Manish 	}
1469eaf3c0c6SChopra, Manish 
14700a7fb11cSYuval Mintz 	/* Allocate LL2 interface if needed */
14710a7fb11cSYuval Mintz 	if (QED_LEADING_HWFN(cdev)->using_ll2) {
14720a7fb11cSYuval Mintz 		rc = qed_ll2_alloc_if(cdev);
14730a7fb11cSYuval Mintz 		if (rc)
14740a7fb11cSYuval Mintz 			goto err3;
14750a7fb11cSYuval Mintz 	}
14761408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
1477fe56b9e6SYuval Mintz 		hwfn = QED_LEADING_HWFN(cdev);
1478fe56b9e6SYuval Mintz 		drv_version.version = (params->drv_major << 24) |
1479fe56b9e6SYuval Mintz 				      (params->drv_minor << 16) |
1480fe56b9e6SYuval Mintz 				      (params->drv_rev << 8) |
1481fe56b9e6SYuval Mintz 				      (params->drv_eng);
1482fe56b9e6SYuval Mintz 		strlcpy(drv_version.name, params->name,
1483fe56b9e6SYuval Mintz 			MCP_DRV_VER_STR_SIZE - 4);
1484fe56b9e6SYuval Mintz 		rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt,
1485fe56b9e6SYuval Mintz 					      &drv_version);
1486fe56b9e6SYuval Mintz 		if (rc) {
1487fe56b9e6SYuval Mintz 			DP_NOTICE(cdev, "Failed sending drv version command\n");
1488de0e4fd2SWenwen Wang 			goto err4;
1489fe56b9e6SYuval Mintz 		}
14901408cc1fSYuval Mintz 	}
1491fe56b9e6SYuval Mintz 
14928c925c44SYuval Mintz 	qed_reset_vport_stats(cdev);
14938c925c44SYuval Mintz 
1494fe56b9e6SYuval Mintz 	return 0;
1495fe56b9e6SYuval Mintz 
1496de0e4fd2SWenwen Wang err4:
1497de0e4fd2SWenwen Wang 	qed_ll2_dealloc_if(cdev);
14980a7fb11cSYuval Mintz err3:
14990a7fb11cSYuval Mintz 	qed_hw_stop(cdev);
1500fe56b9e6SYuval Mintz err2:
15018c925c44SYuval Mintz 	qed_hw_timers_stop_all(cdev);
15021408cc1fSYuval Mintz 	if (IS_PF(cdev))
15038c925c44SYuval Mintz 		qed_slowpath_irq_free(cdev);
15048c925c44SYuval Mintz 	qed_free_stream_mem(cdev);
1505fe56b9e6SYuval Mintz 	qed_disable_msix(cdev);
1506fe56b9e6SYuval Mintz err1:
1507fe56b9e6SYuval Mintz 	qed_resc_free(cdev);
1508fe56b9e6SYuval Mintz err:
15091408cc1fSYuval Mintz 	if (IS_PF(cdev))
1510fe56b9e6SYuval Mintz 		release_firmware(cdev->firmware);
1511fe56b9e6SYuval Mintz 
1512d51e4af5SChopra, Manish 	if (IS_PF(cdev) && (cdev->num_hwfns == 1) &&
1513d51e4af5SChopra, Manish 	    QED_LEADING_HWFN(cdev)->p_arfs_ptt)
1514d51e4af5SChopra, Manish 		qed_ptt_release(QED_LEADING_HWFN(cdev),
1515d51e4af5SChopra, Manish 				QED_LEADING_HWFN(cdev)->p_arfs_ptt);
1516c78c70faSSudarsana Reddy Kalluru 
151737bff2b9SYuval Mintz 	qed_iov_wq_stop(cdev, false);
151837bff2b9SYuval Mintz 
151959ccf86fSSudarsana Reddy Kalluru 	qed_slowpath_wq_stop(cdev);
152059ccf86fSSudarsana Reddy Kalluru 
1521fe56b9e6SYuval Mintz 	return rc;
1522fe56b9e6SYuval Mintz }
1523fe56b9e6SYuval Mintz 
1524fe56b9e6SYuval Mintz static int qed_slowpath_stop(struct qed_dev *cdev)
1525fe56b9e6SYuval Mintz {
1526fe56b9e6SYuval Mintz 	if (!cdev)
1527fe56b9e6SYuval Mintz 		return -ENODEV;
1528fe56b9e6SYuval Mintz 
152959ccf86fSSudarsana Reddy Kalluru 	qed_slowpath_wq_stop(cdev);
153059ccf86fSSudarsana Reddy Kalluru 
15310a7fb11cSYuval Mintz 	qed_ll2_dealloc_if(cdev);
15320a7fb11cSYuval Mintz 
15331408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
1534d51e4af5SChopra, Manish 		if (cdev->num_hwfns == 1)
1535d51e4af5SChopra, Manish 			qed_ptt_release(QED_LEADING_HWFN(cdev),
1536d51e4af5SChopra, Manish 					QED_LEADING_HWFN(cdev)->p_arfs_ptt);
1537fe56b9e6SYuval Mintz 		qed_free_stream_mem(cdev);
1538c5ac9319SYuval Mintz 		if (IS_QED_ETH_IF(cdev))
15390b55e27dSYuval Mintz 			qed_sriov_disable(cdev, true);
15405f027d7aSMintz, Yuval 	}
1541fe56b9e6SYuval Mintz 
1542fe56b9e6SYuval Mintz 	qed_nic_stop(cdev);
15435f027d7aSMintz, Yuval 
15445f027d7aSMintz, Yuval 	if (IS_PF(cdev))
1545fe56b9e6SYuval Mintz 		qed_slowpath_irq_free(cdev);
1546fe56b9e6SYuval Mintz 
1547fe56b9e6SYuval Mintz 	qed_disable_msix(cdev);
15481226337aSTomer Tayar 
15491226337aSTomer Tayar 	qed_resc_free(cdev);
1550fe56b9e6SYuval Mintz 
155137bff2b9SYuval Mintz 	qed_iov_wq_stop(cdev, true);
155237bff2b9SYuval Mintz 
15531408cc1fSYuval Mintz 	if (IS_PF(cdev))
1554fe56b9e6SYuval Mintz 		release_firmware(cdev->firmware);
1555fe56b9e6SYuval Mintz 
1556fe56b9e6SYuval Mintz 	return 0;
1557fe56b9e6SYuval Mintz }
1558fe56b9e6SYuval Mintz 
1559712c3cbfSMintz, Yuval static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE])
1560fe56b9e6SYuval Mintz {
1561fe56b9e6SYuval Mintz 	int i;
1562fe56b9e6SYuval Mintz 
1563fe56b9e6SYuval Mintz 	memcpy(cdev->name, name, NAME_SIZE);
1564fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i)
1565fe56b9e6SYuval Mintz 		snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i);
1566fe56b9e6SYuval Mintz }
1567fe56b9e6SYuval Mintz 
1568fe56b9e6SYuval Mintz static u32 qed_sb_init(struct qed_dev *cdev,
1569fe56b9e6SYuval Mintz 		       struct qed_sb_info *sb_info,
1570fe56b9e6SYuval Mintz 		       void *sb_virt_addr,
1571fe56b9e6SYuval Mintz 		       dma_addr_t sb_phy_addr, u16 sb_id,
1572fe56b9e6SYuval Mintz 		       enum qed_sb_type type)
1573fe56b9e6SYuval Mintz {
1574fe56b9e6SYuval Mintz 	struct qed_hwfn *p_hwfn;
157585750d74SMintz, Yuval 	struct qed_ptt *p_ptt;
1576fe56b9e6SYuval Mintz 	u16 rel_sb_id;
1577fe56b9e6SYuval Mintz 	u32 rc;
1578fe56b9e6SYuval Mintz 
157908eb1fb0SMichal Kalderon 	/* RoCE/Storage use a single engine in CMT mode while L2 uses both */
158008eb1fb0SMichal Kalderon 	if (type == QED_SB_TYPE_L2_QUEUE) {
158108eb1fb0SMichal Kalderon 		p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns];
158208eb1fb0SMichal Kalderon 		rel_sb_id = sb_id / cdev->num_hwfns;
158308eb1fb0SMichal Kalderon 	} else {
158408eb1fb0SMichal Kalderon 		p_hwfn = QED_AFFIN_HWFN(cdev);
158508eb1fb0SMichal Kalderon 		rel_sb_id = sb_id;
158608eb1fb0SMichal Kalderon 	}
1587fe56b9e6SYuval Mintz 
1588fe56b9e6SYuval Mintz 	DP_VERBOSE(cdev, NETIF_MSG_INTR,
1589fe56b9e6SYuval Mintz 		   "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n",
159008eb1fb0SMichal Kalderon 		   IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id);
1591fe56b9e6SYuval Mintz 
159285750d74SMintz, Yuval 	if (IS_PF(p_hwfn->cdev)) {
159385750d74SMintz, Yuval 		p_ptt = qed_ptt_acquire(p_hwfn);
159485750d74SMintz, Yuval 		if (!p_ptt)
159585750d74SMintz, Yuval 			return -EBUSY;
159685750d74SMintz, Yuval 
159785750d74SMintz, Yuval 		rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr,
159885750d74SMintz, Yuval 				     sb_phy_addr, rel_sb_id);
159985750d74SMintz, Yuval 		qed_ptt_release(p_hwfn, p_ptt);
160085750d74SMintz, Yuval 	} else {
160185750d74SMintz, Yuval 		rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr,
160285750d74SMintz, Yuval 				     sb_phy_addr, rel_sb_id);
160385750d74SMintz, Yuval 	}
1604fe56b9e6SYuval Mintz 
1605fe56b9e6SYuval Mintz 	return rc;
1606fe56b9e6SYuval Mintz }
1607fe56b9e6SYuval Mintz 
1608fe56b9e6SYuval Mintz static u32 qed_sb_release(struct qed_dev *cdev,
160908eb1fb0SMichal Kalderon 			  struct qed_sb_info *sb_info,
161008eb1fb0SMichal Kalderon 			  u16 sb_id,
161108eb1fb0SMichal Kalderon 			  enum qed_sb_type type)
1612fe56b9e6SYuval Mintz {
1613fe56b9e6SYuval Mintz 	struct qed_hwfn *p_hwfn;
1614fe56b9e6SYuval Mintz 	u16 rel_sb_id;
1615fe56b9e6SYuval Mintz 	u32 rc;
1616fe56b9e6SYuval Mintz 
161708eb1fb0SMichal Kalderon 	/* RoCE/Storage use a single engine in CMT mode while L2 uses both */
161808eb1fb0SMichal Kalderon 	if (type == QED_SB_TYPE_L2_QUEUE) {
161908eb1fb0SMichal Kalderon 		p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns];
1620fe56b9e6SYuval Mintz 		rel_sb_id = sb_id / cdev->num_hwfns;
162108eb1fb0SMichal Kalderon 	} else {
162208eb1fb0SMichal Kalderon 		p_hwfn = QED_AFFIN_HWFN(cdev);
162308eb1fb0SMichal Kalderon 		rel_sb_id = sb_id;
162408eb1fb0SMichal Kalderon 	}
1625fe56b9e6SYuval Mintz 
1626fe56b9e6SYuval Mintz 	DP_VERBOSE(cdev, NETIF_MSG_INTR,
1627fe56b9e6SYuval Mintz 		   "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n",
162808eb1fb0SMichal Kalderon 		   IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id);
1629fe56b9e6SYuval Mintz 
1630fe56b9e6SYuval Mintz 	rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id);
1631fe56b9e6SYuval Mintz 
1632fe56b9e6SYuval Mintz 	return rc;
1633fe56b9e6SYuval Mintz }
1634fe56b9e6SYuval Mintz 
1635fe7cd2bfSYuval Mintz static bool qed_can_link_change(struct qed_dev *cdev)
1636fe7cd2bfSYuval Mintz {
1637fe7cd2bfSYuval Mintz 	return true;
1638fe7cd2bfSYuval Mintz }
1639fe7cd2bfSYuval Mintz 
164099785a87SAlexander Lobakin static void qed_set_ext_speed_params(struct qed_mcp_link_params *link_params,
164199785a87SAlexander Lobakin 				     const struct qed_link_params *params)
164299785a87SAlexander Lobakin {
164399785a87SAlexander Lobakin 	struct qed_mcp_link_speed_params *ext_speed = &link_params->ext_speed;
164499785a87SAlexander Lobakin 	const struct qed_mfw_speed_map *map;
164599785a87SAlexander Lobakin 	u32 i;
164699785a87SAlexander Lobakin 
164799785a87SAlexander Lobakin 	if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG)
164899785a87SAlexander Lobakin 		ext_speed->autoneg = !!params->autoneg;
164999785a87SAlexander Lobakin 
165099785a87SAlexander Lobakin 	if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) {
165199785a87SAlexander Lobakin 		ext_speed->advertised_speeds = 0;
165299785a87SAlexander Lobakin 
165399785a87SAlexander Lobakin 		for (i = 0; i < ARRAY_SIZE(qed_mfw_ext_maps); i++) {
165499785a87SAlexander Lobakin 			map = qed_mfw_ext_maps + i;
165599785a87SAlexander Lobakin 
165699785a87SAlexander Lobakin 			if (linkmode_intersects(params->adv_speeds, map->caps))
165799785a87SAlexander Lobakin 				ext_speed->advertised_speeds |= map->mfw_val;
165899785a87SAlexander Lobakin 		}
165999785a87SAlexander Lobakin 	}
166099785a87SAlexander Lobakin 
166199785a87SAlexander Lobakin 	if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) {
166299785a87SAlexander Lobakin 		switch (params->forced_speed) {
166399785a87SAlexander Lobakin 		case SPEED_1000:
166499785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_1G;
166599785a87SAlexander Lobakin 			break;
166699785a87SAlexander Lobakin 		case SPEED_10000:
166799785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_10G;
166899785a87SAlexander Lobakin 			break;
166999785a87SAlexander Lobakin 		case SPEED_20000:
167099785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_20G;
167199785a87SAlexander Lobakin 			break;
167299785a87SAlexander Lobakin 		case SPEED_25000:
167399785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_25G;
167499785a87SAlexander Lobakin 			break;
167599785a87SAlexander Lobakin 		case SPEED_40000:
167699785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_40G;
167799785a87SAlexander Lobakin 			break;
167899785a87SAlexander Lobakin 		case SPEED_50000:
167999785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_50G_R |
168099785a87SAlexander Lobakin 						  QED_EXT_SPEED_50G_R2;
168199785a87SAlexander Lobakin 			break;
168299785a87SAlexander Lobakin 		case SPEED_100000:
168399785a87SAlexander Lobakin 			ext_speed->forced_speed = QED_EXT_SPEED_100G_R2 |
168499785a87SAlexander Lobakin 						  QED_EXT_SPEED_100G_R4 |
168599785a87SAlexander Lobakin 						  QED_EXT_SPEED_100G_P4;
168699785a87SAlexander Lobakin 			break;
168799785a87SAlexander Lobakin 		default:
168899785a87SAlexander Lobakin 			break;
168999785a87SAlexander Lobakin 		}
169099785a87SAlexander Lobakin 	}
169199785a87SAlexander Lobakin 
169299785a87SAlexander Lobakin 	if (!(params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG))
169399785a87SAlexander Lobakin 		return;
169499785a87SAlexander Lobakin 
169599785a87SAlexander Lobakin 	switch (params->forced_speed) {
169699785a87SAlexander Lobakin 	case SPEED_25000:
169799785a87SAlexander Lobakin 		switch (params->fec) {
169899785a87SAlexander Lobakin 		case FEC_FORCE_MODE_NONE:
169999785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_25G_NONE;
170099785a87SAlexander Lobakin 			break;
170199785a87SAlexander Lobakin 		case FEC_FORCE_MODE_FIRECODE:
170299785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_25G_BASE_R;
170399785a87SAlexander Lobakin 			break;
170499785a87SAlexander Lobakin 		case FEC_FORCE_MODE_RS:
170599785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528;
170699785a87SAlexander Lobakin 			break;
170799785a87SAlexander Lobakin 		case FEC_FORCE_MODE_AUTO:
170899785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_25G_RS528 |
170999785a87SAlexander Lobakin 						    ETH_EXT_FEC_25G_BASE_R |
171099785a87SAlexander Lobakin 						    ETH_EXT_FEC_25G_NONE;
171199785a87SAlexander Lobakin 			break;
171299785a87SAlexander Lobakin 		default:
171399785a87SAlexander Lobakin 			break;
171499785a87SAlexander Lobakin 		}
171599785a87SAlexander Lobakin 
171699785a87SAlexander Lobakin 		break;
171799785a87SAlexander Lobakin 	case SPEED_40000:
171899785a87SAlexander Lobakin 		switch (params->fec) {
171999785a87SAlexander Lobakin 		case FEC_FORCE_MODE_NONE:
172099785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_40G_NONE;
172199785a87SAlexander Lobakin 			break;
172299785a87SAlexander Lobakin 		case FEC_FORCE_MODE_FIRECODE:
172399785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R;
172499785a87SAlexander Lobakin 			break;
172599785a87SAlexander Lobakin 		case FEC_FORCE_MODE_AUTO:
172699785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_40G_BASE_R |
172799785a87SAlexander Lobakin 						    ETH_EXT_FEC_40G_NONE;
172899785a87SAlexander Lobakin 			break;
172999785a87SAlexander Lobakin 		default:
173099785a87SAlexander Lobakin 			break;
173199785a87SAlexander Lobakin 		}
173299785a87SAlexander Lobakin 
173399785a87SAlexander Lobakin 		break;
173499785a87SAlexander Lobakin 	case SPEED_50000:
173599785a87SAlexander Lobakin 		switch (params->fec) {
173699785a87SAlexander Lobakin 		case FEC_FORCE_MODE_NONE:
173799785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_50G_NONE;
173899785a87SAlexander Lobakin 			break;
173999785a87SAlexander Lobakin 		case FEC_FORCE_MODE_FIRECODE:
174099785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_50G_BASE_R;
174199785a87SAlexander Lobakin 			break;
174299785a87SAlexander Lobakin 		case FEC_FORCE_MODE_RS:
174399785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528;
174499785a87SAlexander Lobakin 			break;
174599785a87SAlexander Lobakin 		case FEC_FORCE_MODE_AUTO:
174699785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_50G_RS528 |
174799785a87SAlexander Lobakin 						    ETH_EXT_FEC_50G_BASE_R |
174899785a87SAlexander Lobakin 						    ETH_EXT_FEC_50G_NONE;
174999785a87SAlexander Lobakin 			break;
175099785a87SAlexander Lobakin 		default:
175199785a87SAlexander Lobakin 			break;
175299785a87SAlexander Lobakin 		}
175399785a87SAlexander Lobakin 
175499785a87SAlexander Lobakin 		break;
175599785a87SAlexander Lobakin 	case SPEED_100000:
175699785a87SAlexander Lobakin 		switch (params->fec) {
175799785a87SAlexander Lobakin 		case FEC_FORCE_MODE_NONE:
175899785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_100G_NONE;
175999785a87SAlexander Lobakin 			break;
176099785a87SAlexander Lobakin 		case FEC_FORCE_MODE_FIRECODE:
176199785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_100G_BASE_R;
176299785a87SAlexander Lobakin 			break;
176399785a87SAlexander Lobakin 		case FEC_FORCE_MODE_RS:
176499785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528;
176599785a87SAlexander Lobakin 			break;
176699785a87SAlexander Lobakin 		case FEC_FORCE_MODE_AUTO:
176799785a87SAlexander Lobakin 			link_params->ext_fec_mode = ETH_EXT_FEC_100G_RS528 |
176899785a87SAlexander Lobakin 						    ETH_EXT_FEC_100G_BASE_R |
176999785a87SAlexander Lobakin 						    ETH_EXT_FEC_100G_NONE;
177099785a87SAlexander Lobakin 			break;
177199785a87SAlexander Lobakin 		default:
177299785a87SAlexander Lobakin 			break;
177399785a87SAlexander Lobakin 		}
177499785a87SAlexander Lobakin 
177599785a87SAlexander Lobakin 		break;
177699785a87SAlexander Lobakin 	default:
177799785a87SAlexander Lobakin 		break;
177899785a87SAlexander Lobakin 	}
177999785a87SAlexander Lobakin }
178099785a87SAlexander Lobakin 
1781351a4dedSYuval Mintz static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
1782cc875c2eSYuval Mintz {
1783cc875c2eSYuval Mintz 	struct qed_mcp_link_params *link_params;
1784097818fcSAlexander Lobakin 	struct qed_mcp_link_speed_params *speed;
1785097818fcSAlexander Lobakin 	const struct qed_mfw_speed_map *map;
1786bdb5d8ecSAlexander Lobakin 	struct qed_hwfn *hwfn;
1787cc875c2eSYuval Mintz 	struct qed_ptt *ptt;
1788cc875c2eSYuval Mintz 	int rc;
1789097818fcSAlexander Lobakin 	u32 i;
1790cc875c2eSYuval Mintz 
1791cc875c2eSYuval Mintz 	if (!cdev)
1792cc875c2eSYuval Mintz 		return -ENODEV;
1793cc875c2eSYuval Mintz 
1794cc875c2eSYuval Mintz 	/* The link should be set only once per PF */
1795cc875c2eSYuval Mintz 	hwfn = &cdev->hwfns[0];
1796cc875c2eSYuval Mintz 
179765ed2ffdSMintz, Yuval 	/* When VF wants to set link, force it to read the bulletin instead.
179865ed2ffdSMintz, Yuval 	 * This mimics the PF behavior, where a noitification [both immediate
179965ed2ffdSMintz, Yuval 	 * and possible later] would be generated when changing properties.
180065ed2ffdSMintz, Yuval 	 */
180165ed2ffdSMintz, Yuval 	if (IS_VF(cdev)) {
180265ed2ffdSMintz, Yuval 		qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG);
180365ed2ffdSMintz, Yuval 		return 0;
180465ed2ffdSMintz, Yuval 	}
180565ed2ffdSMintz, Yuval 
1806cc875c2eSYuval Mintz 	ptt = qed_ptt_acquire(hwfn);
1807cc875c2eSYuval Mintz 	if (!ptt)
1808cc875c2eSYuval Mintz 		return -EBUSY;
1809cc875c2eSYuval Mintz 
1810cc875c2eSYuval Mintz 	link_params = qed_mcp_get_link_params(hwfn);
1811bdb5d8ecSAlexander Lobakin 	if (!link_params)
1812bdb5d8ecSAlexander Lobakin 		return -ENODATA;
1813bdb5d8ecSAlexander Lobakin 
1814097818fcSAlexander Lobakin 	speed = &link_params->speed;
1815097818fcSAlexander Lobakin 
1816cc875c2eSYuval Mintz 	if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG)
1817097818fcSAlexander Lobakin 		speed->autoneg = !!params->autoneg;
1818bdb5d8ecSAlexander Lobakin 
1819cc875c2eSYuval Mintz 	if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) {
1820097818fcSAlexander Lobakin 		speed->advertised_speeds = 0;
1821bdb5d8ecSAlexander Lobakin 
1822097818fcSAlexander Lobakin 		for (i = 0; i < ARRAY_SIZE(qed_mfw_legacy_maps); i++) {
1823097818fcSAlexander Lobakin 			map = qed_mfw_legacy_maps + i;
1824bdb5d8ecSAlexander Lobakin 
1825097818fcSAlexander Lobakin 			if (linkmode_intersects(params->adv_speeds, map->caps))
1826097818fcSAlexander Lobakin 				speed->advertised_speeds |= map->mfw_val;
1827097818fcSAlexander Lobakin 		}
1828cc875c2eSYuval Mintz 	}
1829bdb5d8ecSAlexander Lobakin 
1830cc875c2eSYuval Mintz 	if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED)
1831097818fcSAlexander Lobakin 		speed->forced_speed = params->forced_speed;
1832097818fcSAlexander Lobakin 
183399785a87SAlexander Lobakin 	if (qed_mcp_is_ext_speed_supported(hwfn))
183499785a87SAlexander Lobakin 		qed_set_ext_speed_params(link_params, params);
183599785a87SAlexander Lobakin 
1836a43f235fSSudarsana Reddy Kalluru 	if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) {
1837a43f235fSSudarsana Reddy Kalluru 		if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
1838a43f235fSSudarsana Reddy Kalluru 			link_params->pause.autoneg = true;
1839a43f235fSSudarsana Reddy Kalluru 		else
1840a43f235fSSudarsana Reddy Kalluru 			link_params->pause.autoneg = false;
1841a43f235fSSudarsana Reddy Kalluru 		if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE)
1842a43f235fSSudarsana Reddy Kalluru 			link_params->pause.forced_rx = true;
1843a43f235fSSudarsana Reddy Kalluru 		else
1844a43f235fSSudarsana Reddy Kalluru 			link_params->pause.forced_rx = false;
1845a43f235fSSudarsana Reddy Kalluru 		if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE)
1846a43f235fSSudarsana Reddy Kalluru 			link_params->pause.forced_tx = true;
1847a43f235fSSudarsana Reddy Kalluru 		else
1848a43f235fSSudarsana Reddy Kalluru 			link_params->pause.forced_tx = false;
1849a43f235fSSudarsana Reddy Kalluru 	}
1850097818fcSAlexander Lobakin 
185103dc76caSSudarsana Reddy Kalluru 	if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) {
185203dc76caSSudarsana Reddy Kalluru 		switch (params->loopback_mode) {
185303dc76caSSudarsana Reddy Kalluru 		case QED_LINK_LOOPBACK_INT_PHY:
1854351a4dedSYuval Mintz 			link_params->loopback_mode = ETH_LOOPBACK_INT_PHY;
185503dc76caSSudarsana Reddy Kalluru 			break;
185603dc76caSSudarsana Reddy Kalluru 		case QED_LINK_LOOPBACK_EXT_PHY:
1857351a4dedSYuval Mintz 			link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY;
185803dc76caSSudarsana Reddy Kalluru 			break;
185903dc76caSSudarsana Reddy Kalluru 		case QED_LINK_LOOPBACK_EXT:
1860351a4dedSYuval Mintz 			link_params->loopback_mode = ETH_LOOPBACK_EXT;
186103dc76caSSudarsana Reddy Kalluru 			break;
186203dc76caSSudarsana Reddy Kalluru 		case QED_LINK_LOOPBACK_MAC:
1863351a4dedSYuval Mintz 			link_params->loopback_mode = ETH_LOOPBACK_MAC;
186403dc76caSSudarsana Reddy Kalluru 			break;
186598e675ecSAlexander Lobakin 		case QED_LINK_LOOPBACK_CNIG_AH_ONLY_0123:
186698e675ecSAlexander Lobakin 			link_params->loopback_mode =
186798e675ecSAlexander Lobakin 				ETH_LOOPBACK_CNIG_AH_ONLY_0123;
186898e675ecSAlexander Lobakin 			break;
186998e675ecSAlexander Lobakin 		case QED_LINK_LOOPBACK_CNIG_AH_ONLY_2301:
187098e675ecSAlexander Lobakin 			link_params->loopback_mode =
187198e675ecSAlexander Lobakin 				ETH_LOOPBACK_CNIG_AH_ONLY_2301;
187298e675ecSAlexander Lobakin 			break;
187398e675ecSAlexander Lobakin 		case QED_LINK_LOOPBACK_PCS_AH_ONLY:
187498e675ecSAlexander Lobakin 			link_params->loopback_mode = ETH_LOOPBACK_PCS_AH_ONLY;
187598e675ecSAlexander Lobakin 			break;
187698e675ecSAlexander Lobakin 		case QED_LINK_LOOPBACK_REVERSE_MAC_AH_ONLY:
187798e675ecSAlexander Lobakin 			link_params->loopback_mode =
187898e675ecSAlexander Lobakin 				ETH_LOOPBACK_REVERSE_MAC_AH_ONLY;
187998e675ecSAlexander Lobakin 			break;
188098e675ecSAlexander Lobakin 		case QED_LINK_LOOPBACK_INT_PHY_FEA_AH_ONLY:
188198e675ecSAlexander Lobakin 			link_params->loopback_mode =
188298e675ecSAlexander Lobakin 				ETH_LOOPBACK_INT_PHY_FEA_AH_ONLY;
188398e675ecSAlexander Lobakin 			break;
188403dc76caSSudarsana Reddy Kalluru 		default:
1885351a4dedSYuval Mintz 			link_params->loopback_mode = ETH_LOOPBACK_NONE;
188603dc76caSSudarsana Reddy Kalluru 			break;
188703dc76caSSudarsana Reddy Kalluru 		}
188803dc76caSSudarsana Reddy Kalluru 	}
1889cc875c2eSYuval Mintz 
1890645874e5SSudarsana Reddy Kalluru 	if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG)
1891645874e5SSudarsana Reddy Kalluru 		memcpy(&link_params->eee, &params->eee,
1892645874e5SSudarsana Reddy Kalluru 		       sizeof(link_params->eee));
1893645874e5SSudarsana Reddy Kalluru 
1894ae7e6937SAlexander Lobakin 	if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)
1895ae7e6937SAlexander Lobakin 		link_params->fec = params->fec;
1896ae7e6937SAlexander Lobakin 
1897cc875c2eSYuval Mintz 	rc = qed_mcp_set_link(hwfn, ptt, params->link_up);
1898cc875c2eSYuval Mintz 
1899cc875c2eSYuval Mintz 	qed_ptt_release(hwfn, ptt);
1900cc875c2eSYuval Mintz 
1901cc875c2eSYuval Mintz 	return rc;
1902cc875c2eSYuval Mintz }
1903cc875c2eSYuval Mintz 
1904cc875c2eSYuval Mintz static int qed_get_port_type(u32 media_type)
1905cc875c2eSYuval Mintz {
1906cc875c2eSYuval Mintz 	int port_type;
1907cc875c2eSYuval Mintz 
1908cc875c2eSYuval Mintz 	switch (media_type) {
1909cc875c2eSYuval Mintz 	case MEDIA_SFPP_10G_FIBER:
1910cc875c2eSYuval Mintz 	case MEDIA_SFP_1G_FIBER:
1911cc875c2eSYuval Mintz 	case MEDIA_XFP_FIBER:
1912b639f197SYuval Mintz 	case MEDIA_MODULE_FIBER:
1913cc875c2eSYuval Mintz 		port_type = PORT_FIBRE;
1914cc875c2eSYuval Mintz 		break;
1915cc875c2eSYuval Mintz 	case MEDIA_DA_TWINAX:
1916cc875c2eSYuval Mintz 		port_type = PORT_DA;
1917cc875c2eSYuval Mintz 		break;
1918cc875c2eSYuval Mintz 	case MEDIA_BASE_T:
1919cc875c2eSYuval Mintz 		port_type = PORT_TP;
1920cc875c2eSYuval Mintz 		break;
192199785a87SAlexander Lobakin 	case MEDIA_KR:
1922cc875c2eSYuval Mintz 	case MEDIA_NOT_PRESENT:
1923cc875c2eSYuval Mintz 		port_type = PORT_NONE;
1924cc875c2eSYuval Mintz 		break;
1925cc875c2eSYuval Mintz 	case MEDIA_UNSPECIFIED:
1926cc875c2eSYuval Mintz 	default:
1927cc875c2eSYuval Mintz 		port_type = PORT_OTHER;
1928cc875c2eSYuval Mintz 		break;
1929cc875c2eSYuval Mintz 	}
1930cc875c2eSYuval Mintz 	return port_type;
1931cc875c2eSYuval Mintz }
1932cc875c2eSYuval Mintz 
193314b84e86SArnd Bergmann static int qed_get_link_data(struct qed_hwfn *hwfn,
193414b84e86SArnd Bergmann 			     struct qed_mcp_link_params *params,
193514b84e86SArnd Bergmann 			     struct qed_mcp_link_state *link,
193614b84e86SArnd Bergmann 			     struct qed_mcp_link_capabilities *link_caps)
193714b84e86SArnd Bergmann {
193814b84e86SArnd Bergmann 	void *p;
193914b84e86SArnd Bergmann 
194014b84e86SArnd Bergmann 	if (!IS_PF(hwfn->cdev)) {
194114b84e86SArnd Bergmann 		qed_vf_get_link_params(hwfn, params);
194214b84e86SArnd Bergmann 		qed_vf_get_link_state(hwfn, link);
194314b84e86SArnd Bergmann 		qed_vf_get_link_caps(hwfn, link_caps);
194414b84e86SArnd Bergmann 
194514b84e86SArnd Bergmann 		return 0;
194614b84e86SArnd Bergmann 	}
194714b84e86SArnd Bergmann 
194814b84e86SArnd Bergmann 	p = qed_mcp_get_link_params(hwfn);
194914b84e86SArnd Bergmann 	if (!p)
195014b84e86SArnd Bergmann 		return -ENXIO;
195114b84e86SArnd Bergmann 	memcpy(params, p, sizeof(*params));
195214b84e86SArnd Bergmann 
195314b84e86SArnd Bergmann 	p = qed_mcp_get_link_state(hwfn);
195414b84e86SArnd Bergmann 	if (!p)
195514b84e86SArnd Bergmann 		return -ENXIO;
195614b84e86SArnd Bergmann 	memcpy(link, p, sizeof(*link));
195714b84e86SArnd Bergmann 
195814b84e86SArnd Bergmann 	p = qed_mcp_get_link_capabilities(hwfn);
195914b84e86SArnd Bergmann 	if (!p)
196014b84e86SArnd Bergmann 		return -ENXIO;
196114b84e86SArnd Bergmann 	memcpy(link_caps, p, sizeof(*link_caps));
196214b84e86SArnd Bergmann 
196314b84e86SArnd Bergmann 	return 0;
196414b84e86SArnd Bergmann }
196514b84e86SArnd Bergmann 
1966c56a8be7SRahul Verma static void qed_fill_link_capability(struct qed_hwfn *hwfn,
1967c56a8be7SRahul Verma 				     struct qed_ptt *ptt, u32 capability,
1968bdb5d8ecSAlexander Lobakin 				     unsigned long *if_caps)
1969c56a8be7SRahul Verma {
1970c56a8be7SRahul Verma 	u32 media_type, tcvr_state, tcvr_type;
1971c56a8be7SRahul Verma 	u32 speed_mask, board_cfg;
1972c56a8be7SRahul Verma 
1973c56a8be7SRahul Verma 	if (qed_mcp_get_media_type(hwfn, ptt, &media_type))
1974c56a8be7SRahul Verma 		media_type = MEDIA_UNSPECIFIED;
1975c56a8be7SRahul Verma 
1976c56a8be7SRahul Verma 	if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type))
1977c56a8be7SRahul Verma 		tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED;
1978c56a8be7SRahul Verma 
1979c56a8be7SRahul Verma 	if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask))
1980c56a8be7SRahul Verma 		speed_mask = 0xFFFFFFFF;
1981c56a8be7SRahul Verma 
1982c56a8be7SRahul Verma 	if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg))
1983c56a8be7SRahul Verma 		board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED;
1984c56a8be7SRahul Verma 
1985c56a8be7SRahul Verma 	DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV,
1986c56a8be7SRahul Verma 		   "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n",
1987c56a8be7SRahul Verma 		   media_type, tcvr_state, tcvr_type, speed_mask, board_cfg);
1988c56a8be7SRahul Verma 
1989c56a8be7SRahul Verma 	switch (media_type) {
1990c56a8be7SRahul Verma 	case MEDIA_DA_TWINAX:
1991bdb5d8ecSAlexander Lobakin 		phylink_set(if_caps, FIBRE);
1992bdb5d8ecSAlexander Lobakin 
1993c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
1994bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 20000baseKR2_Full);
1995bdb5d8ecSAlexander Lobakin 
1996c56a8be7SRahul Verma 		/* For DAC media multiple speed capabilities are supported */
19979228b7c1SAlexander Lobakin 		capability |= speed_mask;
19989228b7c1SAlexander Lobakin 
1999c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
2000bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 1000baseKX_Full);
2001c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
2002bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 10000baseCR_Full);
20039228b7c1SAlexander Lobakin 
2004c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
20059228b7c1SAlexander Lobakin 			switch (tcvr_type) {
20069228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_40G_CR4:
20079228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR:
20089228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR:
2009bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 40000baseCR4_Full);
20109228b7c1SAlexander Lobakin 				break;
20119228b7c1SAlexander Lobakin 			default:
20129228b7c1SAlexander Lobakin 				break;
20139228b7c1SAlexander Lobakin 			}
20149228b7c1SAlexander Lobakin 
2015c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
2016bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 25000baseCR_Full);
2017c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
2018bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 50000baseCR2_Full);
20199228b7c1SAlexander Lobakin 
2020c56a8be7SRahul Verma 		if (capability &
2021c56a8be7SRahul Verma 		    NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
20229228b7c1SAlexander Lobakin 			switch (tcvr_type) {
20239228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_100G_CR4:
20249228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR:
2025bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 100000baseCR4_Full);
20269228b7c1SAlexander Lobakin 				break;
20279228b7c1SAlexander Lobakin 			default:
20289228b7c1SAlexander Lobakin 				break;
20299228b7c1SAlexander Lobakin 			}
2030bdb5d8ecSAlexander Lobakin 
2031c56a8be7SRahul Verma 		break;
2032c56a8be7SRahul Verma 	case MEDIA_BASE_T:
2033bdb5d8ecSAlexander Lobakin 		phylink_set(if_caps, TP);
2034bdb5d8ecSAlexander Lobakin 
2035c56a8be7SRahul Verma 		if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) {
2036c56a8be7SRahul Verma 			if (capability &
2037bdb5d8ecSAlexander Lobakin 			    NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
2038bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 1000baseT_Full);
2039c56a8be7SRahul Verma 			if (capability &
2040bdb5d8ecSAlexander Lobakin 			    NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
2041bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 10000baseT_Full);
2042c56a8be7SRahul Verma 		}
2043bdb5d8ecSAlexander Lobakin 
2044c56a8be7SRahul Verma 		if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) {
2045bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, FIBRE);
2046bdb5d8ecSAlexander Lobakin 
20479228b7c1SAlexander Lobakin 			switch (tcvr_type) {
20489228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_1000BASET:
2049bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 1000baseT_Full);
20509228b7c1SAlexander Lobakin 				break;
20519228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_10G_BASET:
2052bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 10000baseT_Full);
20539228b7c1SAlexander Lobakin 				break;
20549228b7c1SAlexander Lobakin 			default:
20559228b7c1SAlexander Lobakin 				break;
20569228b7c1SAlexander Lobakin 			}
2057c56a8be7SRahul Verma 		}
2058bdb5d8ecSAlexander Lobakin 
2059c56a8be7SRahul Verma 		break;
2060c56a8be7SRahul Verma 	case MEDIA_SFP_1G_FIBER:
2061c56a8be7SRahul Verma 	case MEDIA_SFPP_10G_FIBER:
2062c56a8be7SRahul Verma 	case MEDIA_XFP_FIBER:
2063c56a8be7SRahul Verma 	case MEDIA_MODULE_FIBER:
2064bdb5d8ecSAlexander Lobakin 		phylink_set(if_caps, FIBRE);
20659228b7c1SAlexander Lobakin 		capability |= speed_mask;
2066bdb5d8ecSAlexander Lobakin 
20679228b7c1SAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
20689228b7c1SAlexander Lobakin 			switch (tcvr_type) {
20699228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_1G_LX:
20709228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_1G_SX:
20719228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR:
20729228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR:
2073bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 1000baseKX_Full);
20749228b7c1SAlexander Lobakin 				break;
20759228b7c1SAlexander Lobakin 			default:
20769228b7c1SAlexander Lobakin 				break;
2077c56a8be7SRahul Verma 			}
2078bdb5d8ecSAlexander Lobakin 
20799228b7c1SAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
20809228b7c1SAlexander Lobakin 			switch (tcvr_type) {
20819228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_10G_SR:
20829228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR:
20839228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR:
20849228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR:
2085bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 10000baseSR_Full);
20869228b7c1SAlexander Lobakin 				break;
20879228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_10G_LR:
20889228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR:
20899228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR:
20909228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR:
2091bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 10000baseLR_Full);
20929228b7c1SAlexander Lobakin 				break;
20939228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_10G_LRM:
2094bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 10000baseLRM_Full);
20959228b7c1SAlexander Lobakin 				break;
20969228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_10G_ER:
2097bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 10000baseR_FEC);
20989228b7c1SAlexander Lobakin 				break;
20999228b7c1SAlexander Lobakin 			default:
21009228b7c1SAlexander Lobakin 				break;
2101c56a8be7SRahul Verma 			}
2102bdb5d8ecSAlexander Lobakin 
2103c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
2104bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 20000baseKR2_Full);
2105bdb5d8ecSAlexander Lobakin 
21069228b7c1SAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
21079228b7c1SAlexander Lobakin 			switch (tcvr_type) {
21089228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_25G_SR:
21099228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR:
2110bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 25000baseSR_Full);
21119228b7c1SAlexander Lobakin 				break;
21129228b7c1SAlexander Lobakin 			default:
21139228b7c1SAlexander Lobakin 				break;
2114c56a8be7SRahul Verma 			}
2115bdb5d8ecSAlexander Lobakin 
21169228b7c1SAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
21179228b7c1SAlexander Lobakin 			switch (tcvr_type) {
21189228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_40G_LR4:
21199228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR:
21209228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR:
2121bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 40000baseLR4_Full);
21229228b7c1SAlexander Lobakin 				break;
21239228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_40G_SR4:
21249228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR:
21259228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR:
2126bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 40000baseSR4_Full);
21279228b7c1SAlexander Lobakin 				break;
21289228b7c1SAlexander Lobakin 			default:
21299228b7c1SAlexander Lobakin 				break;
2130c56a8be7SRahul Verma 			}
2131bdb5d8ecSAlexander Lobakin 
2132bdb5d8ecSAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
2133bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 50000baseKR2_Full);
2134bdb5d8ecSAlexander Lobakin 
2135c56a8be7SRahul Verma 		if (capability &
21369228b7c1SAlexander Lobakin 		    NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
21379228b7c1SAlexander Lobakin 			switch (tcvr_type) {
21389228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_100G_SR4:
21399228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR:
2140bdb5d8ecSAlexander Lobakin 				phylink_set(if_caps, 100000baseSR4_Full);
21419228b7c1SAlexander Lobakin 				break;
21429228b7c1SAlexander Lobakin 			case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR:
21439228b7c1SAlexander Lobakin 				phylink_set(if_caps, 100000baseLR4_ER4_Full);
21449228b7c1SAlexander Lobakin 				break;
21459228b7c1SAlexander Lobakin 			default:
21469228b7c1SAlexander Lobakin 				break;
2147c56a8be7SRahul Verma 			}
2148c56a8be7SRahul Verma 
2149c56a8be7SRahul Verma 		break;
2150c56a8be7SRahul Verma 	case MEDIA_KR:
2151bdb5d8ecSAlexander Lobakin 		phylink_set(if_caps, Backplane);
2152bdb5d8ecSAlexander Lobakin 
2153c56a8be7SRahul Verma 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
2154bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 20000baseKR2_Full);
2155bdb5d8ecSAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
2156bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 1000baseKX_Full);
2157bdb5d8ecSAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
2158bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 10000baseKR_Full);
2159bdb5d8ecSAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
2160bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 25000baseKR_Full);
2161bdb5d8ecSAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
2162bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 40000baseKR4_Full);
2163bdb5d8ecSAlexander Lobakin 		if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
2164bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 50000baseKR2_Full);
2165c56a8be7SRahul Verma 		if (capability &
2166c56a8be7SRahul Verma 		    NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
2167bdb5d8ecSAlexander Lobakin 			phylink_set(if_caps, 100000baseKR4_Full);
2168bdb5d8ecSAlexander Lobakin 
2169c56a8be7SRahul Verma 		break;
2170c56a8be7SRahul Verma 	case MEDIA_UNSPECIFIED:
2171c56a8be7SRahul Verma 	case MEDIA_NOT_PRESENT:
21729228b7c1SAlexander Lobakin 	default:
2173c56a8be7SRahul Verma 		DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG,
2174c56a8be7SRahul Verma 			   "Unknown media and transceiver type;\n");
2175c56a8be7SRahul Verma 		break;
2176c56a8be7SRahul Verma 	}
2177c56a8be7SRahul Verma }
2178c56a8be7SRahul Verma 
21793c41486eSAlexander Lobakin static void qed_lp_caps_to_speed_mask(u32 caps, u32 *speed_mask)
21803c41486eSAlexander Lobakin {
21813c41486eSAlexander Lobakin 	*speed_mask = 0;
21823c41486eSAlexander Lobakin 
21833c41486eSAlexander Lobakin 	if (caps &
21843c41486eSAlexander Lobakin 	    (QED_LINK_PARTNER_SPEED_1G_FD | QED_LINK_PARTNER_SPEED_1G_HD))
21853c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
21863c41486eSAlexander Lobakin 	if (caps & QED_LINK_PARTNER_SPEED_10G)
21873c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
21883c41486eSAlexander Lobakin 	if (caps & QED_LINK_PARTNER_SPEED_20G)
21893c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G;
21903c41486eSAlexander Lobakin 	if (caps & QED_LINK_PARTNER_SPEED_25G)
21913c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
21923c41486eSAlexander Lobakin 	if (caps & QED_LINK_PARTNER_SPEED_40G)
21933c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
21943c41486eSAlexander Lobakin 	if (caps & QED_LINK_PARTNER_SPEED_50G)
21953c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G;
21963c41486eSAlexander Lobakin 	if (caps & QED_LINK_PARTNER_SPEED_100G)
21973c41486eSAlexander Lobakin 		*speed_mask |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G;
21983c41486eSAlexander Lobakin }
21993c41486eSAlexander Lobakin 
2200cc875c2eSYuval Mintz static void qed_fill_link(struct qed_hwfn *hwfn,
2201706d0891SRahul Verma 			  struct qed_ptt *ptt,
2202cc875c2eSYuval Mintz 			  struct qed_link_output *if_link)
2203cc875c2eSYuval Mintz {
2204c56a8be7SRahul Verma 	struct qed_mcp_link_capabilities link_caps;
2205cc875c2eSYuval Mintz 	struct qed_mcp_link_params params;
2206cc875c2eSYuval Mintz 	struct qed_mcp_link_state link;
22073c41486eSAlexander Lobakin 	u32 media_type, speed_mask;
2208cc875c2eSYuval Mintz 
2209cc875c2eSYuval Mintz 	memset(if_link, 0, sizeof(*if_link));
2210cc875c2eSYuval Mintz 
2211cc875c2eSYuval Mintz 	/* Prepare source inputs */
221214b84e86SArnd Bergmann 	if (qed_get_link_data(hwfn, &params, &link, &link_caps)) {
221314b84e86SArnd Bergmann 		dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n");
221414b84e86SArnd Bergmann 		return;
22151408cc1fSYuval Mintz 	}
2216cc875c2eSYuval Mintz 
2217cc875c2eSYuval Mintz 	/* Set the link parameters to pass to protocol driver */
2218cc875c2eSYuval Mintz 	if (link.link_up)
2219cc875c2eSYuval Mintz 		if_link->link_up = true;
2220cc875c2eSYuval Mintz 
222199785a87SAlexander Lobakin 	if (IS_PF(hwfn->cdev) && qed_mcp_is_ext_speed_supported(hwfn)) {
222299785a87SAlexander Lobakin 		if (link_caps.default_ext_autoneg)
222399785a87SAlexander Lobakin 			phylink_set(if_link->supported_caps, Autoneg);
222499785a87SAlexander Lobakin 
222599785a87SAlexander Lobakin 		linkmode_copy(if_link->advertised_caps, if_link->supported_caps);
222699785a87SAlexander Lobakin 
222799785a87SAlexander Lobakin 		if (params.ext_speed.autoneg)
222899785a87SAlexander Lobakin 			phylink_set(if_link->advertised_caps, Autoneg);
222999785a87SAlexander Lobakin 		else
223099785a87SAlexander Lobakin 			phylink_clear(if_link->advertised_caps, Autoneg);
223199785a87SAlexander Lobakin 
223299785a87SAlexander Lobakin 		qed_fill_link_capability(hwfn, ptt,
223399785a87SAlexander Lobakin 					 params.ext_speed.advertised_speeds,
223499785a87SAlexander Lobakin 					 if_link->advertised_caps);
223599785a87SAlexander Lobakin 	} else {
223634f9199cSsudarsana.kalluru@cavium.com 		if (link_caps.default_speed_autoneg)
2237bdb5d8ecSAlexander Lobakin 			phylink_set(if_link->supported_caps, Autoneg);
2238cc875c2eSYuval Mintz 
2239bdb5d8ecSAlexander Lobakin 		linkmode_copy(if_link->advertised_caps, if_link->supported_caps);
2240bdb5d8ecSAlexander Lobakin 
224134f9199cSsudarsana.kalluru@cavium.com 		if (params.speed.autoneg)
2242bdb5d8ecSAlexander Lobakin 			phylink_set(if_link->advertised_caps, Autoneg);
224334f9199cSsudarsana.kalluru@cavium.com 		else
2244bdb5d8ecSAlexander Lobakin 			phylink_clear(if_link->advertised_caps, Autoneg);
224599785a87SAlexander Lobakin 	}
224699785a87SAlexander Lobakin 
224799785a87SAlexander Lobakin 	if (params.pause.autoneg ||
224899785a87SAlexander Lobakin 	    (params.pause.forced_rx && params.pause.forced_tx))
224999785a87SAlexander Lobakin 		phylink_set(if_link->supported_caps, Asym_Pause);
225099785a87SAlexander Lobakin 	if (params.pause.autoneg || params.pause.forced_rx ||
225199785a87SAlexander Lobakin 	    params.pause.forced_tx)
225299785a87SAlexander Lobakin 		phylink_set(if_link->supported_caps, Pause);
2253cc875c2eSYuval Mintz 
2254ae7e6937SAlexander Lobakin 	if_link->sup_fec = link_caps.fec_default;
2255ae7e6937SAlexander Lobakin 	if_link->active_fec = params.fec;
2256ae7e6937SAlexander Lobakin 
2257c56a8be7SRahul Verma 	/* Fill link advertised capability */
2258c56a8be7SRahul Verma 	qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds,
2259bdb5d8ecSAlexander Lobakin 				 if_link->advertised_caps);
22603c41486eSAlexander Lobakin 
2261c56a8be7SRahul Verma 	/* Fill link supported capability */
2262c56a8be7SRahul Verma 	qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities,
2263bdb5d8ecSAlexander Lobakin 				 if_link->supported_caps);
2264cc875c2eSYuval Mintz 
22653c41486eSAlexander Lobakin 	/* Fill partner advertised capability */
22663c41486eSAlexander Lobakin 	qed_lp_caps_to_speed_mask(link.partner_adv_speed, &speed_mask);
22673c41486eSAlexander Lobakin 	qed_fill_link_capability(hwfn, ptt, speed_mask, if_link->lp_caps);
22683c41486eSAlexander Lobakin 
2269cc875c2eSYuval Mintz 	if (link.link_up)
2270cc875c2eSYuval Mintz 		if_link->speed = link.speed;
2271cc875c2eSYuval Mintz 
2272cc875c2eSYuval Mintz 	/* TODO - fill duplex properly */
2273cc875c2eSYuval Mintz 	if_link->duplex = DUPLEX_FULL;
2274706d0891SRahul Verma 	qed_mcp_get_media_type(hwfn, ptt, &media_type);
2275cc875c2eSYuval Mintz 	if_link->port = qed_get_port_type(media_type);
2276cc875c2eSYuval Mintz 
2277cc875c2eSYuval Mintz 	if_link->autoneg = params.speed.autoneg;
2278cc875c2eSYuval Mintz 
2279cc875c2eSYuval Mintz 	if (params.pause.autoneg)
2280cc875c2eSYuval Mintz 		if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
2281cc875c2eSYuval Mintz 	if (params.pause.forced_rx)
2282cc875c2eSYuval Mintz 		if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE;
2283cc875c2eSYuval Mintz 	if (params.pause.forced_tx)
2284cc875c2eSYuval Mintz 		if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE;
2285cc875c2eSYuval Mintz 
2286cc875c2eSYuval Mintz 	if (link.an_complete)
2287bdb5d8ecSAlexander Lobakin 		phylink_set(if_link->lp_caps, Autoneg);
2288cc875c2eSYuval Mintz 	if (link.partner_adv_pause)
2289bdb5d8ecSAlexander Lobakin 		phylink_set(if_link->lp_caps, Pause);
2290cc875c2eSYuval Mintz 	if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE ||
2291cc875c2eSYuval Mintz 	    link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE)
2292bdb5d8ecSAlexander Lobakin 		phylink_set(if_link->lp_caps, Asym_Pause);
2293645874e5SSudarsana Reddy Kalluru 
2294645874e5SSudarsana Reddy Kalluru 	if (link_caps.default_eee == QED_MCP_EEE_UNSUPPORTED) {
2295645874e5SSudarsana Reddy Kalluru 		if_link->eee_supported = false;
2296645874e5SSudarsana Reddy Kalluru 	} else {
2297645874e5SSudarsana Reddy Kalluru 		if_link->eee_supported = true;
2298645874e5SSudarsana Reddy Kalluru 		if_link->eee_active = link.eee_active;
2299645874e5SSudarsana Reddy Kalluru 		if_link->sup_caps = link_caps.eee_speed_caps;
2300645874e5SSudarsana Reddy Kalluru 		/* MFW clears adv_caps on eee disable; use configured value */
2301645874e5SSudarsana Reddy Kalluru 		if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps :
2302645874e5SSudarsana Reddy Kalluru 					params.eee.adv_caps;
2303645874e5SSudarsana Reddy Kalluru 		if_link->eee.lp_adv_caps = link.eee_lp_adv_caps;
2304645874e5SSudarsana Reddy Kalluru 		if_link->eee.enable = params.eee.enable;
2305645874e5SSudarsana Reddy Kalluru 		if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable;
2306645874e5SSudarsana Reddy Kalluru 		if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer;
2307645874e5SSudarsana Reddy Kalluru 	}
2308cc875c2eSYuval Mintz }
2309cc875c2eSYuval Mintz 
2310cc875c2eSYuval Mintz static void qed_get_current_link(struct qed_dev *cdev,
2311cc875c2eSYuval Mintz 				 struct qed_link_output *if_link)
2312cc875c2eSYuval Mintz {
2313706d0891SRahul Verma 	struct qed_hwfn *hwfn;
2314706d0891SRahul Verma 	struct qed_ptt *ptt;
231536558c3dSYuval Mintz 	int i;
231636558c3dSYuval Mintz 
2317706d0891SRahul Verma 	hwfn = &cdev->hwfns[0];
2318706d0891SRahul Verma 	if (IS_PF(cdev)) {
2319706d0891SRahul Verma 		ptt = qed_ptt_acquire(hwfn);
2320706d0891SRahul Verma 		if (ptt) {
2321706d0891SRahul Verma 			qed_fill_link(hwfn, ptt, if_link);
2322706d0891SRahul Verma 			qed_ptt_release(hwfn, ptt);
2323706d0891SRahul Verma 		} else {
2324706d0891SRahul Verma 			DP_NOTICE(hwfn, "Failed to fill link; No PTT\n");
2325706d0891SRahul Verma 		}
2326706d0891SRahul Verma 	} else {
2327706d0891SRahul Verma 		qed_fill_link(hwfn, NULL, if_link);
2328706d0891SRahul Verma 	}
232936558c3dSYuval Mintz 
233036558c3dSYuval Mintz 	for_each_hwfn(cdev, i)
233136558c3dSYuval Mintz 		qed_inform_vf_link_state(&cdev->hwfns[i]);
2332cc875c2eSYuval Mintz }
2333cc875c2eSYuval Mintz 
2334706d0891SRahul Verma void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt)
2335cc875c2eSYuval Mintz {
2336cc875c2eSYuval Mintz 	void *cookie = hwfn->cdev->ops_cookie;
2337cc875c2eSYuval Mintz 	struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common;
2338cc875c2eSYuval Mintz 	struct qed_link_output if_link;
2339cc875c2eSYuval Mintz 
2340706d0891SRahul Verma 	qed_fill_link(hwfn, ptt, &if_link);
234136558c3dSYuval Mintz 	qed_inform_vf_link_state(hwfn);
2342cc875c2eSYuval Mintz 
2343cc875c2eSYuval Mintz 	if (IS_LEAD_HWFN(hwfn) && cookie)
2344cc875c2eSYuval Mintz 		op->link_update(cookie, &if_link);
2345cc875c2eSYuval Mintz }
2346cc875c2eSYuval Mintz 
2347699fed4aSSudarsana Reddy Kalluru void qed_bw_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt)
2348699fed4aSSudarsana Reddy Kalluru {
2349699fed4aSSudarsana Reddy Kalluru 	void *cookie = hwfn->cdev->ops_cookie;
2350699fed4aSSudarsana Reddy Kalluru 	struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common;
2351699fed4aSSudarsana Reddy Kalluru 
2352699fed4aSSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(hwfn) && cookie && op && op->bw_update)
2353699fed4aSSudarsana Reddy Kalluru 		op->bw_update(cookie);
2354699fed4aSSudarsana Reddy Kalluru }
2355699fed4aSSudarsana Reddy Kalluru 
2356fe56b9e6SYuval Mintz static int qed_drain(struct qed_dev *cdev)
2357fe56b9e6SYuval Mintz {
2358fe56b9e6SYuval Mintz 	struct qed_hwfn *hwfn;
2359fe56b9e6SYuval Mintz 	struct qed_ptt *ptt;
2360fe56b9e6SYuval Mintz 	int i, rc;
2361fe56b9e6SYuval Mintz 
23621408cc1fSYuval Mintz 	if (IS_VF(cdev))
23631408cc1fSYuval Mintz 		return 0;
23641408cc1fSYuval Mintz 
2365fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2366fe56b9e6SYuval Mintz 		hwfn = &cdev->hwfns[i];
2367fe56b9e6SYuval Mintz 		ptt = qed_ptt_acquire(hwfn);
2368fe56b9e6SYuval Mintz 		if (!ptt) {
2369fe56b9e6SYuval Mintz 			DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n");
2370fe56b9e6SYuval Mintz 			return -EBUSY;
2371fe56b9e6SYuval Mintz 		}
2372fe56b9e6SYuval Mintz 		rc = qed_mcp_drain(hwfn, ptt);
23739aaa4e8bSDenis Bolotin 		qed_ptt_release(hwfn, ptt);
2374fe56b9e6SYuval Mintz 		if (rc)
2375fe56b9e6SYuval Mintz 			return rc;
2376fe56b9e6SYuval Mintz 	}
2377fe56b9e6SYuval Mintz 
2378fe56b9e6SYuval Mintz 	return 0;
2379fe56b9e6SYuval Mintz }
2380fe56b9e6SYuval Mintz 
23813a69cae8SSudarsana Reddy Kalluru static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev,
23823a69cae8SSudarsana Reddy Kalluru 					  struct qed_nvm_image_att *nvm_image,
23833a69cae8SSudarsana Reddy Kalluru 					  u32 *crc)
23843a69cae8SSudarsana Reddy Kalluru {
23853a69cae8SSudarsana Reddy Kalluru 	u8 *buf = NULL;
23865ab90341SAlexander Lobakin 	int rc;
23873a69cae8SSudarsana Reddy Kalluru 
23883a69cae8SSudarsana Reddy Kalluru 	/* Allocate a buffer for holding the nvram image */
23893a69cae8SSudarsana Reddy Kalluru 	buf = kzalloc(nvm_image->length, GFP_KERNEL);
23903a69cae8SSudarsana Reddy Kalluru 	if (!buf)
23913a69cae8SSudarsana Reddy Kalluru 		return -ENOMEM;
23923a69cae8SSudarsana Reddy Kalluru 
23933a69cae8SSudarsana Reddy Kalluru 	/* Read image into buffer */
23943a69cae8SSudarsana Reddy Kalluru 	rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr,
23953a69cae8SSudarsana Reddy Kalluru 			      buf, nvm_image->length);
23963a69cae8SSudarsana Reddy Kalluru 	if (rc) {
23973a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Failed reading image from nvm\n");
23983a69cae8SSudarsana Reddy Kalluru 		goto out;
23993a69cae8SSudarsana Reddy Kalluru 	}
24003a69cae8SSudarsana Reddy Kalluru 
24013a69cae8SSudarsana Reddy Kalluru 	/* Convert the buffer into big-endian format (excluding the
24023a69cae8SSudarsana Reddy Kalluru 	 * closing 4 bytes of CRC).
24033a69cae8SSudarsana Reddy Kalluru 	 */
24045ab90341SAlexander Lobakin 	cpu_to_be32_array((__force __be32 *)buf, (const u32 *)buf,
24055ab90341SAlexander Lobakin 			  DIV_ROUND_UP(nvm_image->length - 4, 4));
24063a69cae8SSudarsana Reddy Kalluru 
24073a69cae8SSudarsana Reddy Kalluru 	/* Calc CRC for the "actual" image buffer, i.e. not including
24083a69cae8SSudarsana Reddy Kalluru 	 * the last 4 CRC bytes.
24093a69cae8SSudarsana Reddy Kalluru 	 */
24105ab90341SAlexander Lobakin 	*crc = ~crc32(~0U, buf, nvm_image->length - 4);
24115ab90341SAlexander Lobakin 	*crc = (__force u32)cpu_to_be32p(crc);
24123a69cae8SSudarsana Reddy Kalluru 
24133a69cae8SSudarsana Reddy Kalluru out:
24143a69cae8SSudarsana Reddy Kalluru 	kfree(buf);
24153a69cae8SSudarsana Reddy Kalluru 
24163a69cae8SSudarsana Reddy Kalluru 	return rc;
24173a69cae8SSudarsana Reddy Kalluru }
24183a69cae8SSudarsana Reddy Kalluru 
24193a69cae8SSudarsana Reddy Kalluru /* Binary file format -
24203a69cae8SSudarsana Reddy Kalluru  *     /----------------------------------------------------------------------\
24213a69cae8SSudarsana Reddy Kalluru  * 0B  |                       0x4 [command index]                            |
24223a69cae8SSudarsana Reddy Kalluru  * 4B  | image_type     | Options        |  Number of register settings       |
24233a69cae8SSudarsana Reddy Kalluru  * 8B  |                       Value                                          |
24243a69cae8SSudarsana Reddy Kalluru  * 12B |                       Mask                                           |
24253a69cae8SSudarsana Reddy Kalluru  * 16B |                       Offset                                         |
24263a69cae8SSudarsana Reddy Kalluru  *     \----------------------------------------------------------------------/
24273a69cae8SSudarsana Reddy Kalluru  * There can be several Value-Mask-Offset sets as specified by 'Number of...'.
24283a69cae8SSudarsana Reddy Kalluru  * Options - 0'b - Calculate & Update CRC for image
24293a69cae8SSudarsana Reddy Kalluru  */
24303a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data,
24313a69cae8SSudarsana Reddy Kalluru 				      bool *check_resp)
24323a69cae8SSudarsana Reddy Kalluru {
24333a69cae8SSudarsana Reddy Kalluru 	struct qed_nvm_image_att nvm_image;
24343a69cae8SSudarsana Reddy Kalluru 	struct qed_hwfn *p_hwfn;
24353a69cae8SSudarsana Reddy Kalluru 	bool is_crc = false;
24363a69cae8SSudarsana Reddy Kalluru 	u32 image_type;
24373a69cae8SSudarsana Reddy Kalluru 	int rc = 0, i;
24383a69cae8SSudarsana Reddy Kalluru 	u16 len;
24393a69cae8SSudarsana Reddy Kalluru 
24403a69cae8SSudarsana Reddy Kalluru 	*data += 4;
24413a69cae8SSudarsana Reddy Kalluru 	image_type = **data;
24423a69cae8SSudarsana Reddy Kalluru 	p_hwfn = QED_LEADING_HWFN(cdev);
24433a69cae8SSudarsana Reddy Kalluru 	for (i = 0; i < p_hwfn->nvm_info.num_images; i++)
24443a69cae8SSudarsana Reddy Kalluru 		if (image_type == p_hwfn->nvm_info.image_att[i].image_type)
24453a69cae8SSudarsana Reddy Kalluru 			break;
24463a69cae8SSudarsana Reddy Kalluru 	if (i == p_hwfn->nvm_info.num_images) {
24473a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Failed to find nvram image of type %08x\n",
24483a69cae8SSudarsana Reddy Kalluru 		       image_type);
24493a69cae8SSudarsana Reddy Kalluru 		return -ENOENT;
24503a69cae8SSudarsana Reddy Kalluru 	}
24513a69cae8SSudarsana Reddy Kalluru 
24523a69cae8SSudarsana Reddy Kalluru 	nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr;
24533a69cae8SSudarsana Reddy Kalluru 	nvm_image.length = p_hwfn->nvm_info.image_att[i].len;
24543a69cae8SSudarsana Reddy Kalluru 
24553a69cae8SSudarsana Reddy Kalluru 	DP_VERBOSE(cdev, NETIF_MSG_DRV,
24563a69cae8SSudarsana Reddy Kalluru 		   "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n",
24573a69cae8SSudarsana Reddy Kalluru 		   **data, image_type, nvm_image.start_addr,
24583a69cae8SSudarsana Reddy Kalluru 		   nvm_image.start_addr + nvm_image.length - 1);
24593a69cae8SSudarsana Reddy Kalluru 	(*data)++;
24603a69cae8SSudarsana Reddy Kalluru 	is_crc = !!(**data & BIT(0));
24613a69cae8SSudarsana Reddy Kalluru 	(*data)++;
24623a69cae8SSudarsana Reddy Kalluru 	len = *((u16 *)*data);
24633a69cae8SSudarsana Reddy Kalluru 	*data += 2;
24643a69cae8SSudarsana Reddy Kalluru 	if (is_crc) {
24653a69cae8SSudarsana Reddy Kalluru 		u32 crc = 0;
24663a69cae8SSudarsana Reddy Kalluru 
24673a69cae8SSudarsana Reddy Kalluru 		rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc);
24683a69cae8SSudarsana Reddy Kalluru 		if (rc) {
24693a69cae8SSudarsana Reddy Kalluru 			DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc);
24703a69cae8SSudarsana Reddy Kalluru 			goto exit;
24713a69cae8SSudarsana Reddy Kalluru 		}
24723a69cae8SSudarsana Reddy Kalluru 
24733a69cae8SSudarsana Reddy Kalluru 		rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM,
24743a69cae8SSudarsana Reddy Kalluru 				       (nvm_image.start_addr +
24753a69cae8SSudarsana Reddy Kalluru 					nvm_image.length - 4), (u8 *)&crc, 4);
24763a69cae8SSudarsana Reddy Kalluru 		if (rc)
24773a69cae8SSudarsana Reddy Kalluru 			DP_ERR(cdev, "Failed writing to %08x, rc = %d\n",
24783a69cae8SSudarsana Reddy Kalluru 			       nvm_image.start_addr + nvm_image.length - 4, rc);
24793a69cae8SSudarsana Reddy Kalluru 		goto exit;
24803a69cae8SSudarsana Reddy Kalluru 	}
24813a69cae8SSudarsana Reddy Kalluru 
24823a69cae8SSudarsana Reddy Kalluru 	/* Iterate over the values for setting */
24833a69cae8SSudarsana Reddy Kalluru 	while (len) {
24843a69cae8SSudarsana Reddy Kalluru 		u32 offset, mask, value, cur_value;
24853a69cae8SSudarsana Reddy Kalluru 		u8 buf[4];
24863a69cae8SSudarsana Reddy Kalluru 
24873a69cae8SSudarsana Reddy Kalluru 		value = *((u32 *)*data);
24883a69cae8SSudarsana Reddy Kalluru 		*data += 4;
24893a69cae8SSudarsana Reddy Kalluru 		mask = *((u32 *)*data);
24903a69cae8SSudarsana Reddy Kalluru 		*data += 4;
24913a69cae8SSudarsana Reddy Kalluru 		offset = *((u32 *)*data);
24923a69cae8SSudarsana Reddy Kalluru 		*data += 4;
24933a69cae8SSudarsana Reddy Kalluru 
24943a69cae8SSudarsana Reddy Kalluru 		rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf,
24953a69cae8SSudarsana Reddy Kalluru 				      4);
24963a69cae8SSudarsana Reddy Kalluru 		if (rc) {
24973a69cae8SSudarsana Reddy Kalluru 			DP_ERR(cdev, "Failed reading from %08x\n",
24983a69cae8SSudarsana Reddy Kalluru 			       nvm_image.start_addr + offset);
24993a69cae8SSudarsana Reddy Kalluru 			goto exit;
25003a69cae8SSudarsana Reddy Kalluru 		}
25013a69cae8SSudarsana Reddy Kalluru 
25023a69cae8SSudarsana Reddy Kalluru 		cur_value = le32_to_cpu(*((__le32 *)buf));
25033a69cae8SSudarsana Reddy Kalluru 		DP_VERBOSE(cdev, NETIF_MSG_DRV,
25043a69cae8SSudarsana Reddy Kalluru 			   "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n",
25053a69cae8SSudarsana Reddy Kalluru 			   nvm_image.start_addr + offset, cur_value,
25063a69cae8SSudarsana Reddy Kalluru 			   (cur_value & ~mask) | (value & mask), value, mask);
25073a69cae8SSudarsana Reddy Kalluru 		value = (value & mask) | (cur_value & ~mask);
25083a69cae8SSudarsana Reddy Kalluru 		rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM,
25093a69cae8SSudarsana Reddy Kalluru 				       nvm_image.start_addr + offset,
25103a69cae8SSudarsana Reddy Kalluru 				       (u8 *)&value, 4);
25113a69cae8SSudarsana Reddy Kalluru 		if (rc) {
25123a69cae8SSudarsana Reddy Kalluru 			DP_ERR(cdev, "Failed writing to %08x\n",
25133a69cae8SSudarsana Reddy Kalluru 			       nvm_image.start_addr + offset);
25143a69cae8SSudarsana Reddy Kalluru 			goto exit;
25153a69cae8SSudarsana Reddy Kalluru 		}
25163a69cae8SSudarsana Reddy Kalluru 
25173a69cae8SSudarsana Reddy Kalluru 		len--;
25183a69cae8SSudarsana Reddy Kalluru 	}
25193a69cae8SSudarsana Reddy Kalluru exit:
25203a69cae8SSudarsana Reddy Kalluru 	return rc;
25213a69cae8SSudarsana Reddy Kalluru }
25223a69cae8SSudarsana Reddy Kalluru 
25233a69cae8SSudarsana Reddy Kalluru /* Binary file format -
25243a69cae8SSudarsana Reddy Kalluru  *     /----------------------------------------------------------------------\
25253a69cae8SSudarsana Reddy Kalluru  * 0B  |                       0x3 [command index]                            |
25263a69cae8SSudarsana Reddy Kalluru  * 4B  | b'0: check_response?   | b'1-31  reserved                            |
25273a69cae8SSudarsana Reddy Kalluru  * 8B  | File-type |                   reserved                               |
2528057d2b19SSudarsana Reddy Kalluru  * 12B |                    Image length in bytes                             |
25293a69cae8SSudarsana Reddy Kalluru  *     \----------------------------------------------------------------------/
25303a69cae8SSudarsana Reddy Kalluru  *     Start a new file of the provided type
25313a69cae8SSudarsana Reddy Kalluru  */
25323a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_start(struct qed_dev *cdev,
25333a69cae8SSudarsana Reddy Kalluru 					  const u8 **data, bool *check_resp)
25343a69cae8SSudarsana Reddy Kalluru {
2535057d2b19SSudarsana Reddy Kalluru 	u32 file_type, file_size = 0;
25363a69cae8SSudarsana Reddy Kalluru 	int rc;
25373a69cae8SSudarsana Reddy Kalluru 
25383a69cae8SSudarsana Reddy Kalluru 	*data += 4;
25393a69cae8SSudarsana Reddy Kalluru 	*check_resp = !!(**data & BIT(0));
25403a69cae8SSudarsana Reddy Kalluru 	*data += 4;
2541057d2b19SSudarsana Reddy Kalluru 	file_type = **data;
25423a69cae8SSudarsana Reddy Kalluru 
25433a69cae8SSudarsana Reddy Kalluru 	DP_VERBOSE(cdev, NETIF_MSG_DRV,
2544057d2b19SSudarsana Reddy Kalluru 		   "About to start a new file of type %02x\n", file_type);
2545057d2b19SSudarsana Reddy Kalluru 	if (file_type == DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MBI) {
2546057d2b19SSudarsana Reddy Kalluru 		*data += 4;
2547057d2b19SSudarsana Reddy Kalluru 		file_size = *((u32 *)(*data));
2548057d2b19SSudarsana Reddy Kalluru 	}
2549057d2b19SSudarsana Reddy Kalluru 
2550057d2b19SSudarsana Reddy Kalluru 	rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_BEGIN, file_type,
2551057d2b19SSudarsana Reddy Kalluru 			       (u8 *)(&file_size), 4);
25523a69cae8SSudarsana Reddy Kalluru 	*data += 4;
25533a69cae8SSudarsana Reddy Kalluru 
25543a69cae8SSudarsana Reddy Kalluru 	return rc;
25553a69cae8SSudarsana Reddy Kalluru }
25563a69cae8SSudarsana Reddy Kalluru 
25573a69cae8SSudarsana Reddy Kalluru /* Binary file format -
25583a69cae8SSudarsana Reddy Kalluru  *     /----------------------------------------------------------------------\
25593a69cae8SSudarsana Reddy Kalluru  * 0B  |                       0x2 [command index]                            |
25603a69cae8SSudarsana Reddy Kalluru  * 4B  |                       Length in bytes                                |
25613a69cae8SSudarsana Reddy Kalluru  * 8B  | b'0: check_response?   | b'1-31  reserved                            |
25623a69cae8SSudarsana Reddy Kalluru  * 12B |                       Offset in bytes                                |
25633a69cae8SSudarsana Reddy Kalluru  * 16B |                       Data ...                                       |
25643a69cae8SSudarsana Reddy Kalluru  *     \----------------------------------------------------------------------/
25653a69cae8SSudarsana Reddy Kalluru  *     Write data as part of a file that was previously started. Data should be
25663a69cae8SSudarsana Reddy Kalluru  *     of length equal to that provided in the message
25673a69cae8SSudarsana Reddy Kalluru  */
25683a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_file_data(struct qed_dev *cdev,
25693a69cae8SSudarsana Reddy Kalluru 					 const u8 **data, bool *check_resp)
25703a69cae8SSudarsana Reddy Kalluru {
25713a69cae8SSudarsana Reddy Kalluru 	u32 offset, len;
25723a69cae8SSudarsana Reddy Kalluru 	int rc;
25733a69cae8SSudarsana Reddy Kalluru 
25743a69cae8SSudarsana Reddy Kalluru 	*data += 4;
25753a69cae8SSudarsana Reddy Kalluru 	len = *((u32 *)(*data));
25763a69cae8SSudarsana Reddy Kalluru 	*data += 4;
25773a69cae8SSudarsana Reddy Kalluru 	*check_resp = !!(**data & BIT(0));
25783a69cae8SSudarsana Reddy Kalluru 	*data += 4;
25793a69cae8SSudarsana Reddy Kalluru 	offset = *((u32 *)(*data));
25803a69cae8SSudarsana Reddy Kalluru 	*data += 4;
25813a69cae8SSudarsana Reddy Kalluru 
25823a69cae8SSudarsana Reddy Kalluru 	DP_VERBOSE(cdev, NETIF_MSG_DRV,
25833a69cae8SSudarsana Reddy Kalluru 		   "About to write File-data: %08x bytes to offset %08x\n",
25843a69cae8SSudarsana Reddy Kalluru 		   len, offset);
25853a69cae8SSudarsana Reddy Kalluru 
25863a69cae8SSudarsana Reddy Kalluru 	rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset,
25873a69cae8SSudarsana Reddy Kalluru 			       (char *)(*data), len);
25883a69cae8SSudarsana Reddy Kalluru 	*data += len;
25893a69cae8SSudarsana Reddy Kalluru 
25903a69cae8SSudarsana Reddy Kalluru 	return rc;
25913a69cae8SSudarsana Reddy Kalluru }
25923a69cae8SSudarsana Reddy Kalluru 
25933a69cae8SSudarsana Reddy Kalluru /* Binary file format [General header] -
25943a69cae8SSudarsana Reddy Kalluru  *     /----------------------------------------------------------------------\
25953a69cae8SSudarsana Reddy Kalluru  * 0B  |                       QED_NVM_SIGNATURE                              |
25963a69cae8SSudarsana Reddy Kalluru  * 4B  |                       Length in bytes                                |
25973a69cae8SSudarsana Reddy Kalluru  * 8B  | Highest command in this batchfile |          Reserved                |
25983a69cae8SSudarsana Reddy Kalluru  *     \----------------------------------------------------------------------/
25993a69cae8SSudarsana Reddy Kalluru  */
26003a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash_image_validate(struct qed_dev *cdev,
26013a69cae8SSudarsana Reddy Kalluru 					const struct firmware *image,
26023a69cae8SSudarsana Reddy Kalluru 					const u8 **data)
26033a69cae8SSudarsana Reddy Kalluru {
26043a69cae8SSudarsana Reddy Kalluru 	u32 signature, len;
26053a69cae8SSudarsana Reddy Kalluru 
26063a69cae8SSudarsana Reddy Kalluru 	/* Check minimum size */
26073a69cae8SSudarsana Reddy Kalluru 	if (image->size < 12) {
26083a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size);
26093a69cae8SSudarsana Reddy Kalluru 		return -EINVAL;
26103a69cae8SSudarsana Reddy Kalluru 	}
26113a69cae8SSudarsana Reddy Kalluru 
26123a69cae8SSudarsana Reddy Kalluru 	/* Check signature */
26133a69cae8SSudarsana Reddy Kalluru 	signature = *((u32 *)(*data));
26143a69cae8SSudarsana Reddy Kalluru 	if (signature != QED_NVM_SIGNATURE) {
26153a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Wrong signature '%08x'\n", signature);
26163a69cae8SSudarsana Reddy Kalluru 		return -EINVAL;
26173a69cae8SSudarsana Reddy Kalluru 	}
26183a69cae8SSudarsana Reddy Kalluru 
26193a69cae8SSudarsana Reddy Kalluru 	*data += 4;
26203a69cae8SSudarsana Reddy Kalluru 	/* Validate internal size equals the image-size */
26213a69cae8SSudarsana Reddy Kalluru 	len = *((u32 *)(*data));
26223a69cae8SSudarsana Reddy Kalluru 	if (len != image->size) {
26233a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n",
26243a69cae8SSudarsana Reddy Kalluru 		       len, (u32)image->size);
26253a69cae8SSudarsana Reddy Kalluru 		return -EINVAL;
26263a69cae8SSudarsana Reddy Kalluru 	}
26273a69cae8SSudarsana Reddy Kalluru 
26283a69cae8SSudarsana Reddy Kalluru 	*data += 4;
26293a69cae8SSudarsana Reddy Kalluru 	/* Make sure driver familiar with all commands necessary for this */
26303a69cae8SSudarsana Reddy Kalluru 	if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) {
26313a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n",
26323a69cae8SSudarsana Reddy Kalluru 		       *((u16 *)(*data)));
26333a69cae8SSudarsana Reddy Kalluru 		return -EINVAL;
26343a69cae8SSudarsana Reddy Kalluru 	}
26353a69cae8SSudarsana Reddy Kalluru 
26363a69cae8SSudarsana Reddy Kalluru 	*data += 4;
26373a69cae8SSudarsana Reddy Kalluru 
26383a69cae8SSudarsana Reddy Kalluru 	return 0;
26393a69cae8SSudarsana Reddy Kalluru }
26403a69cae8SSudarsana Reddy Kalluru 
26410dabbe1bSSudarsana Reddy Kalluru /* Binary file format -
26420dabbe1bSSudarsana Reddy Kalluru  *     /----------------------------------------------------------------------\
26430dabbe1bSSudarsana Reddy Kalluru  * 0B  |                       0x5 [command index]                            |
26442da244a5SSudarsana Reddy Kalluru  * 4B  | Number of config attributes     |          Reserved                  |
26452da244a5SSudarsana Reddy Kalluru  * 4B  | Config ID                       | Entity ID      | Length            |
26462da244a5SSudarsana Reddy Kalluru  * 4B  | Value                                                                |
26470dabbe1bSSudarsana Reddy Kalluru  *     |                                                                      |
26480dabbe1bSSudarsana Reddy Kalluru  *     \----------------------------------------------------------------------/
26492da244a5SSudarsana Reddy Kalluru  * There can be several cfg_id-entity_id-Length-Value sets as specified by
26502da244a5SSudarsana Reddy Kalluru  * 'Number of config attributes'.
26510dabbe1bSSudarsana Reddy Kalluru  *
26520dabbe1bSSudarsana Reddy Kalluru  * The API parses config attributes from the user provided buffer and flashes
26530dabbe1bSSudarsana Reddy Kalluru  * them to the respective NVM path using Management FW inerface.
26540dabbe1bSSudarsana Reddy Kalluru  */
26550dabbe1bSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data)
26560dabbe1bSSudarsana Reddy Kalluru {
26570dabbe1bSSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
26580dabbe1bSSudarsana Reddy Kalluru 	u8 entity_id, len, buf[32];
2659c63b0968SSudarsana Reddy Kalluru 	bool need_nvm_init = true;
26600dabbe1bSSudarsana Reddy Kalluru 	struct qed_ptt *ptt;
26610dabbe1bSSudarsana Reddy Kalluru 	u16 cfg_id, count;
26620dabbe1bSSudarsana Reddy Kalluru 	int rc = 0, i;
26630dabbe1bSSudarsana Reddy Kalluru 	u32 flags;
26640dabbe1bSSudarsana Reddy Kalluru 
26650dabbe1bSSudarsana Reddy Kalluru 	ptt = qed_ptt_acquire(hwfn);
26660dabbe1bSSudarsana Reddy Kalluru 	if (!ptt)
26670dabbe1bSSudarsana Reddy Kalluru 		return -EAGAIN;
26680dabbe1bSSudarsana Reddy Kalluru 
26690dabbe1bSSudarsana Reddy Kalluru 	/* NVM CFG ID attribute header */
26700dabbe1bSSudarsana Reddy Kalluru 	*data += 4;
26710dabbe1bSSudarsana Reddy Kalluru 	count = *((u16 *)*data);
26722da244a5SSudarsana Reddy Kalluru 	*data += 4;
26730dabbe1bSSudarsana Reddy Kalluru 
26740dabbe1bSSudarsana Reddy Kalluru 	DP_VERBOSE(cdev, NETIF_MSG_DRV,
26752da244a5SSudarsana Reddy Kalluru 		   "Read config ids: num_attrs = %0d\n", count);
2676c63b0968SSudarsana Reddy Kalluru 	/* NVM CFG ID attributes. Start loop index from 1 to avoid additional
2677c63b0968SSudarsana Reddy Kalluru 	 * arithmetic operations in the implementation.
2678c63b0968SSudarsana Reddy Kalluru 	 */
2679c63b0968SSudarsana Reddy Kalluru 	for (i = 1; i <= count; i++) {
26800dabbe1bSSudarsana Reddy Kalluru 		cfg_id = *((u16 *)*data);
26810dabbe1bSSudarsana Reddy Kalluru 		*data += 2;
26822da244a5SSudarsana Reddy Kalluru 		entity_id = **data;
26832da244a5SSudarsana Reddy Kalluru 		(*data)++;
26840dabbe1bSSudarsana Reddy Kalluru 		len = **data;
26850dabbe1bSSudarsana Reddy Kalluru 		(*data)++;
26860dabbe1bSSudarsana Reddy Kalluru 		memcpy(buf, *data, len);
26870dabbe1bSSudarsana Reddy Kalluru 		*data += len;
26880dabbe1bSSudarsana Reddy Kalluru 
2689c63b0968SSudarsana Reddy Kalluru 		flags = 0;
2690c63b0968SSudarsana Reddy Kalluru 		if (need_nvm_init) {
2691c63b0968SSudarsana Reddy Kalluru 			flags |= QED_NVM_CFG_OPTION_INIT;
2692c63b0968SSudarsana Reddy Kalluru 			need_nvm_init = false;
2693c63b0968SSudarsana Reddy Kalluru 		}
2694c63b0968SSudarsana Reddy Kalluru 
2695c63b0968SSudarsana Reddy Kalluru 		/* Commit to flash and free the resources */
2696c63b0968SSudarsana Reddy Kalluru 		if (!(i % QED_NVM_CFG_MAX_ATTRS) || i == count) {
2697c63b0968SSudarsana Reddy Kalluru 			flags |= QED_NVM_CFG_OPTION_COMMIT |
2698c63b0968SSudarsana Reddy Kalluru 				 QED_NVM_CFG_OPTION_FREE;
2699c63b0968SSudarsana Reddy Kalluru 			need_nvm_init = true;
2700c63b0968SSudarsana Reddy Kalluru 		}
2701c63b0968SSudarsana Reddy Kalluru 
2702c63b0968SSudarsana Reddy Kalluru 		if (entity_id)
2703c63b0968SSudarsana Reddy Kalluru 			flags |= QED_NVM_CFG_OPTION_ENTITY_SEL;
27040dabbe1bSSudarsana Reddy Kalluru 
27050dabbe1bSSudarsana Reddy Kalluru 		DP_VERBOSE(cdev, NETIF_MSG_DRV,
27062da244a5SSudarsana Reddy Kalluru 			   "cfg_id = %d entity = %d len = %d\n", cfg_id,
27072da244a5SSudarsana Reddy Kalluru 			   entity_id, len);
27080dabbe1bSSudarsana Reddy Kalluru 		rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags,
27090dabbe1bSSudarsana Reddy Kalluru 					 buf, len);
27100dabbe1bSSudarsana Reddy Kalluru 		if (rc) {
27110dabbe1bSSudarsana Reddy Kalluru 			DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id);
27120dabbe1bSSudarsana Reddy Kalluru 			break;
27130dabbe1bSSudarsana Reddy Kalluru 		}
27140dabbe1bSSudarsana Reddy Kalluru 	}
27150dabbe1bSSudarsana Reddy Kalluru 
27160dabbe1bSSudarsana Reddy Kalluru 	qed_ptt_release(hwfn, ptt);
27170dabbe1bSSudarsana Reddy Kalluru 
27180dabbe1bSSudarsana Reddy Kalluru 	return rc;
27190dabbe1bSSudarsana Reddy Kalluru }
27200dabbe1bSSudarsana Reddy Kalluru 
27219e54ba7cSSudarsana Reddy Kalluru #define QED_MAX_NVM_BUF_LEN	32
27229e54ba7cSSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_len(struct qed_dev *cdev, u32 cmd)
27239e54ba7cSSudarsana Reddy Kalluru {
27249e54ba7cSSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
27259e54ba7cSSudarsana Reddy Kalluru 	u8 buf[QED_MAX_NVM_BUF_LEN];
27269e54ba7cSSudarsana Reddy Kalluru 	struct qed_ptt *ptt;
27279e54ba7cSSudarsana Reddy Kalluru 	u32 len;
27289e54ba7cSSudarsana Reddy Kalluru 	int rc;
27299e54ba7cSSudarsana Reddy Kalluru 
27309e54ba7cSSudarsana Reddy Kalluru 	ptt = qed_ptt_acquire(hwfn);
27319e54ba7cSSudarsana Reddy Kalluru 	if (!ptt)
27329e54ba7cSSudarsana Reddy Kalluru 		return QED_MAX_NVM_BUF_LEN;
27339e54ba7cSSudarsana Reddy Kalluru 
27349e54ba7cSSudarsana Reddy Kalluru 	rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, 0, QED_NVM_CFG_GET_FLAGS, buf,
27359e54ba7cSSudarsana Reddy Kalluru 				 &len);
27369e54ba7cSSudarsana Reddy Kalluru 	if (rc || !len) {
27379e54ba7cSSudarsana Reddy Kalluru 		DP_ERR(cdev, "Error %d reading %d\n", rc, cmd);
27389e54ba7cSSudarsana Reddy Kalluru 		len = QED_MAX_NVM_BUF_LEN;
27399e54ba7cSSudarsana Reddy Kalluru 	}
27409e54ba7cSSudarsana Reddy Kalluru 
27419e54ba7cSSudarsana Reddy Kalluru 	qed_ptt_release(hwfn, ptt);
27429e54ba7cSSudarsana Reddy Kalluru 
27439e54ba7cSSudarsana Reddy Kalluru 	return len;
27449e54ba7cSSudarsana Reddy Kalluru }
27459e54ba7cSSudarsana Reddy Kalluru 
27462d4c8495SSudarsana Reddy Kalluru static int qed_nvm_flash_cfg_read(struct qed_dev *cdev, u8 **data,
27472d4c8495SSudarsana Reddy Kalluru 				  u32 cmd, u32 entity_id)
27482d4c8495SSudarsana Reddy Kalluru {
27492d4c8495SSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
27502d4c8495SSudarsana Reddy Kalluru 	struct qed_ptt *ptt;
27512d4c8495SSudarsana Reddy Kalluru 	u32 flags, len;
27522d4c8495SSudarsana Reddy Kalluru 	int rc = 0;
27532d4c8495SSudarsana Reddy Kalluru 
27542d4c8495SSudarsana Reddy Kalluru 	ptt = qed_ptt_acquire(hwfn);
27552d4c8495SSudarsana Reddy Kalluru 	if (!ptt)
27562d4c8495SSudarsana Reddy Kalluru 		return -EAGAIN;
27572d4c8495SSudarsana Reddy Kalluru 
27582d4c8495SSudarsana Reddy Kalluru 	DP_VERBOSE(cdev, NETIF_MSG_DRV,
27592d4c8495SSudarsana Reddy Kalluru 		   "Read config cmd = %d entity id %d\n", cmd, entity_id);
27602d4c8495SSudarsana Reddy Kalluru 	flags = entity_id ? QED_NVM_CFG_GET_PF_FLAGS : QED_NVM_CFG_GET_FLAGS;
27612d4c8495SSudarsana Reddy Kalluru 	rc = qed_mcp_nvm_get_cfg(hwfn, ptt, cmd, entity_id, flags, *data, &len);
27622d4c8495SSudarsana Reddy Kalluru 	if (rc)
27632d4c8495SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Error %d reading %d\n", rc, cmd);
27642d4c8495SSudarsana Reddy Kalluru 
27652d4c8495SSudarsana Reddy Kalluru 	qed_ptt_release(hwfn, ptt);
27662d4c8495SSudarsana Reddy Kalluru 
27672d4c8495SSudarsana Reddy Kalluru 	return rc;
27682d4c8495SSudarsana Reddy Kalluru }
27692d4c8495SSudarsana Reddy Kalluru 
27703a69cae8SSudarsana Reddy Kalluru static int qed_nvm_flash(struct qed_dev *cdev, const char *name)
27713a69cae8SSudarsana Reddy Kalluru {
27723a69cae8SSudarsana Reddy Kalluru 	const struct firmware *image;
27733a69cae8SSudarsana Reddy Kalluru 	const u8 *data, *data_end;
27743a69cae8SSudarsana Reddy Kalluru 	u32 cmd_type;
27753a69cae8SSudarsana Reddy Kalluru 	int rc;
27763a69cae8SSudarsana Reddy Kalluru 
27773a69cae8SSudarsana Reddy Kalluru 	rc = request_firmware(&image, name, &cdev->pdev->dev);
27783a69cae8SSudarsana Reddy Kalluru 	if (rc) {
27793a69cae8SSudarsana Reddy Kalluru 		DP_ERR(cdev, "Failed to find '%s'\n", name);
27803a69cae8SSudarsana Reddy Kalluru 		return rc;
27813a69cae8SSudarsana Reddy Kalluru 	}
27823a69cae8SSudarsana Reddy Kalluru 
27833a69cae8SSudarsana Reddy Kalluru 	DP_VERBOSE(cdev, NETIF_MSG_DRV,
27843a69cae8SSudarsana Reddy Kalluru 		   "Flashing '%s' - firmware's data at %p, size is %08x\n",
27853a69cae8SSudarsana Reddy Kalluru 		   name, image->data, (u32)image->size);
27863a69cae8SSudarsana Reddy Kalluru 	data = image->data;
27873a69cae8SSudarsana Reddy Kalluru 	data_end = data + image->size;
27883a69cae8SSudarsana Reddy Kalluru 
27893a69cae8SSudarsana Reddy Kalluru 	rc = qed_nvm_flash_image_validate(cdev, image, &data);
27903a69cae8SSudarsana Reddy Kalluru 	if (rc)
27913a69cae8SSudarsana Reddy Kalluru 		goto exit;
27923a69cae8SSudarsana Reddy Kalluru 
27933a69cae8SSudarsana Reddy Kalluru 	while (data < data_end) {
27943a69cae8SSudarsana Reddy Kalluru 		bool check_resp = false;
27953a69cae8SSudarsana Reddy Kalluru 
27963a69cae8SSudarsana Reddy Kalluru 		/* Parse the actual command */
27973a69cae8SSudarsana Reddy Kalluru 		cmd_type = *((u32 *)data);
27983a69cae8SSudarsana Reddy Kalluru 		switch (cmd_type) {
27993a69cae8SSudarsana Reddy Kalluru 		case QED_NVM_FLASH_CMD_FILE_DATA:
28003a69cae8SSudarsana Reddy Kalluru 			rc = qed_nvm_flash_image_file_data(cdev, &data,
28013a69cae8SSudarsana Reddy Kalluru 							   &check_resp);
28023a69cae8SSudarsana Reddy Kalluru 			break;
28033a69cae8SSudarsana Reddy Kalluru 		case QED_NVM_FLASH_CMD_FILE_START:
28043a69cae8SSudarsana Reddy Kalluru 			rc = qed_nvm_flash_image_file_start(cdev, &data,
28053a69cae8SSudarsana Reddy Kalluru 							    &check_resp);
28063a69cae8SSudarsana Reddy Kalluru 			break;
28073a69cae8SSudarsana Reddy Kalluru 		case QED_NVM_FLASH_CMD_NVM_CHANGE:
28083a69cae8SSudarsana Reddy Kalluru 			rc = qed_nvm_flash_image_access(cdev, &data,
28093a69cae8SSudarsana Reddy Kalluru 							&check_resp);
28103a69cae8SSudarsana Reddy Kalluru 			break;
28110dabbe1bSSudarsana Reddy Kalluru 		case QED_NVM_FLASH_CMD_NVM_CFG_ID:
28120dabbe1bSSudarsana Reddy Kalluru 			rc = qed_nvm_flash_cfg_write(cdev, &data);
28130dabbe1bSSudarsana Reddy Kalluru 			break;
28143a69cae8SSudarsana Reddy Kalluru 		default:
28153a69cae8SSudarsana Reddy Kalluru 			DP_ERR(cdev, "Unknown command %08x\n", cmd_type);
28163a69cae8SSudarsana Reddy Kalluru 			rc = -EINVAL;
28173a69cae8SSudarsana Reddy Kalluru 			goto exit;
28183a69cae8SSudarsana Reddy Kalluru 		}
28193a69cae8SSudarsana Reddy Kalluru 
28203a69cae8SSudarsana Reddy Kalluru 		if (rc) {
28213a69cae8SSudarsana Reddy Kalluru 			DP_ERR(cdev, "Command %08x failed\n", cmd_type);
28223a69cae8SSudarsana Reddy Kalluru 			goto exit;
28233a69cae8SSudarsana Reddy Kalluru 		}
28243a69cae8SSudarsana Reddy Kalluru 
28253a69cae8SSudarsana Reddy Kalluru 		/* Check response if needed */
28263a69cae8SSudarsana Reddy Kalluru 		if (check_resp) {
28273a69cae8SSudarsana Reddy Kalluru 			u32 mcp_response = 0;
28283a69cae8SSudarsana Reddy Kalluru 
28293a69cae8SSudarsana Reddy Kalluru 			if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) {
28303a69cae8SSudarsana Reddy Kalluru 				DP_ERR(cdev, "Failed getting MCP response\n");
28313a69cae8SSudarsana Reddy Kalluru 				rc = -EINVAL;
28323a69cae8SSudarsana Reddy Kalluru 				goto exit;
28333a69cae8SSudarsana Reddy Kalluru 			}
28343a69cae8SSudarsana Reddy Kalluru 
28353a69cae8SSudarsana Reddy Kalluru 			switch (mcp_response & FW_MSG_CODE_MASK) {
28363a69cae8SSudarsana Reddy Kalluru 			case FW_MSG_CODE_OK:
28373a69cae8SSudarsana Reddy Kalluru 			case FW_MSG_CODE_NVM_OK:
28383a69cae8SSudarsana Reddy Kalluru 			case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK:
28393a69cae8SSudarsana Reddy Kalluru 			case FW_MSG_CODE_PHY_OK:
28403a69cae8SSudarsana Reddy Kalluru 				break;
28413a69cae8SSudarsana Reddy Kalluru 			default:
28423a69cae8SSudarsana Reddy Kalluru 				DP_ERR(cdev, "MFW returns error: %08x\n",
28433a69cae8SSudarsana Reddy Kalluru 				       mcp_response);
28443a69cae8SSudarsana Reddy Kalluru 				rc = -EINVAL;
28453a69cae8SSudarsana Reddy Kalluru 				goto exit;
28463a69cae8SSudarsana Reddy Kalluru 			}
28473a69cae8SSudarsana Reddy Kalluru 		}
28483a69cae8SSudarsana Reddy Kalluru 	}
28493a69cae8SSudarsana Reddy Kalluru 
28503a69cae8SSudarsana Reddy Kalluru exit:
28513a69cae8SSudarsana Reddy Kalluru 	release_firmware(image);
28523a69cae8SSudarsana Reddy Kalluru 
28533a69cae8SSudarsana Reddy Kalluru 	return rc;
28543a69cae8SSudarsana Reddy Kalluru }
28553a69cae8SSudarsana Reddy Kalluru 
285620675b37SMintz, Yuval static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type,
285720675b37SMintz, Yuval 			     u8 *buf, u16 len)
285820675b37SMintz, Yuval {
285920675b37SMintz, Yuval 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
286020675b37SMintz, Yuval 
2861b60bfdfeSDenis Bolotin 	return qed_mcp_get_nvm_image(hwfn, type, buf, len);
286220675b37SMintz, Yuval }
286320675b37SMintz, Yuval 
286464515dc8STomer Tayar void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn)
286564515dc8STomer Tayar {
286664515dc8STomer Tayar 	struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common;
286764515dc8STomer Tayar 	void *cookie = p_hwfn->cdev->ops_cookie;
286864515dc8STomer Tayar 
286964515dc8STomer Tayar 	if (ops && ops->schedule_recovery_handler)
287064515dc8STomer Tayar 		ops->schedule_recovery_handler(cookie);
287164515dc8STomer Tayar }
287264515dc8STomer Tayar 
2873c6b7314dSAlexander Lobakin static const char * const qed_hw_err_type_descr[] = {
2874d639836aSIgor Russkikh 	[QED_HW_ERR_FAN_FAIL]		= "Fan Failure",
2875d639836aSIgor Russkikh 	[QED_HW_ERR_MFW_RESP_FAIL]	= "MFW Response Failure",
2876d639836aSIgor Russkikh 	[QED_HW_ERR_HW_ATTN]		= "HW Attention",
2877d639836aSIgor Russkikh 	[QED_HW_ERR_DMAE_FAIL]		= "DMAE Failure",
2878d639836aSIgor Russkikh 	[QED_HW_ERR_RAMROD_FAIL]	= "Ramrod Failure",
2879d639836aSIgor Russkikh 	[QED_HW_ERR_FW_ASSERT]		= "FW Assertion",
2880d639836aSIgor Russkikh 	[QED_HW_ERR_LAST]		= "Unknown",
2881d639836aSIgor Russkikh };
2882d639836aSIgor Russkikh 
2883d639836aSIgor Russkikh void qed_hw_error_occurred(struct qed_hwfn *p_hwfn,
2884d639836aSIgor Russkikh 			   enum qed_hw_err_type err_type)
2885d639836aSIgor Russkikh {
2886d639836aSIgor Russkikh 	struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common;
2887d639836aSIgor Russkikh 	void *cookie = p_hwfn->cdev->ops_cookie;
2888c6b7314dSAlexander Lobakin 	const char *err_str;
2889d639836aSIgor Russkikh 
2890d639836aSIgor Russkikh 	if (err_type > QED_HW_ERR_LAST)
2891d639836aSIgor Russkikh 		err_type = QED_HW_ERR_LAST;
2892d639836aSIgor Russkikh 	err_str = qed_hw_err_type_descr[err_type];
2893d639836aSIgor Russkikh 
2894d639836aSIgor Russkikh 	DP_NOTICE(p_hwfn, "HW error occurred [%s]\n", err_str);
2895d639836aSIgor Russkikh 
2896936c7ba4SIgor Russkikh 	/* Call the HW error handler of the protocol driver.
2897936c7ba4SIgor Russkikh 	 * If it is not available - perform a minimal handling of preventing
2898936c7ba4SIgor Russkikh 	 * HW attentions from being reasserted.
2899d639836aSIgor Russkikh 	 */
2900d639836aSIgor Russkikh 	if (ops && ops->schedule_hw_err_handler)
2901d639836aSIgor Russkikh 		ops->schedule_hw_err_handler(cookie, err_type);
2902936c7ba4SIgor Russkikh 	else
2903936c7ba4SIgor Russkikh 		qed_int_attn_clr_enable(p_hwfn->cdev, true);
2904d639836aSIgor Russkikh }
2905d639836aSIgor Russkikh 
2906722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal,
2907477f2d14SRahul Verma 			    void *handle)
2908722003acSSudarsana Reddy Kalluru {
2909477f2d14SRahul Verma 		return qed_set_queue_coalesce(rx_coal, tx_coal, handle);
2910722003acSSudarsana Reddy Kalluru }
2911722003acSSudarsana Reddy Kalluru 
291291420b83SSudarsana Kalluru static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
291391420b83SSudarsana Kalluru {
291491420b83SSudarsana Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
291591420b83SSudarsana Kalluru 	struct qed_ptt *ptt;
291691420b83SSudarsana Kalluru 	int status = 0;
291791420b83SSudarsana Kalluru 
291891420b83SSudarsana Kalluru 	ptt = qed_ptt_acquire(hwfn);
291991420b83SSudarsana Kalluru 	if (!ptt)
292091420b83SSudarsana Kalluru 		return -EAGAIN;
292191420b83SSudarsana Kalluru 
292291420b83SSudarsana Kalluru 	status = qed_mcp_set_led(hwfn, ptt, mode);
292391420b83SSudarsana Kalluru 
292491420b83SSudarsana Kalluru 	qed_ptt_release(hwfn, ptt);
292591420b83SSudarsana Kalluru 
292691420b83SSudarsana Kalluru 	return status;
292791420b83SSudarsana Kalluru }
292891420b83SSudarsana Kalluru 
292964515dc8STomer Tayar static int qed_recovery_process(struct qed_dev *cdev)
293064515dc8STomer Tayar {
293164515dc8STomer Tayar 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
293264515dc8STomer Tayar 	struct qed_ptt *p_ptt;
293364515dc8STomer Tayar 	int rc = 0;
293464515dc8STomer Tayar 
293564515dc8STomer Tayar 	p_ptt = qed_ptt_acquire(p_hwfn);
293664515dc8STomer Tayar 	if (!p_ptt)
293764515dc8STomer Tayar 		return -EAGAIN;
293864515dc8STomer Tayar 
293964515dc8STomer Tayar 	rc = qed_start_recovery_process(p_hwfn, p_ptt);
294064515dc8STomer Tayar 
294164515dc8STomer Tayar 	qed_ptt_release(p_hwfn, p_ptt);
294264515dc8STomer Tayar 
294364515dc8STomer Tayar 	return rc;
294464515dc8STomer Tayar }
294564515dc8STomer Tayar 
294614d39648SMintz, Yuval static int qed_update_wol(struct qed_dev *cdev, bool enabled)
294714d39648SMintz, Yuval {
294814d39648SMintz, Yuval 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
294914d39648SMintz, Yuval 	struct qed_ptt *ptt;
295014d39648SMintz, Yuval 	int rc = 0;
295114d39648SMintz, Yuval 
295214d39648SMintz, Yuval 	if (IS_VF(cdev))
295314d39648SMintz, Yuval 		return 0;
295414d39648SMintz, Yuval 
295514d39648SMintz, Yuval 	ptt = qed_ptt_acquire(hwfn);
295614d39648SMintz, Yuval 	if (!ptt)
295714d39648SMintz, Yuval 		return -EAGAIN;
295814d39648SMintz, Yuval 
295914d39648SMintz, Yuval 	rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED
296014d39648SMintz, Yuval 				   : QED_OV_WOL_DISABLED);
296114d39648SMintz, Yuval 	if (rc)
296214d39648SMintz, Yuval 		goto out;
296314d39648SMintz, Yuval 	rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV);
296414d39648SMintz, Yuval 
296514d39648SMintz, Yuval out:
296614d39648SMintz, Yuval 	qed_ptt_release(hwfn, ptt);
296714d39648SMintz, Yuval 	return rc;
296814d39648SMintz, Yuval }
296914d39648SMintz, Yuval 
29700fefbfbaSSudarsana Kalluru static int qed_update_drv_state(struct qed_dev *cdev, bool active)
29710fefbfbaSSudarsana Kalluru {
29720fefbfbaSSudarsana Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
29730fefbfbaSSudarsana Kalluru 	struct qed_ptt *ptt;
29740fefbfbaSSudarsana Kalluru 	int status = 0;
29750fefbfbaSSudarsana Kalluru 
29760fefbfbaSSudarsana Kalluru 	if (IS_VF(cdev))
29770fefbfbaSSudarsana Kalluru 		return 0;
29780fefbfbaSSudarsana Kalluru 
29790fefbfbaSSudarsana Kalluru 	ptt = qed_ptt_acquire(hwfn);
29800fefbfbaSSudarsana Kalluru 	if (!ptt)
29810fefbfbaSSudarsana Kalluru 		return -EAGAIN;
29820fefbfbaSSudarsana Kalluru 
29830fefbfbaSSudarsana Kalluru 	status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ?
29840fefbfbaSSudarsana Kalluru 						QED_OV_DRIVER_STATE_ACTIVE :
29850fefbfbaSSudarsana Kalluru 						QED_OV_DRIVER_STATE_DISABLED);
29860fefbfbaSSudarsana Kalluru 
29870fefbfbaSSudarsana Kalluru 	qed_ptt_release(hwfn, ptt);
29880fefbfbaSSudarsana Kalluru 
29890fefbfbaSSudarsana Kalluru 	return status;
29900fefbfbaSSudarsana Kalluru }
29910fefbfbaSSudarsana Kalluru 
29920fefbfbaSSudarsana Kalluru static int qed_update_mac(struct qed_dev *cdev, u8 *mac)
29930fefbfbaSSudarsana Kalluru {
29940fefbfbaSSudarsana Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
29950fefbfbaSSudarsana Kalluru 	struct qed_ptt *ptt;
29960fefbfbaSSudarsana Kalluru 	int status = 0;
29970fefbfbaSSudarsana Kalluru 
29980fefbfbaSSudarsana Kalluru 	if (IS_VF(cdev))
29990fefbfbaSSudarsana Kalluru 		return 0;
30000fefbfbaSSudarsana Kalluru 
30010fefbfbaSSudarsana Kalluru 	ptt = qed_ptt_acquire(hwfn);
30020fefbfbaSSudarsana Kalluru 	if (!ptt)
30030fefbfbaSSudarsana Kalluru 		return -EAGAIN;
30040fefbfbaSSudarsana Kalluru 
30050fefbfbaSSudarsana Kalluru 	status = qed_mcp_ov_update_mac(hwfn, ptt, mac);
30060fefbfbaSSudarsana Kalluru 	if (status)
30070fefbfbaSSudarsana Kalluru 		goto out;
30080fefbfbaSSudarsana Kalluru 
30090fefbfbaSSudarsana Kalluru 	status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV);
30100fefbfbaSSudarsana Kalluru 
30110fefbfbaSSudarsana Kalluru out:
30120fefbfbaSSudarsana Kalluru 	qed_ptt_release(hwfn, ptt);
30130fefbfbaSSudarsana Kalluru 	return status;
30140fefbfbaSSudarsana Kalluru }
30150fefbfbaSSudarsana Kalluru 
30160fefbfbaSSudarsana Kalluru static int qed_update_mtu(struct qed_dev *cdev, u16 mtu)
30170fefbfbaSSudarsana Kalluru {
30180fefbfbaSSudarsana Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
30190fefbfbaSSudarsana Kalluru 	struct qed_ptt *ptt;
30200fefbfbaSSudarsana Kalluru 	int status = 0;
30210fefbfbaSSudarsana Kalluru 
30220fefbfbaSSudarsana Kalluru 	if (IS_VF(cdev))
30230fefbfbaSSudarsana Kalluru 		return 0;
30240fefbfbaSSudarsana Kalluru 
30250fefbfbaSSudarsana Kalluru 	ptt = qed_ptt_acquire(hwfn);
30260fefbfbaSSudarsana Kalluru 	if (!ptt)
30270fefbfbaSSudarsana Kalluru 		return -EAGAIN;
30280fefbfbaSSudarsana Kalluru 
30290fefbfbaSSudarsana Kalluru 	status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu);
30300fefbfbaSSudarsana Kalluru 	if (status)
30310fefbfbaSSudarsana Kalluru 		goto out;
30320fefbfbaSSudarsana Kalluru 
30330fefbfbaSSudarsana Kalluru 	status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV);
30340fefbfbaSSudarsana Kalluru 
30350fefbfbaSSudarsana Kalluru out:
30360fefbfbaSSudarsana Kalluru 	qed_ptt_release(hwfn, ptt);
30370fefbfbaSSudarsana Kalluru 	return status;
30380fefbfbaSSudarsana Kalluru }
30390fefbfbaSSudarsana Kalluru 
3040b51dab46SSudarsana Reddy Kalluru static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf,
3041b51dab46SSudarsana Reddy Kalluru 				  u8 dev_addr, u32 offset, u32 len)
3042b51dab46SSudarsana Reddy Kalluru {
3043b51dab46SSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
3044b51dab46SSudarsana Reddy Kalluru 	struct qed_ptt *ptt;
3045b51dab46SSudarsana Reddy Kalluru 	int rc = 0;
3046b51dab46SSudarsana Reddy Kalluru 
3047b51dab46SSudarsana Reddy Kalluru 	if (IS_VF(cdev))
3048b51dab46SSudarsana Reddy Kalluru 		return 0;
3049b51dab46SSudarsana Reddy Kalluru 
3050b51dab46SSudarsana Reddy Kalluru 	ptt = qed_ptt_acquire(hwfn);
3051b51dab46SSudarsana Reddy Kalluru 	if (!ptt)
3052b51dab46SSudarsana Reddy Kalluru 		return -EAGAIN;
3053b51dab46SSudarsana Reddy Kalluru 
3054b51dab46SSudarsana Reddy Kalluru 	rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr,
3055b51dab46SSudarsana Reddy Kalluru 				  offset, len, buf);
3056b51dab46SSudarsana Reddy Kalluru 
3057b51dab46SSudarsana Reddy Kalluru 	qed_ptt_release(hwfn, ptt);
3058b51dab46SSudarsana Reddy Kalluru 
3059b51dab46SSudarsana Reddy Kalluru 	return rc;
3060b51dab46SSudarsana Reddy Kalluru }
3061b51dab46SSudarsana Reddy Kalluru 
30623b86bd07SSudarsana Reddy Kalluru static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val)
30633b86bd07SSudarsana Reddy Kalluru {
30643b86bd07SSudarsana Reddy Kalluru 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
30653b86bd07SSudarsana Reddy Kalluru 	struct qed_ptt *ptt;
30663b86bd07SSudarsana Reddy Kalluru 	int rc = 0;
30673b86bd07SSudarsana Reddy Kalluru 
30683b86bd07SSudarsana Reddy Kalluru 	if (IS_VF(cdev))
30693b86bd07SSudarsana Reddy Kalluru 		return 0;
30703b86bd07SSudarsana Reddy Kalluru 
30713b86bd07SSudarsana Reddy Kalluru 	ptt = qed_ptt_acquire(hwfn);
30723b86bd07SSudarsana Reddy Kalluru 	if (!ptt)
30733b86bd07SSudarsana Reddy Kalluru 		return -EAGAIN;
30743b86bd07SSudarsana Reddy Kalluru 
30752d22bc83SMichal Kalderon 	rc = qed_dbg_grc_config(hwfn, cfg_id, val);
30763b86bd07SSudarsana Reddy Kalluru 
30773b86bd07SSudarsana Reddy Kalluru 	qed_ptt_release(hwfn, ptt);
30783b86bd07SSudarsana Reddy Kalluru 
30793b86bd07SSudarsana Reddy Kalluru 	return rc;
30803b86bd07SSudarsana Reddy Kalluru }
30813b86bd07SSudarsana Reddy Kalluru 
308208eb1fb0SMichal Kalderon static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev)
308308eb1fb0SMichal Kalderon {
308408eb1fb0SMichal Kalderon 	return QED_AFFIN_HWFN_IDX(cdev);
308508eb1fb0SMichal Kalderon }
308608eb1fb0SMichal Kalderon 
30878c93beafSYuval Mintz static struct qed_selftest_ops qed_selftest_ops_pass = {
308803dc76caSSudarsana Reddy Kalluru 	.selftest_memory = &qed_selftest_memory,
308903dc76caSSudarsana Reddy Kalluru 	.selftest_interrupt = &qed_selftest_interrupt,
309003dc76caSSudarsana Reddy Kalluru 	.selftest_register = &qed_selftest_register,
309103dc76caSSudarsana Reddy Kalluru 	.selftest_clock = &qed_selftest_clock,
30927a4b21b7SMintz, Yuval 	.selftest_nvram = &qed_selftest_nvram,
309303dc76caSSudarsana Reddy Kalluru };
309403dc76caSSudarsana Reddy Kalluru 
3095fe56b9e6SYuval Mintz const struct qed_common_ops qed_common_ops_pass = {
309603dc76caSSudarsana Reddy Kalluru 	.selftest = &qed_selftest_ops_pass,
3097fe56b9e6SYuval Mintz 	.probe = &qed_probe,
3098fe56b9e6SYuval Mintz 	.remove = &qed_remove,
3099fe56b9e6SYuval Mintz 	.set_power_state = &qed_set_power_state,
3100712c3cbfSMintz, Yuval 	.set_name = &qed_set_name,
3101fe56b9e6SYuval Mintz 	.update_pf_params = &qed_update_pf_params,
3102fe56b9e6SYuval Mintz 	.slowpath_start = &qed_slowpath_start,
3103fe56b9e6SYuval Mintz 	.slowpath_stop = &qed_slowpath_stop,
3104fe56b9e6SYuval Mintz 	.set_fp_int = &qed_set_int_fp,
3105fe56b9e6SYuval Mintz 	.get_fp_int = &qed_get_int_fp,
3106fe56b9e6SYuval Mintz 	.sb_init = &qed_sb_init,
3107fe56b9e6SYuval Mintz 	.sb_release = &qed_sb_release,
3108fe56b9e6SYuval Mintz 	.simd_handler_config = &qed_simd_handler_config,
3109fe56b9e6SYuval Mintz 	.simd_handler_clean = &qed_simd_handler_clean,
31101e128c81SArun Easi 	.dbg_grc = &qed_dbg_grc,
31111e128c81SArun Easi 	.dbg_grc_size = &qed_dbg_grc_size,
3112fe7cd2bfSYuval Mintz 	.can_link_change = &qed_can_link_change,
3113cc875c2eSYuval Mintz 	.set_link = &qed_set_link,
3114cc875c2eSYuval Mintz 	.get_link = &qed_get_current_link,
3115fe56b9e6SYuval Mintz 	.drain = &qed_drain,
3116fe56b9e6SYuval Mintz 	.update_msglvl = &qed_init_dp,
3117e0971c83STomer Tayar 	.dbg_all_data = &qed_dbg_all_data,
3118e0971c83STomer Tayar 	.dbg_all_data_size = &qed_dbg_all_data_size,
3119fe56b9e6SYuval Mintz 	.chain_alloc = &qed_chain_alloc,
3120fe56b9e6SYuval Mintz 	.chain_free = &qed_chain_free,
31213a69cae8SSudarsana Reddy Kalluru 	.nvm_flash = &qed_nvm_flash,
312220675b37SMintz, Yuval 	.nvm_get_image = &qed_nvm_get_image,
3123722003acSSudarsana Reddy Kalluru 	.set_coalesce = &qed_set_coalesce,
312491420b83SSudarsana Kalluru 	.set_led = &qed_set_led,
312564515dc8STomer Tayar 	.recovery_process = &qed_recovery_process,
312664515dc8STomer Tayar 	.recovery_prolog = &qed_recovery_prolog,
3127936c7ba4SIgor Russkikh 	.attn_clr_enable = &qed_int_attn_clr_enable,
31280fefbfbaSSudarsana Kalluru 	.update_drv_state = &qed_update_drv_state,
31290fefbfbaSSudarsana Kalluru 	.update_mac = &qed_update_mac,
31300fefbfbaSSudarsana Kalluru 	.update_mtu = &qed_update_mtu,
313114d39648SMintz, Yuval 	.update_wol = &qed_update_wol,
31320e1f1044SAriel Elior 	.db_recovery_add = &qed_db_recovery_add,
31330e1f1044SAriel Elior 	.db_recovery_del = &qed_db_recovery_del,
3134b51dab46SSudarsana Reddy Kalluru 	.read_module_eeprom = &qed_read_module_eeprom,
313508eb1fb0SMichal Kalderon 	.get_affin_hwfn_idx = &qed_get_affin_hwfn_idx,
31362d4c8495SSudarsana Reddy Kalluru 	.read_nvm_cfg = &qed_nvm_flash_cfg_read,
31379e54ba7cSSudarsana Reddy Kalluru 	.read_nvm_cfg_len = &qed_nvm_flash_cfg_len,
31383b86bd07SSudarsana Reddy Kalluru 	.set_grc_config = &qed_set_grc_config,
3139fe56b9e6SYuval Mintz };
31406c754246SSudarsana Reddy Kalluru 
31416c754246SSudarsana Reddy Kalluru void qed_get_protocol_stats(struct qed_dev *cdev,
31426c754246SSudarsana Reddy Kalluru 			    enum qed_mcp_protocol_type type,
31436c754246SSudarsana Reddy Kalluru 			    union qed_mcp_protocol_stats *stats)
31446c754246SSudarsana Reddy Kalluru {
31456c754246SSudarsana Reddy Kalluru 	struct qed_eth_stats eth_stats;
31466c754246SSudarsana Reddy Kalluru 
31476c754246SSudarsana Reddy Kalluru 	memset(stats, 0, sizeof(*stats));
31486c754246SSudarsana Reddy Kalluru 
31496c754246SSudarsana Reddy Kalluru 	switch (type) {
31506c754246SSudarsana Reddy Kalluru 	case QED_MCP_LAN_STATS:
31516c754246SSudarsana Reddy Kalluru 		qed_get_vport_stats(cdev, &eth_stats);
31529c79ddaaSMintz, Yuval 		stats->lan_stats.ucast_rx_pkts =
31539c79ddaaSMintz, Yuval 					eth_stats.common.rx_ucast_pkts;
31549c79ddaaSMintz, Yuval 		stats->lan_stats.ucast_tx_pkts =
31559c79ddaaSMintz, Yuval 					eth_stats.common.tx_ucast_pkts;
31566c754246SSudarsana Reddy Kalluru 		stats->lan_stats.fcs_err = -1;
31576c754246SSudarsana Reddy Kalluru 		break;
31581e128c81SArun Easi 	case QED_MCP_FCOE_STATS:
31591e128c81SArun Easi 		qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats);
31601e128c81SArun Easi 		break;
31612f2b2614SMintz, Yuval 	case QED_MCP_ISCSI_STATS:
31622f2b2614SMintz, Yuval 		qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats);
31632f2b2614SMintz, Yuval 		break;
31646c754246SSudarsana Reddy Kalluru 	default:
3165512c7840SMintz, Yuval 		DP_VERBOSE(cdev, QED_MSG_SP,
3166512c7840SMintz, Yuval 			   "Invalid protocol type = %d\n", type);
31676c754246SSudarsana Reddy Kalluru 		return;
31686c754246SSudarsana Reddy Kalluru 	}
31696c754246SSudarsana Reddy Kalluru }
31702528c389SSudarsana Reddy Kalluru 
317159ccf86fSSudarsana Reddy Kalluru int qed_mfw_tlv_req(struct qed_hwfn *hwfn)
317259ccf86fSSudarsana Reddy Kalluru {
317359ccf86fSSudarsana Reddy Kalluru 	DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV,
317459ccf86fSSudarsana Reddy Kalluru 		   "Scheduling slowpath task [Flag: %d]\n",
317559ccf86fSSudarsana Reddy Kalluru 		   QED_SLOWPATH_MFW_TLV_REQ);
317659ccf86fSSudarsana Reddy Kalluru 	smp_mb__before_atomic();
317759ccf86fSSudarsana Reddy Kalluru 	set_bit(QED_SLOWPATH_MFW_TLV_REQ, &hwfn->slowpath_task_flags);
317859ccf86fSSudarsana Reddy Kalluru 	smp_mb__after_atomic();
317959ccf86fSSudarsana Reddy Kalluru 	queue_delayed_work(hwfn->slowpath_wq, &hwfn->slowpath_task, 0);
318059ccf86fSSudarsana Reddy Kalluru 
318159ccf86fSSudarsana Reddy Kalluru 	return 0;
318259ccf86fSSudarsana Reddy Kalluru }
318359ccf86fSSudarsana Reddy Kalluru 
318459ccf86fSSudarsana Reddy Kalluru static void
318559ccf86fSSudarsana Reddy Kalluru qed_fill_generic_tlv_data(struct qed_dev *cdev, struct qed_mfw_tlv_generic *tlv)
318659ccf86fSSudarsana Reddy Kalluru {
318759ccf86fSSudarsana Reddy Kalluru 	struct qed_common_cb_ops *op = cdev->protocol_ops.common;
318859ccf86fSSudarsana Reddy Kalluru 	struct qed_eth_stats_common *p_common;
318959ccf86fSSudarsana Reddy Kalluru 	struct qed_generic_tlvs gen_tlvs;
319059ccf86fSSudarsana Reddy Kalluru 	struct qed_eth_stats stats;
319159ccf86fSSudarsana Reddy Kalluru 	int i;
319259ccf86fSSudarsana Reddy Kalluru 
319359ccf86fSSudarsana Reddy Kalluru 	memset(&gen_tlvs, 0, sizeof(gen_tlvs));
319459ccf86fSSudarsana Reddy Kalluru 	op->get_generic_tlv_data(cdev->ops_cookie, &gen_tlvs);
319559ccf86fSSudarsana Reddy Kalluru 
319659ccf86fSSudarsana Reddy Kalluru 	if (gen_tlvs.feat_flags & QED_TLV_IP_CSUM)
319759ccf86fSSudarsana Reddy Kalluru 		tlv->flags.ipv4_csum_offload = true;
319859ccf86fSSudarsana Reddy Kalluru 	if (gen_tlvs.feat_flags & QED_TLV_LSO)
319959ccf86fSSudarsana Reddy Kalluru 		tlv->flags.lso_supported = true;
320059ccf86fSSudarsana Reddy Kalluru 	tlv->flags.b_set = true;
320159ccf86fSSudarsana Reddy Kalluru 
320259ccf86fSSudarsana Reddy Kalluru 	for (i = 0; i < QED_TLV_MAC_COUNT; i++) {
320359ccf86fSSudarsana Reddy Kalluru 		if (is_valid_ether_addr(gen_tlvs.mac[i])) {
320459ccf86fSSudarsana Reddy Kalluru 			ether_addr_copy(tlv->mac[i], gen_tlvs.mac[i]);
320559ccf86fSSudarsana Reddy Kalluru 			tlv->mac_set[i] = true;
320659ccf86fSSudarsana Reddy Kalluru 		}
320759ccf86fSSudarsana Reddy Kalluru 	}
320859ccf86fSSudarsana Reddy Kalluru 
320959ccf86fSSudarsana Reddy Kalluru 	qed_get_vport_stats(cdev, &stats);
321059ccf86fSSudarsana Reddy Kalluru 	p_common = &stats.common;
321159ccf86fSSudarsana Reddy Kalluru 	tlv->rx_frames = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts +
321259ccf86fSSudarsana Reddy Kalluru 			 p_common->rx_bcast_pkts;
321359ccf86fSSudarsana Reddy Kalluru 	tlv->rx_frames_set = true;
321459ccf86fSSudarsana Reddy Kalluru 	tlv->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes +
321559ccf86fSSudarsana Reddy Kalluru 			p_common->rx_bcast_bytes;
321659ccf86fSSudarsana Reddy Kalluru 	tlv->rx_bytes_set = true;
321759ccf86fSSudarsana Reddy Kalluru 	tlv->tx_frames = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts +
321859ccf86fSSudarsana Reddy Kalluru 			 p_common->tx_bcast_pkts;
321959ccf86fSSudarsana Reddy Kalluru 	tlv->tx_frames_set = true;
322059ccf86fSSudarsana Reddy Kalluru 	tlv->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes +
322159ccf86fSSudarsana Reddy Kalluru 			p_common->tx_bcast_bytes;
322259ccf86fSSudarsana Reddy Kalluru 	tlv->rx_bytes_set = true;
322359ccf86fSSudarsana Reddy Kalluru }
322459ccf86fSSudarsana Reddy Kalluru 
32252528c389SSudarsana Reddy Kalluru int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn, enum qed_mfw_tlv_type type,
32262528c389SSudarsana Reddy Kalluru 			  union qed_mfw_tlv_data *tlv_buf)
32272528c389SSudarsana Reddy Kalluru {
322859ccf86fSSudarsana Reddy Kalluru 	struct qed_dev *cdev = hwfn->cdev;
322959ccf86fSSudarsana Reddy Kalluru 	struct qed_common_cb_ops *ops;
323059ccf86fSSudarsana Reddy Kalluru 
323159ccf86fSSudarsana Reddy Kalluru 	ops = cdev->protocol_ops.common;
323259ccf86fSSudarsana Reddy Kalluru 	if (!ops || !ops->get_protocol_tlv_data || !ops->get_generic_tlv_data) {
323359ccf86fSSudarsana Reddy Kalluru 		DP_NOTICE(hwfn, "Can't collect TLV management info\n");
32342528c389SSudarsana Reddy Kalluru 		return -EINVAL;
32352528c389SSudarsana Reddy Kalluru 	}
323659ccf86fSSudarsana Reddy Kalluru 
323759ccf86fSSudarsana Reddy Kalluru 	switch (type) {
323859ccf86fSSudarsana Reddy Kalluru 	case QED_MFW_TLV_GENERIC:
323959ccf86fSSudarsana Reddy Kalluru 		qed_fill_generic_tlv_data(hwfn->cdev, &tlv_buf->generic);
324059ccf86fSSudarsana Reddy Kalluru 		break;
324159ccf86fSSudarsana Reddy Kalluru 	case QED_MFW_TLV_ETH:
324259ccf86fSSudarsana Reddy Kalluru 		ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->eth);
324359ccf86fSSudarsana Reddy Kalluru 		break;
324459ccf86fSSudarsana Reddy Kalluru 	case QED_MFW_TLV_FCOE:
324559ccf86fSSudarsana Reddy Kalluru 		ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->fcoe);
324659ccf86fSSudarsana Reddy Kalluru 		break;
324759ccf86fSSudarsana Reddy Kalluru 	case QED_MFW_TLV_ISCSI:
324859ccf86fSSudarsana Reddy Kalluru 		ops->get_protocol_tlv_data(cdev->ops_cookie, &tlv_buf->iscsi);
324959ccf86fSSudarsana Reddy Kalluru 		break;
325059ccf86fSSudarsana Reddy Kalluru 	default:
325159ccf86fSSudarsana Reddy Kalluru 		break;
325259ccf86fSSudarsana Reddy Kalluru 	}
325359ccf86fSSudarsana Reddy Kalluru 
325459ccf86fSSudarsana Reddy Kalluru 	return 0;
325559ccf86fSSudarsana Reddy Kalluru }
3256