1fe56b9e6SYuval Mintz /* QLogic qed NIC Driver
2e8f1cb50SMintz, Yuval  * Copyright (c) 2015-2017  QLogic Corporation
3fe56b9e6SYuval Mintz  *
4e8f1cb50SMintz, Yuval  * This software is available to you under a choice of one of two
5e8f1cb50SMintz, Yuval  * licenses.  You may choose to be licensed under the terms of the GNU
6e8f1cb50SMintz, Yuval  * General Public License (GPL) Version 2, available from the file
7e8f1cb50SMintz, Yuval  * COPYING in the main directory of this source tree, or the
8e8f1cb50SMintz, Yuval  * OpenIB.org BSD license below:
9e8f1cb50SMintz, Yuval  *
10e8f1cb50SMintz, Yuval  *     Redistribution and use in source and binary forms, with or
11e8f1cb50SMintz, Yuval  *     without modification, are permitted provided that the following
12e8f1cb50SMintz, Yuval  *     conditions are met:
13e8f1cb50SMintz, Yuval  *
14e8f1cb50SMintz, Yuval  *      - Redistributions of source code must retain the above
15e8f1cb50SMintz, Yuval  *        copyright notice, this list of conditions and the following
16e8f1cb50SMintz, Yuval  *        disclaimer.
17e8f1cb50SMintz, Yuval  *
18e8f1cb50SMintz, Yuval  *      - Redistributions in binary form must reproduce the above
19e8f1cb50SMintz, Yuval  *        copyright notice, this list of conditions and the following
20e8f1cb50SMintz, Yuval  *        disclaimer in the documentation and /or other materials
21e8f1cb50SMintz, Yuval  *        provided with the distribution.
22e8f1cb50SMintz, Yuval  *
23e8f1cb50SMintz, Yuval  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24e8f1cb50SMintz, Yuval  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25e8f1cb50SMintz, Yuval  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26e8f1cb50SMintz, Yuval  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27e8f1cb50SMintz, Yuval  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28e8f1cb50SMintz, Yuval  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29e8f1cb50SMintz, Yuval  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30e8f1cb50SMintz, Yuval  * SOFTWARE.
31fe56b9e6SYuval Mintz  */
32fe56b9e6SYuval Mintz 
33fe56b9e6SYuval Mintz #include <linux/types.h>
34fe56b9e6SYuval Mintz #include <asm/byteorder.h>
35fe56b9e6SYuval Mintz #include <linux/io.h>
36fe56b9e6SYuval Mintz #include <linux/delay.h>
37fe56b9e6SYuval Mintz #include <linux/dma-mapping.h>
38fe56b9e6SYuval Mintz #include <linux/errno.h>
39fe56b9e6SYuval Mintz #include <linux/kernel.h>
40fe56b9e6SYuval Mintz #include <linux/mutex.h>
41fe56b9e6SYuval Mintz #include <linux/pci.h>
42fe56b9e6SYuval Mintz #include <linux/slab.h>
43fe56b9e6SYuval Mintz #include <linux/string.h>
44a91eb52aSYuval Mintz #include <linux/vmalloc.h>
45fe56b9e6SYuval Mintz #include <linux/etherdevice.h>
46fe56b9e6SYuval Mintz #include <linux/qed/qed_chain.h>
47fe56b9e6SYuval Mintz #include <linux/qed/qed_if.h>
48fe56b9e6SYuval Mintz #include "qed.h"
49fe56b9e6SYuval Mintz #include "qed_cxt.h"
5039651abdSSudarsana Reddy Kalluru #include "qed_dcbx.h"
51fe56b9e6SYuval Mintz #include "qed_dev_api.h"
521e128c81SArun Easi #include "qed_fcoe.h"
53fe56b9e6SYuval Mintz #include "qed_hsi.h"
54fe56b9e6SYuval Mintz #include "qed_hw.h"
55fe56b9e6SYuval Mintz #include "qed_init_ops.h"
56fe56b9e6SYuval Mintz #include "qed_int.h"
57fc831825SYuval Mintz #include "qed_iscsi.h"
580a7fb11cSYuval Mintz #include "qed_ll2.h"
59fe56b9e6SYuval Mintz #include "qed_mcp.h"
601d6cff4fSYuval Mintz #include "qed_ooo.h"
61fe56b9e6SYuval Mintz #include "qed_reg_addr.h"
62fe56b9e6SYuval Mintz #include "qed_sp.h"
6332a47e72SYuval Mintz #include "qed_sriov.h"
640b55e27dSYuval Mintz #include "qed_vf.h"
65b71b9afdSKalderon, Michal #include "qed_rdma.h"
66fe56b9e6SYuval Mintz 
670caf5b26SWei Yongjun static DEFINE_SPINLOCK(qm_lock);
6839651abdSSudarsana Reddy Kalluru 
6936907cd5SAriel Elior /******************** Doorbell Recovery *******************/
7036907cd5SAriel Elior /* The doorbell recovery mechanism consists of a list of entries which represent
7136907cd5SAriel Elior  * doorbelling entities (l2 queues, roce sq/rq/cqs, the slowpath spq, etc). Each
7236907cd5SAriel Elior  * entity needs to register with the mechanism and provide the parameters
7336907cd5SAriel Elior  * describing it's doorbell, including a location where last used doorbell data
7436907cd5SAriel Elior  * can be found. The doorbell execute function will traverse the list and
7536907cd5SAriel Elior  * doorbell all of the registered entries.
7636907cd5SAriel Elior  */
7736907cd5SAriel Elior struct qed_db_recovery_entry {
7836907cd5SAriel Elior 	struct list_head list_entry;
7936907cd5SAriel Elior 	void __iomem *db_addr;
8036907cd5SAriel Elior 	void *db_data;
8136907cd5SAriel Elior 	enum qed_db_rec_width db_width;
8236907cd5SAriel Elior 	enum qed_db_rec_space db_space;
8336907cd5SAriel Elior 	u8 hwfn_idx;
8436907cd5SAriel Elior };
8536907cd5SAriel Elior 
8636907cd5SAriel Elior /* Display a single doorbell recovery entry */
8736907cd5SAriel Elior static void qed_db_recovery_dp_entry(struct qed_hwfn *p_hwfn,
8836907cd5SAriel Elior 				     struct qed_db_recovery_entry *db_entry,
8936907cd5SAriel Elior 				     char *action)
9036907cd5SAriel Elior {
9136907cd5SAriel Elior 	DP_VERBOSE(p_hwfn,
9236907cd5SAriel Elior 		   QED_MSG_SPQ,
9336907cd5SAriel Elior 		   "(%s: db_entry %p, addr %p, data %p, width %s, %s space, hwfn %d)\n",
9436907cd5SAriel Elior 		   action,
9536907cd5SAriel Elior 		   db_entry,
9636907cd5SAriel Elior 		   db_entry->db_addr,
9736907cd5SAriel Elior 		   db_entry->db_data,
9836907cd5SAriel Elior 		   db_entry->db_width == DB_REC_WIDTH_32B ? "32b" : "64b",
9936907cd5SAriel Elior 		   db_entry->db_space == DB_REC_USER ? "user" : "kernel",
10036907cd5SAriel Elior 		   db_entry->hwfn_idx);
10136907cd5SAriel Elior }
10236907cd5SAriel Elior 
10336907cd5SAriel Elior /* Doorbell address sanity (address within doorbell bar range) */
10436907cd5SAriel Elior static bool qed_db_rec_sanity(struct qed_dev *cdev,
105b61b04adSDenis Bolotin 			      void __iomem *db_addr,
106b61b04adSDenis Bolotin 			      enum qed_db_rec_width db_width,
107b61b04adSDenis Bolotin 			      void *db_data)
10836907cd5SAriel Elior {
109b61b04adSDenis Bolotin 	u32 width = (db_width == DB_REC_WIDTH_32B) ? 32 : 64;
110b61b04adSDenis Bolotin 
11136907cd5SAriel Elior 	/* Make sure doorbell address is within the doorbell bar */
11236907cd5SAriel Elior 	if (db_addr < cdev->doorbells ||
113b61b04adSDenis Bolotin 	    (u8 __iomem *)db_addr + width >
11436907cd5SAriel Elior 	    (u8 __iomem *)cdev->doorbells + cdev->db_size) {
11536907cd5SAriel Elior 		WARN(true,
11636907cd5SAriel Elior 		     "Illegal doorbell address: %p. Legal range for doorbell addresses is [%p..%p]\n",
11736907cd5SAriel Elior 		     db_addr,
11836907cd5SAriel Elior 		     cdev->doorbells,
11936907cd5SAriel Elior 		     (u8 __iomem *)cdev->doorbells + cdev->db_size);
12036907cd5SAriel Elior 		return false;
12136907cd5SAriel Elior 	}
12236907cd5SAriel Elior 
12336907cd5SAriel Elior 	/* ake sure doorbell data pointer is not null */
12436907cd5SAriel Elior 	if (!db_data) {
12536907cd5SAriel Elior 		WARN(true, "Illegal doorbell data pointer: %p", db_data);
12636907cd5SAriel Elior 		return false;
12736907cd5SAriel Elior 	}
12836907cd5SAriel Elior 
12936907cd5SAriel Elior 	return true;
13036907cd5SAriel Elior }
13136907cd5SAriel Elior 
13236907cd5SAriel Elior /* Find hwfn according to the doorbell address */
13336907cd5SAriel Elior static struct qed_hwfn *qed_db_rec_find_hwfn(struct qed_dev *cdev,
13436907cd5SAriel Elior 					     void __iomem *db_addr)
13536907cd5SAriel Elior {
13636907cd5SAriel Elior 	struct qed_hwfn *p_hwfn;
13736907cd5SAriel Elior 
13836907cd5SAriel Elior 	/* In CMT doorbell bar is split down the middle between engine 0 and enigne 1 */
13936907cd5SAriel Elior 	if (cdev->num_hwfns > 1)
14036907cd5SAriel Elior 		p_hwfn = db_addr < cdev->hwfns[1].doorbells ?
14136907cd5SAriel Elior 		    &cdev->hwfns[0] : &cdev->hwfns[1];
14236907cd5SAriel Elior 	else
14336907cd5SAriel Elior 		p_hwfn = QED_LEADING_HWFN(cdev);
14436907cd5SAriel Elior 
14536907cd5SAriel Elior 	return p_hwfn;
14636907cd5SAriel Elior }
14736907cd5SAriel Elior 
14836907cd5SAriel Elior /* Add a new entry to the doorbell recovery mechanism */
14936907cd5SAriel Elior int qed_db_recovery_add(struct qed_dev *cdev,
15036907cd5SAriel Elior 			void __iomem *db_addr,
15136907cd5SAriel Elior 			void *db_data,
15236907cd5SAriel Elior 			enum qed_db_rec_width db_width,
15336907cd5SAriel Elior 			enum qed_db_rec_space db_space)
15436907cd5SAriel Elior {
15536907cd5SAriel Elior 	struct qed_db_recovery_entry *db_entry;
15636907cd5SAriel Elior 	struct qed_hwfn *p_hwfn;
15736907cd5SAriel Elior 
15836907cd5SAriel Elior 	/* Shortcircuit VFs, for now */
15936907cd5SAriel Elior 	if (IS_VF(cdev)) {
16036907cd5SAriel Elior 		DP_VERBOSE(cdev,
16136907cd5SAriel Elior 			   QED_MSG_IOV, "db recovery - skipping VF doorbell\n");
16236907cd5SAriel Elior 		return 0;
16336907cd5SAriel Elior 	}
16436907cd5SAriel Elior 
16536907cd5SAriel Elior 	/* Sanitize doorbell address */
166b61b04adSDenis Bolotin 	if (!qed_db_rec_sanity(cdev, db_addr, db_width, db_data))
16736907cd5SAriel Elior 		return -EINVAL;
16836907cd5SAriel Elior 
16936907cd5SAriel Elior 	/* Obtain hwfn from doorbell address */
17036907cd5SAriel Elior 	p_hwfn = qed_db_rec_find_hwfn(cdev, db_addr);
17136907cd5SAriel Elior 
17236907cd5SAriel Elior 	/* Create entry */
17336907cd5SAriel Elior 	db_entry = kzalloc(sizeof(*db_entry), GFP_KERNEL);
17436907cd5SAriel Elior 	if (!db_entry) {
17536907cd5SAriel Elior 		DP_NOTICE(cdev, "Failed to allocate a db recovery entry\n");
17636907cd5SAriel Elior 		return -ENOMEM;
17736907cd5SAriel Elior 	}
17836907cd5SAriel Elior 
17936907cd5SAriel Elior 	/* Populate entry */
18036907cd5SAriel Elior 	db_entry->db_addr = db_addr;
18136907cd5SAriel Elior 	db_entry->db_data = db_data;
18236907cd5SAriel Elior 	db_entry->db_width = db_width;
18336907cd5SAriel Elior 	db_entry->db_space = db_space;
18436907cd5SAriel Elior 	db_entry->hwfn_idx = p_hwfn->my_id;
18536907cd5SAriel Elior 
18636907cd5SAriel Elior 	/* Display */
18736907cd5SAriel Elior 	qed_db_recovery_dp_entry(p_hwfn, db_entry, "Adding");
18836907cd5SAriel Elior 
18936907cd5SAriel Elior 	/* Protect the list */
19036907cd5SAriel Elior 	spin_lock_bh(&p_hwfn->db_recovery_info.lock);
19136907cd5SAriel Elior 	list_add_tail(&db_entry->list_entry, &p_hwfn->db_recovery_info.list);
19236907cd5SAriel Elior 	spin_unlock_bh(&p_hwfn->db_recovery_info.lock);
19336907cd5SAriel Elior 
19436907cd5SAriel Elior 	return 0;
19536907cd5SAriel Elior }
19636907cd5SAriel Elior 
19736907cd5SAriel Elior /* Remove an entry from the doorbell recovery mechanism */
19836907cd5SAriel Elior int qed_db_recovery_del(struct qed_dev *cdev,
19936907cd5SAriel Elior 			void __iomem *db_addr, void *db_data)
20036907cd5SAriel Elior {
20136907cd5SAriel Elior 	struct qed_db_recovery_entry *db_entry = NULL;
20236907cd5SAriel Elior 	struct qed_hwfn *p_hwfn;
20336907cd5SAriel Elior 	int rc = -EINVAL;
20436907cd5SAriel Elior 
20536907cd5SAriel Elior 	/* Shortcircuit VFs, for now */
20636907cd5SAriel Elior 	if (IS_VF(cdev)) {
20736907cd5SAriel Elior 		DP_VERBOSE(cdev,
20836907cd5SAriel Elior 			   QED_MSG_IOV, "db recovery - skipping VF doorbell\n");
20936907cd5SAriel Elior 		return 0;
21036907cd5SAriel Elior 	}
21136907cd5SAriel Elior 
21236907cd5SAriel Elior 	/* Obtain hwfn from doorbell address */
21336907cd5SAriel Elior 	p_hwfn = qed_db_rec_find_hwfn(cdev, db_addr);
21436907cd5SAriel Elior 
21536907cd5SAriel Elior 	/* Protect the list */
21636907cd5SAriel Elior 	spin_lock_bh(&p_hwfn->db_recovery_info.lock);
21736907cd5SAriel Elior 	list_for_each_entry(db_entry,
21836907cd5SAriel Elior 			    &p_hwfn->db_recovery_info.list, list_entry) {
21936907cd5SAriel Elior 		/* search according to db_data addr since db_addr is not unique (roce) */
22036907cd5SAriel Elior 		if (db_entry->db_data == db_data) {
22136907cd5SAriel Elior 			qed_db_recovery_dp_entry(p_hwfn, db_entry, "Deleting");
22236907cd5SAriel Elior 			list_del(&db_entry->list_entry);
22336907cd5SAriel Elior 			rc = 0;
22436907cd5SAriel Elior 			break;
22536907cd5SAriel Elior 		}
22636907cd5SAriel Elior 	}
22736907cd5SAriel Elior 
22836907cd5SAriel Elior 	spin_unlock_bh(&p_hwfn->db_recovery_info.lock);
22936907cd5SAriel Elior 
23036907cd5SAriel Elior 	if (rc == -EINVAL)
23136907cd5SAriel Elior 
23236907cd5SAriel Elior 		DP_NOTICE(p_hwfn,
23336907cd5SAriel Elior 			  "Failed to find element in list. Key (db_data addr) was %p. db_addr was %p\n",
23436907cd5SAriel Elior 			  db_data, db_addr);
23536907cd5SAriel Elior 	else
23636907cd5SAriel Elior 		kfree(db_entry);
23736907cd5SAriel Elior 
23836907cd5SAriel Elior 	return rc;
23936907cd5SAriel Elior }
24036907cd5SAriel Elior 
24136907cd5SAriel Elior /* Initialize the doorbell recovery mechanism */
24236907cd5SAriel Elior static int qed_db_recovery_setup(struct qed_hwfn *p_hwfn)
24336907cd5SAriel Elior {
24436907cd5SAriel Elior 	DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "Setting up db recovery\n");
24536907cd5SAriel Elior 
24636907cd5SAriel Elior 	/* Make sure db_size was set in cdev */
24736907cd5SAriel Elior 	if (!p_hwfn->cdev->db_size) {
24836907cd5SAriel Elior 		DP_ERR(p_hwfn->cdev, "db_size not set\n");
24936907cd5SAriel Elior 		return -EINVAL;
25036907cd5SAriel Elior 	}
25136907cd5SAriel Elior 
25236907cd5SAriel Elior 	INIT_LIST_HEAD(&p_hwfn->db_recovery_info.list);
25336907cd5SAriel Elior 	spin_lock_init(&p_hwfn->db_recovery_info.lock);
25436907cd5SAriel Elior 	p_hwfn->db_recovery_info.db_recovery_counter = 0;
25536907cd5SAriel Elior 
25636907cd5SAriel Elior 	return 0;
25736907cd5SAriel Elior }
25836907cd5SAriel Elior 
25936907cd5SAriel Elior /* Destroy the doorbell recovery mechanism */
26036907cd5SAriel Elior static void qed_db_recovery_teardown(struct qed_hwfn *p_hwfn)
26136907cd5SAriel Elior {
26236907cd5SAriel Elior 	struct qed_db_recovery_entry *db_entry = NULL;
26336907cd5SAriel Elior 
26436907cd5SAriel Elior 	DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "Tearing down db recovery\n");
26536907cd5SAriel Elior 	if (!list_empty(&p_hwfn->db_recovery_info.list)) {
26636907cd5SAriel Elior 		DP_VERBOSE(p_hwfn,
26736907cd5SAriel Elior 			   QED_MSG_SPQ,
26836907cd5SAriel Elior 			   "Doorbell Recovery teardown found the doorbell recovery list was not empty (Expected in disorderly driver unload (e.g. recovery) otherwise this probably means some flow forgot to db_recovery_del). Prepare to purge doorbell recovery list...\n");
26936907cd5SAriel Elior 		while (!list_empty(&p_hwfn->db_recovery_info.list)) {
27036907cd5SAriel Elior 			db_entry =
27136907cd5SAriel Elior 			    list_first_entry(&p_hwfn->db_recovery_info.list,
27236907cd5SAriel Elior 					     struct qed_db_recovery_entry,
27336907cd5SAriel Elior 					     list_entry);
27436907cd5SAriel Elior 			qed_db_recovery_dp_entry(p_hwfn, db_entry, "Purging");
27536907cd5SAriel Elior 			list_del(&db_entry->list_entry);
27636907cd5SAriel Elior 			kfree(db_entry);
27736907cd5SAriel Elior 		}
27836907cd5SAriel Elior 	}
27936907cd5SAriel Elior 	p_hwfn->db_recovery_info.db_recovery_counter = 0;
28036907cd5SAriel Elior }
28136907cd5SAriel Elior 
28236907cd5SAriel Elior /* Print the content of the doorbell recovery mechanism */
28336907cd5SAriel Elior void qed_db_recovery_dp(struct qed_hwfn *p_hwfn)
28436907cd5SAriel Elior {
28536907cd5SAriel Elior 	struct qed_db_recovery_entry *db_entry = NULL;
28636907cd5SAriel Elior 
28736907cd5SAriel Elior 	DP_NOTICE(p_hwfn,
288d1ecf8a6SColin Ian King 		  "Displaying doorbell recovery database. Counter was %d\n",
28936907cd5SAriel Elior 		  p_hwfn->db_recovery_info.db_recovery_counter);
29036907cd5SAriel Elior 
29136907cd5SAriel Elior 	/* Protect the list */
29236907cd5SAriel Elior 	spin_lock_bh(&p_hwfn->db_recovery_info.lock);
29336907cd5SAriel Elior 	list_for_each_entry(db_entry,
29436907cd5SAriel Elior 			    &p_hwfn->db_recovery_info.list, list_entry) {
29536907cd5SAriel Elior 		qed_db_recovery_dp_entry(p_hwfn, db_entry, "Printing");
29636907cd5SAriel Elior 	}
29736907cd5SAriel Elior 
29836907cd5SAriel Elior 	spin_unlock_bh(&p_hwfn->db_recovery_info.lock);
29936907cd5SAriel Elior }
30036907cd5SAriel Elior 
30136907cd5SAriel Elior /* Ring the doorbell of a single doorbell recovery entry */
30236907cd5SAriel Elior static void qed_db_recovery_ring(struct qed_hwfn *p_hwfn,
3039ac6bb14SDenis Bolotin 				 struct qed_db_recovery_entry *db_entry)
30436907cd5SAriel Elior {
30536907cd5SAriel Elior 	/* Print according to width */
30636907cd5SAriel Elior 	if (db_entry->db_width == DB_REC_WIDTH_32B) {
30736907cd5SAriel Elior 		DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
3089ac6bb14SDenis Bolotin 			   "ringing doorbell address %p data %x\n",
30936907cd5SAriel Elior 			   db_entry->db_addr,
31036907cd5SAriel Elior 			   *(u32 *)db_entry->db_data);
31136907cd5SAriel Elior 	} else {
31236907cd5SAriel Elior 		DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
3139ac6bb14SDenis Bolotin 			   "ringing doorbell address %p data %llx\n",
31436907cd5SAriel Elior 			   db_entry->db_addr,
31536907cd5SAriel Elior 			   *(u64 *)(db_entry->db_data));
31636907cd5SAriel Elior 	}
31736907cd5SAriel Elior 
31836907cd5SAriel Elior 	/* Sanity */
31936907cd5SAriel Elior 	if (!qed_db_rec_sanity(p_hwfn->cdev, db_entry->db_addr,
320b61b04adSDenis Bolotin 			       db_entry->db_width, db_entry->db_data))
32136907cd5SAriel Elior 		return;
32236907cd5SAriel Elior 
32336907cd5SAriel Elior 	/* Flush the write combined buffer. Since there are multiple doorbelling
32436907cd5SAriel Elior 	 * entities using the same address, if we don't flush, a transaction
32536907cd5SAriel Elior 	 * could be lost.
32636907cd5SAriel Elior 	 */
32736907cd5SAriel Elior 	wmb();
32836907cd5SAriel Elior 
32936907cd5SAriel Elior 	/* Ring the doorbell */
33036907cd5SAriel Elior 	if (db_entry->db_width == DB_REC_WIDTH_32B)
33136907cd5SAriel Elior 		DIRECT_REG_WR(db_entry->db_addr,
33236907cd5SAriel Elior 			      *(u32 *)(db_entry->db_data));
33336907cd5SAriel Elior 	else
33436907cd5SAriel Elior 		DIRECT_REG_WR64(db_entry->db_addr,
33536907cd5SAriel Elior 				*(u64 *)(db_entry->db_data));
33636907cd5SAriel Elior 
33736907cd5SAriel Elior 	/* Flush the write combined buffer. Next doorbell may come from a
33836907cd5SAriel Elior 	 * different entity to the same address...
33936907cd5SAriel Elior 	 */
34036907cd5SAriel Elior 	wmb();
34136907cd5SAriel Elior }
34236907cd5SAriel Elior 
34336907cd5SAriel Elior /* Traverse the doorbell recovery entry list and ring all the doorbells */
3449ac6bb14SDenis Bolotin void qed_db_recovery_execute(struct qed_hwfn *p_hwfn)
34536907cd5SAriel Elior {
34636907cd5SAriel Elior 	struct qed_db_recovery_entry *db_entry = NULL;
34736907cd5SAriel Elior 
3489ac6bb14SDenis Bolotin 	DP_NOTICE(p_hwfn, "Executing doorbell recovery. Counter was %d\n",
34936907cd5SAriel Elior 		  p_hwfn->db_recovery_info.db_recovery_counter);
35036907cd5SAriel Elior 
35136907cd5SAriel Elior 	/* Track amount of times recovery was executed */
35236907cd5SAriel Elior 	p_hwfn->db_recovery_info.db_recovery_counter++;
35336907cd5SAriel Elior 
35436907cd5SAriel Elior 	/* Protect the list */
35536907cd5SAriel Elior 	spin_lock_bh(&p_hwfn->db_recovery_info.lock);
35636907cd5SAriel Elior 	list_for_each_entry(db_entry,
3579ac6bb14SDenis Bolotin 			    &p_hwfn->db_recovery_info.list, list_entry)
3589ac6bb14SDenis Bolotin 		qed_db_recovery_ring(p_hwfn, db_entry);
35936907cd5SAriel Elior 	spin_unlock_bh(&p_hwfn->db_recovery_info.lock);
36036907cd5SAriel Elior }
36136907cd5SAriel Elior 
36236907cd5SAriel Elior /******************** Doorbell Recovery end ****************/
36336907cd5SAriel Elior 
36479284adeSMichal Kalderon /********************************** NIG LLH ***********************************/
36579284adeSMichal Kalderon 
36679284adeSMichal Kalderon enum qed_llh_filter_type {
36779284adeSMichal Kalderon 	QED_LLH_FILTER_TYPE_MAC,
36879284adeSMichal Kalderon 	QED_LLH_FILTER_TYPE_PROTOCOL,
36979284adeSMichal Kalderon };
37079284adeSMichal Kalderon 
37179284adeSMichal Kalderon struct qed_llh_mac_filter {
37279284adeSMichal Kalderon 	u8 addr[ETH_ALEN];
37379284adeSMichal Kalderon };
37479284adeSMichal Kalderon 
37579284adeSMichal Kalderon struct qed_llh_protocol_filter {
37679284adeSMichal Kalderon 	enum qed_llh_prot_filter_type_t type;
37779284adeSMichal Kalderon 	u16 source_port_or_eth_type;
37879284adeSMichal Kalderon 	u16 dest_port;
37979284adeSMichal Kalderon };
38079284adeSMichal Kalderon 
38179284adeSMichal Kalderon union qed_llh_filter {
38279284adeSMichal Kalderon 	struct qed_llh_mac_filter mac;
38379284adeSMichal Kalderon 	struct qed_llh_protocol_filter protocol;
38479284adeSMichal Kalderon };
38579284adeSMichal Kalderon 
38679284adeSMichal Kalderon struct qed_llh_filter_info {
38779284adeSMichal Kalderon 	bool b_enabled;
38879284adeSMichal Kalderon 	u32 ref_cnt;
38979284adeSMichal Kalderon 	enum qed_llh_filter_type type;
39079284adeSMichal Kalderon 	union qed_llh_filter filter;
39179284adeSMichal Kalderon };
39279284adeSMichal Kalderon 
39379284adeSMichal Kalderon struct qed_llh_info {
39479284adeSMichal Kalderon 	/* Number of LLH filters banks */
39579284adeSMichal Kalderon 	u8 num_ppfid;
39679284adeSMichal Kalderon 
39779284adeSMichal Kalderon #define MAX_NUM_PPFID   8
39879284adeSMichal Kalderon 	u8 ppfid_array[MAX_NUM_PPFID];
39979284adeSMichal Kalderon 
40079284adeSMichal Kalderon 	/* Array of filters arrays:
40179284adeSMichal Kalderon 	 * "num_ppfid" elements of filters banks, where each is an array of
40279284adeSMichal Kalderon 	 * "NIG_REG_LLH_FUNC_FILTER_EN_SIZE" filters.
40379284adeSMichal Kalderon 	 */
40479284adeSMichal Kalderon 	struct qed_llh_filter_info **pp_filters;
40579284adeSMichal Kalderon };
40679284adeSMichal Kalderon 
40779284adeSMichal Kalderon static void qed_llh_free(struct qed_dev *cdev)
40879284adeSMichal Kalderon {
40979284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
41079284adeSMichal Kalderon 	u32 i;
41179284adeSMichal Kalderon 
41279284adeSMichal Kalderon 	if (p_llh_info) {
41379284adeSMichal Kalderon 		if (p_llh_info->pp_filters)
41479284adeSMichal Kalderon 			for (i = 0; i < p_llh_info->num_ppfid; i++)
41579284adeSMichal Kalderon 				kfree(p_llh_info->pp_filters[i]);
41679284adeSMichal Kalderon 
41779284adeSMichal Kalderon 		kfree(p_llh_info->pp_filters);
41879284adeSMichal Kalderon 	}
41979284adeSMichal Kalderon 
42079284adeSMichal Kalderon 	kfree(p_llh_info);
42179284adeSMichal Kalderon 	cdev->p_llh_info = NULL;
42279284adeSMichal Kalderon }
42379284adeSMichal Kalderon 
42479284adeSMichal Kalderon static int qed_llh_alloc(struct qed_dev *cdev)
42579284adeSMichal Kalderon {
42679284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info;
42779284adeSMichal Kalderon 	u32 size, i;
42879284adeSMichal Kalderon 
42979284adeSMichal Kalderon 	p_llh_info = kzalloc(sizeof(*p_llh_info), GFP_KERNEL);
43079284adeSMichal Kalderon 	if (!p_llh_info)
43179284adeSMichal Kalderon 		return -ENOMEM;
43279284adeSMichal Kalderon 	cdev->p_llh_info = p_llh_info;
43379284adeSMichal Kalderon 
43479284adeSMichal Kalderon 	for (i = 0; i < MAX_NUM_PPFID; i++) {
43579284adeSMichal Kalderon 		if (!(cdev->ppfid_bitmap & (0x1 << i)))
43679284adeSMichal Kalderon 			continue;
43779284adeSMichal Kalderon 
43879284adeSMichal Kalderon 		p_llh_info->ppfid_array[p_llh_info->num_ppfid] = i;
43979284adeSMichal Kalderon 		DP_VERBOSE(cdev, QED_MSG_SP, "ppfid_array[%d] = %hhd\n",
44079284adeSMichal Kalderon 			   p_llh_info->num_ppfid, i);
44179284adeSMichal Kalderon 		p_llh_info->num_ppfid++;
44279284adeSMichal Kalderon 	}
44379284adeSMichal Kalderon 
44479284adeSMichal Kalderon 	size = p_llh_info->num_ppfid * sizeof(*p_llh_info->pp_filters);
44579284adeSMichal Kalderon 	p_llh_info->pp_filters = kzalloc(size, GFP_KERNEL);
44679284adeSMichal Kalderon 	if (!p_llh_info->pp_filters)
44779284adeSMichal Kalderon 		return -ENOMEM;
44879284adeSMichal Kalderon 
44979284adeSMichal Kalderon 	size = NIG_REG_LLH_FUNC_FILTER_EN_SIZE *
45079284adeSMichal Kalderon 	    sizeof(**p_llh_info->pp_filters);
45179284adeSMichal Kalderon 	for (i = 0; i < p_llh_info->num_ppfid; i++) {
45279284adeSMichal Kalderon 		p_llh_info->pp_filters[i] = kzalloc(size, GFP_KERNEL);
45379284adeSMichal Kalderon 		if (!p_llh_info->pp_filters[i])
45479284adeSMichal Kalderon 			return -ENOMEM;
45579284adeSMichal Kalderon 	}
45679284adeSMichal Kalderon 
45779284adeSMichal Kalderon 	return 0;
45879284adeSMichal Kalderon }
45979284adeSMichal Kalderon 
46079284adeSMichal Kalderon static int qed_llh_shadow_sanity(struct qed_dev *cdev,
46179284adeSMichal Kalderon 				 u8 ppfid, u8 filter_idx, const char *action)
46279284adeSMichal Kalderon {
46379284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
46479284adeSMichal Kalderon 
46579284adeSMichal Kalderon 	if (ppfid >= p_llh_info->num_ppfid) {
46679284adeSMichal Kalderon 		DP_NOTICE(cdev,
46779284adeSMichal Kalderon 			  "LLH shadow [%s]: using ppfid %d while only %d ppfids are available\n",
46879284adeSMichal Kalderon 			  action, ppfid, p_llh_info->num_ppfid);
46979284adeSMichal Kalderon 		return -EINVAL;
47079284adeSMichal Kalderon 	}
47179284adeSMichal Kalderon 
47279284adeSMichal Kalderon 	if (filter_idx >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
47379284adeSMichal Kalderon 		DP_NOTICE(cdev,
47479284adeSMichal Kalderon 			  "LLH shadow [%s]: using filter_idx %d while only %d filters are available\n",
47579284adeSMichal Kalderon 			  action, filter_idx, NIG_REG_LLH_FUNC_FILTER_EN_SIZE);
47679284adeSMichal Kalderon 		return -EINVAL;
47779284adeSMichal Kalderon 	}
47879284adeSMichal Kalderon 
47979284adeSMichal Kalderon 	return 0;
48079284adeSMichal Kalderon }
48179284adeSMichal Kalderon 
48279284adeSMichal Kalderon #define QED_LLH_INVALID_FILTER_IDX      0xff
48379284adeSMichal Kalderon 
48479284adeSMichal Kalderon static int
48579284adeSMichal Kalderon qed_llh_shadow_search_filter(struct qed_dev *cdev,
48679284adeSMichal Kalderon 			     u8 ppfid,
48779284adeSMichal Kalderon 			     union qed_llh_filter *p_filter, u8 *p_filter_idx)
48879284adeSMichal Kalderon {
48979284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
49079284adeSMichal Kalderon 	struct qed_llh_filter_info *p_filters;
49179284adeSMichal Kalderon 	int rc;
49279284adeSMichal Kalderon 	u8 i;
49379284adeSMichal Kalderon 
49479284adeSMichal Kalderon 	rc = qed_llh_shadow_sanity(cdev, ppfid, 0, "search");
49579284adeSMichal Kalderon 	if (rc)
49679284adeSMichal Kalderon 		return rc;
49779284adeSMichal Kalderon 
49879284adeSMichal Kalderon 	*p_filter_idx = QED_LLH_INVALID_FILTER_IDX;
49979284adeSMichal Kalderon 
50079284adeSMichal Kalderon 	p_filters = p_llh_info->pp_filters[ppfid];
50179284adeSMichal Kalderon 	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
50279284adeSMichal Kalderon 		if (!memcmp(p_filter, &p_filters[i].filter,
50379284adeSMichal Kalderon 			    sizeof(*p_filter))) {
50479284adeSMichal Kalderon 			*p_filter_idx = i;
50579284adeSMichal Kalderon 			break;
50679284adeSMichal Kalderon 		}
50779284adeSMichal Kalderon 	}
50879284adeSMichal Kalderon 
50979284adeSMichal Kalderon 	return 0;
51079284adeSMichal Kalderon }
51179284adeSMichal Kalderon 
51279284adeSMichal Kalderon static int
51379284adeSMichal Kalderon qed_llh_shadow_get_free_idx(struct qed_dev *cdev, u8 ppfid, u8 *p_filter_idx)
51479284adeSMichal Kalderon {
51579284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
51679284adeSMichal Kalderon 	struct qed_llh_filter_info *p_filters;
51779284adeSMichal Kalderon 	int rc;
51879284adeSMichal Kalderon 	u8 i;
51979284adeSMichal Kalderon 
52079284adeSMichal Kalderon 	rc = qed_llh_shadow_sanity(cdev, ppfid, 0, "get_free_idx");
52179284adeSMichal Kalderon 	if (rc)
52279284adeSMichal Kalderon 		return rc;
52379284adeSMichal Kalderon 
52479284adeSMichal Kalderon 	*p_filter_idx = QED_LLH_INVALID_FILTER_IDX;
52579284adeSMichal Kalderon 
52679284adeSMichal Kalderon 	p_filters = p_llh_info->pp_filters[ppfid];
52779284adeSMichal Kalderon 	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
52879284adeSMichal Kalderon 		if (!p_filters[i].b_enabled) {
52979284adeSMichal Kalderon 			*p_filter_idx = i;
53079284adeSMichal Kalderon 			break;
53179284adeSMichal Kalderon 		}
53279284adeSMichal Kalderon 	}
53379284adeSMichal Kalderon 
53479284adeSMichal Kalderon 	return 0;
53579284adeSMichal Kalderon }
53679284adeSMichal Kalderon 
53779284adeSMichal Kalderon static int
53879284adeSMichal Kalderon __qed_llh_shadow_add_filter(struct qed_dev *cdev,
53979284adeSMichal Kalderon 			    u8 ppfid,
54079284adeSMichal Kalderon 			    u8 filter_idx,
54179284adeSMichal Kalderon 			    enum qed_llh_filter_type type,
54279284adeSMichal Kalderon 			    union qed_llh_filter *p_filter, u32 *p_ref_cnt)
54379284adeSMichal Kalderon {
54479284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
54579284adeSMichal Kalderon 	struct qed_llh_filter_info *p_filters;
54679284adeSMichal Kalderon 	int rc;
54779284adeSMichal Kalderon 
54879284adeSMichal Kalderon 	rc = qed_llh_shadow_sanity(cdev, ppfid, filter_idx, "add");
54979284adeSMichal Kalderon 	if (rc)
55079284adeSMichal Kalderon 		return rc;
55179284adeSMichal Kalderon 
55279284adeSMichal Kalderon 	p_filters = p_llh_info->pp_filters[ppfid];
55379284adeSMichal Kalderon 	if (!p_filters[filter_idx].ref_cnt) {
55479284adeSMichal Kalderon 		p_filters[filter_idx].b_enabled = true;
55579284adeSMichal Kalderon 		p_filters[filter_idx].type = type;
55679284adeSMichal Kalderon 		memcpy(&p_filters[filter_idx].filter, p_filter,
55779284adeSMichal Kalderon 		       sizeof(p_filters[filter_idx].filter));
55879284adeSMichal Kalderon 	}
55979284adeSMichal Kalderon 
56079284adeSMichal Kalderon 	*p_ref_cnt = ++p_filters[filter_idx].ref_cnt;
56179284adeSMichal Kalderon 
56279284adeSMichal Kalderon 	return 0;
56379284adeSMichal Kalderon }
56479284adeSMichal Kalderon 
56579284adeSMichal Kalderon static int
56679284adeSMichal Kalderon qed_llh_shadow_add_filter(struct qed_dev *cdev,
56779284adeSMichal Kalderon 			  u8 ppfid,
56879284adeSMichal Kalderon 			  enum qed_llh_filter_type type,
56979284adeSMichal Kalderon 			  union qed_llh_filter *p_filter,
57079284adeSMichal Kalderon 			  u8 *p_filter_idx, u32 *p_ref_cnt)
57179284adeSMichal Kalderon {
57279284adeSMichal Kalderon 	int rc;
57379284adeSMichal Kalderon 
57479284adeSMichal Kalderon 	/* Check if the same filter already exist */
57579284adeSMichal Kalderon 	rc = qed_llh_shadow_search_filter(cdev, ppfid, p_filter, p_filter_idx);
57679284adeSMichal Kalderon 	if (rc)
57779284adeSMichal Kalderon 		return rc;
57879284adeSMichal Kalderon 
57979284adeSMichal Kalderon 	/* Find a new entry in case of a new filter */
58079284adeSMichal Kalderon 	if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) {
58179284adeSMichal Kalderon 		rc = qed_llh_shadow_get_free_idx(cdev, ppfid, p_filter_idx);
58279284adeSMichal Kalderon 		if (rc)
58379284adeSMichal Kalderon 			return rc;
58479284adeSMichal Kalderon 	}
58579284adeSMichal Kalderon 
58679284adeSMichal Kalderon 	/* No free entry was found */
58779284adeSMichal Kalderon 	if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) {
58879284adeSMichal Kalderon 		DP_NOTICE(cdev,
58979284adeSMichal Kalderon 			  "Failed to find an empty LLH filter to utilize [ppfid %d]\n",
59079284adeSMichal Kalderon 			  ppfid);
59179284adeSMichal Kalderon 		return -EINVAL;
59279284adeSMichal Kalderon 	}
59379284adeSMichal Kalderon 
59479284adeSMichal Kalderon 	return __qed_llh_shadow_add_filter(cdev, ppfid, *p_filter_idx, type,
59579284adeSMichal Kalderon 					   p_filter, p_ref_cnt);
59679284adeSMichal Kalderon }
59779284adeSMichal Kalderon 
59879284adeSMichal Kalderon static int
59979284adeSMichal Kalderon __qed_llh_shadow_remove_filter(struct qed_dev *cdev,
60079284adeSMichal Kalderon 			       u8 ppfid, u8 filter_idx, u32 *p_ref_cnt)
60179284adeSMichal Kalderon {
60279284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
60379284adeSMichal Kalderon 	struct qed_llh_filter_info *p_filters;
60479284adeSMichal Kalderon 	int rc;
60579284adeSMichal Kalderon 
60679284adeSMichal Kalderon 	rc = qed_llh_shadow_sanity(cdev, ppfid, filter_idx, "remove");
60779284adeSMichal Kalderon 	if (rc)
60879284adeSMichal Kalderon 		return rc;
60979284adeSMichal Kalderon 
61079284adeSMichal Kalderon 	p_filters = p_llh_info->pp_filters[ppfid];
61179284adeSMichal Kalderon 	if (!p_filters[filter_idx].ref_cnt) {
61279284adeSMichal Kalderon 		DP_NOTICE(cdev,
61379284adeSMichal Kalderon 			  "LLH shadow: trying to remove a filter with ref_cnt=0\n");
61479284adeSMichal Kalderon 		return -EINVAL;
61579284adeSMichal Kalderon 	}
61679284adeSMichal Kalderon 
61779284adeSMichal Kalderon 	*p_ref_cnt = --p_filters[filter_idx].ref_cnt;
61879284adeSMichal Kalderon 	if (!p_filters[filter_idx].ref_cnt)
61979284adeSMichal Kalderon 		memset(&p_filters[filter_idx],
62079284adeSMichal Kalderon 		       0, sizeof(p_filters[filter_idx]));
62179284adeSMichal Kalderon 
62279284adeSMichal Kalderon 	return 0;
62379284adeSMichal Kalderon }
62479284adeSMichal Kalderon 
62579284adeSMichal Kalderon static int
62679284adeSMichal Kalderon qed_llh_shadow_remove_filter(struct qed_dev *cdev,
62779284adeSMichal Kalderon 			     u8 ppfid,
62879284adeSMichal Kalderon 			     union qed_llh_filter *p_filter,
62979284adeSMichal Kalderon 			     u8 *p_filter_idx, u32 *p_ref_cnt)
63079284adeSMichal Kalderon {
63179284adeSMichal Kalderon 	int rc;
63279284adeSMichal Kalderon 
63379284adeSMichal Kalderon 	rc = qed_llh_shadow_search_filter(cdev, ppfid, p_filter, p_filter_idx);
63479284adeSMichal Kalderon 	if (rc)
63579284adeSMichal Kalderon 		return rc;
63679284adeSMichal Kalderon 
63779284adeSMichal Kalderon 	/* No matching filter was found */
63879284adeSMichal Kalderon 	if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) {
63979284adeSMichal Kalderon 		DP_NOTICE(cdev, "Failed to find a filter in the LLH shadow\n");
64079284adeSMichal Kalderon 		return -EINVAL;
64179284adeSMichal Kalderon 	}
64279284adeSMichal Kalderon 
64379284adeSMichal Kalderon 	return __qed_llh_shadow_remove_filter(cdev, ppfid, *p_filter_idx,
64479284adeSMichal Kalderon 					      p_ref_cnt);
64579284adeSMichal Kalderon }
64679284adeSMichal Kalderon 
64779284adeSMichal Kalderon static int qed_llh_abs_ppfid(struct qed_dev *cdev, u8 ppfid, u8 *p_abs_ppfid)
64879284adeSMichal Kalderon {
64979284adeSMichal Kalderon 	struct qed_llh_info *p_llh_info = cdev->p_llh_info;
65079284adeSMichal Kalderon 
65179284adeSMichal Kalderon 	if (ppfid >= p_llh_info->num_ppfid) {
65279284adeSMichal Kalderon 		DP_NOTICE(cdev,
65379284adeSMichal Kalderon 			  "ppfid %d is not valid, available indices are 0..%hhd\n",
65479284adeSMichal Kalderon 			  ppfid, p_llh_info->num_ppfid - 1);
65579284adeSMichal Kalderon 		return -EINVAL;
65679284adeSMichal Kalderon 	}
65779284adeSMichal Kalderon 
65879284adeSMichal Kalderon 	*p_abs_ppfid = p_llh_info->ppfid_array[ppfid];
65979284adeSMichal Kalderon 
66079284adeSMichal Kalderon 	return 0;
66179284adeSMichal Kalderon }
66279284adeSMichal Kalderon 
66379284adeSMichal Kalderon static int
66479284adeSMichal Kalderon qed_llh_set_engine_affin(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
66579284adeSMichal Kalderon {
66679284adeSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
66779284adeSMichal Kalderon 	enum qed_eng eng;
66879284adeSMichal Kalderon 	u8 ppfid;
66979284adeSMichal Kalderon 	int rc;
67079284adeSMichal Kalderon 
67179284adeSMichal Kalderon 	rc = qed_mcp_get_engine_config(p_hwfn, p_ptt);
67279284adeSMichal Kalderon 	if (rc != 0 && rc != -EOPNOTSUPP) {
67379284adeSMichal Kalderon 		DP_NOTICE(p_hwfn,
67479284adeSMichal Kalderon 			  "Failed to get the engine affinity configuration\n");
67579284adeSMichal Kalderon 		return rc;
67679284adeSMichal Kalderon 	}
67779284adeSMichal Kalderon 
67879284adeSMichal Kalderon 	/* RoCE PF is bound to a single engine */
67979284adeSMichal Kalderon 	if (QED_IS_ROCE_PERSONALITY(p_hwfn)) {
68079284adeSMichal Kalderon 		eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
68179284adeSMichal Kalderon 		rc = qed_llh_set_roce_affinity(cdev, eng);
68279284adeSMichal Kalderon 		if (rc) {
68379284adeSMichal Kalderon 			DP_NOTICE(cdev,
68479284adeSMichal Kalderon 				  "Failed to set the RoCE engine affinity\n");
68579284adeSMichal Kalderon 			return rc;
68679284adeSMichal Kalderon 		}
68779284adeSMichal Kalderon 
68879284adeSMichal Kalderon 		DP_VERBOSE(cdev,
68979284adeSMichal Kalderon 			   QED_MSG_SP,
69079284adeSMichal Kalderon 			   "LLH: Set the engine affinity of RoCE packets as %d\n",
69179284adeSMichal Kalderon 			   eng);
69279284adeSMichal Kalderon 	}
69379284adeSMichal Kalderon 
69479284adeSMichal Kalderon 	/* Storage PF is bound to a single engine while L2 PF uses both */
69579284adeSMichal Kalderon 	if (QED_IS_FCOE_PERSONALITY(p_hwfn) || QED_IS_ISCSI_PERSONALITY(p_hwfn))
69679284adeSMichal Kalderon 		eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
69779284adeSMichal Kalderon 	else			/* L2_PERSONALITY */
69879284adeSMichal Kalderon 		eng = QED_BOTH_ENG;
69979284adeSMichal Kalderon 
70079284adeSMichal Kalderon 	for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
70179284adeSMichal Kalderon 		rc = qed_llh_set_ppfid_affinity(cdev, ppfid, eng);
70279284adeSMichal Kalderon 		if (rc) {
70379284adeSMichal Kalderon 			DP_NOTICE(cdev,
70479284adeSMichal Kalderon 				  "Failed to set the engine affinity of ppfid %d\n",
70579284adeSMichal Kalderon 				  ppfid);
70679284adeSMichal Kalderon 			return rc;
70779284adeSMichal Kalderon 		}
70879284adeSMichal Kalderon 	}
70979284adeSMichal Kalderon 
71079284adeSMichal Kalderon 	DP_VERBOSE(cdev, QED_MSG_SP,
71179284adeSMichal Kalderon 		   "LLH: Set the engine affinity of non-RoCE packets as %d\n",
71279284adeSMichal Kalderon 		   eng);
71379284adeSMichal Kalderon 
71479284adeSMichal Kalderon 	return 0;
71579284adeSMichal Kalderon }
71679284adeSMichal Kalderon 
71779284adeSMichal Kalderon static int qed_llh_hw_init_pf(struct qed_hwfn *p_hwfn,
71879284adeSMichal Kalderon 			      struct qed_ptt *p_ptt)
71979284adeSMichal Kalderon {
72079284adeSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
72179284adeSMichal Kalderon 	u8 ppfid, abs_ppfid;
72279284adeSMichal Kalderon 	int rc;
72379284adeSMichal Kalderon 
72479284adeSMichal Kalderon 	for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
72579284adeSMichal Kalderon 		u32 addr;
72679284adeSMichal Kalderon 
72779284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
72879284adeSMichal Kalderon 		if (rc)
72979284adeSMichal Kalderon 			return rc;
73079284adeSMichal Kalderon 
73179284adeSMichal Kalderon 		addr = NIG_REG_LLH_PPFID2PFID_TBL_0 + abs_ppfid * 0x4;
73279284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, p_hwfn->rel_pf_id);
73379284adeSMichal Kalderon 	}
73479284adeSMichal Kalderon 
73579284adeSMichal Kalderon 	if (test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) &&
73679284adeSMichal Kalderon 	    !QED_IS_FCOE_PERSONALITY(p_hwfn)) {
73779284adeSMichal Kalderon 		rc = qed_llh_add_mac_filter(cdev, 0,
73879284adeSMichal Kalderon 					    p_hwfn->hw_info.hw_mac_addr);
73979284adeSMichal Kalderon 		if (rc)
74079284adeSMichal Kalderon 			DP_NOTICE(cdev,
74179284adeSMichal Kalderon 				  "Failed to add an LLH filter with the primary MAC\n");
74279284adeSMichal Kalderon 	}
74379284adeSMichal Kalderon 
74479284adeSMichal Kalderon 	if (QED_IS_CMT(cdev)) {
74579284adeSMichal Kalderon 		rc = qed_llh_set_engine_affin(p_hwfn, p_ptt);
74679284adeSMichal Kalderon 		if (rc)
74779284adeSMichal Kalderon 			return rc;
74879284adeSMichal Kalderon 	}
74979284adeSMichal Kalderon 
75079284adeSMichal Kalderon 	return 0;
75179284adeSMichal Kalderon }
75279284adeSMichal Kalderon 
75379284adeSMichal Kalderon u8 qed_llh_get_num_ppfid(struct qed_dev *cdev)
75479284adeSMichal Kalderon {
75579284adeSMichal Kalderon 	return cdev->p_llh_info->num_ppfid;
75679284adeSMichal Kalderon }
75779284adeSMichal Kalderon 
75879284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_MASK             0x3
75979284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_SHIFT            0
76079284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_MASK         0x3
76179284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_SHIFT        2
76279284adeSMichal Kalderon 
76379284adeSMichal Kalderon int qed_llh_set_ppfid_affinity(struct qed_dev *cdev, u8 ppfid, enum qed_eng eng)
76479284adeSMichal Kalderon {
76579284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
76679284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
76779284adeSMichal Kalderon 	u32 addr, val, eng_sel;
76879284adeSMichal Kalderon 	u8 abs_ppfid;
76979284adeSMichal Kalderon 	int rc = 0;
77079284adeSMichal Kalderon 
77179284adeSMichal Kalderon 	if (!p_ptt)
77279284adeSMichal Kalderon 		return -EAGAIN;
77379284adeSMichal Kalderon 
77479284adeSMichal Kalderon 	if (!QED_IS_CMT(cdev))
77579284adeSMichal Kalderon 		goto out;
77679284adeSMichal Kalderon 
77779284adeSMichal Kalderon 	rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
77879284adeSMichal Kalderon 	if (rc)
77979284adeSMichal Kalderon 		goto out;
78079284adeSMichal Kalderon 
78179284adeSMichal Kalderon 	switch (eng) {
78279284adeSMichal Kalderon 	case QED_ENG0:
78379284adeSMichal Kalderon 		eng_sel = 0;
78479284adeSMichal Kalderon 		break;
78579284adeSMichal Kalderon 	case QED_ENG1:
78679284adeSMichal Kalderon 		eng_sel = 1;
78779284adeSMichal Kalderon 		break;
78879284adeSMichal Kalderon 	case QED_BOTH_ENG:
78979284adeSMichal Kalderon 		eng_sel = 2;
79079284adeSMichal Kalderon 		break;
79179284adeSMichal Kalderon 	default:
79279284adeSMichal Kalderon 		DP_NOTICE(cdev, "Invalid affinity value for ppfid [%d]\n", eng);
79379284adeSMichal Kalderon 		rc = -EINVAL;
79479284adeSMichal Kalderon 		goto out;
79579284adeSMichal Kalderon 	}
79679284adeSMichal Kalderon 
79779284adeSMichal Kalderon 	addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
79879284adeSMichal Kalderon 	val = qed_rd(p_hwfn, p_ptt, addr);
79979284adeSMichal Kalderon 	SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE, eng_sel);
80079284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, val);
80179284adeSMichal Kalderon 
80279284adeSMichal Kalderon 	/* The iWARP affinity is set as the affinity of ppfid 0 */
80379284adeSMichal Kalderon 	if (!ppfid && QED_IS_IWARP_PERSONALITY(p_hwfn))
80479284adeSMichal Kalderon 		cdev->iwarp_affin = (eng == QED_ENG1) ? 1 : 0;
80579284adeSMichal Kalderon out:
80679284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
80779284adeSMichal Kalderon 
80879284adeSMichal Kalderon 	return rc;
80979284adeSMichal Kalderon }
81079284adeSMichal Kalderon 
81179284adeSMichal Kalderon int qed_llh_set_roce_affinity(struct qed_dev *cdev, enum qed_eng eng)
81279284adeSMichal Kalderon {
81379284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
81479284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
81579284adeSMichal Kalderon 	u32 addr, val, eng_sel;
81679284adeSMichal Kalderon 	u8 ppfid, abs_ppfid;
81779284adeSMichal Kalderon 	int rc = 0;
81879284adeSMichal Kalderon 
81979284adeSMichal Kalderon 	if (!p_ptt)
82079284adeSMichal Kalderon 		return -EAGAIN;
82179284adeSMichal Kalderon 
82279284adeSMichal Kalderon 	if (!QED_IS_CMT(cdev))
82379284adeSMichal Kalderon 		goto out;
82479284adeSMichal Kalderon 
82579284adeSMichal Kalderon 	switch (eng) {
82679284adeSMichal Kalderon 	case QED_ENG0:
82779284adeSMichal Kalderon 		eng_sel = 0;
82879284adeSMichal Kalderon 		break;
82979284adeSMichal Kalderon 	case QED_ENG1:
83079284adeSMichal Kalderon 		eng_sel = 1;
83179284adeSMichal Kalderon 		break;
83279284adeSMichal Kalderon 	case QED_BOTH_ENG:
83379284adeSMichal Kalderon 		eng_sel = 2;
83479284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL,
83579284adeSMichal Kalderon 		       0xf);  /* QP bit 15 */
83679284adeSMichal Kalderon 		break;
83779284adeSMichal Kalderon 	default:
83879284adeSMichal Kalderon 		DP_NOTICE(cdev, "Invalid affinity value for RoCE [%d]\n", eng);
83979284adeSMichal Kalderon 		rc = -EINVAL;
84079284adeSMichal Kalderon 		goto out;
84179284adeSMichal Kalderon 	}
84279284adeSMichal Kalderon 
84379284adeSMichal Kalderon 	for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
84479284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
84579284adeSMichal Kalderon 		if (rc)
84679284adeSMichal Kalderon 			goto out;
84779284adeSMichal Kalderon 
84879284adeSMichal Kalderon 		addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
84979284adeSMichal Kalderon 		val = qed_rd(p_hwfn, p_ptt, addr);
85079284adeSMichal Kalderon 		SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_ROCE, eng_sel);
85179284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, val);
85279284adeSMichal Kalderon 	}
85379284adeSMichal Kalderon out:
85479284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
85579284adeSMichal Kalderon 
85679284adeSMichal Kalderon 	return rc;
85779284adeSMichal Kalderon }
85879284adeSMichal Kalderon 
85979284adeSMichal Kalderon struct qed_llh_filter_details {
86079284adeSMichal Kalderon 	u64 value;
86179284adeSMichal Kalderon 	u32 mode;
86279284adeSMichal Kalderon 	u32 protocol_type;
86379284adeSMichal Kalderon 	u32 hdr_sel;
86479284adeSMichal Kalderon 	u32 enable;
86579284adeSMichal Kalderon };
86679284adeSMichal Kalderon 
86779284adeSMichal Kalderon static int
86879284adeSMichal Kalderon qed_llh_access_filter(struct qed_hwfn *p_hwfn,
86979284adeSMichal Kalderon 		      struct qed_ptt *p_ptt,
87079284adeSMichal Kalderon 		      u8 abs_ppfid,
87179284adeSMichal Kalderon 		      u8 filter_idx,
87279284adeSMichal Kalderon 		      struct qed_llh_filter_details *p_details)
87379284adeSMichal Kalderon {
87479284adeSMichal Kalderon 	struct qed_dmae_params params = {0};
87579284adeSMichal Kalderon 	u32 addr;
87679284adeSMichal Kalderon 	u8 pfid;
87779284adeSMichal Kalderon 	int rc;
87879284adeSMichal Kalderon 
87979284adeSMichal Kalderon 	/* The NIG/LLH registers that are accessed in this function have only 16
88079284adeSMichal Kalderon 	 * rows which are exposed to a PF. I.e. only the 16 filters of its
88179284adeSMichal Kalderon 	 * default ppfid. Accessing filters of other ppfids requires pretending
88279284adeSMichal Kalderon 	 * to another PFs.
88379284adeSMichal Kalderon 	 * The calculation of PPFID->PFID in AH is based on the relative index
88479284adeSMichal Kalderon 	 * of a PF on its port.
88579284adeSMichal Kalderon 	 * For BB the pfid is actually the abs_ppfid.
88679284adeSMichal Kalderon 	 */
88779284adeSMichal Kalderon 	if (QED_IS_BB(p_hwfn->cdev))
88879284adeSMichal Kalderon 		pfid = abs_ppfid;
88979284adeSMichal Kalderon 	else
89079284adeSMichal Kalderon 		pfid = abs_ppfid * p_hwfn->cdev->num_ports_in_engine +
89179284adeSMichal Kalderon 		    MFW_PORT(p_hwfn);
89279284adeSMichal Kalderon 
89379284adeSMichal Kalderon 	/* Filter enable - should be done first when removing a filter */
89479284adeSMichal Kalderon 	if (!p_details->enable) {
89579284adeSMichal Kalderon 		qed_fid_pretend(p_hwfn, p_ptt,
89679284adeSMichal Kalderon 				pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
89779284adeSMichal Kalderon 
89879284adeSMichal Kalderon 		addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4;
89979284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, p_details->enable);
90079284adeSMichal Kalderon 
90179284adeSMichal Kalderon 		qed_fid_pretend(p_hwfn, p_ptt,
90279284adeSMichal Kalderon 				p_hwfn->rel_pf_id <<
90379284adeSMichal Kalderon 				PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
90479284adeSMichal Kalderon 	}
90579284adeSMichal Kalderon 
90679284adeSMichal Kalderon 	/* Filter value */
90779284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * filter_idx * 0x4;
90879284adeSMichal Kalderon 
90979284adeSMichal Kalderon 	params.flags = QED_DMAE_FLAG_PF_DST;
91079284adeSMichal Kalderon 	params.dst_pfid = pfid;
91179284adeSMichal Kalderon 	rc = qed_dmae_host2grc(p_hwfn,
91279284adeSMichal Kalderon 			       p_ptt,
91379284adeSMichal Kalderon 			       (u64)(uintptr_t)&p_details->value,
91479284adeSMichal Kalderon 			       addr, 2 /* size_in_dwords */,
91579284adeSMichal Kalderon 			       &params);
91679284adeSMichal Kalderon 	if (rc)
91779284adeSMichal Kalderon 		return rc;
91879284adeSMichal Kalderon 
91979284adeSMichal Kalderon 	qed_fid_pretend(p_hwfn, p_ptt,
92079284adeSMichal Kalderon 			pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
92179284adeSMichal Kalderon 
92279284adeSMichal Kalderon 	/* Filter mode */
92379284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_MODE + filter_idx * 0x4;
92479284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, p_details->mode);
92579284adeSMichal Kalderon 
92679284adeSMichal Kalderon 	/* Filter protocol type */
92779284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + filter_idx * 0x4;
92879284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, p_details->protocol_type);
92979284adeSMichal Kalderon 
93079284adeSMichal Kalderon 	/* Filter header select */
93179284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_HDR_SEL + filter_idx * 0x4;
93279284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, p_details->hdr_sel);
93379284adeSMichal Kalderon 
93479284adeSMichal Kalderon 	/* Filter enable - should be done last when adding a filter */
93579284adeSMichal Kalderon 	if (p_details->enable) {
93679284adeSMichal Kalderon 		addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4;
93779284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, p_details->enable);
93879284adeSMichal Kalderon 	}
93979284adeSMichal Kalderon 
94079284adeSMichal Kalderon 	qed_fid_pretend(p_hwfn, p_ptt,
94179284adeSMichal Kalderon 			p_hwfn->rel_pf_id <<
94279284adeSMichal Kalderon 			PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
94379284adeSMichal Kalderon 
94479284adeSMichal Kalderon 	return 0;
94579284adeSMichal Kalderon }
94679284adeSMichal Kalderon 
94779284adeSMichal Kalderon static int
94879284adeSMichal Kalderon qed_llh_add_filter(struct qed_hwfn *p_hwfn,
94979284adeSMichal Kalderon 		   struct qed_ptt *p_ptt,
95079284adeSMichal Kalderon 		   u8 abs_ppfid,
95179284adeSMichal Kalderon 		   u8 filter_idx, u8 filter_prot_type, u32 high, u32 low)
95279284adeSMichal Kalderon {
95379284adeSMichal Kalderon 	struct qed_llh_filter_details filter_details;
95479284adeSMichal Kalderon 
95579284adeSMichal Kalderon 	filter_details.enable = 1;
95679284adeSMichal Kalderon 	filter_details.value = ((u64)high << 32) | low;
95779284adeSMichal Kalderon 	filter_details.hdr_sel = 0;
95879284adeSMichal Kalderon 	filter_details.protocol_type = filter_prot_type;
95979284adeSMichal Kalderon 	/* Mode: 0: MAC-address classification 1: protocol classification */
96079284adeSMichal Kalderon 	filter_details.mode = filter_prot_type ? 1 : 0;
96179284adeSMichal Kalderon 
96279284adeSMichal Kalderon 	return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
96379284adeSMichal Kalderon 				     &filter_details);
96479284adeSMichal Kalderon }
96579284adeSMichal Kalderon 
96679284adeSMichal Kalderon static int
96779284adeSMichal Kalderon qed_llh_remove_filter(struct qed_hwfn *p_hwfn,
96879284adeSMichal Kalderon 		      struct qed_ptt *p_ptt, u8 abs_ppfid, u8 filter_idx)
96979284adeSMichal Kalderon {
97079284adeSMichal Kalderon 	struct qed_llh_filter_details filter_details = {0};
97179284adeSMichal Kalderon 
97279284adeSMichal Kalderon 	return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
97379284adeSMichal Kalderon 				     &filter_details);
97479284adeSMichal Kalderon }
97579284adeSMichal Kalderon 
97679284adeSMichal Kalderon int qed_llh_add_mac_filter(struct qed_dev *cdev,
97779284adeSMichal Kalderon 			   u8 ppfid, u8 mac_addr[ETH_ALEN])
97879284adeSMichal Kalderon {
97979284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
98079284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
98179284adeSMichal Kalderon 	union qed_llh_filter filter = {};
98279284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid;
98379284adeSMichal Kalderon 	u32 high, low, ref_cnt;
98479284adeSMichal Kalderon 	int rc = 0;
98579284adeSMichal Kalderon 
98679284adeSMichal Kalderon 	if (!p_ptt)
98779284adeSMichal Kalderon 		return -EAGAIN;
98879284adeSMichal Kalderon 
98979284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
99079284adeSMichal Kalderon 		goto out;
99179284adeSMichal Kalderon 
99279284adeSMichal Kalderon 	memcpy(filter.mac.addr, mac_addr, ETH_ALEN);
99379284adeSMichal Kalderon 	rc = qed_llh_shadow_add_filter(cdev, ppfid,
99479284adeSMichal Kalderon 				       QED_LLH_FILTER_TYPE_MAC,
99579284adeSMichal Kalderon 				       &filter, &filter_idx, &ref_cnt);
99679284adeSMichal Kalderon 	if (rc)
99779284adeSMichal Kalderon 		goto err;
99879284adeSMichal Kalderon 
99979284adeSMichal Kalderon 	/* Configure the LLH only in case of a new the filter */
100079284adeSMichal Kalderon 	if (ref_cnt == 1) {
100179284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
100279284adeSMichal Kalderon 		if (rc)
100379284adeSMichal Kalderon 			goto err;
100479284adeSMichal Kalderon 
100579284adeSMichal Kalderon 		high = mac_addr[1] | (mac_addr[0] << 8);
100679284adeSMichal Kalderon 		low = mac_addr[5] | (mac_addr[4] << 8) | (mac_addr[3] << 16) |
100779284adeSMichal Kalderon 		      (mac_addr[2] << 24);
100879284adeSMichal Kalderon 		rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
100979284adeSMichal Kalderon 					0, high, low);
101079284adeSMichal Kalderon 		if (rc)
101179284adeSMichal Kalderon 			goto err;
101279284adeSMichal Kalderon 	}
101379284adeSMichal Kalderon 
101479284adeSMichal Kalderon 	DP_VERBOSE(cdev,
101579284adeSMichal Kalderon 		   QED_MSG_SP,
101679284adeSMichal Kalderon 		   "LLH: Added MAC filter [%pM] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
101779284adeSMichal Kalderon 		   mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt);
101879284adeSMichal Kalderon 
101979284adeSMichal Kalderon 	goto out;
102079284adeSMichal Kalderon 
102179284adeSMichal Kalderon err:	DP_NOTICE(cdev,
102279284adeSMichal Kalderon 		  "LLH: Failed to add MAC filter [%pM] to ppfid %hhd\n",
102379284adeSMichal Kalderon 		  mac_addr, ppfid);
102479284adeSMichal Kalderon out:
102579284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
102679284adeSMichal Kalderon 
102779284adeSMichal Kalderon 	return rc;
102879284adeSMichal Kalderon }
102979284adeSMichal Kalderon 
103079284adeSMichal Kalderon static int
103179284adeSMichal Kalderon qed_llh_protocol_filter_stringify(struct qed_dev *cdev,
103279284adeSMichal Kalderon 				  enum qed_llh_prot_filter_type_t type,
103379284adeSMichal Kalderon 				  u16 source_port_or_eth_type,
103479284adeSMichal Kalderon 				  u16 dest_port, u8 *str, size_t str_len)
103579284adeSMichal Kalderon {
103679284adeSMichal Kalderon 	switch (type) {
103779284adeSMichal Kalderon 	case QED_LLH_FILTER_ETHERTYPE:
103879284adeSMichal Kalderon 		snprintf(str, str_len, "Ethertype 0x%04x",
103979284adeSMichal Kalderon 			 source_port_or_eth_type);
104079284adeSMichal Kalderon 		break;
104179284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_PORT:
104279284adeSMichal Kalderon 		snprintf(str, str_len, "TCP src port 0x%04x",
104379284adeSMichal Kalderon 			 source_port_or_eth_type);
104479284adeSMichal Kalderon 		break;
104579284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_PORT:
104679284adeSMichal Kalderon 		snprintf(str, str_len, "UDP src port 0x%04x",
104779284adeSMichal Kalderon 			 source_port_or_eth_type);
104879284adeSMichal Kalderon 		break;
104979284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_DEST_PORT:
105079284adeSMichal Kalderon 		snprintf(str, str_len, "TCP dst port 0x%04x", dest_port);
105179284adeSMichal Kalderon 		break;
105279284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_DEST_PORT:
105379284adeSMichal Kalderon 		snprintf(str, str_len, "UDP dst port 0x%04x", dest_port);
105479284adeSMichal Kalderon 		break;
105579284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
105679284adeSMichal Kalderon 		snprintf(str, str_len, "TCP src/dst ports 0x%04x/0x%04x",
105779284adeSMichal Kalderon 			 source_port_or_eth_type, dest_port);
105879284adeSMichal Kalderon 		break;
105979284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
106079284adeSMichal Kalderon 		snprintf(str, str_len, "UDP src/dst ports 0x%04x/0x%04x",
106179284adeSMichal Kalderon 			 source_port_or_eth_type, dest_port);
106279284adeSMichal Kalderon 		break;
106379284adeSMichal Kalderon 	default:
106479284adeSMichal Kalderon 		DP_NOTICE(cdev,
106579284adeSMichal Kalderon 			  "Non valid LLH protocol filter type %d\n", type);
106679284adeSMichal Kalderon 		return -EINVAL;
106779284adeSMichal Kalderon 	}
106879284adeSMichal Kalderon 
106979284adeSMichal Kalderon 	return 0;
107079284adeSMichal Kalderon }
107179284adeSMichal Kalderon 
107279284adeSMichal Kalderon static int
107379284adeSMichal Kalderon qed_llh_protocol_filter_to_hilo(struct qed_dev *cdev,
107479284adeSMichal Kalderon 				enum qed_llh_prot_filter_type_t type,
107579284adeSMichal Kalderon 				u16 source_port_or_eth_type,
107679284adeSMichal Kalderon 				u16 dest_port, u32 *p_high, u32 *p_low)
107779284adeSMichal Kalderon {
107879284adeSMichal Kalderon 	*p_high = 0;
107979284adeSMichal Kalderon 	*p_low = 0;
108079284adeSMichal Kalderon 
108179284adeSMichal Kalderon 	switch (type) {
108279284adeSMichal Kalderon 	case QED_LLH_FILTER_ETHERTYPE:
108379284adeSMichal Kalderon 		*p_high = source_port_or_eth_type;
108479284adeSMichal Kalderon 		break;
108579284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_PORT:
108679284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_PORT:
108779284adeSMichal Kalderon 		*p_low = source_port_or_eth_type << 16;
108879284adeSMichal Kalderon 		break;
108979284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_DEST_PORT:
109079284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_DEST_PORT:
109179284adeSMichal Kalderon 		*p_low = dest_port;
109279284adeSMichal Kalderon 		break;
109379284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
109479284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
109579284adeSMichal Kalderon 		*p_low = (source_port_or_eth_type << 16) | dest_port;
109679284adeSMichal Kalderon 		break;
109779284adeSMichal Kalderon 	default:
109879284adeSMichal Kalderon 		DP_NOTICE(cdev,
109979284adeSMichal Kalderon 			  "Non valid LLH protocol filter type %d\n", type);
110079284adeSMichal Kalderon 		return -EINVAL;
110179284adeSMichal Kalderon 	}
110279284adeSMichal Kalderon 
110379284adeSMichal Kalderon 	return 0;
110479284adeSMichal Kalderon }
110579284adeSMichal Kalderon 
110679284adeSMichal Kalderon int
110779284adeSMichal Kalderon qed_llh_add_protocol_filter(struct qed_dev *cdev,
110879284adeSMichal Kalderon 			    u8 ppfid,
110979284adeSMichal Kalderon 			    enum qed_llh_prot_filter_type_t type,
111079284adeSMichal Kalderon 			    u16 source_port_or_eth_type, u16 dest_port)
111179284adeSMichal Kalderon {
111279284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
111379284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
111479284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid, str[32], type_bitmap;
111579284adeSMichal Kalderon 	union qed_llh_filter filter = {};
111679284adeSMichal Kalderon 	u32 high, low, ref_cnt;
111779284adeSMichal Kalderon 	int rc = 0;
111879284adeSMichal Kalderon 
111979284adeSMichal Kalderon 	if (!p_ptt)
112079284adeSMichal Kalderon 		return -EAGAIN;
112179284adeSMichal Kalderon 
112279284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits))
112379284adeSMichal Kalderon 		goto out;
112479284adeSMichal Kalderon 
112579284adeSMichal Kalderon 	rc = qed_llh_protocol_filter_stringify(cdev, type,
112679284adeSMichal Kalderon 					       source_port_or_eth_type,
112779284adeSMichal Kalderon 					       dest_port, str, sizeof(str));
112879284adeSMichal Kalderon 	if (rc)
112979284adeSMichal Kalderon 		goto err;
113079284adeSMichal Kalderon 
113179284adeSMichal Kalderon 	filter.protocol.type = type;
113279284adeSMichal Kalderon 	filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
113379284adeSMichal Kalderon 	filter.protocol.dest_port = dest_port;
113479284adeSMichal Kalderon 	rc = qed_llh_shadow_add_filter(cdev,
113579284adeSMichal Kalderon 				       ppfid,
113679284adeSMichal Kalderon 				       QED_LLH_FILTER_TYPE_PROTOCOL,
113779284adeSMichal Kalderon 				       &filter, &filter_idx, &ref_cnt);
113879284adeSMichal Kalderon 	if (rc)
113979284adeSMichal Kalderon 		goto err;
114079284adeSMichal Kalderon 
114179284adeSMichal Kalderon 	/* Configure the LLH only in case of a new the filter */
114279284adeSMichal Kalderon 	if (ref_cnt == 1) {
114379284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
114479284adeSMichal Kalderon 		if (rc)
114579284adeSMichal Kalderon 			goto err;
114679284adeSMichal Kalderon 
114779284adeSMichal Kalderon 		rc = qed_llh_protocol_filter_to_hilo(cdev, type,
114879284adeSMichal Kalderon 						     source_port_or_eth_type,
114979284adeSMichal Kalderon 						     dest_port, &high, &low);
115079284adeSMichal Kalderon 		if (rc)
115179284adeSMichal Kalderon 			goto err;
115279284adeSMichal Kalderon 
115379284adeSMichal Kalderon 		type_bitmap = 0x1 << type;
115479284adeSMichal Kalderon 		rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid,
115579284adeSMichal Kalderon 					filter_idx, type_bitmap, high, low);
115679284adeSMichal Kalderon 		if (rc)
115779284adeSMichal Kalderon 			goto err;
115879284adeSMichal Kalderon 	}
115979284adeSMichal Kalderon 
116079284adeSMichal Kalderon 	DP_VERBOSE(cdev,
116179284adeSMichal Kalderon 		   QED_MSG_SP,
116279284adeSMichal Kalderon 		   "LLH: Added protocol filter [%s] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
116379284adeSMichal Kalderon 		   str, ppfid, abs_ppfid, filter_idx, ref_cnt);
116479284adeSMichal Kalderon 
116579284adeSMichal Kalderon 	goto out;
116679284adeSMichal Kalderon 
116779284adeSMichal Kalderon err:	DP_NOTICE(p_hwfn,
116879284adeSMichal Kalderon 		  "LLH: Failed to add protocol filter [%s] to ppfid %hhd\n",
116979284adeSMichal Kalderon 		  str, ppfid);
117079284adeSMichal Kalderon out:
117179284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
117279284adeSMichal Kalderon 
117379284adeSMichal Kalderon 	return rc;
117479284adeSMichal Kalderon }
117579284adeSMichal Kalderon 
117679284adeSMichal Kalderon void qed_llh_remove_mac_filter(struct qed_dev *cdev,
117779284adeSMichal Kalderon 			       u8 ppfid, u8 mac_addr[ETH_ALEN])
117879284adeSMichal Kalderon {
117979284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
118079284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
118179284adeSMichal Kalderon 	union qed_llh_filter filter = {};
118279284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid;
118379284adeSMichal Kalderon 	int rc = 0;
118479284adeSMichal Kalderon 	u32 ref_cnt;
118579284adeSMichal Kalderon 
118679284adeSMichal Kalderon 	if (!p_ptt)
118779284adeSMichal Kalderon 		return;
118879284adeSMichal Kalderon 
118979284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
119079284adeSMichal Kalderon 		goto out;
119179284adeSMichal Kalderon 
119279284adeSMichal Kalderon 	ether_addr_copy(filter.mac.addr, mac_addr);
119379284adeSMichal Kalderon 	rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
119479284adeSMichal Kalderon 					  &ref_cnt);
119579284adeSMichal Kalderon 	if (rc)
119679284adeSMichal Kalderon 		goto err;
119779284adeSMichal Kalderon 
119879284adeSMichal Kalderon 	/* Remove from the LLH in case the filter is not in use */
119979284adeSMichal Kalderon 	if (!ref_cnt) {
120079284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
120179284adeSMichal Kalderon 		if (rc)
120279284adeSMichal Kalderon 			goto err;
120379284adeSMichal Kalderon 
120479284adeSMichal Kalderon 		rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
120579284adeSMichal Kalderon 					   filter_idx);
120679284adeSMichal Kalderon 		if (rc)
120779284adeSMichal Kalderon 			goto err;
120879284adeSMichal Kalderon 	}
120979284adeSMichal Kalderon 
121079284adeSMichal Kalderon 	DP_VERBOSE(cdev,
121179284adeSMichal Kalderon 		   QED_MSG_SP,
121279284adeSMichal Kalderon 		   "LLH: Removed MAC filter [%pM] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
121379284adeSMichal Kalderon 		   mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt);
121479284adeSMichal Kalderon 
121579284adeSMichal Kalderon 	goto out;
121679284adeSMichal Kalderon 
121779284adeSMichal Kalderon err:	DP_NOTICE(cdev,
121879284adeSMichal Kalderon 		  "LLH: Failed to remove MAC filter [%pM] from ppfid %hhd\n",
121979284adeSMichal Kalderon 		  mac_addr, ppfid);
122079284adeSMichal Kalderon out:
122179284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
122279284adeSMichal Kalderon }
122379284adeSMichal Kalderon 
122479284adeSMichal Kalderon void qed_llh_remove_protocol_filter(struct qed_dev *cdev,
122579284adeSMichal Kalderon 				    u8 ppfid,
122679284adeSMichal Kalderon 				    enum qed_llh_prot_filter_type_t type,
122779284adeSMichal Kalderon 				    u16 source_port_or_eth_type, u16 dest_port)
122879284adeSMichal Kalderon {
122979284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
123079284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
123179284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid, str[32];
123279284adeSMichal Kalderon 	union qed_llh_filter filter = {};
123379284adeSMichal Kalderon 	int rc = 0;
123479284adeSMichal Kalderon 	u32 ref_cnt;
123579284adeSMichal Kalderon 
123679284adeSMichal Kalderon 	if (!p_ptt)
123779284adeSMichal Kalderon 		return;
123879284adeSMichal Kalderon 
123979284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits))
124079284adeSMichal Kalderon 		goto out;
124179284adeSMichal Kalderon 
124279284adeSMichal Kalderon 	rc = qed_llh_protocol_filter_stringify(cdev, type,
124379284adeSMichal Kalderon 					       source_port_or_eth_type,
124479284adeSMichal Kalderon 					       dest_port, str, sizeof(str));
124579284adeSMichal Kalderon 	if (rc)
124679284adeSMichal Kalderon 		goto err;
124779284adeSMichal Kalderon 
124879284adeSMichal Kalderon 	filter.protocol.type = type;
124979284adeSMichal Kalderon 	filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
125079284adeSMichal Kalderon 	filter.protocol.dest_port = dest_port;
125179284adeSMichal Kalderon 	rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
125279284adeSMichal Kalderon 					  &ref_cnt);
125379284adeSMichal Kalderon 	if (rc)
125479284adeSMichal Kalderon 		goto err;
125579284adeSMichal Kalderon 
125679284adeSMichal Kalderon 	/* Remove from the LLH in case the filter is not in use */
125779284adeSMichal Kalderon 	if (!ref_cnt) {
125879284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
125979284adeSMichal Kalderon 		if (rc)
126079284adeSMichal Kalderon 			goto err;
126179284adeSMichal Kalderon 
126279284adeSMichal Kalderon 		rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
126379284adeSMichal Kalderon 					   filter_idx);
126479284adeSMichal Kalderon 		if (rc)
126579284adeSMichal Kalderon 			goto err;
126679284adeSMichal Kalderon 	}
126779284adeSMichal Kalderon 
126879284adeSMichal Kalderon 	DP_VERBOSE(cdev,
126979284adeSMichal Kalderon 		   QED_MSG_SP,
127079284adeSMichal Kalderon 		   "LLH: Removed protocol filter [%s] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
127179284adeSMichal Kalderon 		   str, ppfid, abs_ppfid, filter_idx, ref_cnt);
127279284adeSMichal Kalderon 
127379284adeSMichal Kalderon 	goto out;
127479284adeSMichal Kalderon 
127579284adeSMichal Kalderon err:	DP_NOTICE(cdev,
127679284adeSMichal Kalderon 		  "LLH: Failed to remove protocol filter [%s] from ppfid %hhd\n",
127779284adeSMichal Kalderon 		  str, ppfid);
127879284adeSMichal Kalderon out:
127979284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
128079284adeSMichal Kalderon }
128179284adeSMichal Kalderon 
128279284adeSMichal Kalderon /******************************* NIG LLH - End ********************************/
128379284adeSMichal Kalderon 
128451ff1725SRam Amrani #define QED_MIN_DPIS            (4)
128551ff1725SRam Amrani #define QED_MIN_PWM_REGION      (QED_WID_SIZE * QED_MIN_DPIS)
128651ff1725SRam Amrani 
128715582962SRahul Verma static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
128815582962SRahul Verma 			   struct qed_ptt *p_ptt, enum BAR_ID bar_id)
1289c2035eeaSRam Amrani {
1290c2035eeaSRam Amrani 	u32 bar_reg = (bar_id == BAR_ID_0 ?
1291c2035eeaSRam Amrani 		       PGLUE_B_REG_PF_BAR0_SIZE : PGLUE_B_REG_PF_BAR1_SIZE);
12921408cc1fSYuval Mintz 	u32 val;
1293c2035eeaSRam Amrani 
12941408cc1fSYuval Mintz 	if (IS_VF(p_hwfn->cdev))
12951a850bfcSMintz, Yuval 		return qed_vf_hw_bar_size(p_hwfn, bar_id);
12961408cc1fSYuval Mintz 
129715582962SRahul Verma 	val = qed_rd(p_hwfn, p_ptt, bar_reg);
1298c2035eeaSRam Amrani 	if (val)
1299c2035eeaSRam Amrani 		return 1 << (val + 15);
1300c2035eeaSRam Amrani 
1301c2035eeaSRam Amrani 	/* Old MFW initialized above registered only conditionally */
1302c2035eeaSRam Amrani 	if (p_hwfn->cdev->num_hwfns > 1) {
1303c2035eeaSRam Amrani 		DP_INFO(p_hwfn,
1304c2035eeaSRam Amrani 			"BAR size not configured. Assuming BAR size of 256kB for GRC and 512kB for DB\n");
1305c2035eeaSRam Amrani 			return BAR_ID_0 ? 256 * 1024 : 512 * 1024;
1306c2035eeaSRam Amrani 	} else {
1307c2035eeaSRam Amrani 		DP_INFO(p_hwfn,
1308c2035eeaSRam Amrani 			"BAR size not configured. Assuming BAR size of 512kB for GRC and 512kB for DB\n");
1309c2035eeaSRam Amrani 			return 512 * 1024;
1310c2035eeaSRam Amrani 	}
1311c2035eeaSRam Amrani }
1312c2035eeaSRam Amrani 
13131a635e48SYuval Mintz void qed_init_dp(struct qed_dev *cdev, u32 dp_module, u8 dp_level)
1314fe56b9e6SYuval Mintz {
1315fe56b9e6SYuval Mintz 	u32 i;
1316fe56b9e6SYuval Mintz 
1317fe56b9e6SYuval Mintz 	cdev->dp_level = dp_level;
1318fe56b9e6SYuval Mintz 	cdev->dp_module = dp_module;
1319fe56b9e6SYuval Mintz 	for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) {
1320fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1321fe56b9e6SYuval Mintz 
1322fe56b9e6SYuval Mintz 		p_hwfn->dp_level = dp_level;
1323fe56b9e6SYuval Mintz 		p_hwfn->dp_module = dp_module;
1324fe56b9e6SYuval Mintz 	}
1325fe56b9e6SYuval Mintz }
1326fe56b9e6SYuval Mintz 
1327fe56b9e6SYuval Mintz void qed_init_struct(struct qed_dev *cdev)
1328fe56b9e6SYuval Mintz {
1329fe56b9e6SYuval Mintz 	u8 i;
1330fe56b9e6SYuval Mintz 
1331fe56b9e6SYuval Mintz 	for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) {
1332fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1333fe56b9e6SYuval Mintz 
1334fe56b9e6SYuval Mintz 		p_hwfn->cdev = cdev;
1335fe56b9e6SYuval Mintz 		p_hwfn->my_id = i;
1336fe56b9e6SYuval Mintz 		p_hwfn->b_active = false;
1337fe56b9e6SYuval Mintz 
1338fe56b9e6SYuval Mintz 		mutex_init(&p_hwfn->dmae_info.mutex);
1339fe56b9e6SYuval Mintz 	}
1340fe56b9e6SYuval Mintz 
1341fe56b9e6SYuval Mintz 	/* hwfn 0 is always active */
1342fe56b9e6SYuval Mintz 	cdev->hwfns[0].b_active = true;
1343fe56b9e6SYuval Mintz 
1344fe56b9e6SYuval Mintz 	/* set the default cache alignment to 128 */
1345fe56b9e6SYuval Mintz 	cdev->cache_shift = 7;
1346fe56b9e6SYuval Mintz }
1347fe56b9e6SYuval Mintz 
1348fe56b9e6SYuval Mintz static void qed_qm_info_free(struct qed_hwfn *p_hwfn)
1349fe56b9e6SYuval Mintz {
1350fe56b9e6SYuval Mintz 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1351fe56b9e6SYuval Mintz 
1352fe56b9e6SYuval Mintz 	kfree(qm_info->qm_pq_params);
1353fe56b9e6SYuval Mintz 	qm_info->qm_pq_params = NULL;
1354fe56b9e6SYuval Mintz 	kfree(qm_info->qm_vport_params);
1355fe56b9e6SYuval Mintz 	qm_info->qm_vport_params = NULL;
1356fe56b9e6SYuval Mintz 	kfree(qm_info->qm_port_params);
1357fe56b9e6SYuval Mintz 	qm_info->qm_port_params = NULL;
1358bcd197c8SManish Chopra 	kfree(qm_info->wfq_data);
1359bcd197c8SManish Chopra 	qm_info->wfq_data = NULL;
1360fe56b9e6SYuval Mintz }
1361fe56b9e6SYuval Mintz 
1362a3f72307SDenis Bolotin static void qed_dbg_user_data_free(struct qed_hwfn *p_hwfn)
1363a3f72307SDenis Bolotin {
1364a3f72307SDenis Bolotin 	kfree(p_hwfn->dbg_user_info);
1365a3f72307SDenis Bolotin 	p_hwfn->dbg_user_info = NULL;
1366a3f72307SDenis Bolotin }
1367a3f72307SDenis Bolotin 
1368fe56b9e6SYuval Mintz void qed_resc_free(struct qed_dev *cdev)
1369fe56b9e6SYuval Mintz {
1370fe56b9e6SYuval Mintz 	int i;
1371fe56b9e6SYuval Mintz 
13720db711bbSMintz, Yuval 	if (IS_VF(cdev)) {
13730db711bbSMintz, Yuval 		for_each_hwfn(cdev, i)
13740db711bbSMintz, Yuval 			qed_l2_free(&cdev->hwfns[i]);
13751408cc1fSYuval Mintz 		return;
13760db711bbSMintz, Yuval 	}
13771408cc1fSYuval Mintz 
1378fe56b9e6SYuval Mintz 	kfree(cdev->fw_data);
1379fe56b9e6SYuval Mintz 	cdev->fw_data = NULL;
1380fe56b9e6SYuval Mintz 
1381fe56b9e6SYuval Mintz 	kfree(cdev->reset_stats);
13823587cb87STomer Tayar 	cdev->reset_stats = NULL;
1383fe56b9e6SYuval Mintz 
138479284adeSMichal Kalderon 	qed_llh_free(cdev);
138579284adeSMichal Kalderon 
1386fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
1387fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1388fe56b9e6SYuval Mintz 
1389fe56b9e6SYuval Mintz 		qed_cxt_mngr_free(p_hwfn);
1390fe56b9e6SYuval Mintz 		qed_qm_info_free(p_hwfn);
1391fe56b9e6SYuval Mintz 		qed_spq_free(p_hwfn);
13923587cb87STomer Tayar 		qed_eq_free(p_hwfn);
13933587cb87STomer Tayar 		qed_consq_free(p_hwfn);
1394fe56b9e6SYuval Mintz 		qed_int_free(p_hwfn);
13950a7fb11cSYuval Mintz #ifdef CONFIG_QED_LL2
13963587cb87STomer Tayar 		qed_ll2_free(p_hwfn);
13970a7fb11cSYuval Mintz #endif
13981e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
13993587cb87STomer Tayar 			qed_fcoe_free(p_hwfn);
14001e128c81SArun Easi 
14011d6cff4fSYuval Mintz 		if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
14023587cb87STomer Tayar 			qed_iscsi_free(p_hwfn);
14033587cb87STomer Tayar 			qed_ooo_free(p_hwfn);
14041d6cff4fSYuval Mintz 		}
1405291d57f6SMichal Kalderon 
1406291d57f6SMichal Kalderon 		if (QED_IS_RDMA_PERSONALITY(p_hwfn))
1407291d57f6SMichal Kalderon 			qed_rdma_info_free(p_hwfn);
1408291d57f6SMichal Kalderon 
140932a47e72SYuval Mintz 		qed_iov_free(p_hwfn);
14100db711bbSMintz, Yuval 		qed_l2_free(p_hwfn);
1411fe56b9e6SYuval Mintz 		qed_dmae_info_free(p_hwfn);
1412270837b3Ssudarsana.kalluru@cavium.com 		qed_dcbx_info_free(p_hwfn);
1413a3f72307SDenis Bolotin 		qed_dbg_user_data_free(p_hwfn);
141436907cd5SAriel Elior 
141536907cd5SAriel Elior 		/* Destroy doorbell recovery mechanism */
141636907cd5SAriel Elior 		qed_db_recovery_teardown(p_hwfn);
1417fe56b9e6SYuval Mintz 	}
1418fe56b9e6SYuval Mintz }
1419fe56b9e6SYuval Mintz 
1420b5a9ee7cSAriel Elior /******************** QM initialization *******************/
1421b5a9ee7cSAriel Elior #define ACTIVE_TCS_BMAP 0x9f
1422b5a9ee7cSAriel Elior #define ACTIVE_TCS_BMAP_4PORT_K2 0xf
1423b5a9ee7cSAriel Elior 
1424b5a9ee7cSAriel Elior /* determines the physical queue flags for a given PF. */
1425b5a9ee7cSAriel Elior static u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn)
1426fe56b9e6SYuval Mintz {
1427b5a9ee7cSAriel Elior 	u32 flags;
1428fe56b9e6SYuval Mintz 
1429b5a9ee7cSAriel Elior 	/* common flags */
1430b5a9ee7cSAriel Elior 	flags = PQ_FLAGS_LB;
1431fe56b9e6SYuval Mintz 
1432b5a9ee7cSAriel Elior 	/* feature flags */
1433b5a9ee7cSAriel Elior 	if (IS_QED_SRIOV(p_hwfn->cdev))
1434b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_VFS;
1435fe56b9e6SYuval Mintz 
1436b5a9ee7cSAriel Elior 	/* protocol flags */
1437b5a9ee7cSAriel Elior 	switch (p_hwfn->hw_info.personality) {
1438b5a9ee7cSAriel Elior 	case QED_PCI_ETH:
1439b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_MCOS;
1440b5a9ee7cSAriel Elior 		break;
1441b5a9ee7cSAriel Elior 	case QED_PCI_FCOE:
1442b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_OFLD;
1443b5a9ee7cSAriel Elior 		break;
1444b5a9ee7cSAriel Elior 	case QED_PCI_ISCSI:
1445b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_ACK | PQ_FLAGS_OOO | PQ_FLAGS_OFLD;
1446b5a9ee7cSAriel Elior 		break;
1447b5a9ee7cSAriel Elior 	case QED_PCI_ETH_ROCE:
1448b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_MCOS | PQ_FLAGS_OFLD | PQ_FLAGS_LLT;
144961be82b0SDenis Bolotin 		if (IS_QED_MULTI_TC_ROCE(p_hwfn))
145061be82b0SDenis Bolotin 			flags |= PQ_FLAGS_MTC;
1451b5a9ee7cSAriel Elior 		break;
145293c45984SKalderon, Michal 	case QED_PCI_ETH_IWARP:
145393c45984SKalderon, Michal 		flags |= PQ_FLAGS_MCOS | PQ_FLAGS_ACK | PQ_FLAGS_OOO |
145493c45984SKalderon, Michal 		    PQ_FLAGS_OFLD;
145593c45984SKalderon, Michal 		break;
1456b5a9ee7cSAriel Elior 	default:
1457fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn,
1458b5a9ee7cSAriel Elior 		       "unknown personality %d\n", p_hwfn->hw_info.personality);
1459b5a9ee7cSAriel Elior 		return 0;
1460fe56b9e6SYuval Mintz 	}
1461fe56b9e6SYuval Mintz 
1462b5a9ee7cSAriel Elior 	return flags;
1463b5a9ee7cSAriel Elior }
1464b5a9ee7cSAriel Elior 
1465b5a9ee7cSAriel Elior /* Getters for resource amounts necessary for qm initialization */
1466bf774d14SYueHaibing static u8 qed_init_qm_get_num_tcs(struct qed_hwfn *p_hwfn)
1467b5a9ee7cSAriel Elior {
1468b5a9ee7cSAriel Elior 	return p_hwfn->hw_info.num_hw_tc;
1469b5a9ee7cSAriel Elior }
1470b5a9ee7cSAriel Elior 
1471bf774d14SYueHaibing static u16 qed_init_qm_get_num_vfs(struct qed_hwfn *p_hwfn)
1472b5a9ee7cSAriel Elior {
1473b5a9ee7cSAriel Elior 	return IS_QED_SRIOV(p_hwfn->cdev) ?
1474b5a9ee7cSAriel Elior 	       p_hwfn->cdev->p_iov_info->total_vfs : 0;
1475b5a9ee7cSAriel Elior }
1476b5a9ee7cSAriel Elior 
147761be82b0SDenis Bolotin static u8 qed_init_qm_get_num_mtc_tcs(struct qed_hwfn *p_hwfn)
147861be82b0SDenis Bolotin {
147961be82b0SDenis Bolotin 	u32 pq_flags = qed_get_pq_flags(p_hwfn);
148061be82b0SDenis Bolotin 
148161be82b0SDenis Bolotin 	if (!(PQ_FLAGS_MTC & pq_flags))
148261be82b0SDenis Bolotin 		return 1;
148361be82b0SDenis Bolotin 
148461be82b0SDenis Bolotin 	return qed_init_qm_get_num_tcs(p_hwfn);
148561be82b0SDenis Bolotin }
148661be82b0SDenis Bolotin 
1487b5a9ee7cSAriel Elior #define NUM_DEFAULT_RLS 1
1488b5a9ee7cSAriel Elior 
1489bf774d14SYueHaibing static u16 qed_init_qm_get_num_pf_rls(struct qed_hwfn *p_hwfn)
1490b5a9ee7cSAriel Elior {
1491b5a9ee7cSAriel Elior 	u16 num_pf_rls, num_vfs = qed_init_qm_get_num_vfs(p_hwfn);
1492b5a9ee7cSAriel Elior 
1493b5a9ee7cSAriel Elior 	/* num RLs can't exceed resource amount of rls or vports */
1494b5a9ee7cSAriel Elior 	num_pf_rls = (u16) min_t(u32, RESC_NUM(p_hwfn, QED_RL),
1495b5a9ee7cSAriel Elior 				 RESC_NUM(p_hwfn, QED_VPORT));
1496b5a9ee7cSAriel Elior 
1497b5a9ee7cSAriel Elior 	/* Make sure after we reserve there's something left */
1498b5a9ee7cSAriel Elior 	if (num_pf_rls < num_vfs + NUM_DEFAULT_RLS)
1499b5a9ee7cSAriel Elior 		return 0;
1500b5a9ee7cSAriel Elior 
1501b5a9ee7cSAriel Elior 	/* subtract rls necessary for VFs and one default one for the PF */
1502b5a9ee7cSAriel Elior 	num_pf_rls -= num_vfs + NUM_DEFAULT_RLS;
1503b5a9ee7cSAriel Elior 
1504b5a9ee7cSAriel Elior 	return num_pf_rls;
1505b5a9ee7cSAriel Elior }
1506b5a9ee7cSAriel Elior 
1507bf774d14SYueHaibing static u16 qed_init_qm_get_num_vports(struct qed_hwfn *p_hwfn)
1508b5a9ee7cSAriel Elior {
1509b5a9ee7cSAriel Elior 	u32 pq_flags = qed_get_pq_flags(p_hwfn);
1510b5a9ee7cSAriel Elior 
1511b5a9ee7cSAriel Elior 	/* all pqs share the same vport, except for vfs and pf_rl pqs */
1512b5a9ee7cSAriel Elior 	return (!!(PQ_FLAGS_RLS & pq_flags)) *
1513b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_pf_rls(p_hwfn) +
1514b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_VFS & pq_flags)) *
1515b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_vfs(p_hwfn) + 1;
1516b5a9ee7cSAriel Elior }
1517b5a9ee7cSAriel Elior 
1518b5a9ee7cSAriel Elior /* calc amount of PQs according to the requested flags */
1519bf774d14SYueHaibing static u16 qed_init_qm_get_num_pqs(struct qed_hwfn *p_hwfn)
1520b5a9ee7cSAriel Elior {
1521b5a9ee7cSAriel Elior 	u32 pq_flags = qed_get_pq_flags(p_hwfn);
1522b5a9ee7cSAriel Elior 
1523b5a9ee7cSAriel Elior 	return (!!(PQ_FLAGS_RLS & pq_flags)) *
1524b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_pf_rls(p_hwfn) +
1525b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_MCOS & pq_flags)) *
1526b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_tcs(p_hwfn) +
1527b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_LB & pq_flags)) + (!!(PQ_FLAGS_OOO & pq_flags)) +
152861be82b0SDenis Bolotin 	       (!!(PQ_FLAGS_ACK & pq_flags)) +
152961be82b0SDenis Bolotin 	       (!!(PQ_FLAGS_OFLD & pq_flags)) *
153061be82b0SDenis Bolotin 	       qed_init_qm_get_num_mtc_tcs(p_hwfn) +
153161be82b0SDenis Bolotin 	       (!!(PQ_FLAGS_LLT & pq_flags)) *
153261be82b0SDenis Bolotin 	       qed_init_qm_get_num_mtc_tcs(p_hwfn) +
1533b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_VFS & pq_flags)) * qed_init_qm_get_num_vfs(p_hwfn);
1534b5a9ee7cSAriel Elior }
1535b5a9ee7cSAriel Elior 
1536b5a9ee7cSAriel Elior /* initialize the top level QM params */
1537b5a9ee7cSAriel Elior static void qed_init_qm_params(struct qed_hwfn *p_hwfn)
1538b5a9ee7cSAriel Elior {
1539b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1540b5a9ee7cSAriel Elior 	bool four_port;
1541b5a9ee7cSAriel Elior 
1542b5a9ee7cSAriel Elior 	/* pq and vport bases for this PF */
1543b5a9ee7cSAriel Elior 	qm_info->start_pq = (u16) RESC_START(p_hwfn, QED_PQ);
1544b5a9ee7cSAriel Elior 	qm_info->start_vport = (u8) RESC_START(p_hwfn, QED_VPORT);
1545b5a9ee7cSAriel Elior 
1546b5a9ee7cSAriel Elior 	/* rate limiting and weighted fair queueing are always enabled */
1547c7281d59SGustavo A. R. Silva 	qm_info->vport_rl_en = true;
1548c7281d59SGustavo A. R. Silva 	qm_info->vport_wfq_en = true;
1549b5a9ee7cSAriel Elior 
1550b5a9ee7cSAriel Elior 	/* TC config is different for AH 4 port */
155178cea9ffSTomer Tayar 	four_port = p_hwfn->cdev->num_ports_in_engine == MAX_NUM_PORTS_K2;
1552b5a9ee7cSAriel Elior 
1553b5a9ee7cSAriel Elior 	/* in AH 4 port we have fewer TCs per port */
1554b5a9ee7cSAriel Elior 	qm_info->max_phys_tcs_per_port = four_port ? NUM_PHYS_TCS_4PORT_K2 :
1555b5a9ee7cSAriel Elior 						     NUM_OF_PHYS_TCS;
1556b5a9ee7cSAriel Elior 
1557b5a9ee7cSAriel Elior 	/* unless MFW indicated otherwise, ooo_tc == 3 for
1558b5a9ee7cSAriel Elior 	 * AH 4-port and 4 otherwise.
1559fe56b9e6SYuval Mintz 	 */
1560b5a9ee7cSAriel Elior 	if (!qm_info->ooo_tc)
1561b5a9ee7cSAriel Elior 		qm_info->ooo_tc = four_port ? DCBX_TCP_OOO_K2_4PORT_TC :
1562b5a9ee7cSAriel Elior 					      DCBX_TCP_OOO_TC;
1563dbb799c3SYuval Mintz }
1564dbb799c3SYuval Mintz 
1565b5a9ee7cSAriel Elior /* initialize qm vport params */
1566b5a9ee7cSAriel Elior static void qed_init_qm_vport_params(struct qed_hwfn *p_hwfn)
1567b5a9ee7cSAriel Elior {
1568b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1569b5a9ee7cSAriel Elior 	u8 i;
1570fe56b9e6SYuval Mintz 
1571b5a9ee7cSAriel Elior 	/* all vports participate in weighted fair queueing */
1572b5a9ee7cSAriel Elior 	for (i = 0; i < qed_init_qm_get_num_vports(p_hwfn); i++)
1573b5a9ee7cSAriel Elior 		qm_info->qm_vport_params[i].vport_wfq = 1;
1574fe56b9e6SYuval Mintz }
1575fe56b9e6SYuval Mintz 
1576b5a9ee7cSAriel Elior /* initialize qm port params */
1577b5a9ee7cSAriel Elior static void qed_init_qm_port_params(struct qed_hwfn *p_hwfn)
1578b5a9ee7cSAriel Elior {
1579fe56b9e6SYuval Mintz 	/* Initialize qm port parameters */
158078cea9ffSTomer Tayar 	u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engine;
1581b5a9ee7cSAriel Elior 
1582b5a9ee7cSAriel Elior 	/* indicate how ooo and high pri traffic is dealt with */
1583b5a9ee7cSAriel Elior 	active_phys_tcs = num_ports == MAX_NUM_PORTS_K2 ?
1584b5a9ee7cSAriel Elior 			  ACTIVE_TCS_BMAP_4PORT_K2 :
1585b5a9ee7cSAriel Elior 			  ACTIVE_TCS_BMAP;
1586b5a9ee7cSAriel Elior 
1587fe56b9e6SYuval Mintz 	for (i = 0; i < num_ports; i++) {
1588b5a9ee7cSAriel Elior 		struct init_qm_port_params *p_qm_port =
1589b5a9ee7cSAriel Elior 		    &p_hwfn->qm_info.qm_port_params[i];
1590b5a9ee7cSAriel Elior 
1591fe56b9e6SYuval Mintz 		p_qm_port->active = 1;
1592b5a9ee7cSAriel Elior 		p_qm_port->active_phys_tcs = active_phys_tcs;
1593fe56b9e6SYuval Mintz 		p_qm_port->num_pbf_cmd_lines = PBF_MAX_CMD_LINES / num_ports;
1594fe56b9e6SYuval Mintz 		p_qm_port->num_btb_blocks = BTB_MAX_BLOCKS / num_ports;
1595fe56b9e6SYuval Mintz 	}
1596b5a9ee7cSAriel Elior }
1597fe56b9e6SYuval Mintz 
1598b5a9ee7cSAriel Elior /* Reset the params which must be reset for qm init. QM init may be called as
1599b5a9ee7cSAriel Elior  * a result of flows other than driver load (e.g. dcbx renegotiation). Other
1600b5a9ee7cSAriel Elior  * params may be affected by the init but would simply recalculate to the same
1601b5a9ee7cSAriel Elior  * values. The allocations made for QM init, ports, vports, pqs and vfqs are not
1602b5a9ee7cSAriel Elior  * affected as these amounts stay the same.
1603b5a9ee7cSAriel Elior  */
1604b5a9ee7cSAriel Elior static void qed_init_qm_reset_params(struct qed_hwfn *p_hwfn)
1605b5a9ee7cSAriel Elior {
1606b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1607fe56b9e6SYuval Mintz 
1608b5a9ee7cSAriel Elior 	qm_info->num_pqs = 0;
1609b5a9ee7cSAriel Elior 	qm_info->num_vports = 0;
1610b5a9ee7cSAriel Elior 	qm_info->num_pf_rls = 0;
1611b5a9ee7cSAriel Elior 	qm_info->num_vf_pqs = 0;
1612b5a9ee7cSAriel Elior 	qm_info->first_vf_pq = 0;
1613b5a9ee7cSAriel Elior 	qm_info->first_mcos_pq = 0;
1614b5a9ee7cSAriel Elior 	qm_info->first_rl_pq = 0;
1615b5a9ee7cSAriel Elior }
1616fe56b9e6SYuval Mintz 
1617b5a9ee7cSAriel Elior static void qed_init_qm_advance_vport(struct qed_hwfn *p_hwfn)
1618b5a9ee7cSAriel Elior {
1619b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1620b5a9ee7cSAriel Elior 
1621b5a9ee7cSAriel Elior 	qm_info->num_vports++;
1622b5a9ee7cSAriel Elior 
1623b5a9ee7cSAriel Elior 	if (qm_info->num_vports > qed_init_qm_get_num_vports(p_hwfn))
1624b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1625b5a9ee7cSAriel Elior 		       "vport overflow! qm_info->num_vports %d, qm_init_get_num_vports() %d\n",
1626b5a9ee7cSAriel Elior 		       qm_info->num_vports, qed_init_qm_get_num_vports(p_hwfn));
1627b5a9ee7cSAriel Elior }
1628b5a9ee7cSAriel Elior 
1629b5a9ee7cSAriel Elior /* initialize a single pq and manage qm_info resources accounting.
1630b5a9ee7cSAriel Elior  * The pq_init_flags param determines whether the PQ is rate limited
1631b5a9ee7cSAriel Elior  * (for VF or PF) and whether a new vport is allocated to the pq or not
1632b5a9ee7cSAriel Elior  * (i.e. vport will be shared).
1633b5a9ee7cSAriel Elior  */
1634b5a9ee7cSAriel Elior 
1635b5a9ee7cSAriel Elior /* flags for pq init */
1636b5a9ee7cSAriel Elior #define PQ_INIT_SHARE_VPORT     (1 << 0)
1637b5a9ee7cSAriel Elior #define PQ_INIT_PF_RL           (1 << 1)
1638b5a9ee7cSAriel Elior #define PQ_INIT_VF_RL           (1 << 2)
1639b5a9ee7cSAriel Elior 
1640b5a9ee7cSAriel Elior /* defines for pq init */
1641b5a9ee7cSAriel Elior #define PQ_INIT_DEFAULT_WRR_GROUP       1
1642b5a9ee7cSAriel Elior #define PQ_INIT_DEFAULT_TC              0
1643c4259ddaSDenis Bolotin 
1644c4259ddaSDenis Bolotin void qed_hw_info_set_offload_tc(struct qed_hw_info *p_info, u8 tc)
1645c4259ddaSDenis Bolotin {
1646c4259ddaSDenis Bolotin 	p_info->offload_tc = tc;
1647c4259ddaSDenis Bolotin 	p_info->offload_tc_set = true;
1648c4259ddaSDenis Bolotin }
1649c4259ddaSDenis Bolotin 
1650c4259ddaSDenis Bolotin static bool qed_is_offload_tc_set(struct qed_hwfn *p_hwfn)
1651c4259ddaSDenis Bolotin {
1652c4259ddaSDenis Bolotin 	return p_hwfn->hw_info.offload_tc_set;
1653c4259ddaSDenis Bolotin }
1654c4259ddaSDenis Bolotin 
1655c4259ddaSDenis Bolotin static u32 qed_get_offload_tc(struct qed_hwfn *p_hwfn)
1656c4259ddaSDenis Bolotin {
1657c4259ddaSDenis Bolotin 	if (qed_is_offload_tc_set(p_hwfn))
1658c4259ddaSDenis Bolotin 		return p_hwfn->hw_info.offload_tc;
1659c4259ddaSDenis Bolotin 
1660c4259ddaSDenis Bolotin 	return PQ_INIT_DEFAULT_TC;
1661c4259ddaSDenis Bolotin }
1662b5a9ee7cSAriel Elior 
1663b5a9ee7cSAriel Elior static void qed_init_qm_pq(struct qed_hwfn *p_hwfn,
1664b5a9ee7cSAriel Elior 			   struct qed_qm_info *qm_info,
1665b5a9ee7cSAriel Elior 			   u8 tc, u32 pq_init_flags)
1666b5a9ee7cSAriel Elior {
1667b5a9ee7cSAriel Elior 	u16 pq_idx = qm_info->num_pqs, max_pq = qed_init_qm_get_num_pqs(p_hwfn);
1668b5a9ee7cSAriel Elior 
1669b5a9ee7cSAriel Elior 	if (pq_idx > max_pq)
1670b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1671b5a9ee7cSAriel Elior 		       "pq overflow! pq %d, max pq %d\n", pq_idx, max_pq);
1672b5a9ee7cSAriel Elior 
1673b5a9ee7cSAriel Elior 	/* init pq params */
167450bc60cbSMichal Kalderon 	qm_info->qm_pq_params[pq_idx].port_id = p_hwfn->port_id;
1675b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].vport_id = qm_info->start_vport +
1676b5a9ee7cSAriel Elior 	    qm_info->num_vports;
1677b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].tc_id = tc;
1678b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].wrr_group = PQ_INIT_DEFAULT_WRR_GROUP;
1679b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].rl_valid =
1680b5a9ee7cSAriel Elior 	    (pq_init_flags & PQ_INIT_PF_RL || pq_init_flags & PQ_INIT_VF_RL);
1681b5a9ee7cSAriel Elior 
1682b5a9ee7cSAriel Elior 	/* qm params accounting */
1683b5a9ee7cSAriel Elior 	qm_info->num_pqs++;
1684b5a9ee7cSAriel Elior 	if (!(pq_init_flags & PQ_INIT_SHARE_VPORT))
1685b5a9ee7cSAriel Elior 		qm_info->num_vports++;
1686b5a9ee7cSAriel Elior 
1687b5a9ee7cSAriel Elior 	if (pq_init_flags & PQ_INIT_PF_RL)
1688b5a9ee7cSAriel Elior 		qm_info->num_pf_rls++;
1689b5a9ee7cSAriel Elior 
1690b5a9ee7cSAriel Elior 	if (qm_info->num_vports > qed_init_qm_get_num_vports(p_hwfn))
1691b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1692b5a9ee7cSAriel Elior 		       "vport overflow! qm_info->num_vports %d, qm_init_get_num_vports() %d\n",
1693b5a9ee7cSAriel Elior 		       qm_info->num_vports, qed_init_qm_get_num_vports(p_hwfn));
1694b5a9ee7cSAriel Elior 
1695b5a9ee7cSAriel Elior 	if (qm_info->num_pf_rls > qed_init_qm_get_num_pf_rls(p_hwfn))
1696b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1697b5a9ee7cSAriel Elior 		       "rl overflow! qm_info->num_pf_rls %d, qm_init_get_num_pf_rls() %d\n",
1698b5a9ee7cSAriel Elior 		       qm_info->num_pf_rls, qed_init_qm_get_num_pf_rls(p_hwfn));
1699b5a9ee7cSAriel Elior }
1700b5a9ee7cSAriel Elior 
1701b5a9ee7cSAriel Elior /* get pq index according to PQ_FLAGS */
1702b5a9ee7cSAriel Elior static u16 *qed_init_qm_get_idx_from_flags(struct qed_hwfn *p_hwfn,
1703ffb057f9SManish Chopra 					   unsigned long pq_flags)
1704b5a9ee7cSAriel Elior {
1705b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1706b5a9ee7cSAriel Elior 
1707b5a9ee7cSAriel Elior 	/* Can't have multiple flags set here */
1708ffb057f9SManish Chopra 	if (bitmap_weight(&pq_flags,
1709276d43f0SDenis Bolotin 			  sizeof(pq_flags) * BITS_PER_BYTE) > 1) {
1710ffb057f9SManish Chopra 		DP_ERR(p_hwfn, "requested multiple pq flags 0x%lx\n", pq_flags);
1711b5a9ee7cSAriel Elior 		goto err;
1712276d43f0SDenis Bolotin 	}
1713b5a9ee7cSAriel Elior 
1714eb62cca9SDenis Bolotin 	if (!(qed_get_pq_flags(p_hwfn) & pq_flags)) {
1715ffb057f9SManish Chopra 		DP_ERR(p_hwfn, "pq flag 0x%lx is not set\n", pq_flags);
1716eb62cca9SDenis Bolotin 		goto err;
1717eb62cca9SDenis Bolotin 	}
1718eb62cca9SDenis Bolotin 
1719b5a9ee7cSAriel Elior 	switch (pq_flags) {
1720b5a9ee7cSAriel Elior 	case PQ_FLAGS_RLS:
1721b5a9ee7cSAriel Elior 		return &qm_info->first_rl_pq;
1722b5a9ee7cSAriel Elior 	case PQ_FLAGS_MCOS:
1723b5a9ee7cSAriel Elior 		return &qm_info->first_mcos_pq;
1724b5a9ee7cSAriel Elior 	case PQ_FLAGS_LB:
1725b5a9ee7cSAriel Elior 		return &qm_info->pure_lb_pq;
1726b5a9ee7cSAriel Elior 	case PQ_FLAGS_OOO:
1727b5a9ee7cSAriel Elior 		return &qm_info->ooo_pq;
1728b5a9ee7cSAriel Elior 	case PQ_FLAGS_ACK:
1729b5a9ee7cSAriel Elior 		return &qm_info->pure_ack_pq;
1730b5a9ee7cSAriel Elior 	case PQ_FLAGS_OFLD:
173161be82b0SDenis Bolotin 		return &qm_info->first_ofld_pq;
1732b5a9ee7cSAriel Elior 	case PQ_FLAGS_LLT:
173361be82b0SDenis Bolotin 		return &qm_info->first_llt_pq;
1734b5a9ee7cSAriel Elior 	case PQ_FLAGS_VFS:
1735b5a9ee7cSAriel Elior 		return &qm_info->first_vf_pq;
1736b5a9ee7cSAriel Elior 	default:
1737b5a9ee7cSAriel Elior 		goto err;
1738b5a9ee7cSAriel Elior 	}
1739b5a9ee7cSAriel Elior 
1740b5a9ee7cSAriel Elior err:
1741eb62cca9SDenis Bolotin 	return &qm_info->start_pq;
1742b5a9ee7cSAriel Elior }
1743b5a9ee7cSAriel Elior 
1744b5a9ee7cSAriel Elior /* save pq index in qm info */
1745b5a9ee7cSAriel Elior static void qed_init_qm_set_idx(struct qed_hwfn *p_hwfn,
1746b5a9ee7cSAriel Elior 				u32 pq_flags, u16 pq_val)
1747b5a9ee7cSAriel Elior {
1748b5a9ee7cSAriel Elior 	u16 *base_pq_idx = qed_init_qm_get_idx_from_flags(p_hwfn, pq_flags);
1749b5a9ee7cSAriel Elior 
1750b5a9ee7cSAriel Elior 	*base_pq_idx = p_hwfn->qm_info.start_pq + pq_val;
1751b5a9ee7cSAriel Elior }
1752b5a9ee7cSAriel Elior 
1753b5a9ee7cSAriel Elior /* get tx pq index, with the PQ TX base already set (ready for context init) */
1754b5a9ee7cSAriel Elior u16 qed_get_cm_pq_idx(struct qed_hwfn *p_hwfn, u32 pq_flags)
1755b5a9ee7cSAriel Elior {
1756b5a9ee7cSAriel Elior 	u16 *base_pq_idx = qed_init_qm_get_idx_from_flags(p_hwfn, pq_flags);
1757b5a9ee7cSAriel Elior 
1758b5a9ee7cSAriel Elior 	return *base_pq_idx + CM_TX_PQ_BASE;
1759b5a9ee7cSAriel Elior }
1760b5a9ee7cSAriel Elior 
1761b5a9ee7cSAriel Elior u16 qed_get_cm_pq_idx_mcos(struct qed_hwfn *p_hwfn, u8 tc)
1762b5a9ee7cSAriel Elior {
1763b5a9ee7cSAriel Elior 	u8 max_tc = qed_init_qm_get_num_tcs(p_hwfn);
1764b5a9ee7cSAriel Elior 
1765eb62cca9SDenis Bolotin 	if (max_tc == 0) {
1766eb62cca9SDenis Bolotin 		DP_ERR(p_hwfn, "pq with flag 0x%lx do not exist\n",
1767eb62cca9SDenis Bolotin 		       PQ_FLAGS_MCOS);
1768eb62cca9SDenis Bolotin 		return p_hwfn->qm_info.start_pq;
1769eb62cca9SDenis Bolotin 	}
1770eb62cca9SDenis Bolotin 
1771b5a9ee7cSAriel Elior 	if (tc > max_tc)
1772b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn, "tc %d must be smaller than %d\n", tc, max_tc);
1773b5a9ee7cSAriel Elior 
1774eb62cca9SDenis Bolotin 	return qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_MCOS) + (tc % max_tc);
1775b5a9ee7cSAriel Elior }
1776b5a9ee7cSAriel Elior 
1777b5a9ee7cSAriel Elior u16 qed_get_cm_pq_idx_vf(struct qed_hwfn *p_hwfn, u16 vf)
1778b5a9ee7cSAriel Elior {
1779b5a9ee7cSAriel Elior 	u16 max_vf = qed_init_qm_get_num_vfs(p_hwfn);
1780b5a9ee7cSAriel Elior 
1781eb62cca9SDenis Bolotin 	if (max_vf == 0) {
1782eb62cca9SDenis Bolotin 		DP_ERR(p_hwfn, "pq with flag 0x%lx do not exist\n",
1783eb62cca9SDenis Bolotin 		       PQ_FLAGS_VFS);
1784eb62cca9SDenis Bolotin 		return p_hwfn->qm_info.start_pq;
1785eb62cca9SDenis Bolotin 	}
1786eb62cca9SDenis Bolotin 
1787b5a9ee7cSAriel Elior 	if (vf > max_vf)
1788b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn, "vf %d must be smaller than %d\n", vf, max_vf);
1789b5a9ee7cSAriel Elior 
1790eb62cca9SDenis Bolotin 	return qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_VFS) + (vf % max_vf);
1791b5a9ee7cSAriel Elior }
1792b5a9ee7cSAriel Elior 
179361be82b0SDenis Bolotin u16 qed_get_cm_pq_idx_ofld_mtc(struct qed_hwfn *p_hwfn, u8 tc)
179461be82b0SDenis Bolotin {
179561be82b0SDenis Bolotin 	u16 first_ofld_pq, pq_offset;
179661be82b0SDenis Bolotin 
179761be82b0SDenis Bolotin 	first_ofld_pq = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD);
179861be82b0SDenis Bolotin 	pq_offset = (tc < qed_init_qm_get_num_mtc_tcs(p_hwfn)) ?
179961be82b0SDenis Bolotin 		    tc : PQ_INIT_DEFAULT_TC;
180061be82b0SDenis Bolotin 
180161be82b0SDenis Bolotin 	return first_ofld_pq + pq_offset;
180261be82b0SDenis Bolotin }
180361be82b0SDenis Bolotin 
180461be82b0SDenis Bolotin u16 qed_get_cm_pq_idx_llt_mtc(struct qed_hwfn *p_hwfn, u8 tc)
180561be82b0SDenis Bolotin {
180661be82b0SDenis Bolotin 	u16 first_llt_pq, pq_offset;
180761be82b0SDenis Bolotin 
180861be82b0SDenis Bolotin 	first_llt_pq = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LLT);
180961be82b0SDenis Bolotin 	pq_offset = (tc < qed_init_qm_get_num_mtc_tcs(p_hwfn)) ?
181061be82b0SDenis Bolotin 		    tc : PQ_INIT_DEFAULT_TC;
181161be82b0SDenis Bolotin 
181261be82b0SDenis Bolotin 	return first_llt_pq + pq_offset;
181361be82b0SDenis Bolotin }
181461be82b0SDenis Bolotin 
1815b5a9ee7cSAriel Elior /* Functions for creating specific types of pqs */
1816b5a9ee7cSAriel Elior static void qed_init_qm_lb_pq(struct qed_hwfn *p_hwfn)
1817b5a9ee7cSAriel Elior {
1818b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1819b5a9ee7cSAriel Elior 
1820b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_LB))
1821b5a9ee7cSAriel Elior 		return;
1822b5a9ee7cSAriel Elior 
1823b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_LB, qm_info->num_pqs);
1824b5a9ee7cSAriel Elior 	qed_init_qm_pq(p_hwfn, qm_info, PURE_LB_TC, PQ_INIT_SHARE_VPORT);
1825b5a9ee7cSAriel Elior }
1826b5a9ee7cSAriel Elior 
1827b5a9ee7cSAriel Elior static void qed_init_qm_ooo_pq(struct qed_hwfn *p_hwfn)
1828b5a9ee7cSAriel Elior {
1829b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1830b5a9ee7cSAriel Elior 
1831b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_OOO))
1832b5a9ee7cSAriel Elior 		return;
1833b5a9ee7cSAriel Elior 
1834b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_OOO, qm_info->num_pqs);
1835b5a9ee7cSAriel Elior 	qed_init_qm_pq(p_hwfn, qm_info, qm_info->ooo_tc, PQ_INIT_SHARE_VPORT);
1836b5a9ee7cSAriel Elior }
1837b5a9ee7cSAriel Elior 
1838b5a9ee7cSAriel Elior static void qed_init_qm_pure_ack_pq(struct qed_hwfn *p_hwfn)
1839b5a9ee7cSAriel Elior {
1840b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1841b5a9ee7cSAriel Elior 
1842b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_ACK))
1843b5a9ee7cSAriel Elior 		return;
1844b5a9ee7cSAriel Elior 
1845b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_ACK, qm_info->num_pqs);
1846c4259ddaSDenis Bolotin 	qed_init_qm_pq(p_hwfn, qm_info, qed_get_offload_tc(p_hwfn),
1847c4259ddaSDenis Bolotin 		       PQ_INIT_SHARE_VPORT);
1848b5a9ee7cSAriel Elior }
1849b5a9ee7cSAriel Elior 
185061be82b0SDenis Bolotin static void qed_init_qm_mtc_pqs(struct qed_hwfn *p_hwfn)
185161be82b0SDenis Bolotin {
185261be82b0SDenis Bolotin 	u8 num_tcs = qed_init_qm_get_num_mtc_tcs(p_hwfn);
185361be82b0SDenis Bolotin 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
185461be82b0SDenis Bolotin 	u8 tc;
185561be82b0SDenis Bolotin 
185661be82b0SDenis Bolotin 	/* override pq's TC if offload TC is set */
185761be82b0SDenis Bolotin 	for (tc = 0; tc < num_tcs; tc++)
185861be82b0SDenis Bolotin 		qed_init_qm_pq(p_hwfn, qm_info,
185961be82b0SDenis Bolotin 			       qed_is_offload_tc_set(p_hwfn) ?
186061be82b0SDenis Bolotin 			       p_hwfn->hw_info.offload_tc : tc,
186161be82b0SDenis Bolotin 			       PQ_INIT_SHARE_VPORT);
186261be82b0SDenis Bolotin }
186361be82b0SDenis Bolotin 
1864b5a9ee7cSAriel Elior static void qed_init_qm_offload_pq(struct qed_hwfn *p_hwfn)
1865b5a9ee7cSAriel Elior {
1866b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1867b5a9ee7cSAriel Elior 
1868b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_OFLD))
1869b5a9ee7cSAriel Elior 		return;
1870b5a9ee7cSAriel Elior 
1871b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_OFLD, qm_info->num_pqs);
187261be82b0SDenis Bolotin 	qed_init_qm_mtc_pqs(p_hwfn);
1873b5a9ee7cSAriel Elior }
1874b5a9ee7cSAriel Elior 
1875b5a9ee7cSAriel Elior static void qed_init_qm_low_latency_pq(struct qed_hwfn *p_hwfn)
1876b5a9ee7cSAriel Elior {
1877b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1878b5a9ee7cSAriel Elior 
1879b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_LLT))
1880b5a9ee7cSAriel Elior 		return;
1881b5a9ee7cSAriel Elior 
1882b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_LLT, qm_info->num_pqs);
188361be82b0SDenis Bolotin 	qed_init_qm_mtc_pqs(p_hwfn);
1884b5a9ee7cSAriel Elior }
1885b5a9ee7cSAriel Elior 
1886b5a9ee7cSAriel Elior static void qed_init_qm_mcos_pqs(struct qed_hwfn *p_hwfn)
1887b5a9ee7cSAriel Elior {
1888b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1889b5a9ee7cSAriel Elior 	u8 tc_idx;
1890b5a9ee7cSAriel Elior 
1891b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_MCOS))
1892b5a9ee7cSAriel Elior 		return;
1893b5a9ee7cSAriel Elior 
1894b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_MCOS, qm_info->num_pqs);
1895b5a9ee7cSAriel Elior 	for (tc_idx = 0; tc_idx < qed_init_qm_get_num_tcs(p_hwfn); tc_idx++)
1896b5a9ee7cSAriel Elior 		qed_init_qm_pq(p_hwfn, qm_info, tc_idx, PQ_INIT_SHARE_VPORT);
1897b5a9ee7cSAriel Elior }
1898b5a9ee7cSAriel Elior 
1899b5a9ee7cSAriel Elior static void qed_init_qm_vf_pqs(struct qed_hwfn *p_hwfn)
1900b5a9ee7cSAriel Elior {
1901b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1902b5a9ee7cSAriel Elior 	u16 vf_idx, num_vfs = qed_init_qm_get_num_vfs(p_hwfn);
1903b5a9ee7cSAriel Elior 
1904b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_VFS))
1905b5a9ee7cSAriel Elior 		return;
1906b5a9ee7cSAriel Elior 
1907b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_VFS, qm_info->num_pqs);
19081408cc1fSYuval Mintz 	qm_info->num_vf_pqs = num_vfs;
1909b5a9ee7cSAriel Elior 	for (vf_idx = 0; vf_idx < num_vfs; vf_idx++)
1910b5a9ee7cSAriel Elior 		qed_init_qm_pq(p_hwfn,
1911b5a9ee7cSAriel Elior 			       qm_info, PQ_INIT_DEFAULT_TC, PQ_INIT_VF_RL);
1912b5a9ee7cSAriel Elior }
1913fe56b9e6SYuval Mintz 
1914b5a9ee7cSAriel Elior static void qed_init_qm_rl_pqs(struct qed_hwfn *p_hwfn)
1915b5a9ee7cSAriel Elior {
1916b5a9ee7cSAriel Elior 	u16 pf_rls_idx, num_pf_rls = qed_init_qm_get_num_pf_rls(p_hwfn);
1917b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1918a64b02d5SManish Chopra 
1919b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_RLS))
1920b5a9ee7cSAriel Elior 		return;
1921b5a9ee7cSAriel Elior 
1922b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_RLS, qm_info->num_pqs);
1923b5a9ee7cSAriel Elior 	for (pf_rls_idx = 0; pf_rls_idx < num_pf_rls; pf_rls_idx++)
1924c4259ddaSDenis Bolotin 		qed_init_qm_pq(p_hwfn, qm_info, qed_get_offload_tc(p_hwfn),
1925c4259ddaSDenis Bolotin 			       PQ_INIT_PF_RL);
1926b5a9ee7cSAriel Elior }
1927b5a9ee7cSAriel Elior 
1928b5a9ee7cSAriel Elior static void qed_init_qm_pq_params(struct qed_hwfn *p_hwfn)
1929b5a9ee7cSAriel Elior {
1930b5a9ee7cSAriel Elior 	/* rate limited pqs, must come first (FW assumption) */
1931b5a9ee7cSAriel Elior 	qed_init_qm_rl_pqs(p_hwfn);
1932b5a9ee7cSAriel Elior 
1933b5a9ee7cSAriel Elior 	/* pqs for multi cos */
1934b5a9ee7cSAriel Elior 	qed_init_qm_mcos_pqs(p_hwfn);
1935b5a9ee7cSAriel Elior 
1936b5a9ee7cSAriel Elior 	/* pure loopback pq */
1937b5a9ee7cSAriel Elior 	qed_init_qm_lb_pq(p_hwfn);
1938b5a9ee7cSAriel Elior 
1939b5a9ee7cSAriel Elior 	/* out of order pq */
1940b5a9ee7cSAriel Elior 	qed_init_qm_ooo_pq(p_hwfn);
1941b5a9ee7cSAriel Elior 
1942b5a9ee7cSAriel Elior 	/* pure ack pq */
1943b5a9ee7cSAriel Elior 	qed_init_qm_pure_ack_pq(p_hwfn);
1944b5a9ee7cSAriel Elior 
1945b5a9ee7cSAriel Elior 	/* pq for offloaded protocol */
1946b5a9ee7cSAriel Elior 	qed_init_qm_offload_pq(p_hwfn);
1947b5a9ee7cSAriel Elior 
1948b5a9ee7cSAriel Elior 	/* low latency pq */
1949b5a9ee7cSAriel Elior 	qed_init_qm_low_latency_pq(p_hwfn);
1950b5a9ee7cSAriel Elior 
1951b5a9ee7cSAriel Elior 	/* done sharing vports */
1952b5a9ee7cSAriel Elior 	qed_init_qm_advance_vport(p_hwfn);
1953b5a9ee7cSAriel Elior 
1954b5a9ee7cSAriel Elior 	/* pqs for vfs */
1955b5a9ee7cSAriel Elior 	qed_init_qm_vf_pqs(p_hwfn);
1956b5a9ee7cSAriel Elior }
1957b5a9ee7cSAriel Elior 
1958b5a9ee7cSAriel Elior /* compare values of getters against resources amounts */
1959b5a9ee7cSAriel Elior static int qed_init_qm_sanity(struct qed_hwfn *p_hwfn)
1960b5a9ee7cSAriel Elior {
1961b5a9ee7cSAriel Elior 	if (qed_init_qm_get_num_vports(p_hwfn) > RESC_NUM(p_hwfn, QED_VPORT)) {
1962b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn, "requested amount of vports exceeds resource\n");
1963b5a9ee7cSAriel Elior 		return -EINVAL;
1964b5a9ee7cSAriel Elior 	}
1965b5a9ee7cSAriel Elior 
196661be82b0SDenis Bolotin 	if (qed_init_qm_get_num_pqs(p_hwfn) <= RESC_NUM(p_hwfn, QED_PQ))
196761be82b0SDenis Bolotin 		return 0;
196861be82b0SDenis Bolotin 
196961be82b0SDenis Bolotin 	if (QED_IS_ROCE_PERSONALITY(p_hwfn)) {
197061be82b0SDenis Bolotin 		p_hwfn->hw_info.multi_tc_roce_en = 0;
197161be82b0SDenis Bolotin 		DP_NOTICE(p_hwfn,
197261be82b0SDenis Bolotin 			  "multi-tc roce was disabled to reduce requested amount of pqs\n");
197361be82b0SDenis Bolotin 		if (qed_init_qm_get_num_pqs(p_hwfn) <= RESC_NUM(p_hwfn, QED_PQ))
197461be82b0SDenis Bolotin 			return 0;
1975b5a9ee7cSAriel Elior 	}
1976fe56b9e6SYuval Mintz 
197761be82b0SDenis Bolotin 	DP_ERR(p_hwfn, "requested amount of pqs exceeds resource\n");
197861be82b0SDenis Bolotin 	return -EINVAL;
1979b5a9ee7cSAriel Elior }
1980fe56b9e6SYuval Mintz 
1981b5a9ee7cSAriel Elior static void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn)
1982b5a9ee7cSAriel Elior {
1983b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1984b5a9ee7cSAriel Elior 	struct init_qm_vport_params *vport;
1985b5a9ee7cSAriel Elior 	struct init_qm_port_params *port;
1986b5a9ee7cSAriel Elior 	struct init_qm_pq_params *pq;
1987b5a9ee7cSAriel Elior 	int i, tc;
1988b5a9ee7cSAriel Elior 
1989b5a9ee7cSAriel Elior 	/* top level params */
1990b5a9ee7cSAriel Elior 	DP_VERBOSE(p_hwfn,
1991b5a9ee7cSAriel Elior 		   NETIF_MSG_HW,
199261be82b0SDenis Bolotin 		   "qm init top level params: start_pq %d, start_vport %d, pure_lb_pq %d, offload_pq %d, llt_pq %d, pure_ack_pq %d\n",
1993b5a9ee7cSAriel Elior 		   qm_info->start_pq,
1994b5a9ee7cSAriel Elior 		   qm_info->start_vport,
1995b5a9ee7cSAriel Elior 		   qm_info->pure_lb_pq,
199661be82b0SDenis Bolotin 		   qm_info->first_ofld_pq,
199761be82b0SDenis Bolotin 		   qm_info->first_llt_pq,
199861be82b0SDenis Bolotin 		   qm_info->pure_ack_pq);
1999b5a9ee7cSAriel Elior 	DP_VERBOSE(p_hwfn,
2000b5a9ee7cSAriel Elior 		   NETIF_MSG_HW,
2001b5a9ee7cSAriel Elior 		   "ooo_pq %d, first_vf_pq %d, num_pqs %d, num_vf_pqs %d, num_vports %d, max_phys_tcs_per_port %d\n",
2002b5a9ee7cSAriel Elior 		   qm_info->ooo_pq,
2003b5a9ee7cSAriel Elior 		   qm_info->first_vf_pq,
2004b5a9ee7cSAriel Elior 		   qm_info->num_pqs,
2005b5a9ee7cSAriel Elior 		   qm_info->num_vf_pqs,
2006b5a9ee7cSAriel Elior 		   qm_info->num_vports, qm_info->max_phys_tcs_per_port);
2007b5a9ee7cSAriel Elior 	DP_VERBOSE(p_hwfn,
2008b5a9ee7cSAriel Elior 		   NETIF_MSG_HW,
2009b5a9ee7cSAriel Elior 		   "pf_rl_en %d, pf_wfq_en %d, vport_rl_en %d, vport_wfq_en %d, pf_wfq %d, pf_rl %d, num_pf_rls %d, pq_flags %x\n",
2010b5a9ee7cSAriel Elior 		   qm_info->pf_rl_en,
2011b5a9ee7cSAriel Elior 		   qm_info->pf_wfq_en,
2012b5a9ee7cSAriel Elior 		   qm_info->vport_rl_en,
2013b5a9ee7cSAriel Elior 		   qm_info->vport_wfq_en,
2014b5a9ee7cSAriel Elior 		   qm_info->pf_wfq,
2015b5a9ee7cSAriel Elior 		   qm_info->pf_rl,
2016b5a9ee7cSAriel Elior 		   qm_info->num_pf_rls, qed_get_pq_flags(p_hwfn));
2017b5a9ee7cSAriel Elior 
2018b5a9ee7cSAriel Elior 	/* port table */
201978cea9ffSTomer Tayar 	for (i = 0; i < p_hwfn->cdev->num_ports_in_engine; i++) {
2020b5a9ee7cSAriel Elior 		port = &(qm_info->qm_port_params[i]);
2021b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn,
2022b5a9ee7cSAriel Elior 			   NETIF_MSG_HW,
2023b5a9ee7cSAriel Elior 			   "port idx %d, active %d, active_phys_tcs %d, num_pbf_cmd_lines %d, num_btb_blocks %d, reserved %d\n",
2024b5a9ee7cSAriel Elior 			   i,
2025b5a9ee7cSAriel Elior 			   port->active,
2026b5a9ee7cSAriel Elior 			   port->active_phys_tcs,
2027b5a9ee7cSAriel Elior 			   port->num_pbf_cmd_lines,
2028b5a9ee7cSAriel Elior 			   port->num_btb_blocks, port->reserved);
2029b5a9ee7cSAriel Elior 	}
2030b5a9ee7cSAriel Elior 
2031b5a9ee7cSAriel Elior 	/* vport table */
2032b5a9ee7cSAriel Elior 	for (i = 0; i < qm_info->num_vports; i++) {
2033b5a9ee7cSAriel Elior 		vport = &(qm_info->qm_vport_params[i]);
2034b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn,
2035b5a9ee7cSAriel Elior 			   NETIF_MSG_HW,
2036b5a9ee7cSAriel Elior 			   "vport idx %d, vport_rl %d, wfq %d, first_tx_pq_id [ ",
2037b5a9ee7cSAriel Elior 			   qm_info->start_vport + i,
2038b5a9ee7cSAriel Elior 			   vport->vport_rl, vport->vport_wfq);
2039b5a9ee7cSAriel Elior 		for (tc = 0; tc < NUM_OF_TCS; tc++)
2040b5a9ee7cSAriel Elior 			DP_VERBOSE(p_hwfn,
2041b5a9ee7cSAriel Elior 				   NETIF_MSG_HW,
2042b5a9ee7cSAriel Elior 				   "%d ", vport->first_tx_pq_id[tc]);
2043b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "]\n");
2044b5a9ee7cSAriel Elior 	}
2045b5a9ee7cSAriel Elior 
2046b5a9ee7cSAriel Elior 	/* pq table */
2047b5a9ee7cSAriel Elior 	for (i = 0; i < qm_info->num_pqs; i++) {
2048b5a9ee7cSAriel Elior 		pq = &(qm_info->qm_pq_params[i]);
2049b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn,
2050b5a9ee7cSAriel Elior 			   NETIF_MSG_HW,
205150bc60cbSMichal Kalderon 			   "pq idx %d, port %d, vport_id %d, tc %d, wrr_grp %d, rl_valid %d\n",
2052b5a9ee7cSAriel Elior 			   qm_info->start_pq + i,
205350bc60cbSMichal Kalderon 			   pq->port_id,
2054b5a9ee7cSAriel Elior 			   pq->vport_id,
2055b5a9ee7cSAriel Elior 			   pq->tc_id, pq->wrr_group, pq->rl_valid);
2056b5a9ee7cSAriel Elior 	}
2057b5a9ee7cSAriel Elior }
2058b5a9ee7cSAriel Elior 
2059b5a9ee7cSAriel Elior static void qed_init_qm_info(struct qed_hwfn *p_hwfn)
2060b5a9ee7cSAriel Elior {
2061b5a9ee7cSAriel Elior 	/* reset params required for init run */
2062b5a9ee7cSAriel Elior 	qed_init_qm_reset_params(p_hwfn);
2063b5a9ee7cSAriel Elior 
2064b5a9ee7cSAriel Elior 	/* init QM top level params */
2065b5a9ee7cSAriel Elior 	qed_init_qm_params(p_hwfn);
2066b5a9ee7cSAriel Elior 
2067b5a9ee7cSAriel Elior 	/* init QM port params */
2068b5a9ee7cSAriel Elior 	qed_init_qm_port_params(p_hwfn);
2069b5a9ee7cSAriel Elior 
2070b5a9ee7cSAriel Elior 	/* init QM vport params */
2071b5a9ee7cSAriel Elior 	qed_init_qm_vport_params(p_hwfn);
2072b5a9ee7cSAriel Elior 
2073b5a9ee7cSAriel Elior 	/* init QM physical queue params */
2074b5a9ee7cSAriel Elior 	qed_init_qm_pq_params(p_hwfn);
2075b5a9ee7cSAriel Elior 
2076b5a9ee7cSAriel Elior 	/* display all that init */
2077b5a9ee7cSAriel Elior 	qed_dp_init_qm_params(p_hwfn);
2078fe56b9e6SYuval Mintz }
2079fe56b9e6SYuval Mintz 
208039651abdSSudarsana Reddy Kalluru /* This function reconfigures the QM pf on the fly.
208139651abdSSudarsana Reddy Kalluru  * For this purpose we:
208239651abdSSudarsana Reddy Kalluru  * 1. reconfigure the QM database
2083a2e7699eSTomer Tayar  * 2. set new values to runtime array
208439651abdSSudarsana Reddy Kalluru  * 3. send an sdm_qm_cmd through the rbc interface to stop the QM
208539651abdSSudarsana Reddy Kalluru  * 4. activate init tool in QM_PF stage
208639651abdSSudarsana Reddy Kalluru  * 5. send an sdm_qm_cmd through rbc interface to release the QM
208739651abdSSudarsana Reddy Kalluru  */
208839651abdSSudarsana Reddy Kalluru int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
208939651abdSSudarsana Reddy Kalluru {
209039651abdSSudarsana Reddy Kalluru 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
209139651abdSSudarsana Reddy Kalluru 	bool b_rc;
209239651abdSSudarsana Reddy Kalluru 	int rc;
209339651abdSSudarsana Reddy Kalluru 
209439651abdSSudarsana Reddy Kalluru 	/* initialize qed's qm data structure */
2095b5a9ee7cSAriel Elior 	qed_init_qm_info(p_hwfn);
209639651abdSSudarsana Reddy Kalluru 
209739651abdSSudarsana Reddy Kalluru 	/* stop PF's qm queues */
209839651abdSSudarsana Reddy Kalluru 	spin_lock_bh(&qm_lock);
209939651abdSSudarsana Reddy Kalluru 	b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, false, true,
210039651abdSSudarsana Reddy Kalluru 				    qm_info->start_pq, qm_info->num_pqs);
210139651abdSSudarsana Reddy Kalluru 	spin_unlock_bh(&qm_lock);
210239651abdSSudarsana Reddy Kalluru 	if (!b_rc)
210339651abdSSudarsana Reddy Kalluru 		return -EINVAL;
210439651abdSSudarsana Reddy Kalluru 
210539651abdSSudarsana Reddy Kalluru 	/* clear the QM_PF runtime phase leftovers from previous init */
210639651abdSSudarsana Reddy Kalluru 	qed_init_clear_rt_data(p_hwfn);
210739651abdSSudarsana Reddy Kalluru 
210839651abdSSudarsana Reddy Kalluru 	/* prepare QM portion of runtime array */
2109da090917STomer Tayar 	qed_qm_init_pf(p_hwfn, p_ptt, false);
211039651abdSSudarsana Reddy Kalluru 
211139651abdSSudarsana Reddy Kalluru 	/* activate init tool on runtime array */
211239651abdSSudarsana Reddy Kalluru 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, p_hwfn->rel_pf_id,
211339651abdSSudarsana Reddy Kalluru 			  p_hwfn->hw_info.hw_mode);
211439651abdSSudarsana Reddy Kalluru 	if (rc)
211539651abdSSudarsana Reddy Kalluru 		return rc;
211639651abdSSudarsana Reddy Kalluru 
211739651abdSSudarsana Reddy Kalluru 	/* start PF's qm queues */
211839651abdSSudarsana Reddy Kalluru 	spin_lock_bh(&qm_lock);
211939651abdSSudarsana Reddy Kalluru 	b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, true, true,
212039651abdSSudarsana Reddy Kalluru 				    qm_info->start_pq, qm_info->num_pqs);
212139651abdSSudarsana Reddy Kalluru 	spin_unlock_bh(&qm_lock);
212239651abdSSudarsana Reddy Kalluru 	if (!b_rc)
212339651abdSSudarsana Reddy Kalluru 		return -EINVAL;
212439651abdSSudarsana Reddy Kalluru 
212539651abdSSudarsana Reddy Kalluru 	return 0;
212639651abdSSudarsana Reddy Kalluru }
212739651abdSSudarsana Reddy Kalluru 
2128b5a9ee7cSAriel Elior static int qed_alloc_qm_data(struct qed_hwfn *p_hwfn)
2129b5a9ee7cSAriel Elior {
2130b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
2131b5a9ee7cSAriel Elior 	int rc;
2132b5a9ee7cSAriel Elior 
2133b5a9ee7cSAriel Elior 	rc = qed_init_qm_sanity(p_hwfn);
2134b5a9ee7cSAriel Elior 	if (rc)
2135b5a9ee7cSAriel Elior 		goto alloc_err;
2136b5a9ee7cSAriel Elior 
21376396bb22SKees Cook 	qm_info->qm_pq_params = kcalloc(qed_init_qm_get_num_pqs(p_hwfn),
21386396bb22SKees Cook 					sizeof(*qm_info->qm_pq_params),
2139b5a9ee7cSAriel Elior 					GFP_KERNEL);
2140b5a9ee7cSAriel Elior 	if (!qm_info->qm_pq_params)
2141b5a9ee7cSAriel Elior 		goto alloc_err;
2142b5a9ee7cSAriel Elior 
21436396bb22SKees Cook 	qm_info->qm_vport_params = kcalloc(qed_init_qm_get_num_vports(p_hwfn),
21446396bb22SKees Cook 					   sizeof(*qm_info->qm_vport_params),
2145b5a9ee7cSAriel Elior 					   GFP_KERNEL);
2146b5a9ee7cSAriel Elior 	if (!qm_info->qm_vport_params)
2147b5a9ee7cSAriel Elior 		goto alloc_err;
2148b5a9ee7cSAriel Elior 
21496396bb22SKees Cook 	qm_info->qm_port_params = kcalloc(p_hwfn->cdev->num_ports_in_engine,
21506396bb22SKees Cook 					  sizeof(*qm_info->qm_port_params),
2151b5a9ee7cSAriel Elior 					  GFP_KERNEL);
2152b5a9ee7cSAriel Elior 	if (!qm_info->qm_port_params)
2153b5a9ee7cSAriel Elior 		goto alloc_err;
2154b5a9ee7cSAriel Elior 
21556396bb22SKees Cook 	qm_info->wfq_data = kcalloc(qed_init_qm_get_num_vports(p_hwfn),
21566396bb22SKees Cook 				    sizeof(*qm_info->wfq_data),
2157b5a9ee7cSAriel Elior 				    GFP_KERNEL);
2158b5a9ee7cSAriel Elior 	if (!qm_info->wfq_data)
2159b5a9ee7cSAriel Elior 		goto alloc_err;
2160b5a9ee7cSAriel Elior 
2161b5a9ee7cSAriel Elior 	return 0;
2162b5a9ee7cSAriel Elior 
2163b5a9ee7cSAriel Elior alloc_err:
2164b5a9ee7cSAriel Elior 	DP_NOTICE(p_hwfn, "Failed to allocate memory for QM params\n");
2165b5a9ee7cSAriel Elior 	qed_qm_info_free(p_hwfn);
2166b5a9ee7cSAriel Elior 	return -ENOMEM;
2167b5a9ee7cSAriel Elior }
2168b5a9ee7cSAriel Elior 
2169fe56b9e6SYuval Mintz int qed_resc_alloc(struct qed_dev *cdev)
2170fe56b9e6SYuval Mintz {
2171f9dc4d1fSRam Amrani 	u32 rdma_tasks, excess_tasks;
2172f9dc4d1fSRam Amrani 	u32 line_count;
2173fe56b9e6SYuval Mintz 	int i, rc = 0;
2174fe56b9e6SYuval Mintz 
21750db711bbSMintz, Yuval 	if (IS_VF(cdev)) {
21760db711bbSMintz, Yuval 		for_each_hwfn(cdev, i) {
21770db711bbSMintz, Yuval 			rc = qed_l2_alloc(&cdev->hwfns[i]);
21780db711bbSMintz, Yuval 			if (rc)
21791408cc1fSYuval Mintz 				return rc;
21800db711bbSMintz, Yuval 		}
21810db711bbSMintz, Yuval 		return rc;
21820db711bbSMintz, Yuval 	}
21831408cc1fSYuval Mintz 
2184fe56b9e6SYuval Mintz 	cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL);
2185fe56b9e6SYuval Mintz 	if (!cdev->fw_data)
2186fe56b9e6SYuval Mintz 		return -ENOMEM;
2187fe56b9e6SYuval Mintz 
2188fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2189fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
2190dbb799c3SYuval Mintz 		u32 n_eqes, num_cons;
2191fe56b9e6SYuval Mintz 
219236907cd5SAriel Elior 		/* Initialize the doorbell recovery mechanism */
219336907cd5SAriel Elior 		rc = qed_db_recovery_setup(p_hwfn);
219436907cd5SAriel Elior 		if (rc)
219536907cd5SAriel Elior 			goto alloc_err;
219636907cd5SAriel Elior 
2197fe56b9e6SYuval Mintz 		/* First allocate the context manager structure */
2198fe56b9e6SYuval Mintz 		rc = qed_cxt_mngr_alloc(p_hwfn);
2199fe56b9e6SYuval Mintz 		if (rc)
2200fe56b9e6SYuval Mintz 			goto alloc_err;
2201fe56b9e6SYuval Mintz 
2202fe56b9e6SYuval Mintz 		/* Set the HW cid/tid numbers (in the contest manager)
2203fe56b9e6SYuval Mintz 		 * Must be done prior to any further computations.
2204fe56b9e6SYuval Mintz 		 */
2205f9dc4d1fSRam Amrani 		rc = qed_cxt_set_pf_params(p_hwfn, RDMA_MAX_TIDS);
2206fe56b9e6SYuval Mintz 		if (rc)
2207fe56b9e6SYuval Mintz 			goto alloc_err;
2208fe56b9e6SYuval Mintz 
2209b5a9ee7cSAriel Elior 		rc = qed_alloc_qm_data(p_hwfn);
2210fe56b9e6SYuval Mintz 		if (rc)
2211fe56b9e6SYuval Mintz 			goto alloc_err;
2212fe56b9e6SYuval Mintz 
2213b5a9ee7cSAriel Elior 		/* init qm info */
2214b5a9ee7cSAriel Elior 		qed_init_qm_info(p_hwfn);
2215b5a9ee7cSAriel Elior 
2216fe56b9e6SYuval Mintz 		/* Compute the ILT client partition */
2217f9dc4d1fSRam Amrani 		rc = qed_cxt_cfg_ilt_compute(p_hwfn, &line_count);
2218f9dc4d1fSRam Amrani 		if (rc) {
2219f9dc4d1fSRam Amrani 			DP_NOTICE(p_hwfn,
2220f9dc4d1fSRam Amrani 				  "too many ILT lines; re-computing with less lines\n");
2221f9dc4d1fSRam Amrani 			/* In case there are not enough ILT lines we reduce the
2222f9dc4d1fSRam Amrani 			 * number of RDMA tasks and re-compute.
2223f9dc4d1fSRam Amrani 			 */
2224f9dc4d1fSRam Amrani 			excess_tasks =
2225f9dc4d1fSRam Amrani 			    qed_cxt_cfg_ilt_compute_excess(p_hwfn, line_count);
2226f9dc4d1fSRam Amrani 			if (!excess_tasks)
2227f9dc4d1fSRam Amrani 				goto alloc_err;
2228f9dc4d1fSRam Amrani 
2229f9dc4d1fSRam Amrani 			rdma_tasks = RDMA_MAX_TIDS - excess_tasks;
2230f9dc4d1fSRam Amrani 			rc = qed_cxt_set_pf_params(p_hwfn, rdma_tasks);
2231fe56b9e6SYuval Mintz 			if (rc)
2232fe56b9e6SYuval Mintz 				goto alloc_err;
2233fe56b9e6SYuval Mintz 
2234f9dc4d1fSRam Amrani 			rc = qed_cxt_cfg_ilt_compute(p_hwfn, &line_count);
2235f9dc4d1fSRam Amrani 			if (rc) {
2236f9dc4d1fSRam Amrani 				DP_ERR(p_hwfn,
2237f9dc4d1fSRam Amrani 				       "failed ILT compute. Requested too many lines: %u\n",
2238f9dc4d1fSRam Amrani 				       line_count);
2239f9dc4d1fSRam Amrani 
2240f9dc4d1fSRam Amrani 				goto alloc_err;
2241f9dc4d1fSRam Amrani 			}
2242f9dc4d1fSRam Amrani 		}
2243f9dc4d1fSRam Amrani 
2244fe56b9e6SYuval Mintz 		/* CID map / ILT shadow table / T2
2245fe56b9e6SYuval Mintz 		 * The talbes sizes are determined by the computations above
2246fe56b9e6SYuval Mintz 		 */
2247fe56b9e6SYuval Mintz 		rc = qed_cxt_tables_alloc(p_hwfn);
2248fe56b9e6SYuval Mintz 		if (rc)
2249fe56b9e6SYuval Mintz 			goto alloc_err;
2250fe56b9e6SYuval Mintz 
2251fe56b9e6SYuval Mintz 		/* SPQ, must follow ILT because initializes SPQ context */
2252fe56b9e6SYuval Mintz 		rc = qed_spq_alloc(p_hwfn);
2253fe56b9e6SYuval Mintz 		if (rc)
2254fe56b9e6SYuval Mintz 			goto alloc_err;
2255fe56b9e6SYuval Mintz 
2256fe56b9e6SYuval Mintz 		/* SP status block allocation */
2257fe56b9e6SYuval Mintz 		p_hwfn->p_dpc_ptt = qed_get_reserved_ptt(p_hwfn,
2258fe56b9e6SYuval Mintz 							 RESERVED_PTT_DPC);
2259fe56b9e6SYuval Mintz 
2260fe56b9e6SYuval Mintz 		rc = qed_int_alloc(p_hwfn, p_hwfn->p_main_ptt);
2261fe56b9e6SYuval Mintz 		if (rc)
2262fe56b9e6SYuval Mintz 			goto alloc_err;
2263fe56b9e6SYuval Mintz 
226432a47e72SYuval Mintz 		rc = qed_iov_alloc(p_hwfn);
226532a47e72SYuval Mintz 		if (rc)
226632a47e72SYuval Mintz 			goto alloc_err;
226732a47e72SYuval Mintz 
2268fe56b9e6SYuval Mintz 		/* EQ */
2269dbb799c3SYuval Mintz 		n_eqes = qed_chain_get_capacity(&p_hwfn->p_spq->chain);
2270c851a9dcSKalderon, Michal 		if (QED_IS_RDMA_PERSONALITY(p_hwfn)) {
227167b40dccSKalderon, Michal 			enum protocol_type rdma_proto;
227267b40dccSKalderon, Michal 
227367b40dccSKalderon, Michal 			if (QED_IS_ROCE_PERSONALITY(p_hwfn))
227467b40dccSKalderon, Michal 				rdma_proto = PROTOCOLID_ROCE;
227567b40dccSKalderon, Michal 			else
227667b40dccSKalderon, Michal 				rdma_proto = PROTOCOLID_IWARP;
227767b40dccSKalderon, Michal 
2278dbb799c3SYuval Mintz 			num_cons = qed_cxt_get_proto_cid_count(p_hwfn,
227967b40dccSKalderon, Michal 							       rdma_proto,
22808c93beafSYuval Mintz 							       NULL) * 2;
2281dbb799c3SYuval Mintz 			n_eqes += num_cons + 2 * MAX_NUM_VFS_BB;
2282dbb799c3SYuval Mintz 		} else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
2283dbb799c3SYuval Mintz 			num_cons =
2284dbb799c3SYuval Mintz 			    qed_cxt_get_proto_cid_count(p_hwfn,
22858c93beafSYuval Mintz 							PROTOCOLID_ISCSI,
22868c93beafSYuval Mintz 							NULL);
2287dbb799c3SYuval Mintz 			n_eqes += 2 * num_cons;
2288dbb799c3SYuval Mintz 		}
2289dbb799c3SYuval Mintz 
2290dbb799c3SYuval Mintz 		if (n_eqes > 0xFFFF) {
2291dbb799c3SYuval Mintz 			DP_ERR(p_hwfn,
2292dbb799c3SYuval Mintz 			       "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n",
2293dbb799c3SYuval Mintz 			       n_eqes, 0xFFFF);
22943587cb87STomer Tayar 			goto alloc_no_mem;
22959b15acbfSDan Carpenter 		}
2296dbb799c3SYuval Mintz 
22973587cb87STomer Tayar 		rc = qed_eq_alloc(p_hwfn, (u16) n_eqes);
22983587cb87STomer Tayar 		if (rc)
22993587cb87STomer Tayar 			goto alloc_err;
2300fe56b9e6SYuval Mintz 
23013587cb87STomer Tayar 		rc = qed_consq_alloc(p_hwfn);
23023587cb87STomer Tayar 		if (rc)
23033587cb87STomer Tayar 			goto alloc_err;
2304fe56b9e6SYuval Mintz 
23050db711bbSMintz, Yuval 		rc = qed_l2_alloc(p_hwfn);
23060db711bbSMintz, Yuval 		if (rc)
23070db711bbSMintz, Yuval 			goto alloc_err;
23080db711bbSMintz, Yuval 
23090a7fb11cSYuval Mintz #ifdef CONFIG_QED_LL2
23100a7fb11cSYuval Mintz 		if (p_hwfn->using_ll2) {
23113587cb87STomer Tayar 			rc = qed_ll2_alloc(p_hwfn);
23123587cb87STomer Tayar 			if (rc)
23133587cb87STomer Tayar 				goto alloc_err;
23140a7fb11cSYuval Mintz 		}
23150a7fb11cSYuval Mintz #endif
23161e128c81SArun Easi 
23171e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE) {
23183587cb87STomer Tayar 			rc = qed_fcoe_alloc(p_hwfn);
23193587cb87STomer Tayar 			if (rc)
23203587cb87STomer Tayar 				goto alloc_err;
23211e128c81SArun Easi 		}
23221e128c81SArun Easi 
2323fc831825SYuval Mintz 		if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
23243587cb87STomer Tayar 			rc = qed_iscsi_alloc(p_hwfn);
23253587cb87STomer Tayar 			if (rc)
23263587cb87STomer Tayar 				goto alloc_err;
23273587cb87STomer Tayar 			rc = qed_ooo_alloc(p_hwfn);
23283587cb87STomer Tayar 			if (rc)
23293587cb87STomer Tayar 				goto alloc_err;
2330fc831825SYuval Mintz 		}
23310a7fb11cSYuval Mintz 
2332291d57f6SMichal Kalderon 		if (QED_IS_RDMA_PERSONALITY(p_hwfn)) {
2333291d57f6SMichal Kalderon 			rc = qed_rdma_info_alloc(p_hwfn);
2334291d57f6SMichal Kalderon 			if (rc)
2335291d57f6SMichal Kalderon 				goto alloc_err;
2336291d57f6SMichal Kalderon 		}
2337291d57f6SMichal Kalderon 
2338fe56b9e6SYuval Mintz 		/* DMA info initialization */
2339fe56b9e6SYuval Mintz 		rc = qed_dmae_info_alloc(p_hwfn);
23402591c280SJoe Perches 		if (rc)
2341fe56b9e6SYuval Mintz 			goto alloc_err;
234239651abdSSudarsana Reddy Kalluru 
234339651abdSSudarsana Reddy Kalluru 		/* DCBX initialization */
234439651abdSSudarsana Reddy Kalluru 		rc = qed_dcbx_info_alloc(p_hwfn);
23452591c280SJoe Perches 		if (rc)
234639651abdSSudarsana Reddy Kalluru 			goto alloc_err;
2347a3f72307SDenis Bolotin 
2348a3f72307SDenis Bolotin 		rc = qed_dbg_alloc_user_data(p_hwfn);
2349a3f72307SDenis Bolotin 		if (rc)
2350a3f72307SDenis Bolotin 			goto alloc_err;
235139651abdSSudarsana Reddy Kalluru 	}
2352fe56b9e6SYuval Mintz 
235379284adeSMichal Kalderon 	rc = qed_llh_alloc(cdev);
235479284adeSMichal Kalderon 	if (rc) {
235579284adeSMichal Kalderon 		DP_NOTICE(cdev,
235679284adeSMichal Kalderon 			  "Failed to allocate memory for the llh_info structure\n");
235779284adeSMichal Kalderon 		goto alloc_err;
235879284adeSMichal Kalderon 	}
235979284adeSMichal Kalderon 
2360fe56b9e6SYuval Mintz 	cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
23612591c280SJoe Perches 	if (!cdev->reset_stats)
236283aeb933SYuval Mintz 		goto alloc_no_mem;
2363fe56b9e6SYuval Mintz 
2364fe56b9e6SYuval Mintz 	return 0;
2365fe56b9e6SYuval Mintz 
2366dbb799c3SYuval Mintz alloc_no_mem:
2367dbb799c3SYuval Mintz 	rc = -ENOMEM;
2368fe56b9e6SYuval Mintz alloc_err:
2369fe56b9e6SYuval Mintz 	qed_resc_free(cdev);
2370fe56b9e6SYuval Mintz 	return rc;
2371fe56b9e6SYuval Mintz }
2372fe56b9e6SYuval Mintz 
2373fe56b9e6SYuval Mintz void qed_resc_setup(struct qed_dev *cdev)
2374fe56b9e6SYuval Mintz {
2375fe56b9e6SYuval Mintz 	int i;
2376fe56b9e6SYuval Mintz 
23770db711bbSMintz, Yuval 	if (IS_VF(cdev)) {
23780db711bbSMintz, Yuval 		for_each_hwfn(cdev, i)
23790db711bbSMintz, Yuval 			qed_l2_setup(&cdev->hwfns[i]);
23801408cc1fSYuval Mintz 		return;
23810db711bbSMintz, Yuval 	}
23821408cc1fSYuval Mintz 
2383fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2384fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
2385fe56b9e6SYuval Mintz 
2386fe56b9e6SYuval Mintz 		qed_cxt_mngr_setup(p_hwfn);
2387fe56b9e6SYuval Mintz 		qed_spq_setup(p_hwfn);
23883587cb87STomer Tayar 		qed_eq_setup(p_hwfn);
23893587cb87STomer Tayar 		qed_consq_setup(p_hwfn);
2390fe56b9e6SYuval Mintz 
2391fe56b9e6SYuval Mintz 		/* Read shadow of current MFW mailbox */
2392fe56b9e6SYuval Mintz 		qed_mcp_read_mb(p_hwfn, p_hwfn->p_main_ptt);
2393fe56b9e6SYuval Mintz 		memcpy(p_hwfn->mcp_info->mfw_mb_shadow,
2394fe56b9e6SYuval Mintz 		       p_hwfn->mcp_info->mfw_mb_cur,
2395fe56b9e6SYuval Mintz 		       p_hwfn->mcp_info->mfw_mb_length);
2396fe56b9e6SYuval Mintz 
2397fe56b9e6SYuval Mintz 		qed_int_setup(p_hwfn, p_hwfn->p_main_ptt);
239832a47e72SYuval Mintz 
23990db711bbSMintz, Yuval 		qed_l2_setup(p_hwfn);
24001ee240e3SMintz, Yuval 		qed_iov_setup(p_hwfn);
24010a7fb11cSYuval Mintz #ifdef CONFIG_QED_LL2
24020a7fb11cSYuval Mintz 		if (p_hwfn->using_ll2)
24033587cb87STomer Tayar 			qed_ll2_setup(p_hwfn);
24040a7fb11cSYuval Mintz #endif
24051e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
24063587cb87STomer Tayar 			qed_fcoe_setup(p_hwfn);
24071e128c81SArun Easi 
24081d6cff4fSYuval Mintz 		if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
24093587cb87STomer Tayar 			qed_iscsi_setup(p_hwfn);
24103587cb87STomer Tayar 			qed_ooo_setup(p_hwfn);
24111d6cff4fSYuval Mintz 		}
2412fe56b9e6SYuval Mintz 	}
2413fe56b9e6SYuval Mintz }
2414fe56b9e6SYuval Mintz 
2415fe56b9e6SYuval Mintz #define FINAL_CLEANUP_POLL_CNT          (100)
2416fe56b9e6SYuval Mintz #define FINAL_CLEANUP_POLL_TIME         (10)
2417fe56b9e6SYuval Mintz int qed_final_cleanup(struct qed_hwfn *p_hwfn,
24180b55e27dSYuval Mintz 		      struct qed_ptt *p_ptt, u16 id, bool is_vf)
2419fe56b9e6SYuval Mintz {
2420fe56b9e6SYuval Mintz 	u32 command = 0, addr, count = FINAL_CLEANUP_POLL_CNT;
2421fe56b9e6SYuval Mintz 	int rc = -EBUSY;
2422fe56b9e6SYuval Mintz 
2423fc48b7a6SYuval Mintz 	addr = GTT_BAR0_MAP_REG_USDM_RAM +
2424fc48b7a6SYuval Mintz 		USTORM_FLR_FINAL_ACK_OFFSET(p_hwfn->rel_pf_id);
2425fe56b9e6SYuval Mintz 
24260b55e27dSYuval Mintz 	if (is_vf)
24270b55e27dSYuval Mintz 		id += 0x10;
24280b55e27dSYuval Mintz 
2429fc48b7a6SYuval Mintz 	command |= X_FINAL_CLEANUP_AGG_INT <<
2430fc48b7a6SYuval Mintz 		SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT;
2431fc48b7a6SYuval Mintz 	command |= 1 << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT;
2432fc48b7a6SYuval Mintz 	command |= id << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT;
2433fc48b7a6SYuval Mintz 	command |= SDM_COMP_TYPE_AGG_INT << SDM_OP_GEN_COMP_TYPE_SHIFT;
2434fe56b9e6SYuval Mintz 
2435fe56b9e6SYuval Mintz 	/* Make sure notification is not set before initiating final cleanup */
2436fe56b9e6SYuval Mintz 	if (REG_RD(p_hwfn, addr)) {
24371a635e48SYuval Mintz 		DP_NOTICE(p_hwfn,
2438fe56b9e6SYuval Mintz 			  "Unexpected; Found final cleanup notification before initiating final cleanup\n");
2439fe56b9e6SYuval Mintz 		REG_WR(p_hwfn, addr, 0);
2440fe56b9e6SYuval Mintz 	}
2441fe56b9e6SYuval Mintz 
2442fe56b9e6SYuval Mintz 	DP_VERBOSE(p_hwfn, QED_MSG_IOV,
2443d602de8eSJoe Perches 		   "Sending final cleanup for PFVF[%d] [Command %08x]\n",
2444fe56b9e6SYuval Mintz 		   id, command);
2445fe56b9e6SYuval Mintz 
2446fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, XSDM_REG_OPERATION_GEN, command);
2447fe56b9e6SYuval Mintz 
2448fe56b9e6SYuval Mintz 	/* Poll until completion */
2449fe56b9e6SYuval Mintz 	while (!REG_RD(p_hwfn, addr) && count--)
2450fe56b9e6SYuval Mintz 		msleep(FINAL_CLEANUP_POLL_TIME);
2451fe56b9e6SYuval Mintz 
2452fe56b9e6SYuval Mintz 	if (REG_RD(p_hwfn, addr))
2453fe56b9e6SYuval Mintz 		rc = 0;
2454fe56b9e6SYuval Mintz 	else
2455fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn,
2456fe56b9e6SYuval Mintz 			  "Failed to receive FW final cleanup notification\n");
2457fe56b9e6SYuval Mintz 
2458fe56b9e6SYuval Mintz 	/* Cleanup afterwards */
2459fe56b9e6SYuval Mintz 	REG_WR(p_hwfn, addr, 0);
2460fe56b9e6SYuval Mintz 
2461fe56b9e6SYuval Mintz 	return rc;
2462fe56b9e6SYuval Mintz }
2463fe56b9e6SYuval Mintz 
24649c79ddaaSMintz, Yuval static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn)
2465fe56b9e6SYuval Mintz {
2466fe56b9e6SYuval Mintz 	int hw_mode = 0;
2467fe56b9e6SYuval Mintz 
24689c79ddaaSMintz, Yuval 	if (QED_IS_BB_B0(p_hwfn->cdev)) {
24699c79ddaaSMintz, Yuval 		hw_mode |= 1 << MODE_BB;
24709c79ddaaSMintz, Yuval 	} else if (QED_IS_AH(p_hwfn->cdev)) {
24719c79ddaaSMintz, Yuval 		hw_mode |= 1 << MODE_K2;
24729c79ddaaSMintz, Yuval 	} else {
24739c79ddaaSMintz, Yuval 		DP_NOTICE(p_hwfn, "Unknown chip type %#x\n",
24749c79ddaaSMintz, Yuval 			  p_hwfn->cdev->type);
24759c79ddaaSMintz, Yuval 		return -EINVAL;
24769c79ddaaSMintz, Yuval 	}
2477fe56b9e6SYuval Mintz 
247878cea9ffSTomer Tayar 	switch (p_hwfn->cdev->num_ports_in_engine) {
2479fe56b9e6SYuval Mintz 	case 1:
2480fe56b9e6SYuval Mintz 		hw_mode |= 1 << MODE_PORTS_PER_ENG_1;
2481fe56b9e6SYuval Mintz 		break;
2482fe56b9e6SYuval Mintz 	case 2:
2483fe56b9e6SYuval Mintz 		hw_mode |= 1 << MODE_PORTS_PER_ENG_2;
2484fe56b9e6SYuval Mintz 		break;
2485fe56b9e6SYuval Mintz 	case 4:
2486fe56b9e6SYuval Mintz 		hw_mode |= 1 << MODE_PORTS_PER_ENG_4;
2487fe56b9e6SYuval Mintz 		break;
2488fe56b9e6SYuval Mintz 	default:
2489fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "num_ports_in_engine = %d not supported\n",
249078cea9ffSTomer Tayar 			  p_hwfn->cdev->num_ports_in_engine);
24919c79ddaaSMintz, Yuval 		return -EINVAL;
2492fe56b9e6SYuval Mintz 	}
2493fe56b9e6SYuval Mintz 
24940bc5fe85SSudarsana Reddy Kalluru 	if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits))
2495fc48b7a6SYuval Mintz 		hw_mode |= 1 << MODE_MF_SD;
24960bc5fe85SSudarsana Reddy Kalluru 	else
2497fc48b7a6SYuval Mintz 		hw_mode |= 1 << MODE_MF_SI;
2498fe56b9e6SYuval Mintz 
2499fe56b9e6SYuval Mintz 	hw_mode |= 1 << MODE_ASIC;
2500fe56b9e6SYuval Mintz 
25011af9dcf7SYuval Mintz 	if (p_hwfn->cdev->num_hwfns > 1)
25021af9dcf7SYuval Mintz 		hw_mode |= 1 << MODE_100G;
25031af9dcf7SYuval Mintz 
2504fe56b9e6SYuval Mintz 	p_hwfn->hw_info.hw_mode = hw_mode;
25051af9dcf7SYuval Mintz 
25061af9dcf7SYuval Mintz 	DP_VERBOSE(p_hwfn, (NETIF_MSG_PROBE | NETIF_MSG_IFUP),
25071af9dcf7SYuval Mintz 		   "Configuring function for hw_mode: 0x%08x\n",
25081af9dcf7SYuval Mintz 		   p_hwfn->hw_info.hw_mode);
25099c79ddaaSMintz, Yuval 
25109c79ddaaSMintz, Yuval 	return 0;
2511fe56b9e6SYuval Mintz }
2512fe56b9e6SYuval Mintz 
2513fe56b9e6SYuval Mintz /* Init run time data for all PFs on an engine. */
2514fe56b9e6SYuval Mintz static void qed_init_cau_rt_data(struct qed_dev *cdev)
2515fe56b9e6SYuval Mintz {
2516fe56b9e6SYuval Mintz 	u32 offset = CAU_REG_SB_VAR_MEMORY_RT_OFFSET;
2517d031548eSMintz, Yuval 	int i, igu_sb_id;
2518fe56b9e6SYuval Mintz 
2519fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2520fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
2521fe56b9e6SYuval Mintz 		struct qed_igu_info *p_igu_info;
2522fe56b9e6SYuval Mintz 		struct qed_igu_block *p_block;
2523fe56b9e6SYuval Mintz 		struct cau_sb_entry sb_entry;
2524fe56b9e6SYuval Mintz 
2525fe56b9e6SYuval Mintz 		p_igu_info = p_hwfn->hw_info.p_igu_info;
2526fe56b9e6SYuval Mintz 
2527d031548eSMintz, Yuval 		for (igu_sb_id = 0;
2528d031548eSMintz, Yuval 		     igu_sb_id < QED_MAPPING_MEMORY_SIZE(cdev); igu_sb_id++) {
2529d031548eSMintz, Yuval 			p_block = &p_igu_info->entry[igu_sb_id];
2530d031548eSMintz, Yuval 
2531fe56b9e6SYuval Mintz 			if (!p_block->is_pf)
2532fe56b9e6SYuval Mintz 				continue;
2533fe56b9e6SYuval Mintz 
2534fe56b9e6SYuval Mintz 			qed_init_cau_sb_entry(p_hwfn, &sb_entry,
25351a635e48SYuval Mintz 					      p_block->function_id, 0, 0);
2536d031548eSMintz, Yuval 			STORE_RT_REG_AGG(p_hwfn, offset + igu_sb_id * 2,
2537d031548eSMintz, Yuval 					 sb_entry);
2538fe56b9e6SYuval Mintz 		}
2539fe56b9e6SYuval Mintz 	}
2540fe56b9e6SYuval Mintz }
2541fe56b9e6SYuval Mintz 
254260afed72STomer Tayar static void qed_init_cache_line_size(struct qed_hwfn *p_hwfn,
254360afed72STomer Tayar 				     struct qed_ptt *p_ptt)
254460afed72STomer Tayar {
254560afed72STomer Tayar 	u32 val, wr_mbs, cache_line_size;
254660afed72STomer Tayar 
254760afed72STomer Tayar 	val = qed_rd(p_hwfn, p_ptt, PSWRQ2_REG_WR_MBS0);
254860afed72STomer Tayar 	switch (val) {
254960afed72STomer Tayar 	case 0:
255060afed72STomer Tayar 		wr_mbs = 128;
255160afed72STomer Tayar 		break;
255260afed72STomer Tayar 	case 1:
255360afed72STomer Tayar 		wr_mbs = 256;
255460afed72STomer Tayar 		break;
255560afed72STomer Tayar 	case 2:
255660afed72STomer Tayar 		wr_mbs = 512;
255760afed72STomer Tayar 		break;
255860afed72STomer Tayar 	default:
255960afed72STomer Tayar 		DP_INFO(p_hwfn,
256060afed72STomer Tayar 			"Unexpected value of PSWRQ2_REG_WR_MBS0 [0x%x]. Avoid configuring PGLUE_B_REG_CACHE_LINE_SIZE.\n",
256160afed72STomer Tayar 			val);
256260afed72STomer Tayar 		return;
256360afed72STomer Tayar 	}
256460afed72STomer Tayar 
256560afed72STomer Tayar 	cache_line_size = min_t(u32, L1_CACHE_BYTES, wr_mbs);
256660afed72STomer Tayar 	switch (cache_line_size) {
256760afed72STomer Tayar 	case 32:
256860afed72STomer Tayar 		val = 0;
256960afed72STomer Tayar 		break;
257060afed72STomer Tayar 	case 64:
257160afed72STomer Tayar 		val = 1;
257260afed72STomer Tayar 		break;
257360afed72STomer Tayar 	case 128:
257460afed72STomer Tayar 		val = 2;
257560afed72STomer Tayar 		break;
257660afed72STomer Tayar 	case 256:
257760afed72STomer Tayar 		val = 3;
257860afed72STomer Tayar 		break;
257960afed72STomer Tayar 	default:
258060afed72STomer Tayar 		DP_INFO(p_hwfn,
258160afed72STomer Tayar 			"Unexpected value of cache line size [0x%x]. Avoid configuring PGLUE_B_REG_CACHE_LINE_SIZE.\n",
258260afed72STomer Tayar 			cache_line_size);
258360afed72STomer Tayar 	}
258460afed72STomer Tayar 
258560afed72STomer Tayar 	if (L1_CACHE_BYTES > wr_mbs)
258660afed72STomer Tayar 		DP_INFO(p_hwfn,
258760afed72STomer Tayar 			"The cache line size for padding is suboptimal for performance [OS cache line size 0x%x, wr mbs 0x%x]\n",
258860afed72STomer Tayar 			L1_CACHE_BYTES, wr_mbs);
258960afed72STomer Tayar 
259060afed72STomer Tayar 	STORE_RT_REG(p_hwfn, PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET, val);
2591fc6575bcSMintz, Yuval 	if (val > 0) {
2592fc6575bcSMintz, Yuval 		STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET, val);
2593fc6575bcSMintz, Yuval 		STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET, val);
2594fc6575bcSMintz, Yuval 	}
259560afed72STomer Tayar }
259660afed72STomer Tayar 
2597fe56b9e6SYuval Mintz static int qed_hw_init_common(struct qed_hwfn *p_hwfn,
25981a635e48SYuval Mintz 			      struct qed_ptt *p_ptt, int hw_mode)
2599fe56b9e6SYuval Mintz {
2600fe56b9e6SYuval Mintz 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
2601fe56b9e6SYuval Mintz 	struct qed_qm_common_rt_init_params params;
2602fe56b9e6SYuval Mintz 	struct qed_dev *cdev = p_hwfn->cdev;
26039c79ddaaSMintz, Yuval 	u8 vf_id, max_num_vfs;
2604dbb799c3SYuval Mintz 	u16 num_pfs, pf_id;
26051408cc1fSYuval Mintz 	u32 concrete_fid;
2606fe56b9e6SYuval Mintz 	int rc = 0;
2607fe56b9e6SYuval Mintz 
2608fe56b9e6SYuval Mintz 	qed_init_cau_rt_data(cdev);
2609fe56b9e6SYuval Mintz 
2610fe56b9e6SYuval Mintz 	/* Program GTT windows */
2611fe56b9e6SYuval Mintz 	qed_gtt_init(p_hwfn);
2612fe56b9e6SYuval Mintz 
2613fe56b9e6SYuval Mintz 	if (p_hwfn->mcp_info) {
2614fe56b9e6SYuval Mintz 		if (p_hwfn->mcp_info->func_info.bandwidth_max)
2615c7281d59SGustavo A. R. Silva 			qm_info->pf_rl_en = true;
2616fe56b9e6SYuval Mintz 		if (p_hwfn->mcp_info->func_info.bandwidth_min)
2617c7281d59SGustavo A. R. Silva 			qm_info->pf_wfq_en = true;
2618fe56b9e6SYuval Mintz 	}
2619fe56b9e6SYuval Mintz 
2620fe56b9e6SYuval Mintz 	memset(&params, 0, sizeof(params));
262178cea9ffSTomer Tayar 	params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engine;
2622fe56b9e6SYuval Mintz 	params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port;
2623fe56b9e6SYuval Mintz 	params.pf_rl_en = qm_info->pf_rl_en;
2624fe56b9e6SYuval Mintz 	params.pf_wfq_en = qm_info->pf_wfq_en;
2625fe56b9e6SYuval Mintz 	params.vport_rl_en = qm_info->vport_rl_en;
2626fe56b9e6SYuval Mintz 	params.vport_wfq_en = qm_info->vport_wfq_en;
2627fe56b9e6SYuval Mintz 	params.port_params = qm_info->qm_port_params;
2628fe56b9e6SYuval Mintz 
2629fe56b9e6SYuval Mintz 	qed_qm_common_rt_init(p_hwfn, &params);
2630fe56b9e6SYuval Mintz 
2631fe56b9e6SYuval Mintz 	qed_cxt_hw_init_common(p_hwfn);
2632fe56b9e6SYuval Mintz 
263360afed72STomer Tayar 	qed_init_cache_line_size(p_hwfn, p_ptt);
263460afed72STomer Tayar 
2635fe56b9e6SYuval Mintz 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_ENGINE, ANY_PHASE_ID, hw_mode);
26361a635e48SYuval Mintz 	if (rc)
2637fe56b9e6SYuval Mintz 		return rc;
2638fe56b9e6SYuval Mintz 
2639fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, PSWRQ2_REG_L2P_VALIDATE_VFID, 0);
2640fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_USE_CLIENTID_IN_TAG, 1);
2641fe56b9e6SYuval Mintz 
2642dbb799c3SYuval Mintz 	if (QED_IS_BB(p_hwfn->cdev)) {
2643dbb799c3SYuval Mintz 		num_pfs = NUM_OF_ENG_PFS(p_hwfn->cdev);
2644dbb799c3SYuval Mintz 		for (pf_id = 0; pf_id < num_pfs; pf_id++) {
2645dbb799c3SYuval Mintz 			qed_fid_pretend(p_hwfn, p_ptt, pf_id);
2646dbb799c3SYuval Mintz 			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
2647dbb799c3SYuval Mintz 			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
2648dbb799c3SYuval Mintz 		}
2649dbb799c3SYuval Mintz 		/* pretend to original PF */
2650dbb799c3SYuval Mintz 		qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id);
2651dbb799c3SYuval Mintz 	}
2652fe56b9e6SYuval Mintz 
26539c79ddaaSMintz, Yuval 	max_num_vfs = QED_IS_AH(cdev) ? MAX_NUM_VFS_K2 : MAX_NUM_VFS_BB;
26549c79ddaaSMintz, Yuval 	for (vf_id = 0; vf_id < max_num_vfs; vf_id++) {
26551408cc1fSYuval Mintz 		concrete_fid = qed_vfid_to_concrete(p_hwfn, vf_id);
26561408cc1fSYuval Mintz 		qed_fid_pretend(p_hwfn, p_ptt, (u16) concrete_fid);
26571408cc1fSYuval Mintz 		qed_wr(p_hwfn, p_ptt, CCFC_REG_STRONG_ENABLE_VF, 0x1);
265805fafbfbSYuval Mintz 		qed_wr(p_hwfn, p_ptt, CCFC_REG_WEAK_ENABLE_VF, 0x0);
265905fafbfbSYuval Mintz 		qed_wr(p_hwfn, p_ptt, TCFC_REG_STRONG_ENABLE_VF, 0x1);
266005fafbfbSYuval Mintz 		qed_wr(p_hwfn, p_ptt, TCFC_REG_WEAK_ENABLE_VF, 0x0);
26611408cc1fSYuval Mintz 	}
26621408cc1fSYuval Mintz 	/* pretend to original PF */
26631408cc1fSYuval Mintz 	qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id);
26641408cc1fSYuval Mintz 
2665fe56b9e6SYuval Mintz 	return rc;
2666fe56b9e6SYuval Mintz }
2667fe56b9e6SYuval Mintz 
266851ff1725SRam Amrani static int
266951ff1725SRam Amrani qed_hw_init_dpi_size(struct qed_hwfn *p_hwfn,
267051ff1725SRam Amrani 		     struct qed_ptt *p_ptt, u32 pwm_region_size, u32 n_cpus)
267151ff1725SRam Amrani {
2672107392b7SRam Amrani 	u32 dpi_bit_shift, dpi_count, dpi_page_size;
267351ff1725SRam Amrani 	u32 min_dpis;
2674107392b7SRam Amrani 	u32 n_wids;
267551ff1725SRam Amrani 
267651ff1725SRam Amrani 	/* Calculate DPI size */
2677107392b7SRam Amrani 	n_wids = max_t(u32, QED_MIN_WIDS, n_cpus);
2678107392b7SRam Amrani 	dpi_page_size = QED_WID_SIZE * roundup_pow_of_two(n_wids);
2679107392b7SRam Amrani 	dpi_page_size = (dpi_page_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
268051ff1725SRam Amrani 	dpi_bit_shift = ilog2(dpi_page_size / 4096);
268151ff1725SRam Amrani 	dpi_count = pwm_region_size / dpi_page_size;
268251ff1725SRam Amrani 
268351ff1725SRam Amrani 	min_dpis = p_hwfn->pf_params.rdma_pf_params.min_dpis;
268451ff1725SRam Amrani 	min_dpis = max_t(u32, QED_MIN_DPIS, min_dpis);
268551ff1725SRam Amrani 
268651ff1725SRam Amrani 	p_hwfn->dpi_size = dpi_page_size;
268751ff1725SRam Amrani 	p_hwfn->dpi_count = dpi_count;
268851ff1725SRam Amrani 
268951ff1725SRam Amrani 	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPI_BIT_SHIFT, dpi_bit_shift);
269051ff1725SRam Amrani 
269151ff1725SRam Amrani 	if (dpi_count < min_dpis)
269251ff1725SRam Amrani 		return -EINVAL;
269351ff1725SRam Amrani 
269451ff1725SRam Amrani 	return 0;
269551ff1725SRam Amrani }
269651ff1725SRam Amrani 
269751ff1725SRam Amrani enum QED_ROCE_EDPM_MODE {
269851ff1725SRam Amrani 	QED_ROCE_EDPM_MODE_ENABLE = 0,
269951ff1725SRam Amrani 	QED_ROCE_EDPM_MODE_FORCE_ON = 1,
270051ff1725SRam Amrani 	QED_ROCE_EDPM_MODE_DISABLE = 2,
270151ff1725SRam Amrani };
270251ff1725SRam Amrani 
2703a1b469b8SAriel Elior bool qed_edpm_enabled(struct qed_hwfn *p_hwfn)
2704a1b469b8SAriel Elior {
2705a1b469b8SAriel Elior 	if (p_hwfn->dcbx_no_edpm || p_hwfn->db_bar_no_edpm)
2706a1b469b8SAriel Elior 		return false;
2707a1b469b8SAriel Elior 
2708a1b469b8SAriel Elior 	return true;
2709a1b469b8SAriel Elior }
2710a1b469b8SAriel Elior 
271151ff1725SRam Amrani static int
271251ff1725SRam Amrani qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
271351ff1725SRam Amrani {
271451ff1725SRam Amrani 	u32 pwm_regsize, norm_regsize;
271551ff1725SRam Amrani 	u32 non_pwm_conn, min_addr_reg1;
271620b1bd96SRam Amrani 	u32 db_bar_size, n_cpus = 1;
271751ff1725SRam Amrani 	u32 roce_edpm_mode;
271851ff1725SRam Amrani 	u32 pf_dems_shift;
271951ff1725SRam Amrani 	int rc = 0;
272051ff1725SRam Amrani 	u8 cond;
272151ff1725SRam Amrani 
272215582962SRahul Verma 	db_bar_size = qed_hw_bar_size(p_hwfn, p_ptt, BAR_ID_1);
272351ff1725SRam Amrani 	if (p_hwfn->cdev->num_hwfns > 1)
272451ff1725SRam Amrani 		db_bar_size /= 2;
272551ff1725SRam Amrani 
272651ff1725SRam Amrani 	/* Calculate doorbell regions */
272751ff1725SRam Amrani 	non_pwm_conn = qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_CORE) +
272851ff1725SRam Amrani 		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_CORE,
272951ff1725SRam Amrani 						   NULL) +
273051ff1725SRam Amrani 		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
273151ff1725SRam Amrani 						   NULL);
2732a82dadbcSRam Amrani 	norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE);
273351ff1725SRam Amrani 	min_addr_reg1 = norm_regsize / 4096;
273451ff1725SRam Amrani 	pwm_regsize = db_bar_size - norm_regsize;
273551ff1725SRam Amrani 
273651ff1725SRam Amrani 	/* Check that the normal and PWM sizes are valid */
273751ff1725SRam Amrani 	if (db_bar_size < norm_regsize) {
273851ff1725SRam Amrani 		DP_ERR(p_hwfn->cdev,
273951ff1725SRam Amrani 		       "Doorbell BAR size 0x%x is too small (normal region is 0x%0x )\n",
274051ff1725SRam Amrani 		       db_bar_size, norm_regsize);
274151ff1725SRam Amrani 		return -EINVAL;
274251ff1725SRam Amrani 	}
274351ff1725SRam Amrani 
274451ff1725SRam Amrani 	if (pwm_regsize < QED_MIN_PWM_REGION) {
274551ff1725SRam Amrani 		DP_ERR(p_hwfn->cdev,
274651ff1725SRam Amrani 		       "PWM region size 0x%0x is too small. Should be at least 0x%0x (Doorbell BAR size is 0x%x and normal region size is 0x%0x)\n",
274751ff1725SRam Amrani 		       pwm_regsize,
274851ff1725SRam Amrani 		       QED_MIN_PWM_REGION, db_bar_size, norm_regsize);
274951ff1725SRam Amrani 		return -EINVAL;
275051ff1725SRam Amrani 	}
275151ff1725SRam Amrani 
275251ff1725SRam Amrani 	/* Calculate number of DPIs */
275351ff1725SRam Amrani 	roce_edpm_mode = p_hwfn->pf_params.rdma_pf_params.roce_edpm_mode;
275451ff1725SRam Amrani 	if ((roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE) ||
275551ff1725SRam Amrani 	    ((roce_edpm_mode == QED_ROCE_EDPM_MODE_FORCE_ON))) {
275651ff1725SRam Amrani 		/* Either EDPM is mandatory, or we are attempting to allocate a
275751ff1725SRam Amrani 		 * WID per CPU.
275851ff1725SRam Amrani 		 */
2759c2dedf87SRam Amrani 		n_cpus = num_present_cpus();
276051ff1725SRam Amrani 		rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus);
276151ff1725SRam Amrani 	}
276251ff1725SRam Amrani 
276351ff1725SRam Amrani 	cond = (rc && (roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE)) ||
276451ff1725SRam Amrani 	       (roce_edpm_mode == QED_ROCE_EDPM_MODE_DISABLE);
276551ff1725SRam Amrani 	if (cond || p_hwfn->dcbx_no_edpm) {
276651ff1725SRam Amrani 		/* Either EDPM is disabled from user configuration, or it is
276751ff1725SRam Amrani 		 * disabled via DCBx, or it is not mandatory and we failed to
276851ff1725SRam Amrani 		 * allocated a WID per CPU.
276951ff1725SRam Amrani 		 */
277051ff1725SRam Amrani 		n_cpus = 1;
277151ff1725SRam Amrani 		rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus);
277251ff1725SRam Amrani 
277351ff1725SRam Amrani 		if (cond)
277451ff1725SRam Amrani 			qed_rdma_dpm_bar(p_hwfn, p_ptt);
277551ff1725SRam Amrani 	}
277651ff1725SRam Amrani 
277720b1bd96SRam Amrani 	p_hwfn->wid_count = (u16) n_cpus;
277820b1bd96SRam Amrani 
277951ff1725SRam Amrani 	DP_INFO(p_hwfn,
2780a1b469b8SAriel Elior 		"doorbell bar: normal_region_size=%d, pwm_region_size=%d, dpi_size=%d, dpi_count=%d, roce_edpm=%s, page_size=%lu\n",
278151ff1725SRam Amrani 		norm_regsize,
278251ff1725SRam Amrani 		pwm_regsize,
278351ff1725SRam Amrani 		p_hwfn->dpi_size,
278451ff1725SRam Amrani 		p_hwfn->dpi_count,
2785a1b469b8SAriel Elior 		(!qed_edpm_enabled(p_hwfn)) ?
2786a1b469b8SAriel Elior 		"disabled" : "enabled", PAGE_SIZE);
278751ff1725SRam Amrani 
278851ff1725SRam Amrani 	if (rc) {
278951ff1725SRam Amrani 		DP_ERR(p_hwfn,
279051ff1725SRam Amrani 		       "Failed to allocate enough DPIs. Allocated %d but the current minimum is %d.\n",
279151ff1725SRam Amrani 		       p_hwfn->dpi_count,
279251ff1725SRam Amrani 		       p_hwfn->pf_params.rdma_pf_params.min_dpis);
279351ff1725SRam Amrani 		return -EINVAL;
279451ff1725SRam Amrani 	}
279551ff1725SRam Amrani 
279651ff1725SRam Amrani 	p_hwfn->dpi_start_offset = norm_regsize;
279751ff1725SRam Amrani 
279851ff1725SRam Amrani 	/* DEMS size is configured log2 of DWORDs, hence the division by 4 */
279951ff1725SRam Amrani 	pf_dems_shift = ilog2(QED_PF_DEMS_SIZE / 4);
280051ff1725SRam Amrani 	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_ICID_BIT_SHIFT_NORM, pf_dems_shift);
280151ff1725SRam Amrani 	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_MIN_ADDR_REG1, min_addr_reg1);
280251ff1725SRam Amrani 
280351ff1725SRam Amrani 	return 0;
280451ff1725SRam Amrani }
280551ff1725SRam Amrani 
2806fe56b9e6SYuval Mintz static int qed_hw_init_port(struct qed_hwfn *p_hwfn,
28071a635e48SYuval Mintz 			    struct qed_ptt *p_ptt, int hw_mode)
2808fe56b9e6SYuval Mintz {
2809fc6575bcSMintz, Yuval 	int rc = 0;
2810fc6575bcSMintz, Yuval 
281179284adeSMichal Kalderon 	/* In CMT the gate should be cleared by the 2nd hwfn */
281279284adeSMichal Kalderon 	if (!QED_IS_CMT(p_hwfn->cdev) || !IS_LEAD_HWFN(p_hwfn))
281379284adeSMichal Kalderon 		STORE_RT_REG(p_hwfn, NIG_REG_BRB_GATE_DNTFWD_PORT_RT_OFFSET, 0);
281479284adeSMichal Kalderon 
2815fc6575bcSMintz, Yuval 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode);
2816fc6575bcSMintz, Yuval 	if (rc)
2817fc6575bcSMintz, Yuval 		return rc;
2818fc6575bcSMintz, Yuval 
2819fc6575bcSMintz, Yuval 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE, 0);
2820fc6575bcSMintz, Yuval 
2821fc6575bcSMintz, Yuval 	return 0;
2822fe56b9e6SYuval Mintz }
2823fe56b9e6SYuval Mintz 
2824fe56b9e6SYuval Mintz static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
2825fe56b9e6SYuval Mintz 			  struct qed_ptt *p_ptt,
282619968430SChopra, Manish 			  struct qed_tunnel_info *p_tunn,
2827fe56b9e6SYuval Mintz 			  int hw_mode,
2828fe56b9e6SYuval Mintz 			  bool b_hw_start,
2829fe56b9e6SYuval Mintz 			  enum qed_int_mode int_mode,
2830fe56b9e6SYuval Mintz 			  bool allow_npar_tx_switch)
2831fe56b9e6SYuval Mintz {
2832fe56b9e6SYuval Mintz 	u8 rel_pf_id = p_hwfn->rel_pf_id;
2833fe56b9e6SYuval Mintz 	int rc = 0;
2834fe56b9e6SYuval Mintz 
2835fe56b9e6SYuval Mintz 	if (p_hwfn->mcp_info) {
2836fe56b9e6SYuval Mintz 		struct qed_mcp_function_info *p_info;
2837fe56b9e6SYuval Mintz 
2838fe56b9e6SYuval Mintz 		p_info = &p_hwfn->mcp_info->func_info;
2839fe56b9e6SYuval Mintz 		if (p_info->bandwidth_min)
2840fe56b9e6SYuval Mintz 			p_hwfn->qm_info.pf_wfq = p_info->bandwidth_min;
2841fe56b9e6SYuval Mintz 
2842fe56b9e6SYuval Mintz 		/* Update rate limit once we'll actually have a link */
28434b01e519SManish Chopra 		p_hwfn->qm_info.pf_rl = 100000;
2844fe56b9e6SYuval Mintz 	}
2845fe56b9e6SYuval Mintz 
284615582962SRahul Verma 	qed_cxt_hw_init_pf(p_hwfn, p_ptt);
2847fe56b9e6SYuval Mintz 
2848fe56b9e6SYuval Mintz 	qed_int_igu_init_rt(p_hwfn);
2849fe56b9e6SYuval Mintz 
2850fe56b9e6SYuval Mintz 	/* Set VLAN in NIG if needed */
28511a635e48SYuval Mintz 	if (hw_mode & BIT(MODE_MF_SD)) {
2852fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Configuring LLH_FUNC_TAG\n");
2853fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET, 1);
2854fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET,
2855fe56b9e6SYuval Mintz 			     p_hwfn->hw_info.ovlan);
2856cac6f691SSudarsana Reddy Kalluru 
2857cac6f691SSudarsana Reddy Kalluru 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
2858cac6f691SSudarsana Reddy Kalluru 			   "Configuring LLH_FUNC_FILTER_HDR_SEL\n");
2859cac6f691SSudarsana Reddy Kalluru 		STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET,
2860cac6f691SSudarsana Reddy Kalluru 			     1);
2861fe56b9e6SYuval Mintz 	}
2862fe56b9e6SYuval Mintz 
2863fe56b9e6SYuval Mintz 	/* Enable classification by MAC if needed */
28641a635e48SYuval Mintz 	if (hw_mode & BIT(MODE_MF_SI)) {
2865fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
2866fe56b9e6SYuval Mintz 			   "Configuring TAGMAC_CLS_TYPE\n");
2867fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn,
2868fe56b9e6SYuval Mintz 			     NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET, 1);
2869fe56b9e6SYuval Mintz 	}
2870fe56b9e6SYuval Mintz 
2871a2e7699eSTomer Tayar 	/* Protocol Configuration */
2872dbb799c3SYuval Mintz 	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET,
2873dbb799c3SYuval Mintz 		     (p_hwfn->hw_info.personality == QED_PCI_ISCSI) ? 1 : 0);
28741e128c81SArun Easi 	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET,
28751e128c81SArun Easi 		     (p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0);
2876fe56b9e6SYuval Mintz 	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0);
2877fe56b9e6SYuval Mintz 
2878da090917STomer Tayar 	/* Sanity check before the PF init sequence that uses DMAE */
2879da090917STomer Tayar 	rc = qed_dmae_sanity(p_hwfn, p_ptt, "pf_phase");
2880da090917STomer Tayar 	if (rc)
2881da090917STomer Tayar 		return rc;
2882da090917STomer Tayar 
2883fe56b9e6SYuval Mintz 	/* PF Init sequence */
2884fe56b9e6SYuval Mintz 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_PF, rel_pf_id, hw_mode);
2885fe56b9e6SYuval Mintz 	if (rc)
2886fe56b9e6SYuval Mintz 		return rc;
2887fe56b9e6SYuval Mintz 
2888fe56b9e6SYuval Mintz 	/* QM_PF Init sequence (may be invoked separately e.g. for DCB) */
2889fe56b9e6SYuval Mintz 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, rel_pf_id, hw_mode);
2890fe56b9e6SYuval Mintz 	if (rc)
2891fe56b9e6SYuval Mintz 		return rc;
2892fe56b9e6SYuval Mintz 
2893fe56b9e6SYuval Mintz 	/* Pure runtime initializations - directly to the HW  */
2894fe56b9e6SYuval Mintz 	qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true);
2895fe56b9e6SYuval Mintz 
289651ff1725SRam Amrani 	rc = qed_hw_init_pf_doorbell_bar(p_hwfn, p_ptt);
289751ff1725SRam Amrani 	if (rc)
289851ff1725SRam Amrani 		return rc;
289951ff1725SRam Amrani 
290079284adeSMichal Kalderon 	/* Use the leading hwfn since in CMT only NIG #0 is operational */
290179284adeSMichal Kalderon 	if (IS_LEAD_HWFN(p_hwfn)) {
290279284adeSMichal Kalderon 		rc = qed_llh_hw_init_pf(p_hwfn, p_ptt);
290379284adeSMichal Kalderon 		if (rc)
290479284adeSMichal Kalderon 			return rc;
290579284adeSMichal Kalderon 	}
290679284adeSMichal Kalderon 
2907fe56b9e6SYuval Mintz 	if (b_hw_start) {
2908fe56b9e6SYuval Mintz 		/* enable interrupts */
2909fe56b9e6SYuval Mintz 		qed_int_igu_enable(p_hwfn, p_ptt, int_mode);
2910fe56b9e6SYuval Mintz 
2911fe56b9e6SYuval Mintz 		/* send function start command */
29124f64675fSManish Chopra 		rc = qed_sp_pf_start(p_hwfn, p_ptt, p_tunn,
2913831bfb0eSYuval Mintz 				     allow_npar_tx_switch);
29141e128c81SArun Easi 		if (rc) {
2915fe56b9e6SYuval Mintz 			DP_NOTICE(p_hwfn, "Function start ramrod failed\n");
29161e128c81SArun Easi 			return rc;
29171e128c81SArun Easi 		}
29181e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE) {
29191e128c81SArun Easi 			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TAG1, BIT(2));
29201e128c81SArun Easi 			qed_wr(p_hwfn, p_ptt,
29211e128c81SArun Easi 			       PRS_REG_PKT_LEN_STAT_TAGS_NOT_COUNTED_FIRST,
29221e128c81SArun Easi 			       0x100);
29231e128c81SArun Easi 		}
2924fe56b9e6SYuval Mintz 	}
2925fe56b9e6SYuval Mintz 	return rc;
2926fe56b9e6SYuval Mintz }
2927fe56b9e6SYuval Mintz 
2928666db486STomer Tayar int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn,
2929666db486STomer Tayar 			       struct qed_ptt *p_ptt, bool b_enable)
2930fe56b9e6SYuval Mintz {
2931666db486STomer Tayar 	u32 delay_idx = 0, val, set_val = b_enable ? 1 : 0;
2932fe56b9e6SYuval Mintz 
2933666db486STomer Tayar 	/* Configure the PF's internal FID_enable for master transactions */
2934666db486STomer Tayar 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val);
2935fe56b9e6SYuval Mintz 
2936666db486STomer Tayar 	/* Wait until value is set - try for 1 second every 50us */
2937fe56b9e6SYuval Mintz 	for (delay_idx = 0; delay_idx < 20000; delay_idx++) {
2938fe56b9e6SYuval Mintz 		val = qed_rd(p_hwfn, p_ptt,
2939fe56b9e6SYuval Mintz 			     PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
2940fe56b9e6SYuval Mintz 		if (val == set_val)
2941fe56b9e6SYuval Mintz 			break;
2942fe56b9e6SYuval Mintz 
2943fe56b9e6SYuval Mintz 		usleep_range(50, 60);
2944fe56b9e6SYuval Mintz 	}
2945fe56b9e6SYuval Mintz 
2946fe56b9e6SYuval Mintz 	if (val != set_val) {
2947fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn,
2948fe56b9e6SYuval Mintz 			  "PFID_ENABLE_MASTER wasn't changed after a second\n");
2949fe56b9e6SYuval Mintz 		return -EAGAIN;
2950fe56b9e6SYuval Mintz 	}
2951fe56b9e6SYuval Mintz 
2952fe56b9e6SYuval Mintz 	return 0;
2953fe56b9e6SYuval Mintz }
2954fe56b9e6SYuval Mintz 
2955fe56b9e6SYuval Mintz static void qed_reset_mb_shadow(struct qed_hwfn *p_hwfn,
2956fe56b9e6SYuval Mintz 				struct qed_ptt *p_main_ptt)
2957fe56b9e6SYuval Mintz {
2958fe56b9e6SYuval Mintz 	/* Read shadow of current MFW mailbox */
2959fe56b9e6SYuval Mintz 	qed_mcp_read_mb(p_hwfn, p_main_ptt);
2960fe56b9e6SYuval Mintz 	memcpy(p_hwfn->mcp_info->mfw_mb_shadow,
29611a635e48SYuval Mintz 	       p_hwfn->mcp_info->mfw_mb_cur, p_hwfn->mcp_info->mfw_mb_length);
2962fe56b9e6SYuval Mintz }
2963fe56b9e6SYuval Mintz 
29645d24bcf1STomer Tayar static void
29655d24bcf1STomer Tayar qed_fill_load_req_params(struct qed_load_req_params *p_load_req,
29665d24bcf1STomer Tayar 			 struct qed_drv_load_params *p_drv_load)
29675d24bcf1STomer Tayar {
29685d24bcf1STomer Tayar 	memset(p_load_req, 0, sizeof(*p_load_req));
29695d24bcf1STomer Tayar 
29705d24bcf1STomer Tayar 	p_load_req->drv_role = p_drv_load->is_crash_kernel ?
29715d24bcf1STomer Tayar 			       QED_DRV_ROLE_KDUMP : QED_DRV_ROLE_OS;
29725d24bcf1STomer Tayar 	p_load_req->timeout_val = p_drv_load->mfw_timeout_val;
29735d24bcf1STomer Tayar 	p_load_req->avoid_eng_reset = p_drv_load->avoid_eng_reset;
29745d24bcf1STomer Tayar 	p_load_req->override_force_load = p_drv_load->override_force_load;
29755d24bcf1STomer Tayar }
29765d24bcf1STomer Tayar 
2977eaf3c0c6SChopra, Manish static int qed_vf_start(struct qed_hwfn *p_hwfn,
2978eaf3c0c6SChopra, Manish 			struct qed_hw_init_params *p_params)
2979eaf3c0c6SChopra, Manish {
2980eaf3c0c6SChopra, Manish 	if (p_params->p_tunn) {
2981eaf3c0c6SChopra, Manish 		qed_vf_set_vf_start_tunn_update_param(p_params->p_tunn);
2982eaf3c0c6SChopra, Manish 		qed_vf_pf_tunnel_param_update(p_hwfn, p_params->p_tunn);
2983eaf3c0c6SChopra, Manish 	}
2984eaf3c0c6SChopra, Manish 
2985c7281d59SGustavo A. R. Silva 	p_hwfn->b_int_enabled = true;
2986eaf3c0c6SChopra, Manish 
2987eaf3c0c6SChopra, Manish 	return 0;
2988eaf3c0c6SChopra, Manish }
2989eaf3c0c6SChopra, Manish 
2990666db486STomer Tayar static void qed_pglueb_clear_err(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
2991666db486STomer Tayar {
2992666db486STomer Tayar 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR,
2993666db486STomer Tayar 	       BIT(p_hwfn->abs_pf_id));
2994666db486STomer Tayar }
2995666db486STomer Tayar 
2996c0c2d0b4SMintz, Yuval int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
2997fe56b9e6SYuval Mintz {
29985d24bcf1STomer Tayar 	struct qed_load_req_params load_req_params;
299950fdf601SSudarsana Reddy Kalluru 	u32 load_code, resp, param, drv_mb_param;
30000fefbfbaSSudarsana Kalluru 	bool b_default_mtu = true;
30010fefbfbaSSudarsana Kalluru 	struct qed_hwfn *p_hwfn;
3002666db486STomer Tayar 	int rc = 0, i;
3003cac6f691SSudarsana Reddy Kalluru 	u16 ether_type;
3004fe56b9e6SYuval Mintz 
3005c0c2d0b4SMintz, Yuval 	if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) {
3006bb13ace7SSudarsana Reddy Kalluru 		DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n");
3007bb13ace7SSudarsana Reddy Kalluru 		return -EINVAL;
3008bb13ace7SSudarsana Reddy Kalluru 	}
3009bb13ace7SSudarsana Reddy Kalluru 
30101408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
3011c0c2d0b4SMintz, Yuval 		rc = qed_init_fw_data(cdev, p_params->bin_fw_data);
30121a635e48SYuval Mintz 		if (rc)
3013fe56b9e6SYuval Mintz 			return rc;
30141408cc1fSYuval Mintz 	}
3015fe56b9e6SYuval Mintz 
3016fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
3017666db486STomer Tayar 		p_hwfn = &cdev->hwfns[i];
3018fe56b9e6SYuval Mintz 
30190fefbfbaSSudarsana Kalluru 		/* If management didn't provide a default, set one of our own */
30200fefbfbaSSudarsana Kalluru 		if (!p_hwfn->hw_info.mtu) {
30210fefbfbaSSudarsana Kalluru 			p_hwfn->hw_info.mtu = 1500;
30220fefbfbaSSudarsana Kalluru 			b_default_mtu = false;
30230fefbfbaSSudarsana Kalluru 		}
30240fefbfbaSSudarsana Kalluru 
30251408cc1fSYuval Mintz 		if (IS_VF(cdev)) {
3026eaf3c0c6SChopra, Manish 			qed_vf_start(p_hwfn, p_params);
30271408cc1fSYuval Mintz 			continue;
30281408cc1fSYuval Mintz 		}
30291408cc1fSYuval Mintz 
30309c79ddaaSMintz, Yuval 		rc = qed_calc_hw_mode(p_hwfn);
30319c79ddaaSMintz, Yuval 		if (rc)
30329c79ddaaSMintz, Yuval 			return rc;
3033fe56b9e6SYuval Mintz 
3034cac6f691SSudarsana Reddy Kalluru 		if (IS_PF(cdev) && (test_bit(QED_MF_8021Q_TAGGING,
3035cac6f691SSudarsana Reddy Kalluru 					     &cdev->mf_bits) ||
3036cac6f691SSudarsana Reddy Kalluru 				    test_bit(QED_MF_8021AD_TAGGING,
3037cac6f691SSudarsana Reddy Kalluru 					     &cdev->mf_bits))) {
3038cac6f691SSudarsana Reddy Kalluru 			if (test_bit(QED_MF_8021Q_TAGGING, &cdev->mf_bits))
3039cac6f691SSudarsana Reddy Kalluru 				ether_type = ETH_P_8021Q;
3040cac6f691SSudarsana Reddy Kalluru 			else
3041cac6f691SSudarsana Reddy Kalluru 				ether_type = ETH_P_8021AD;
3042b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, PRS_REG_TAG_ETHERTYPE_0_RT_OFFSET,
3043cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3044b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET,
3045cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3046b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET,
3047cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3048b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, DORQ_REG_TAG1_ETHERTYPE_RT_OFFSET,
3049cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3050b51bdfb9SSudarsana Reddy Kalluru 		}
3051b51bdfb9SSudarsana Reddy Kalluru 
30525d24bcf1STomer Tayar 		qed_fill_load_req_params(&load_req_params,
30535d24bcf1STomer Tayar 					 p_params->p_drv_load_params);
30545d24bcf1STomer Tayar 		rc = qed_mcp_load_req(p_hwfn, p_hwfn->p_main_ptt,
30555d24bcf1STomer Tayar 				      &load_req_params);
3056fe56b9e6SYuval Mintz 		if (rc) {
30575d24bcf1STomer Tayar 			DP_NOTICE(p_hwfn, "Failed sending a LOAD_REQ command\n");
3058fe56b9e6SYuval Mintz 			return rc;
3059fe56b9e6SYuval Mintz 		}
3060fe56b9e6SYuval Mintz 
30615d24bcf1STomer Tayar 		load_code = load_req_params.load_code;
3062fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, QED_MSG_SP,
30635d24bcf1STomer Tayar 			   "Load request was sent. Load code: 0x%x\n",
30645d24bcf1STomer Tayar 			   load_code);
30655d24bcf1STomer Tayar 
306664515dc8STomer Tayar 		/* Only relevant for recovery:
306764515dc8STomer Tayar 		 * Clear the indication after LOAD_REQ is responded by the MFW.
306864515dc8STomer Tayar 		 */
306964515dc8STomer Tayar 		cdev->recov_in_prog = false;
307064515dc8STomer Tayar 
3071645874e5SSudarsana Reddy Kalluru 		qed_mcp_set_capabilities(p_hwfn, p_hwfn->p_main_ptt);
3072645874e5SSudarsana Reddy Kalluru 
30735d24bcf1STomer Tayar 		qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt);
3074fe56b9e6SYuval Mintz 
3075666db486STomer Tayar 		/* Clean up chip from previous driver if such remains exist.
3076666db486STomer Tayar 		 * This is not needed when the PF is the first one on the
3077666db486STomer Tayar 		 * engine, since afterwards we are going to init the FW.
3078666db486STomer Tayar 		 */
3079666db486STomer Tayar 		if (load_code != FW_MSG_CODE_DRV_LOAD_ENGINE) {
3080666db486STomer Tayar 			rc = qed_final_cleanup(p_hwfn, p_hwfn->p_main_ptt,
3081666db486STomer Tayar 					       p_hwfn->rel_pf_id, false);
3082666db486STomer Tayar 			if (rc) {
3083666db486STomer Tayar 				DP_NOTICE(p_hwfn, "Final cleanup failed\n");
3084666db486STomer Tayar 				goto load_err;
3085666db486STomer Tayar 			}
3086666db486STomer Tayar 		}
3087666db486STomer Tayar 
3088666db486STomer Tayar 		/* Log and clear previous pglue_b errors if such exist */
3089666db486STomer Tayar 		qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt);
3090666db486STomer Tayar 
3091666db486STomer Tayar 		/* Enable the PF's internal FID_enable in the PXP */
3092666db486STomer Tayar 		rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt,
3093666db486STomer Tayar 						true);
3094666db486STomer Tayar 		if (rc)
3095666db486STomer Tayar 			goto load_err;
3096666db486STomer Tayar 
3097666db486STomer Tayar 		/* Clear the pglue_b was_error indication.
3098666db486STomer Tayar 		 * In E4 it must be done after the BME and the internal
3099666db486STomer Tayar 		 * FID_enable for the PF are set, since VDMs may cause the
3100666db486STomer Tayar 		 * indication to be set again.
3101666db486STomer Tayar 		 */
3102666db486STomer Tayar 		qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt);
3103fe56b9e6SYuval Mintz 
3104fe56b9e6SYuval Mintz 		switch (load_code) {
3105fe56b9e6SYuval Mintz 		case FW_MSG_CODE_DRV_LOAD_ENGINE:
3106fe56b9e6SYuval Mintz 			rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt,
3107fe56b9e6SYuval Mintz 						p_hwfn->hw_info.hw_mode);
3108fe56b9e6SYuval Mintz 			if (rc)
3109fe56b9e6SYuval Mintz 				break;
311053a42286SGustavo A. R. Silva 		/* Fall through */
3111fe56b9e6SYuval Mintz 		case FW_MSG_CODE_DRV_LOAD_PORT:
3112fe56b9e6SYuval Mintz 			rc = qed_hw_init_port(p_hwfn, p_hwfn->p_main_ptt,
3113fe56b9e6SYuval Mintz 					      p_hwfn->hw_info.hw_mode);
3114fe56b9e6SYuval Mintz 			if (rc)
3115fe56b9e6SYuval Mintz 				break;
3116fe56b9e6SYuval Mintz 
311753a42286SGustavo A. R. Silva 		/* Fall through */
3118fe56b9e6SYuval Mintz 		case FW_MSG_CODE_DRV_LOAD_FUNCTION:
3119fe56b9e6SYuval Mintz 			rc = qed_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt,
3120c0c2d0b4SMintz, Yuval 					    p_params->p_tunn,
3121c0c2d0b4SMintz, Yuval 					    p_hwfn->hw_info.hw_mode,
3122c0c2d0b4SMintz, Yuval 					    p_params->b_hw_start,
3123c0c2d0b4SMintz, Yuval 					    p_params->int_mode,
3124c0c2d0b4SMintz, Yuval 					    p_params->allow_npar_tx_switch);
3125fe56b9e6SYuval Mintz 			break;
3126fe56b9e6SYuval Mintz 		default:
3127c0c2d0b4SMintz, Yuval 			DP_NOTICE(p_hwfn,
3128c0c2d0b4SMintz, Yuval 				  "Unexpected load code [0x%08x]", load_code);
3129fe56b9e6SYuval Mintz 			rc = -EINVAL;
3130fe56b9e6SYuval Mintz 			break;
3131fe56b9e6SYuval Mintz 		}
3132fe56b9e6SYuval Mintz 
3133666db486STomer Tayar 		if (rc) {
3134fe56b9e6SYuval Mintz 			DP_NOTICE(p_hwfn,
3135fe56b9e6SYuval Mintz 				  "init phase failed for loadcode 0x%x (rc %d)\n",
3136fe56b9e6SYuval Mintz 				  load_code, rc);
3137666db486STomer Tayar 			goto load_err;
3138fe56b9e6SYuval Mintz 		}
3139fe56b9e6SYuval Mintz 
3140666db486STomer Tayar 		rc = qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt);
3141666db486STomer Tayar 		if (rc)
3142666db486STomer Tayar 			return rc;
3143fc561c8bSTomer Tayar 
314439651abdSSudarsana Reddy Kalluru 		/* send DCBX attention request command */
314539651abdSSudarsana Reddy Kalluru 		DP_VERBOSE(p_hwfn,
314639651abdSSudarsana Reddy Kalluru 			   QED_MSG_DCB,
314739651abdSSudarsana Reddy Kalluru 			   "sending phony dcbx set command to trigger DCBx attention handling\n");
3148666db486STomer Tayar 		rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
314939651abdSSudarsana Reddy Kalluru 				 DRV_MSG_CODE_SET_DCBX,
315039651abdSSudarsana Reddy Kalluru 				 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT,
3151666db486STomer Tayar 				 &resp, &param);
3152666db486STomer Tayar 		if (rc) {
315339651abdSSudarsana Reddy Kalluru 			DP_NOTICE(p_hwfn,
315439651abdSSudarsana Reddy Kalluru 				  "Failed to send DCBX attention request\n");
3155666db486STomer Tayar 			return rc;
315639651abdSSudarsana Reddy Kalluru 		}
315739651abdSSudarsana Reddy Kalluru 
3158fe56b9e6SYuval Mintz 		p_hwfn->hw_init_done = true;
3159fe56b9e6SYuval Mintz 	}
3160fe56b9e6SYuval Mintz 
31610fefbfbaSSudarsana Kalluru 	if (IS_PF(cdev)) {
31620fefbfbaSSudarsana Kalluru 		p_hwfn = QED_LEADING_HWFN(cdev);
316350fdf601SSudarsana Reddy Kalluru 
316450fdf601SSudarsana Reddy Kalluru 		/* Get pre-negotiated values for stag, bandwidth etc. */
316550fdf601SSudarsana Reddy Kalluru 		DP_VERBOSE(p_hwfn,
316650fdf601SSudarsana Reddy Kalluru 			   QED_MSG_SPQ,
316750fdf601SSudarsana Reddy Kalluru 			   "Sending GET_OEM_UPDATES command to trigger stag/bandwidth attention handling\n");
316850fdf601SSudarsana Reddy Kalluru 		drv_mb_param = 1 << DRV_MB_PARAM_DUMMY_OEM_UPDATES_OFFSET;
316950fdf601SSudarsana Reddy Kalluru 		rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
317050fdf601SSudarsana Reddy Kalluru 				 DRV_MSG_CODE_GET_OEM_UPDATES,
317150fdf601SSudarsana Reddy Kalluru 				 drv_mb_param, &resp, &param);
317250fdf601SSudarsana Reddy Kalluru 		if (rc)
317350fdf601SSudarsana Reddy Kalluru 			DP_NOTICE(p_hwfn,
317450fdf601SSudarsana Reddy Kalluru 				  "Failed to send GET_OEM_UPDATES attention request\n");
317550fdf601SSudarsana Reddy Kalluru 
31765d24bcf1STomer Tayar 		drv_mb_param = STORM_FW_VERSION;
31770fefbfbaSSudarsana Kalluru 		rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
31780fefbfbaSSudarsana Kalluru 				 DRV_MSG_CODE_OV_UPDATE_STORM_FW_VER,
31790fefbfbaSSudarsana Kalluru 				 drv_mb_param, &load_code, &param);
31800fefbfbaSSudarsana Kalluru 		if (rc)
31810fefbfbaSSudarsana Kalluru 			DP_INFO(p_hwfn, "Failed to update firmware version\n");
31820fefbfbaSSudarsana Kalluru 
31830fefbfbaSSudarsana Kalluru 		if (!b_default_mtu) {
31840fefbfbaSSudarsana Kalluru 			rc = qed_mcp_ov_update_mtu(p_hwfn, p_hwfn->p_main_ptt,
31850fefbfbaSSudarsana Kalluru 						   p_hwfn->hw_info.mtu);
31860fefbfbaSSudarsana Kalluru 			if (rc)
31870fefbfbaSSudarsana Kalluru 				DP_INFO(p_hwfn,
31880fefbfbaSSudarsana Kalluru 					"Failed to update default mtu\n");
31890fefbfbaSSudarsana Kalluru 		}
31900fefbfbaSSudarsana Kalluru 
31910fefbfbaSSudarsana Kalluru 		rc = qed_mcp_ov_update_driver_state(p_hwfn,
31920fefbfbaSSudarsana Kalluru 						    p_hwfn->p_main_ptt,
31930fefbfbaSSudarsana Kalluru 						  QED_OV_DRIVER_STATE_DISABLED);
31940fefbfbaSSudarsana Kalluru 		if (rc)
31950fefbfbaSSudarsana Kalluru 			DP_INFO(p_hwfn, "Failed to update driver state\n");
31960fefbfbaSSudarsana Kalluru 
31970fefbfbaSSudarsana Kalluru 		rc = qed_mcp_ov_update_eswitch(p_hwfn, p_hwfn->p_main_ptt,
3198538f8d00SSudarsana Reddy Kalluru 					       QED_OV_ESWITCH_NONE);
31990fefbfbaSSudarsana Kalluru 		if (rc)
32000fefbfbaSSudarsana Kalluru 			DP_INFO(p_hwfn, "Failed to update eswitch mode\n");
32010fefbfbaSSudarsana Kalluru 	}
32020fefbfbaSSudarsana Kalluru 
3203fe56b9e6SYuval Mintz 	return 0;
3204666db486STomer Tayar 
3205666db486STomer Tayar load_err:
3206666db486STomer Tayar 	/* The MFW load lock should be released also when initialization fails.
3207666db486STomer Tayar 	 */
3208666db486STomer Tayar 	qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt);
3209666db486STomer Tayar 	return rc;
3210fe56b9e6SYuval Mintz }
3211fe56b9e6SYuval Mintz 
3212fe56b9e6SYuval Mintz #define QED_HW_STOP_RETRY_LIMIT (10)
32131a635e48SYuval Mintz static void qed_hw_timers_stop(struct qed_dev *cdev,
32141a635e48SYuval Mintz 			       struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
32158c925c44SYuval Mintz {
32168c925c44SYuval Mintz 	int i;
32178c925c44SYuval Mintz 
32188c925c44SYuval Mintz 	/* close timers */
32198c925c44SYuval Mintz 	qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
32208c925c44SYuval Mintz 	qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
32218c925c44SYuval Mintz 
322264515dc8STomer Tayar 	if (cdev->recov_in_prog)
322364515dc8STomer Tayar 		return;
322464515dc8STomer Tayar 
32258c925c44SYuval Mintz 	for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
32268c925c44SYuval Mintz 		if ((!qed_rd(p_hwfn, p_ptt,
32278c925c44SYuval Mintz 			     TM_REG_PF_SCAN_ACTIVE_CONN)) &&
32281a635e48SYuval Mintz 		    (!qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK)))
32298c925c44SYuval Mintz 			break;
32308c925c44SYuval Mintz 
32318c925c44SYuval Mintz 		/* Dependent on number of connection/tasks, possibly
32328c925c44SYuval Mintz 		 * 1ms sleep is required between polls
32338c925c44SYuval Mintz 		 */
32348c925c44SYuval Mintz 		usleep_range(1000, 2000);
32358c925c44SYuval Mintz 	}
32368c925c44SYuval Mintz 
32378c925c44SYuval Mintz 	if (i < QED_HW_STOP_RETRY_LIMIT)
32388c925c44SYuval Mintz 		return;
32398c925c44SYuval Mintz 
32408c925c44SYuval Mintz 	DP_NOTICE(p_hwfn,
32418c925c44SYuval Mintz 		  "Timers linear scans are not over [Connection %02x Tasks %02x]\n",
32428c925c44SYuval Mintz 		  (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN),
32438c925c44SYuval Mintz 		  (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK));
32448c925c44SYuval Mintz }
32458c925c44SYuval Mintz 
32468c925c44SYuval Mintz void qed_hw_timers_stop_all(struct qed_dev *cdev)
32478c925c44SYuval Mintz {
32488c925c44SYuval Mintz 	int j;
32498c925c44SYuval Mintz 
32508c925c44SYuval Mintz 	for_each_hwfn(cdev, j) {
32518c925c44SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
32528c925c44SYuval Mintz 		struct qed_ptt *p_ptt = p_hwfn->p_main_ptt;
32538c925c44SYuval Mintz 
32548c925c44SYuval Mintz 		qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
32558c925c44SYuval Mintz 	}
32568c925c44SYuval Mintz }
32578c925c44SYuval Mintz 
3258fe56b9e6SYuval Mintz int qed_hw_stop(struct qed_dev *cdev)
3259fe56b9e6SYuval Mintz {
32601226337aSTomer Tayar 	struct qed_hwfn *p_hwfn;
32611226337aSTomer Tayar 	struct qed_ptt *p_ptt;
32621226337aSTomer Tayar 	int rc, rc2 = 0;
32638c925c44SYuval Mintz 	int j;
3264fe56b9e6SYuval Mintz 
3265fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, j) {
32661226337aSTomer Tayar 		p_hwfn = &cdev->hwfns[j];
32671226337aSTomer Tayar 		p_ptt = p_hwfn->p_main_ptt;
3268fe56b9e6SYuval Mintz 
3269fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_IFDOWN, "Stopping hw/fw\n");
3270fe56b9e6SYuval Mintz 
32711408cc1fSYuval Mintz 		if (IS_VF(cdev)) {
32720b55e27dSYuval Mintz 			qed_vf_pf_int_cleanup(p_hwfn);
32731226337aSTomer Tayar 			rc = qed_vf_pf_reset(p_hwfn);
32741226337aSTomer Tayar 			if (rc) {
32751226337aSTomer Tayar 				DP_NOTICE(p_hwfn,
32761226337aSTomer Tayar 					  "qed_vf_pf_reset failed. rc = %d.\n",
32771226337aSTomer Tayar 					  rc);
32781226337aSTomer Tayar 				rc2 = -EINVAL;
32791226337aSTomer Tayar 			}
32801408cc1fSYuval Mintz 			continue;
32811408cc1fSYuval Mintz 		}
32821408cc1fSYuval Mintz 
3283fe56b9e6SYuval Mintz 		/* mark the hw as uninitialized... */
3284fe56b9e6SYuval Mintz 		p_hwfn->hw_init_done = false;
3285fe56b9e6SYuval Mintz 
32861226337aSTomer Tayar 		/* Send unload command to MCP */
328764515dc8STomer Tayar 		if (!cdev->recov_in_prog) {
32881226337aSTomer Tayar 			rc = qed_mcp_unload_req(p_hwfn, p_ptt);
32891226337aSTomer Tayar 			if (rc) {
32908c925c44SYuval Mintz 				DP_NOTICE(p_hwfn,
32911226337aSTomer Tayar 					  "Failed sending a UNLOAD_REQ command. rc = %d.\n",
32921226337aSTomer Tayar 					  rc);
32931226337aSTomer Tayar 				rc2 = -EINVAL;
32941226337aSTomer Tayar 			}
329564515dc8STomer Tayar 		}
32961226337aSTomer Tayar 
32971226337aSTomer Tayar 		qed_slowpath_irq_sync(p_hwfn);
32981226337aSTomer Tayar 
32991226337aSTomer Tayar 		/* After this point no MFW attentions are expected, e.g. prevent
33001226337aSTomer Tayar 		 * race between pf stop and dcbx pf update.
33011226337aSTomer Tayar 		 */
33021226337aSTomer Tayar 		rc = qed_sp_pf_stop(p_hwfn);
33031226337aSTomer Tayar 		if (rc) {
33041226337aSTomer Tayar 			DP_NOTICE(p_hwfn,
33051226337aSTomer Tayar 				  "Failed to close PF against FW [rc = %d]. Continue to stop HW to prevent illegal host access by the device.\n",
33061226337aSTomer Tayar 				  rc);
33071226337aSTomer Tayar 			rc2 = -EINVAL;
33081226337aSTomer Tayar 		}
3309fe56b9e6SYuval Mintz 
3310fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt,
3311fe56b9e6SYuval Mintz 		       NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1);
3312fe56b9e6SYuval Mintz 
3313fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
3314fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0);
3315fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0);
3316fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
3317fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
3318fe56b9e6SYuval Mintz 
33198c925c44SYuval Mintz 		qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
3320fe56b9e6SYuval Mintz 
3321fe56b9e6SYuval Mintz 		/* Disable Attention Generation */
3322fe56b9e6SYuval Mintz 		qed_int_igu_disable_int(p_hwfn, p_ptt);
3323fe56b9e6SYuval Mintz 
3324fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0);
3325fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0);
3326fe56b9e6SYuval Mintz 
3327fe56b9e6SYuval Mintz 		qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, true);
3328fe56b9e6SYuval Mintz 
3329fe56b9e6SYuval Mintz 		/* Need to wait 1ms to guarantee SBs are cleared */
3330fe56b9e6SYuval Mintz 		usleep_range(1000, 2000);
33311226337aSTomer Tayar 
33321226337aSTomer Tayar 		/* Disable PF in HW blocks */
33331226337aSTomer Tayar 		qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DB_ENABLE, 0);
33341226337aSTomer Tayar 		qed_wr(p_hwfn, p_ptt, QM_REG_PF_EN, 0);
33351226337aSTomer Tayar 
333679284adeSMichal Kalderon 		if (IS_LEAD_HWFN(p_hwfn) &&
333779284adeSMichal Kalderon 		    test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) &&
333879284adeSMichal Kalderon 		    !QED_IS_FCOE_PERSONALITY(p_hwfn))
333979284adeSMichal Kalderon 			qed_llh_remove_mac_filter(cdev, 0,
334079284adeSMichal Kalderon 						  p_hwfn->hw_info.hw_mac_addr);
334179284adeSMichal Kalderon 
334264515dc8STomer Tayar 		if (!cdev->recov_in_prog) {
334364515dc8STomer Tayar 			rc = qed_mcp_unload_done(p_hwfn, p_ptt);
33441226337aSTomer Tayar 			if (rc) {
33451226337aSTomer Tayar 				DP_NOTICE(p_hwfn,
33461226337aSTomer Tayar 					  "Failed sending a UNLOAD_DONE command. rc = %d.\n",
33471226337aSTomer Tayar 					  rc);
33481226337aSTomer Tayar 				rc2 = -EINVAL;
33491226337aSTomer Tayar 			}
3350fe56b9e6SYuval Mintz 		}
335164515dc8STomer Tayar 	}
3352fe56b9e6SYuval Mintz 
335364515dc8STomer Tayar 	if (IS_PF(cdev) && !cdev->recov_in_prog) {
33541226337aSTomer Tayar 		p_hwfn = QED_LEADING_HWFN(cdev);
33551226337aSTomer Tayar 		p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt;
33561226337aSTomer Tayar 
3357666db486STomer Tayar 		/* Clear the PF's internal FID_enable in the PXP.
3358666db486STomer Tayar 		 * In CMT this should only be done for first hw-function, and
3359666db486STomer Tayar 		 * only after all transactions have stopped for all active
3360666db486STomer Tayar 		 * hw-functions.
3361fe56b9e6SYuval Mintz 		 */
3362666db486STomer Tayar 		rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false);
33631226337aSTomer Tayar 		if (rc) {
33641226337aSTomer Tayar 			DP_NOTICE(p_hwfn,
3365666db486STomer Tayar 				  "qed_pglueb_set_pfid_enable() failed. rc = %d.\n",
3366666db486STomer Tayar 				  rc);
33671226337aSTomer Tayar 			rc2 = -EINVAL;
33681226337aSTomer Tayar 		}
33691408cc1fSYuval Mintz 	}
3370fe56b9e6SYuval Mintz 
33711226337aSTomer Tayar 	return rc2;
3372fe56b9e6SYuval Mintz }
3373fe56b9e6SYuval Mintz 
337415582962SRahul Verma int qed_hw_stop_fastpath(struct qed_dev *cdev)
3375cee4d264SManish Chopra {
33768c925c44SYuval Mintz 	int j;
3377cee4d264SManish Chopra 
3378cee4d264SManish Chopra 	for_each_hwfn(cdev, j) {
3379cee4d264SManish Chopra 		struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
338015582962SRahul Verma 		struct qed_ptt *p_ptt;
3381cee4d264SManish Chopra 
3382dacd88d6SYuval Mintz 		if (IS_VF(cdev)) {
3383dacd88d6SYuval Mintz 			qed_vf_pf_int_cleanup(p_hwfn);
3384dacd88d6SYuval Mintz 			continue;
3385dacd88d6SYuval Mintz 		}
338615582962SRahul Verma 		p_ptt = qed_ptt_acquire(p_hwfn);
338715582962SRahul Verma 		if (!p_ptt)
338815582962SRahul Verma 			return -EAGAIN;
3389dacd88d6SYuval Mintz 
3390cee4d264SManish Chopra 		DP_VERBOSE(p_hwfn,
33911a635e48SYuval Mintz 			   NETIF_MSG_IFDOWN, "Shutting down the fastpath\n");
3392cee4d264SManish Chopra 
3393cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt,
3394cee4d264SManish Chopra 		       NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1);
3395cee4d264SManish Chopra 
3396cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
3397cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0);
3398cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0);
3399cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
3400cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
3401cee4d264SManish Chopra 
3402cee4d264SManish Chopra 		qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, false);
3403cee4d264SManish Chopra 
3404cee4d264SManish Chopra 		/* Need to wait 1ms to guarantee SBs are cleared */
3405cee4d264SManish Chopra 		usleep_range(1000, 2000);
340615582962SRahul Verma 		qed_ptt_release(p_hwfn, p_ptt);
3407cee4d264SManish Chopra 	}
3408cee4d264SManish Chopra 
340915582962SRahul Verma 	return 0;
341015582962SRahul Verma }
341115582962SRahul Verma 
341215582962SRahul Verma int qed_hw_start_fastpath(struct qed_hwfn *p_hwfn)
3413cee4d264SManish Chopra {
341415582962SRahul Verma 	struct qed_ptt *p_ptt;
341515582962SRahul Verma 
3416dacd88d6SYuval Mintz 	if (IS_VF(p_hwfn->cdev))
341715582962SRahul Verma 		return 0;
341815582962SRahul Verma 
341915582962SRahul Verma 	p_ptt = qed_ptt_acquire(p_hwfn);
342015582962SRahul Verma 	if (!p_ptt)
342115582962SRahul Verma 		return -EAGAIN;
3422dacd88d6SYuval Mintz 
3423f855df22SMichal Kalderon 	if (p_hwfn->p_rdma_info &&
3424291d57f6SMichal Kalderon 	    p_hwfn->p_rdma_info->active && p_hwfn->b_rdma_enabled_in_prs)
3425f855df22SMichal Kalderon 		qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0x1);
3426f855df22SMichal Kalderon 
3427cee4d264SManish Chopra 	/* Re-open incoming traffic */
342815582962SRahul Verma 	qed_wr(p_hwfn, p_ptt, NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x0);
342915582962SRahul Verma 	qed_ptt_release(p_hwfn, p_ptt);
343015582962SRahul Verma 
343115582962SRahul Verma 	return 0;
3432cee4d264SManish Chopra }
3433cee4d264SManish Chopra 
3434fe56b9e6SYuval Mintz /* Free hwfn memory and resources acquired in hw_hwfn_prepare */
3435fe56b9e6SYuval Mintz static void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn)
3436fe56b9e6SYuval Mintz {
3437fe56b9e6SYuval Mintz 	qed_ptt_pool_free(p_hwfn);
3438fe56b9e6SYuval Mintz 	kfree(p_hwfn->hw_info.p_igu_info);
34393587cb87STomer Tayar 	p_hwfn->hw_info.p_igu_info = NULL;
3440fe56b9e6SYuval Mintz }
3441fe56b9e6SYuval Mintz 
3442fe56b9e6SYuval Mintz /* Setup bar access */
344312e09c69SYuval Mintz static void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn)
3444fe56b9e6SYuval Mintz {
3445fe56b9e6SYuval Mintz 	/* clear indirect access */
34469c79ddaaSMintz, Yuval 	if (QED_IS_AH(p_hwfn->cdev)) {
34479c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34489c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_E8_F0_K2, 0);
34499c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34509c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_EC_F0_K2, 0);
34519c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34529c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_F0_F0_K2, 0);
34539c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34549c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_F4_F0_K2, 0);
34559c79ddaaSMintz, Yuval 	} else {
34569c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34579c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_88_F0_BB, 0);
34589c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34599c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_8C_F0_BB, 0);
34609c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34619c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_90_F0_BB, 0);
34629c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34639c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_94_F0_BB, 0);
34649c79ddaaSMintz, Yuval 	}
3465fe56b9e6SYuval Mintz 
3466666db486STomer Tayar 	/* Clean previous pglue_b errors if such exist */
3467666db486STomer Tayar 	qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt);
3468fe56b9e6SYuval Mintz 
3469fe56b9e6SYuval Mintz 	/* enable internal target-read */
3470fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_hwfn->p_main_ptt,
3471fe56b9e6SYuval Mintz 	       PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
3472fe56b9e6SYuval Mintz }
3473fe56b9e6SYuval Mintz 
3474fe56b9e6SYuval Mintz static void get_function_id(struct qed_hwfn *p_hwfn)
3475fe56b9e6SYuval Mintz {
3476fe56b9e6SYuval Mintz 	/* ME Register */
34771a635e48SYuval Mintz 	p_hwfn->hw_info.opaque_fid = (u16) REG_RD(p_hwfn,
34781a635e48SYuval Mintz 						  PXP_PF_ME_OPAQUE_ADDR);
3479fe56b9e6SYuval Mintz 
3480fe56b9e6SYuval Mintz 	p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, PXP_PF_ME_CONCRETE_ADDR);
3481fe56b9e6SYuval Mintz 
3482fe56b9e6SYuval Mintz 	p_hwfn->abs_pf_id = (p_hwfn->hw_info.concrete_fid >> 16) & 0xf;
3483fe56b9e6SYuval Mintz 	p_hwfn->rel_pf_id = GET_FIELD(p_hwfn->hw_info.concrete_fid,
3484fe56b9e6SYuval Mintz 				      PXP_CONCRETE_FID_PFID);
3485fe56b9e6SYuval Mintz 	p_hwfn->port_id = GET_FIELD(p_hwfn->hw_info.concrete_fid,
3486fe56b9e6SYuval Mintz 				    PXP_CONCRETE_FID_PORT);
3487525ef5c0SYuval Mintz 
3488525ef5c0SYuval Mintz 	DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE,
3489525ef5c0SYuval Mintz 		   "Read ME register: Concrete 0x%08x Opaque 0x%04x\n",
3490525ef5c0SYuval Mintz 		   p_hwfn->hw_info.concrete_fid, p_hwfn->hw_info.opaque_fid);
3491fe56b9e6SYuval Mintz }
3492fe56b9e6SYuval Mintz 
349325c089d7SYuval Mintz static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
349425c089d7SYuval Mintz {
349525c089d7SYuval Mintz 	u32 *feat_num = p_hwfn->hw_info.feat_num;
3496ebbdcc66SMintz, Yuval 	struct qed_sb_cnt_info sb_cnt;
3497810bb1f0SMintz, Yuval 	u32 non_l2_sbs = 0;
349825c089d7SYuval Mintz 
3499ebbdcc66SMintz, Yuval 	memset(&sb_cnt, 0, sizeof(sb_cnt));
3500ebbdcc66SMintz, Yuval 	qed_int_get_num_sbs(p_hwfn, &sb_cnt);
3501ebbdcc66SMintz, Yuval 
35020189efb8SYuval Mintz 	if (IS_ENABLED(CONFIG_QED_RDMA) &&
3503c851a9dcSKalderon, Michal 	    QED_IS_RDMA_PERSONALITY(p_hwfn)) {
35040189efb8SYuval Mintz 		/* Roce CNQ each requires: 1 status block + 1 CNQ. We divide
35050189efb8SYuval Mintz 		 * the status blocks equally between L2 / RoCE but with
35060189efb8SYuval Mintz 		 * consideration as to how many l2 queues / cnqs we have.
350751ff1725SRam Amrani 		 */
350851ff1725SRam Amrani 		feat_num[QED_RDMA_CNQ] =
3509ebbdcc66SMintz, Yuval 			min_t(u32, sb_cnt.cnt / 2,
351051ff1725SRam Amrani 			      RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM));
3511810bb1f0SMintz, Yuval 
3512810bb1f0SMintz, Yuval 		non_l2_sbs = feat_num[QED_RDMA_CNQ];
351351ff1725SRam Amrani 	}
3514c851a9dcSKalderon, Michal 	if (QED_IS_L2_PERSONALITY(p_hwfn)) {
3515dec26533SMintz, Yuval 		/* Start by allocating VF queues, then PF's */
3516dec26533SMintz, Yuval 		feat_num[QED_VF_L2_QUE] = min_t(u32,
3517dec26533SMintz, Yuval 						RESC_NUM(p_hwfn, QED_L2_QUEUE),
3518ebbdcc66SMintz, Yuval 						sb_cnt.iov_cnt);
3519810bb1f0SMintz, Yuval 		feat_num[QED_PF_L2_QUE] = min_t(u32,
3520ebbdcc66SMintz, Yuval 						sb_cnt.cnt - non_l2_sbs,
3521dec26533SMintz, Yuval 						RESC_NUM(p_hwfn,
3522dec26533SMintz, Yuval 							 QED_L2_QUEUE) -
3523dec26533SMintz, Yuval 						FEAT_NUM(p_hwfn,
3524dec26533SMintz, Yuval 							 QED_VF_L2_QUE));
3525dec26533SMintz, Yuval 	}
35265a1f965aSMintz, Yuval 
3527c851a9dcSKalderon, Michal 	if (QED_IS_FCOE_PERSONALITY(p_hwfn))
35283c5da942SMintz, Yuval 		feat_num[QED_FCOE_CQ] =  min_t(u32, sb_cnt.cnt,
35293c5da942SMintz, Yuval 					       RESC_NUM(p_hwfn,
35303c5da942SMintz, Yuval 							QED_CMDQS_CQS));
35313c5da942SMintz, Yuval 
3532c851a9dcSKalderon, Michal 	if (QED_IS_ISCSI_PERSONALITY(p_hwfn))
3533ebbdcc66SMintz, Yuval 		feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt,
353408737a3fSMintz, Yuval 					       RESC_NUM(p_hwfn,
353508737a3fSMintz, Yuval 							QED_CMDQS_CQS));
35365a1f965aSMintz, Yuval 	DP_VERBOSE(p_hwfn,
35375a1f965aSMintz, Yuval 		   NETIF_MSG_PROBE,
35383c5da942SMintz, Yuval 		   "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d #SBS=%d\n",
35395a1f965aSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE),
35405a1f965aSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE),
35415a1f965aSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ),
35423c5da942SMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_FCOE_CQ),
354308737a3fSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ),
3544ebbdcc66SMintz, Yuval 		   (int)sb_cnt.cnt);
354525c089d7SYuval Mintz }
354625c089d7SYuval Mintz 
35479c8517c4STomer Tayar const char *qed_hw_get_resc_name(enum qed_resources res_id)
35482edbff8dSTomer Tayar {
35492edbff8dSTomer Tayar 	switch (res_id) {
35502edbff8dSTomer Tayar 	case QED_L2_QUEUE:
35512edbff8dSTomer Tayar 		return "L2_QUEUE";
35522edbff8dSTomer Tayar 	case QED_VPORT:
35532edbff8dSTomer Tayar 		return "VPORT";
35542edbff8dSTomer Tayar 	case QED_RSS_ENG:
35552edbff8dSTomer Tayar 		return "RSS_ENG";
35562edbff8dSTomer Tayar 	case QED_PQ:
35572edbff8dSTomer Tayar 		return "PQ";
35582edbff8dSTomer Tayar 	case QED_RL:
35592edbff8dSTomer Tayar 		return "RL";
35602edbff8dSTomer Tayar 	case QED_MAC:
35612edbff8dSTomer Tayar 		return "MAC";
35622edbff8dSTomer Tayar 	case QED_VLAN:
35632edbff8dSTomer Tayar 		return "VLAN";
35642edbff8dSTomer Tayar 	case QED_RDMA_CNQ_RAM:
35652edbff8dSTomer Tayar 		return "RDMA_CNQ_RAM";
35662edbff8dSTomer Tayar 	case QED_ILT:
35672edbff8dSTomer Tayar 		return "ILT";
35682edbff8dSTomer Tayar 	case QED_LL2_QUEUE:
35692edbff8dSTomer Tayar 		return "LL2_QUEUE";
35702edbff8dSTomer Tayar 	case QED_CMDQS_CQS:
35712edbff8dSTomer Tayar 		return "CMDQS_CQS";
35722edbff8dSTomer Tayar 	case QED_RDMA_STATS_QUEUE:
35732edbff8dSTomer Tayar 		return "RDMA_STATS_QUEUE";
35749c8517c4STomer Tayar 	case QED_BDQ:
35759c8517c4STomer Tayar 		return "BDQ";
35769c8517c4STomer Tayar 	case QED_SB:
35779c8517c4STomer Tayar 		return "SB";
35782edbff8dSTomer Tayar 	default:
35792edbff8dSTomer Tayar 		return "UNKNOWN_RESOURCE";
35802edbff8dSTomer Tayar 	}
35812edbff8dSTomer Tayar }
35822edbff8dSTomer Tayar 
35839c8517c4STomer Tayar static int
35849c8517c4STomer Tayar __qed_hw_set_soft_resc_size(struct qed_hwfn *p_hwfn,
35859c8517c4STomer Tayar 			    struct qed_ptt *p_ptt,
35869c8517c4STomer Tayar 			    enum qed_resources res_id,
35879c8517c4STomer Tayar 			    u32 resc_max_val, u32 *p_mcp_resp)
35889c8517c4STomer Tayar {
35899c8517c4STomer Tayar 	int rc;
35909c8517c4STomer Tayar 
35919c8517c4STomer Tayar 	rc = qed_mcp_set_resc_max_val(p_hwfn, p_ptt, res_id,
35929c8517c4STomer Tayar 				      resc_max_val, p_mcp_resp);
35939c8517c4STomer Tayar 	if (rc) {
35949c8517c4STomer Tayar 		DP_NOTICE(p_hwfn,
35959c8517c4STomer Tayar 			  "MFW response failure for a max value setting of resource %d [%s]\n",
35969c8517c4STomer Tayar 			  res_id, qed_hw_get_resc_name(res_id));
35979c8517c4STomer Tayar 		return rc;
35989c8517c4STomer Tayar 	}
35999c8517c4STomer Tayar 
36009c8517c4STomer Tayar 	if (*p_mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK)
36019c8517c4STomer Tayar 		DP_INFO(p_hwfn,
36029c8517c4STomer Tayar 			"Failed to set the max value of resource %d [%s]. mcp_resp = 0x%08x.\n",
36039c8517c4STomer Tayar 			res_id, qed_hw_get_resc_name(res_id), *p_mcp_resp);
36049c8517c4STomer Tayar 
36059c8517c4STomer Tayar 	return 0;
36069c8517c4STomer Tayar }
36079c8517c4STomer Tayar 
36089c8517c4STomer Tayar static int
36099c8517c4STomer Tayar qed_hw_set_soft_resc_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
36109c8517c4STomer Tayar {
36119c8517c4STomer Tayar 	bool b_ah = QED_IS_AH(p_hwfn->cdev);
36129c8517c4STomer Tayar 	u32 resc_max_val, mcp_resp;
36139c8517c4STomer Tayar 	u8 res_id;
36149c8517c4STomer Tayar 	int rc;
36159c8517c4STomer Tayar 
36169c8517c4STomer Tayar 	for (res_id = 0; res_id < QED_MAX_RESC; res_id++) {
36179c8517c4STomer Tayar 		switch (res_id) {
36189c8517c4STomer Tayar 		case QED_LL2_QUEUE:
36199c8517c4STomer Tayar 			resc_max_val = MAX_NUM_LL2_RX_QUEUES;
36209c8517c4STomer Tayar 			break;
36219c8517c4STomer Tayar 		case QED_RDMA_CNQ_RAM:
36229c8517c4STomer Tayar 			/* No need for a case for QED_CMDQS_CQS since
36239c8517c4STomer Tayar 			 * CNQ/CMDQS are the same resource.
36249c8517c4STomer Tayar 			 */
3625da090917STomer Tayar 			resc_max_val = NUM_OF_GLOBAL_QUEUES;
36269c8517c4STomer Tayar 			break;
36279c8517c4STomer Tayar 		case QED_RDMA_STATS_QUEUE:
36289c8517c4STomer Tayar 			resc_max_val = b_ah ? RDMA_NUM_STATISTIC_COUNTERS_K2
36299c8517c4STomer Tayar 			    : RDMA_NUM_STATISTIC_COUNTERS_BB;
36309c8517c4STomer Tayar 			break;
36319c8517c4STomer Tayar 		case QED_BDQ:
36329c8517c4STomer Tayar 			resc_max_val = BDQ_NUM_RESOURCES;
36339c8517c4STomer Tayar 			break;
36349c8517c4STomer Tayar 		default:
36359c8517c4STomer Tayar 			continue;
36369c8517c4STomer Tayar 		}
36379c8517c4STomer Tayar 
36389c8517c4STomer Tayar 		rc = __qed_hw_set_soft_resc_size(p_hwfn, p_ptt, res_id,
36399c8517c4STomer Tayar 						 resc_max_val, &mcp_resp);
36409c8517c4STomer Tayar 		if (rc)
36419c8517c4STomer Tayar 			return rc;
36429c8517c4STomer Tayar 
36439c8517c4STomer Tayar 		/* There's no point to continue to the next resource if the
36449c8517c4STomer Tayar 		 * command is not supported by the MFW.
36459c8517c4STomer Tayar 		 * We do continue if the command is supported but the resource
36469c8517c4STomer Tayar 		 * is unknown to the MFW. Such a resource will be later
36479c8517c4STomer Tayar 		 * configured with the default allocation values.
36489c8517c4STomer Tayar 		 */
36499c8517c4STomer Tayar 		if (mcp_resp == FW_MSG_CODE_UNSUPPORTED)
36509c8517c4STomer Tayar 			return -EINVAL;
36519c8517c4STomer Tayar 	}
36529c8517c4STomer Tayar 
36539c8517c4STomer Tayar 	return 0;
36549c8517c4STomer Tayar }
36559c8517c4STomer Tayar 
36569c8517c4STomer Tayar static
36579c8517c4STomer Tayar int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn,
36589c8517c4STomer Tayar 			 enum qed_resources res_id,
36599c8517c4STomer Tayar 			 u32 *p_resc_num, u32 *p_resc_start)
36609c8517c4STomer Tayar {
36619c8517c4STomer Tayar 	u8 num_funcs = p_hwfn->num_funcs_on_engine;
36629c8517c4STomer Tayar 	bool b_ah = QED_IS_AH(p_hwfn->cdev);
36639c8517c4STomer Tayar 
36649c8517c4STomer Tayar 	switch (res_id) {
36659c8517c4STomer Tayar 	case QED_L2_QUEUE:
36669c8517c4STomer Tayar 		*p_resc_num = (b_ah ? MAX_NUM_L2_QUEUES_K2 :
36679c8517c4STomer Tayar 			       MAX_NUM_L2_QUEUES_BB) / num_funcs;
36689c8517c4STomer Tayar 		break;
36699c8517c4STomer Tayar 	case QED_VPORT:
36709c8517c4STomer Tayar 		*p_resc_num = (b_ah ? MAX_NUM_VPORTS_K2 :
36719c8517c4STomer Tayar 			       MAX_NUM_VPORTS_BB) / num_funcs;
36729c8517c4STomer Tayar 		break;
36739c8517c4STomer Tayar 	case QED_RSS_ENG:
36749c8517c4STomer Tayar 		*p_resc_num = (b_ah ? ETH_RSS_ENGINE_NUM_K2 :
36759c8517c4STomer Tayar 			       ETH_RSS_ENGINE_NUM_BB) / num_funcs;
36769c8517c4STomer Tayar 		break;
36779c8517c4STomer Tayar 	case QED_PQ:
36789c8517c4STomer Tayar 		*p_resc_num = (b_ah ? MAX_QM_TX_QUEUES_K2 :
36799c8517c4STomer Tayar 			       MAX_QM_TX_QUEUES_BB) / num_funcs;
36809c8517c4STomer Tayar 		*p_resc_num &= ~0x7;	/* The granularity of the PQs is 8 */
36819c8517c4STomer Tayar 		break;
36829c8517c4STomer Tayar 	case QED_RL:
36839c8517c4STomer Tayar 		*p_resc_num = MAX_QM_GLOBAL_RLS / num_funcs;
36849c8517c4STomer Tayar 		break;
36859c8517c4STomer Tayar 	case QED_MAC:
36869c8517c4STomer Tayar 	case QED_VLAN:
36879c8517c4STomer Tayar 		/* Each VFC resource can accommodate both a MAC and a VLAN */
36889c8517c4STomer Tayar 		*p_resc_num = ETH_NUM_MAC_FILTERS / num_funcs;
36899c8517c4STomer Tayar 		break;
36909c8517c4STomer Tayar 	case QED_ILT:
36919c8517c4STomer Tayar 		*p_resc_num = (b_ah ? PXP_NUM_ILT_RECORDS_K2 :
36929c8517c4STomer Tayar 			       PXP_NUM_ILT_RECORDS_BB) / num_funcs;
36939c8517c4STomer Tayar 		break;
36949c8517c4STomer Tayar 	case QED_LL2_QUEUE:
36959c8517c4STomer Tayar 		*p_resc_num = MAX_NUM_LL2_RX_QUEUES / num_funcs;
36969c8517c4STomer Tayar 		break;
36979c8517c4STomer Tayar 	case QED_RDMA_CNQ_RAM:
36989c8517c4STomer Tayar 	case QED_CMDQS_CQS:
36999c8517c4STomer Tayar 		/* CNQ/CMDQS are the same resource */
3700da090917STomer Tayar 		*p_resc_num = NUM_OF_GLOBAL_QUEUES / num_funcs;
37019c8517c4STomer Tayar 		break;
37029c8517c4STomer Tayar 	case QED_RDMA_STATS_QUEUE:
37039c8517c4STomer Tayar 		*p_resc_num = (b_ah ? RDMA_NUM_STATISTIC_COUNTERS_K2 :
37049c8517c4STomer Tayar 			       RDMA_NUM_STATISTIC_COUNTERS_BB) / num_funcs;
37059c8517c4STomer Tayar 		break;
37069c8517c4STomer Tayar 	case QED_BDQ:
37079c8517c4STomer Tayar 		if (p_hwfn->hw_info.personality != QED_PCI_ISCSI &&
37089c8517c4STomer Tayar 		    p_hwfn->hw_info.personality != QED_PCI_FCOE)
37099c8517c4STomer Tayar 			*p_resc_num = 0;
37109c8517c4STomer Tayar 		else
37119c8517c4STomer Tayar 			*p_resc_num = 1;
37129c8517c4STomer Tayar 		break;
37139c8517c4STomer Tayar 	case QED_SB:
3714ebbdcc66SMintz, Yuval 		/* Since we want its value to reflect whether MFW supports
3715ebbdcc66SMintz, Yuval 		 * the new scheme, have a default of 0.
3716ebbdcc66SMintz, Yuval 		 */
3717ebbdcc66SMintz, Yuval 		*p_resc_num = 0;
37189c8517c4STomer Tayar 		break;
37199c8517c4STomer Tayar 	default:
37209c8517c4STomer Tayar 		return -EINVAL;
37219c8517c4STomer Tayar 	}
37229c8517c4STomer Tayar 
37239c8517c4STomer Tayar 	switch (res_id) {
37249c8517c4STomer Tayar 	case QED_BDQ:
37259c8517c4STomer Tayar 		if (!*p_resc_num)
37269c8517c4STomer Tayar 			*p_resc_start = 0;
372778cea9ffSTomer Tayar 		else if (p_hwfn->cdev->num_ports_in_engine == 4)
37289c8517c4STomer Tayar 			*p_resc_start = p_hwfn->port_id;
37299c8517c4STomer Tayar 		else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI)
37309c8517c4STomer Tayar 			*p_resc_start = p_hwfn->port_id;
37319c8517c4STomer Tayar 		else if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
37329c8517c4STomer Tayar 			*p_resc_start = p_hwfn->port_id + 2;
37339c8517c4STomer Tayar 		break;
37349c8517c4STomer Tayar 	default:
37359c8517c4STomer Tayar 		*p_resc_start = *p_resc_num * p_hwfn->enabled_func_idx;
37369c8517c4STomer Tayar 		break;
37379c8517c4STomer Tayar 	}
37389c8517c4STomer Tayar 
37399c8517c4STomer Tayar 	return 0;
37409c8517c4STomer Tayar }
37419c8517c4STomer Tayar 
37429c8517c4STomer Tayar static int __qed_hw_set_resc_info(struct qed_hwfn *p_hwfn,
37432edbff8dSTomer Tayar 				  enum qed_resources res_id)
37442edbff8dSTomer Tayar {
37459c8517c4STomer Tayar 	u32 dflt_resc_num = 0, dflt_resc_start = 0;
37469c8517c4STomer Tayar 	u32 mcp_resp, *p_resc_num, *p_resc_start;
37472edbff8dSTomer Tayar 	int rc;
37482edbff8dSTomer Tayar 
37492edbff8dSTomer Tayar 	p_resc_num = &RESC_NUM(p_hwfn, res_id);
37502edbff8dSTomer Tayar 	p_resc_start = &RESC_START(p_hwfn, res_id);
37512edbff8dSTomer Tayar 
37529c8517c4STomer Tayar 	rc = qed_hw_get_dflt_resc(p_hwfn, res_id, &dflt_resc_num,
37539c8517c4STomer Tayar 				  &dflt_resc_start);
37549c8517c4STomer Tayar 	if (rc) {
37552edbff8dSTomer Tayar 		DP_ERR(p_hwfn,
37562edbff8dSTomer Tayar 		       "Failed to get default amount for resource %d [%s]\n",
37572edbff8dSTomer Tayar 		       res_id, qed_hw_get_resc_name(res_id));
37589c8517c4STomer Tayar 		return rc;
37592edbff8dSTomer Tayar 	}
37602edbff8dSTomer Tayar 
37619c8517c4STomer Tayar 	rc = qed_mcp_get_resc_info(p_hwfn, p_hwfn->p_main_ptt, res_id,
37629c8517c4STomer Tayar 				   &mcp_resp, p_resc_num, p_resc_start);
37632edbff8dSTomer Tayar 	if (rc) {
37642edbff8dSTomer Tayar 		DP_NOTICE(p_hwfn,
37652edbff8dSTomer Tayar 			  "MFW response failure for an allocation request for resource %d [%s]\n",
37662edbff8dSTomer Tayar 			  res_id, qed_hw_get_resc_name(res_id));
37672edbff8dSTomer Tayar 		return rc;
37682edbff8dSTomer Tayar 	}
37692edbff8dSTomer Tayar 
37702edbff8dSTomer Tayar 	/* Default driver values are applied in the following cases:
37712edbff8dSTomer Tayar 	 * - The resource allocation MB command is not supported by the MFW
37722edbff8dSTomer Tayar 	 * - There is an internal error in the MFW while processing the request
37732edbff8dSTomer Tayar 	 * - The resource ID is unknown to the MFW
37742edbff8dSTomer Tayar 	 */
37759c8517c4STomer Tayar 	if (mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK) {
37769c8517c4STomer Tayar 		DP_INFO(p_hwfn,
37779c8517c4STomer Tayar 			"Failed to receive allocation info for resource %d [%s]. mcp_resp = 0x%x. Applying default values [%d,%d].\n",
37782edbff8dSTomer Tayar 			res_id,
37792edbff8dSTomer Tayar 			qed_hw_get_resc_name(res_id),
37802edbff8dSTomer Tayar 			mcp_resp, dflt_resc_num, dflt_resc_start);
37812edbff8dSTomer Tayar 		*p_resc_num = dflt_resc_num;
37822edbff8dSTomer Tayar 		*p_resc_start = dflt_resc_start;
37832edbff8dSTomer Tayar 		goto out;
37842edbff8dSTomer Tayar 	}
37852edbff8dSTomer Tayar 
37862edbff8dSTomer Tayar out:
37872edbff8dSTomer Tayar 	/* PQs have to divide by 8 [that's the HW granularity].
37882edbff8dSTomer Tayar 	 * Reduce number so it would fit.
37892edbff8dSTomer Tayar 	 */
37902edbff8dSTomer Tayar 	if ((res_id == QED_PQ) && ((*p_resc_num % 8) || (*p_resc_start % 8))) {
37912edbff8dSTomer Tayar 		DP_INFO(p_hwfn,
37922edbff8dSTomer Tayar 			"PQs need to align by 8; Number %08x --> %08x, Start %08x --> %08x\n",
37932edbff8dSTomer Tayar 			*p_resc_num,
37942edbff8dSTomer Tayar 			(*p_resc_num) & ~0x7,
37952edbff8dSTomer Tayar 			*p_resc_start, (*p_resc_start) & ~0x7);
37962edbff8dSTomer Tayar 		*p_resc_num &= ~0x7;
37972edbff8dSTomer Tayar 		*p_resc_start &= ~0x7;
37982edbff8dSTomer Tayar 	}
37992edbff8dSTomer Tayar 
38002edbff8dSTomer Tayar 	return 0;
38012edbff8dSTomer Tayar }
38022edbff8dSTomer Tayar 
38039c8517c4STomer Tayar static int qed_hw_set_resc_info(struct qed_hwfn *p_hwfn)
3804fe56b9e6SYuval Mintz {
38059c8517c4STomer Tayar 	int rc;
38069c8517c4STomer Tayar 	u8 res_id;
38079c8517c4STomer Tayar 
38089c8517c4STomer Tayar 	for (res_id = 0; res_id < QED_MAX_RESC; res_id++) {
38099c8517c4STomer Tayar 		rc = __qed_hw_set_resc_info(p_hwfn, res_id);
38109c8517c4STomer Tayar 		if (rc)
38119c8517c4STomer Tayar 			return rc;
38129c8517c4STomer Tayar 	}
38139c8517c4STomer Tayar 
38149c8517c4STomer Tayar 	return 0;
38159c8517c4STomer Tayar }
38169c8517c4STomer Tayar 
381779284adeSMichal Kalderon static int qed_hw_get_ppfid_bitmap(struct qed_hwfn *p_hwfn,
381879284adeSMichal Kalderon 				   struct qed_ptt *p_ptt)
381979284adeSMichal Kalderon {
382079284adeSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
382179284adeSMichal Kalderon 	u8 native_ppfid_idx;
382279284adeSMichal Kalderon 	int rc;
382379284adeSMichal Kalderon 
382479284adeSMichal Kalderon 	/* Calculation of BB/AH is different for native_ppfid_idx */
382579284adeSMichal Kalderon 	if (QED_IS_BB(cdev))
382679284adeSMichal Kalderon 		native_ppfid_idx = p_hwfn->rel_pf_id;
382779284adeSMichal Kalderon 	else
382879284adeSMichal Kalderon 		native_ppfid_idx = p_hwfn->rel_pf_id /
382979284adeSMichal Kalderon 		    cdev->num_ports_in_engine;
383079284adeSMichal Kalderon 
383179284adeSMichal Kalderon 	rc = qed_mcp_get_ppfid_bitmap(p_hwfn, p_ptt);
383279284adeSMichal Kalderon 	if (rc != 0 && rc != -EOPNOTSUPP)
383379284adeSMichal Kalderon 		return rc;
383479284adeSMichal Kalderon 	else if (rc == -EOPNOTSUPP)
383579284adeSMichal Kalderon 		cdev->ppfid_bitmap = 0x1 << native_ppfid_idx;
383679284adeSMichal Kalderon 
383779284adeSMichal Kalderon 	if (!(cdev->ppfid_bitmap & (0x1 << native_ppfid_idx))) {
383879284adeSMichal Kalderon 		DP_INFO(p_hwfn,
383979284adeSMichal Kalderon 			"Fix the PPFID bitmap to inculde the native PPFID [native_ppfid_idx %hhd, orig_bitmap 0x%hhx]\n",
384079284adeSMichal Kalderon 			native_ppfid_idx, cdev->ppfid_bitmap);
384179284adeSMichal Kalderon 		cdev->ppfid_bitmap = 0x1 << native_ppfid_idx;
384279284adeSMichal Kalderon 	}
384379284adeSMichal Kalderon 
384479284adeSMichal Kalderon 	return 0;
384579284adeSMichal Kalderon }
384679284adeSMichal Kalderon 
38479c8517c4STomer Tayar static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
38489c8517c4STomer Tayar {
38499c8517c4STomer Tayar 	struct qed_resc_unlock_params resc_unlock_params;
38509c8517c4STomer Tayar 	struct qed_resc_lock_params resc_lock_params;
38519c79ddaaSMintz, Yuval 	bool b_ah = QED_IS_AH(p_hwfn->cdev);
38522edbff8dSTomer Tayar 	u8 res_id;
38532edbff8dSTomer Tayar 	int rc;
3854fe56b9e6SYuval Mintz 
38559c8517c4STomer Tayar 	/* Setting the max values of the soft resources and the following
38569c8517c4STomer Tayar 	 * resources allocation queries should be atomic. Since several PFs can
38579c8517c4STomer Tayar 	 * run in parallel - a resource lock is needed.
38589c8517c4STomer Tayar 	 * If either the resource lock or resource set value commands are not
38599c8517c4STomer Tayar 	 * supported - skip the the max values setting, release the lock if
38609c8517c4STomer Tayar 	 * needed, and proceed to the queries. Other failures, including a
38619c8517c4STomer Tayar 	 * failure to acquire the lock, will cause this function to fail.
38629c8517c4STomer Tayar 	 */
3863f470f22cSsudarsana.kalluru@cavium.com 	qed_mcp_resc_lock_default_init(&resc_lock_params, &resc_unlock_params,
3864f470f22cSsudarsana.kalluru@cavium.com 				       QED_RESC_LOCK_RESC_ALLOC, false);
38659c8517c4STomer Tayar 
38669c8517c4STomer Tayar 	rc = qed_mcp_resc_lock(p_hwfn, p_ptt, &resc_lock_params);
38679c8517c4STomer Tayar 	if (rc && rc != -EINVAL) {
38682edbff8dSTomer Tayar 		return rc;
38699c8517c4STomer Tayar 	} else if (rc == -EINVAL) {
38709c8517c4STomer Tayar 		DP_INFO(p_hwfn,
38719c8517c4STomer Tayar 			"Skip the max values setting of the soft resources since the resource lock is not supported by the MFW\n");
38729c8517c4STomer Tayar 	} else if (!rc && !resc_lock_params.b_granted) {
38739c8517c4STomer Tayar 		DP_NOTICE(p_hwfn,
38749c8517c4STomer Tayar 			  "Failed to acquire the resource lock for the resource allocation commands\n");
38759c8517c4STomer Tayar 		return -EBUSY;
38769c8517c4STomer Tayar 	} else {
38779c8517c4STomer Tayar 		rc = qed_hw_set_soft_resc_size(p_hwfn, p_ptt);
38789c8517c4STomer Tayar 		if (rc && rc != -EINVAL) {
38799c8517c4STomer Tayar 			DP_NOTICE(p_hwfn,
38809c8517c4STomer Tayar 				  "Failed to set the max values of the soft resources\n");
38819c8517c4STomer Tayar 			goto unlock_and_exit;
38829c8517c4STomer Tayar 		} else if (rc == -EINVAL) {
38839c8517c4STomer Tayar 			DP_INFO(p_hwfn,
38849c8517c4STomer Tayar 				"Skip the max values setting of the soft resources since it is not supported by the MFW\n");
38859c8517c4STomer Tayar 			rc = qed_mcp_resc_unlock(p_hwfn, p_ptt,
38869c8517c4STomer Tayar 						 &resc_unlock_params);
38879c8517c4STomer Tayar 			if (rc)
38889c8517c4STomer Tayar 				DP_INFO(p_hwfn,
38899c8517c4STomer Tayar 					"Failed to release the resource lock for the resource allocation commands\n");
38909c8517c4STomer Tayar 		}
38919c8517c4STomer Tayar 	}
38929c8517c4STomer Tayar 
38939c8517c4STomer Tayar 	rc = qed_hw_set_resc_info(p_hwfn);
38949c8517c4STomer Tayar 	if (rc)
38959c8517c4STomer Tayar 		goto unlock_and_exit;
38969c8517c4STomer Tayar 
38979c8517c4STomer Tayar 	if (resc_lock_params.b_granted && !resc_unlock_params.b_released) {
38989c8517c4STomer Tayar 		rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, &resc_unlock_params);
38999c8517c4STomer Tayar 		if (rc)
39009c8517c4STomer Tayar 			DP_INFO(p_hwfn,
39019c8517c4STomer Tayar 				"Failed to release the resource lock for the resource allocation commands\n");
39022edbff8dSTomer Tayar 	}
3903dbb799c3SYuval Mintz 
390479284adeSMichal Kalderon 	/* PPFID bitmap */
390579284adeSMichal Kalderon 	if (IS_LEAD_HWFN(p_hwfn)) {
390679284adeSMichal Kalderon 		rc = qed_hw_get_ppfid_bitmap(p_hwfn, p_ptt);
390779284adeSMichal Kalderon 		if (rc)
390879284adeSMichal Kalderon 			return rc;
390979284adeSMichal Kalderon 	}
391079284adeSMichal Kalderon 
3911dbb799c3SYuval Mintz 	/* Sanity for ILT */
39129c79ddaaSMintz, Yuval 	if ((b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_K2)) ||
39139c79ddaaSMintz, Yuval 	    (!b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_BB))) {
3914dbb799c3SYuval Mintz 		DP_NOTICE(p_hwfn, "Can't assign ILT pages [%08x,...,%08x]\n",
3915dbb799c3SYuval Mintz 			  RESC_START(p_hwfn, QED_ILT),
3916dbb799c3SYuval Mintz 			  RESC_END(p_hwfn, QED_ILT) - 1);
3917dbb799c3SYuval Mintz 		return -EINVAL;
3918dbb799c3SYuval Mintz 	}
3919fe56b9e6SYuval Mintz 
3920ebbdcc66SMintz, Yuval 	/* This will also learn the number of SBs from MFW */
3921ebbdcc66SMintz, Yuval 	if (qed_int_igu_reset_cam(p_hwfn, p_ptt))
3922ebbdcc66SMintz, Yuval 		return -EINVAL;
3923ebbdcc66SMintz, Yuval 
392425c089d7SYuval Mintz 	qed_hw_set_feat(p_hwfn);
392525c089d7SYuval Mintz 
39262edbff8dSTomer Tayar 	for (res_id = 0; res_id < QED_MAX_RESC; res_id++)
39272edbff8dSTomer Tayar 		DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, "%s = %d start = %d\n",
39282edbff8dSTomer Tayar 			   qed_hw_get_resc_name(res_id),
39292edbff8dSTomer Tayar 			   RESC_NUM(p_hwfn, res_id),
39302edbff8dSTomer Tayar 			   RESC_START(p_hwfn, res_id));
3931dbb799c3SYuval Mintz 
3932dbb799c3SYuval Mintz 	return 0;
39339c8517c4STomer Tayar 
39349c8517c4STomer Tayar unlock_and_exit:
39359c8517c4STomer Tayar 	if (resc_lock_params.b_granted && !resc_unlock_params.b_released)
39369c8517c4STomer Tayar 		qed_mcp_resc_unlock(p_hwfn, p_ptt, &resc_unlock_params);
39379c8517c4STomer Tayar 	return rc;
3938fe56b9e6SYuval Mintz }
3939fe56b9e6SYuval Mintz 
39401a635e48SYuval Mintz static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
3941fe56b9e6SYuval Mintz {
3942fc48b7a6SYuval Mintz 	u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities;
39431e128c81SArun Easi 	u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
3944645874e5SSudarsana Reddy Kalluru 	struct qed_mcp_link_capabilities *p_caps;
3945cc875c2eSYuval Mintz 	struct qed_mcp_link_params *link;
3946fe56b9e6SYuval Mintz 
3947fe56b9e6SYuval Mintz 	/* Read global nvm_cfg address */
3948fe56b9e6SYuval Mintz 	nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0);
3949fe56b9e6SYuval Mintz 
3950fe56b9e6SYuval Mintz 	/* Verify MCP has initialized it */
3951fe56b9e6SYuval Mintz 	if (!nvm_cfg_addr) {
3952fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Shared memory not initialized\n");
3953fe56b9e6SYuval Mintz 		return -EINVAL;
3954fe56b9e6SYuval Mintz 	}
3955fe56b9e6SYuval Mintz 
3956fe56b9e6SYuval Mintz 	/* Read nvm_cfg1  (Notice this is just offset, and not offsize (TBD) */
3957fe56b9e6SYuval Mintz 	nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4);
3958fe56b9e6SYuval Mintz 
3959cc875c2eSYuval Mintz 	addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
3960cc875c2eSYuval Mintz 	       offsetof(struct nvm_cfg1, glob) +
3961cc875c2eSYuval Mintz 	       offsetof(struct nvm_cfg1_glob, core_cfg);
3962cc875c2eSYuval Mintz 
3963cc875c2eSYuval Mintz 	core_cfg = qed_rd(p_hwfn, p_ptt, addr);
3964cc875c2eSYuval Mintz 
3965cc875c2eSYuval Mintz 	switch ((core_cfg & NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK) >>
3966cc875c2eSYuval Mintz 		NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET) {
3967351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G:
3968cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X40G;
3969cc875c2eSYuval Mintz 		break;
3970351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G:
3971cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X50G;
3972cc875c2eSYuval Mintz 		break;
3973351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G:
3974cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X100G;
3975cc875c2eSYuval Mintz 		break;
3976351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F:
3977cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X10G_F;
3978cc875c2eSYuval Mintz 		break;
3979351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E:
3980cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X10G_E;
3981cc875c2eSYuval Mintz 		break;
3982351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G:
3983cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X20G;
3984cc875c2eSYuval Mintz 		break;
3985351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G:
3986cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X40G;
3987cc875c2eSYuval Mintz 		break;
3988351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G:
3989cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X25G;
3990cc875c2eSYuval Mintz 		break;
39919c79ddaaSMintz, Yuval 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X10G:
39929c79ddaaSMintz, Yuval 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X10G;
39939c79ddaaSMintz, Yuval 		break;
3994351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G:
3995cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X25G;
3996cc875c2eSYuval Mintz 		break;
39979c79ddaaSMintz, Yuval 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X25G:
39989c79ddaaSMintz, Yuval 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X25G;
39999c79ddaaSMintz, Yuval 		break;
4000cc875c2eSYuval Mintz 	default:
40011a635e48SYuval Mintz 		DP_NOTICE(p_hwfn, "Unknown port mode in 0x%08x\n", core_cfg);
4002cc875c2eSYuval Mintz 		break;
4003cc875c2eSYuval Mintz 	}
4004cc875c2eSYuval Mintz 
4005cc875c2eSYuval Mintz 	/* Read default link configuration */
4006cc875c2eSYuval Mintz 	link = &p_hwfn->mcp_info->link_input;
4007645874e5SSudarsana Reddy Kalluru 	p_caps = &p_hwfn->mcp_info->link_capabilities;
4008cc875c2eSYuval Mintz 	port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4009cc875c2eSYuval Mintz 			offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]);
4010cc875c2eSYuval Mintz 	link_temp = qed_rd(p_hwfn, p_ptt,
4011cc875c2eSYuval Mintz 			   port_cfg_addr +
4012cc875c2eSYuval Mintz 			   offsetof(struct nvm_cfg1_port, speed_cap_mask));
401383aeb933SYuval Mintz 	link_temp &= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_MASK;
401483aeb933SYuval Mintz 	link->speed.advertised_speeds = link_temp;
4015cc875c2eSYuval Mintz 
401683aeb933SYuval Mintz 	link_temp = link->speed.advertised_speeds;
401783aeb933SYuval Mintz 	p_hwfn->mcp_info->link_capabilities.speed_capabilities = link_temp;
4018cc875c2eSYuval Mintz 
4019cc875c2eSYuval Mintz 	link_temp = qed_rd(p_hwfn, p_ptt,
4020cc875c2eSYuval Mintz 			   port_cfg_addr +
4021cc875c2eSYuval Mintz 			   offsetof(struct nvm_cfg1_port, link_settings));
4022cc875c2eSYuval Mintz 	switch ((link_temp & NVM_CFG1_PORT_DRV_LINK_SPEED_MASK) >>
4023cc875c2eSYuval Mintz 		NVM_CFG1_PORT_DRV_LINK_SPEED_OFFSET) {
4024cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG:
4025cc875c2eSYuval Mintz 		link->speed.autoneg = true;
4026cc875c2eSYuval Mintz 		break;
4027cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_1G:
4028cc875c2eSYuval Mintz 		link->speed.forced_speed = 1000;
4029cc875c2eSYuval Mintz 		break;
4030cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_10G:
4031cc875c2eSYuval Mintz 		link->speed.forced_speed = 10000;
4032cc875c2eSYuval Mintz 		break;
40335bf0961cSSudarsana Reddy Kalluru 	case NVM_CFG1_PORT_DRV_LINK_SPEED_20G:
40345bf0961cSSudarsana Reddy Kalluru 		link->speed.forced_speed = 20000;
40355bf0961cSSudarsana Reddy Kalluru 		break;
4036cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_25G:
4037cc875c2eSYuval Mintz 		link->speed.forced_speed = 25000;
4038cc875c2eSYuval Mintz 		break;
4039cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_40G:
4040cc875c2eSYuval Mintz 		link->speed.forced_speed = 40000;
4041cc875c2eSYuval Mintz 		break;
4042cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_50G:
4043cc875c2eSYuval Mintz 		link->speed.forced_speed = 50000;
4044cc875c2eSYuval Mintz 		break;
4045351a4dedSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_BB_100G:
4046cc875c2eSYuval Mintz 		link->speed.forced_speed = 100000;
4047cc875c2eSYuval Mintz 		break;
4048cc875c2eSYuval Mintz 	default:
40491a635e48SYuval Mintz 		DP_NOTICE(p_hwfn, "Unknown Speed in 0x%08x\n", link_temp);
4050cc875c2eSYuval Mintz 	}
4051cc875c2eSYuval Mintz 
405234f9199cSsudarsana.kalluru@cavium.com 	p_hwfn->mcp_info->link_capabilities.default_speed_autoneg =
405334f9199cSsudarsana.kalluru@cavium.com 		link->speed.autoneg;
405434f9199cSsudarsana.kalluru@cavium.com 
4055cc875c2eSYuval Mintz 	link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK;
4056cc875c2eSYuval Mintz 	link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET;
4057cc875c2eSYuval Mintz 	link->pause.autoneg = !!(link_temp &
4058cc875c2eSYuval Mintz 				 NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG);
4059cc875c2eSYuval Mintz 	link->pause.forced_rx = !!(link_temp &
4060cc875c2eSYuval Mintz 				   NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX);
4061cc875c2eSYuval Mintz 	link->pause.forced_tx = !!(link_temp &
4062cc875c2eSYuval Mintz 				   NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
4063cc875c2eSYuval Mintz 	link->loopback_mode = 0;
4064cc875c2eSYuval Mintz 
4065645874e5SSudarsana Reddy Kalluru 	if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
4066645874e5SSudarsana Reddy Kalluru 		link_temp = qed_rd(p_hwfn, p_ptt, port_cfg_addr +
4067645874e5SSudarsana Reddy Kalluru 				   offsetof(struct nvm_cfg1_port, ext_phy));
4068645874e5SSudarsana Reddy Kalluru 		link_temp &= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK;
4069645874e5SSudarsana Reddy Kalluru 		link_temp >>= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET;
4070645874e5SSudarsana Reddy Kalluru 		p_caps->default_eee = QED_MCP_EEE_ENABLED;
4071645874e5SSudarsana Reddy Kalluru 		link->eee.enable = true;
4072645874e5SSudarsana Reddy Kalluru 		switch (link_temp) {
4073645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED:
4074645874e5SSudarsana Reddy Kalluru 			p_caps->default_eee = QED_MCP_EEE_DISABLED;
4075645874e5SSudarsana Reddy Kalluru 			link->eee.enable = false;
4076645874e5SSudarsana Reddy Kalluru 			break;
4077645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED:
4078645874e5SSudarsana Reddy Kalluru 			p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_BALANCED_TIME;
4079645874e5SSudarsana Reddy Kalluru 			break;
4080645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE:
4081645874e5SSudarsana Reddy Kalluru 			p_caps->eee_lpi_timer =
4082645874e5SSudarsana Reddy Kalluru 			    EEE_TX_TIMER_USEC_AGGRESSIVE_TIME;
4083645874e5SSudarsana Reddy Kalluru 			break;
4084645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY:
4085645874e5SSudarsana Reddy Kalluru 			p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_LATENCY_TIME;
4086645874e5SSudarsana Reddy Kalluru 			break;
4087645874e5SSudarsana Reddy Kalluru 		}
4088645874e5SSudarsana Reddy Kalluru 
4089645874e5SSudarsana Reddy Kalluru 		link->eee.tx_lpi_timer = p_caps->eee_lpi_timer;
4090645874e5SSudarsana Reddy Kalluru 		link->eee.tx_lpi_enable = link->eee.enable;
4091645874e5SSudarsana Reddy Kalluru 		link->eee.adv_caps = QED_EEE_1G_ADV | QED_EEE_10G_ADV;
4092645874e5SSudarsana Reddy Kalluru 	} else {
4093645874e5SSudarsana Reddy Kalluru 		p_caps->default_eee = QED_MCP_EEE_UNSUPPORTED;
4094645874e5SSudarsana Reddy Kalluru 	}
4095645874e5SSudarsana Reddy Kalluru 
4096645874e5SSudarsana Reddy Kalluru 	DP_VERBOSE(p_hwfn,
4097645874e5SSudarsana Reddy Kalluru 		   NETIF_MSG_LINK,
4098645874e5SSudarsana Reddy Kalluru 		   "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x EEE: %02x [%08x usec]\n",
4099645874e5SSudarsana Reddy Kalluru 		   link->speed.forced_speed,
4100645874e5SSudarsana Reddy Kalluru 		   link->speed.advertised_speeds,
4101645874e5SSudarsana Reddy Kalluru 		   link->speed.autoneg,
4102645874e5SSudarsana Reddy Kalluru 		   link->pause.autoneg,
4103645874e5SSudarsana Reddy Kalluru 		   p_caps->default_eee, p_caps->eee_lpi_timer);
4104cc875c2eSYuval Mintz 
4105b51bdfb9SSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn)) {
4106b51bdfb9SSudarsana Reddy Kalluru 		struct qed_dev *cdev = p_hwfn->cdev;
4107b51bdfb9SSudarsana Reddy Kalluru 
4108fe56b9e6SYuval Mintz 		/* Read Multi-function information from shmem */
4109fe56b9e6SYuval Mintz 		addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4110fe56b9e6SYuval Mintz 		       offsetof(struct nvm_cfg1, glob) +
4111fe56b9e6SYuval Mintz 		       offsetof(struct nvm_cfg1_glob, generic_cont0);
4112fe56b9e6SYuval Mintz 
4113fe56b9e6SYuval Mintz 		generic_cont0 = qed_rd(p_hwfn, p_ptt, addr);
4114fe56b9e6SYuval Mintz 
4115fe56b9e6SYuval Mintz 		mf_mode = (generic_cont0 & NVM_CFG1_GLOB_MF_MODE_MASK) >>
4116fe56b9e6SYuval Mintz 			  NVM_CFG1_GLOB_MF_MODE_OFFSET;
4117fe56b9e6SYuval Mintz 
4118fe56b9e6SYuval Mintz 		switch (mf_mode) {
4119fe56b9e6SYuval Mintz 		case NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED:
4120b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS);
4121b51bdfb9SSudarsana Reddy Kalluru 			break;
4122cac6f691SSudarsana Reddy Kalluru 		case NVM_CFG1_GLOB_MF_MODE_UFP:
4123cac6f691SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS) |
4124cac6f691SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
4125cac6f691SSudarsana Reddy Kalluru 					BIT(QED_MF_UFP_SPECIFIC) |
41261a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_8021Q_TAGGING) |
41271a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_DONT_ADD_VLAN0_TAG);
4128cac6f691SSudarsana Reddy Kalluru 			break;
4129b51bdfb9SSudarsana Reddy Kalluru 		case NVM_CFG1_GLOB_MF_MODE_BD:
4130b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS) |
4131b51bdfb9SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
41321a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_8021AD_TAGGING) |
41331a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_DONT_ADD_VLAN0_TAG);
4134fe56b9e6SYuval Mintz 			break;
4135fe56b9e6SYuval Mintz 		case NVM_CFG1_GLOB_MF_MODE_NPAR1_0:
4136b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
41370bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
41380bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LL2_NON_UNICAST) |
41390bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_INTER_PF_SWITCH);
4140fe56b9e6SYuval Mintz 			break;
4141fc48b7a6SYuval Mintz 		case NVM_CFG1_GLOB_MF_MODE_DEFAULT:
4142b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
41430bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
41440bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LL2_NON_UNICAST);
41450bc5fe85SSudarsana Reddy Kalluru 			if (QED_IS_BB(p_hwfn->cdev))
4146b51bdfb9SSudarsana Reddy Kalluru 				cdev->mf_bits |= BIT(QED_MF_NEED_DEF_PF);
4147fe56b9e6SYuval Mintz 			break;
4148fe56b9e6SYuval Mintz 		}
41490bc5fe85SSudarsana Reddy Kalluru 
41500bc5fe85SSudarsana Reddy Kalluru 		DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
4151b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits);
4152b51bdfb9SSudarsana Reddy Kalluru 	}
4153b51bdfb9SSudarsana Reddy Kalluru 
4154b51bdfb9SSudarsana Reddy Kalluru 	DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
41550bc5fe85SSudarsana Reddy Kalluru 		p_hwfn->cdev->mf_bits);
4156fe56b9e6SYuval Mintz 
4157b51bdfb9SSudarsana Reddy Kalluru 	/* Read device capabilities information from shmem */
4158fc48b7a6SYuval Mintz 	addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4159fc48b7a6SYuval Mintz 		offsetof(struct nvm_cfg1, glob) +
4160fc48b7a6SYuval Mintz 		offsetof(struct nvm_cfg1_glob, device_capabilities);
4161fc48b7a6SYuval Mintz 
4162fc48b7a6SYuval Mintz 	device_capabilities = qed_rd(p_hwfn, p_ptt, addr);
4163fc48b7a6SYuval Mintz 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET)
4164fc48b7a6SYuval Mintz 		__set_bit(QED_DEV_CAP_ETH,
4165fc48b7a6SYuval Mintz 			  &p_hwfn->hw_info.device_capabilities);
41661e128c81SArun Easi 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_FCOE)
41671e128c81SArun Easi 		__set_bit(QED_DEV_CAP_FCOE,
41681e128c81SArun Easi 			  &p_hwfn->hw_info.device_capabilities);
4169c5ac9319SYuval Mintz 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI)
4170c5ac9319SYuval Mintz 		__set_bit(QED_DEV_CAP_ISCSI,
4171c5ac9319SYuval Mintz 			  &p_hwfn->hw_info.device_capabilities);
4172c5ac9319SYuval Mintz 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE)
4173c5ac9319SYuval Mintz 		__set_bit(QED_DEV_CAP_ROCE,
4174c5ac9319SYuval Mintz 			  &p_hwfn->hw_info.device_capabilities);
4175fc48b7a6SYuval Mintz 
4176fe56b9e6SYuval Mintz 	return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt);
4177fe56b9e6SYuval Mintz }
4178fe56b9e6SYuval Mintz 
41791408cc1fSYuval Mintz static void qed_get_num_funcs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
41801408cc1fSYuval Mintz {
4181dbb799c3SYuval Mintz 	u8 num_funcs, enabled_func_idx = p_hwfn->rel_pf_id;
4182dbb799c3SYuval Mintz 	u32 reg_function_hide, tmp, eng_mask, low_pfs_mask;
41839c79ddaaSMintz, Yuval 	struct qed_dev *cdev = p_hwfn->cdev;
41841408cc1fSYuval Mintz 
41859c79ddaaSMintz, Yuval 	num_funcs = QED_IS_AH(cdev) ? MAX_NUM_PFS_K2 : MAX_NUM_PFS_BB;
41861408cc1fSYuval Mintz 
41871408cc1fSYuval Mintz 	/* Bit 0 of MISCS_REG_FUNCTION_HIDE indicates whether the bypass values
41881408cc1fSYuval Mintz 	 * in the other bits are selected.
41891408cc1fSYuval Mintz 	 * Bits 1-15 are for functions 1-15, respectively, and their value is
41901408cc1fSYuval Mintz 	 * '0' only for enabled functions (function 0 always exists and
41911408cc1fSYuval Mintz 	 * enabled).
41921408cc1fSYuval Mintz 	 * In case of CMT, only the "even" functions are enabled, and thus the
41931408cc1fSYuval Mintz 	 * number of functions for both hwfns is learnt from the same bits.
41941408cc1fSYuval Mintz 	 */
41951408cc1fSYuval Mintz 	reg_function_hide = qed_rd(p_hwfn, p_ptt, MISCS_REG_FUNCTION_HIDE);
41961408cc1fSYuval Mintz 
41971408cc1fSYuval Mintz 	if (reg_function_hide & 0x1) {
41989c79ddaaSMintz, Yuval 		if (QED_IS_BB(cdev)) {
41999c79ddaaSMintz, Yuval 			if (QED_PATH_ID(p_hwfn) && cdev->num_hwfns == 1) {
42001408cc1fSYuval Mintz 				num_funcs = 0;
42011408cc1fSYuval Mintz 				eng_mask = 0xaaaa;
42021408cc1fSYuval Mintz 			} else {
42031408cc1fSYuval Mintz 				num_funcs = 1;
42041408cc1fSYuval Mintz 				eng_mask = 0x5554;
42051408cc1fSYuval Mintz 			}
42069c79ddaaSMintz, Yuval 		} else {
42079c79ddaaSMintz, Yuval 			num_funcs = 1;
42089c79ddaaSMintz, Yuval 			eng_mask = 0xfffe;
42099c79ddaaSMintz, Yuval 		}
42101408cc1fSYuval Mintz 
42111408cc1fSYuval Mintz 		/* Get the number of the enabled functions on the engine */
42121408cc1fSYuval Mintz 		tmp = (reg_function_hide ^ 0xffffffff) & eng_mask;
42131408cc1fSYuval Mintz 		while (tmp) {
42141408cc1fSYuval Mintz 			if (tmp & 0x1)
42151408cc1fSYuval Mintz 				num_funcs++;
42161408cc1fSYuval Mintz 			tmp >>= 0x1;
42171408cc1fSYuval Mintz 		}
4218dbb799c3SYuval Mintz 
4219dbb799c3SYuval Mintz 		/* Get the PF index within the enabled functions */
4220dbb799c3SYuval Mintz 		low_pfs_mask = (0x1 << p_hwfn->abs_pf_id) - 1;
4221dbb799c3SYuval Mintz 		tmp = reg_function_hide & eng_mask & low_pfs_mask;
4222dbb799c3SYuval Mintz 		while (tmp) {
4223dbb799c3SYuval Mintz 			if (tmp & 0x1)
4224dbb799c3SYuval Mintz 				enabled_func_idx--;
4225dbb799c3SYuval Mintz 			tmp >>= 0x1;
4226dbb799c3SYuval Mintz 		}
42271408cc1fSYuval Mintz 	}
42281408cc1fSYuval Mintz 
42291408cc1fSYuval Mintz 	p_hwfn->num_funcs_on_engine = num_funcs;
4230dbb799c3SYuval Mintz 	p_hwfn->enabled_func_idx = enabled_func_idx;
42311408cc1fSYuval Mintz 
42321408cc1fSYuval Mintz 	DP_VERBOSE(p_hwfn,
42331408cc1fSYuval Mintz 		   NETIF_MSG_PROBE,
4234525ef5c0SYuval Mintz 		   "PF [rel_id %d, abs_id %d] occupies index %d within the %d enabled functions on the engine\n",
42351408cc1fSYuval Mintz 		   p_hwfn->rel_pf_id,
42361408cc1fSYuval Mintz 		   p_hwfn->abs_pf_id,
4237525ef5c0SYuval Mintz 		   p_hwfn->enabled_func_idx, p_hwfn->num_funcs_on_engine);
42381408cc1fSYuval Mintz }
42391408cc1fSYuval Mintz 
42409c79ddaaSMintz, Yuval static void qed_hw_info_port_num(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
42419c79ddaaSMintz, Yuval {
42420ebcebbeSSudarsana Reddy Kalluru 	u32 addr, global_offsize, global_addr, port_mode;
42430ebcebbeSSudarsana Reddy Kalluru 	struct qed_dev *cdev = p_hwfn->cdev;
42440ebcebbeSSudarsana Reddy Kalluru 
42450ebcebbeSSudarsana Reddy Kalluru 	/* In CMT there is always only one port */
42460ebcebbeSSudarsana Reddy Kalluru 	if (cdev->num_hwfns > 1) {
42470ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 1;
42480ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports = 1;
42490ebcebbeSSudarsana Reddy Kalluru 		return;
42500ebcebbeSSudarsana Reddy Kalluru 	}
42510ebcebbeSSudarsana Reddy Kalluru 
42520ebcebbeSSudarsana Reddy Kalluru 	/* Determine the number of ports per engine */
42530ebcebbeSSudarsana Reddy Kalluru 	port_mode = qed_rd(p_hwfn, p_ptt, MISC_REG_PORT_MODE);
42540ebcebbeSSudarsana Reddy Kalluru 	switch (port_mode) {
42550ebcebbeSSudarsana Reddy Kalluru 	case 0x0:
42560ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 1;
42570ebcebbeSSudarsana Reddy Kalluru 		break;
42580ebcebbeSSudarsana Reddy Kalluru 	case 0x1:
42590ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 2;
42600ebcebbeSSudarsana Reddy Kalluru 		break;
42610ebcebbeSSudarsana Reddy Kalluru 	case 0x2:
42620ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 4;
42630ebcebbeSSudarsana Reddy Kalluru 		break;
42640ebcebbeSSudarsana Reddy Kalluru 	default:
42650ebcebbeSSudarsana Reddy Kalluru 		DP_NOTICE(p_hwfn, "Unknown port mode 0x%08x\n", port_mode);
42660ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 1;	/* Default to something */
42670ebcebbeSSudarsana Reddy Kalluru 		break;
42680ebcebbeSSudarsana Reddy Kalluru 	}
42690ebcebbeSSudarsana Reddy Kalluru 
42700ebcebbeSSudarsana Reddy Kalluru 	/* Get the total number of ports of the device */
42710ebcebbeSSudarsana Reddy Kalluru 	addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
42720ebcebbeSSudarsana Reddy Kalluru 				    PUBLIC_GLOBAL);
42730ebcebbeSSudarsana Reddy Kalluru 	global_offsize = qed_rd(p_hwfn, p_ptt, addr);
42740ebcebbeSSudarsana Reddy Kalluru 	global_addr = SECTION_ADDR(global_offsize, 0);
42750ebcebbeSSudarsana Reddy Kalluru 	addr = global_addr + offsetof(struct public_global, max_ports);
42760ebcebbeSSudarsana Reddy Kalluru 	cdev->num_ports = (u8)qed_rd(p_hwfn, p_ptt, addr);
42779c79ddaaSMintz, Yuval }
42789c79ddaaSMintz, Yuval 
4279645874e5SSudarsana Reddy Kalluru static void qed_get_eee_caps(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
4280645874e5SSudarsana Reddy Kalluru {
4281645874e5SSudarsana Reddy Kalluru 	struct qed_mcp_link_capabilities *p_caps;
4282645874e5SSudarsana Reddy Kalluru 	u32 eee_status;
4283645874e5SSudarsana Reddy Kalluru 
4284645874e5SSudarsana Reddy Kalluru 	p_caps = &p_hwfn->mcp_info->link_capabilities;
4285645874e5SSudarsana Reddy Kalluru 	if (p_caps->default_eee == QED_MCP_EEE_UNSUPPORTED)
4286645874e5SSudarsana Reddy Kalluru 		return;
4287645874e5SSudarsana Reddy Kalluru 
4288645874e5SSudarsana Reddy Kalluru 	p_caps->eee_speed_caps = 0;
4289645874e5SSudarsana Reddy Kalluru 	eee_status = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
4290645874e5SSudarsana Reddy Kalluru 			    offsetof(struct public_port, eee_status));
4291645874e5SSudarsana Reddy Kalluru 	eee_status = (eee_status & EEE_SUPPORTED_SPEED_MASK) >>
4292645874e5SSudarsana Reddy Kalluru 			EEE_SUPPORTED_SPEED_OFFSET;
4293645874e5SSudarsana Reddy Kalluru 
4294645874e5SSudarsana Reddy Kalluru 	if (eee_status & EEE_1G_SUPPORTED)
4295645874e5SSudarsana Reddy Kalluru 		p_caps->eee_speed_caps |= QED_EEE_1G_ADV;
4296645874e5SSudarsana Reddy Kalluru 	if (eee_status & EEE_10G_ADV)
4297645874e5SSudarsana Reddy Kalluru 		p_caps->eee_speed_caps |= QED_EEE_10G_ADV;
4298645874e5SSudarsana Reddy Kalluru }
4299645874e5SSudarsana Reddy Kalluru 
43009c79ddaaSMintz, Yuval static int
43019c79ddaaSMintz, Yuval qed_get_hw_info(struct qed_hwfn *p_hwfn,
43029c79ddaaSMintz, Yuval 		struct qed_ptt *p_ptt,
43039c79ddaaSMintz, Yuval 		enum qed_pci_personality personality)
43049c79ddaaSMintz, Yuval {
43059c79ddaaSMintz, Yuval 	int rc;
43069c79ddaaSMintz, Yuval 
43079c79ddaaSMintz, Yuval 	/* Since all information is common, only first hwfns should do this */
43089c79ddaaSMintz, Yuval 	if (IS_LEAD_HWFN(p_hwfn)) {
43099c79ddaaSMintz, Yuval 		rc = qed_iov_hw_info(p_hwfn);
43109c79ddaaSMintz, Yuval 		if (rc)
43119c79ddaaSMintz, Yuval 			return rc;
43129c79ddaaSMintz, Yuval 	}
43139c79ddaaSMintz, Yuval 
43140ebcebbeSSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn))
43159c79ddaaSMintz, Yuval 		qed_hw_info_port_num(p_hwfn, p_ptt);
4316fe56b9e6SYuval Mintz 
4317645874e5SSudarsana Reddy Kalluru 	qed_mcp_get_capabilities(p_hwfn, p_ptt);
4318645874e5SSudarsana Reddy Kalluru 
4319fe56b9e6SYuval Mintz 	qed_hw_get_nvm_info(p_hwfn, p_ptt);
4320fe56b9e6SYuval Mintz 
4321fe56b9e6SYuval Mintz 	rc = qed_int_igu_read_cam(p_hwfn, p_ptt);
4322fe56b9e6SYuval Mintz 	if (rc)
4323fe56b9e6SYuval Mintz 		return rc;
4324fe56b9e6SYuval Mintz 
4325fe56b9e6SYuval Mintz 	if (qed_mcp_is_init(p_hwfn))
4326fe56b9e6SYuval Mintz 		ether_addr_copy(p_hwfn->hw_info.hw_mac_addr,
4327fe56b9e6SYuval Mintz 				p_hwfn->mcp_info->func_info.mac);
4328fe56b9e6SYuval Mintz 	else
4329fe56b9e6SYuval Mintz 		eth_random_addr(p_hwfn->hw_info.hw_mac_addr);
4330fe56b9e6SYuval Mintz 
4331fe56b9e6SYuval Mintz 	if (qed_mcp_is_init(p_hwfn)) {
4332fe56b9e6SYuval Mintz 		if (p_hwfn->mcp_info->func_info.ovlan != QED_MCP_VLAN_UNSET)
4333fe56b9e6SYuval Mintz 			p_hwfn->hw_info.ovlan =
4334fe56b9e6SYuval Mintz 				p_hwfn->mcp_info->func_info.ovlan;
4335fe56b9e6SYuval Mintz 
4336fe56b9e6SYuval Mintz 		qed_mcp_cmd_port_init(p_hwfn, p_ptt);
4337645874e5SSudarsana Reddy Kalluru 
4338645874e5SSudarsana Reddy Kalluru 		qed_get_eee_caps(p_hwfn, p_ptt);
4339cac6f691SSudarsana Reddy Kalluru 
4340cac6f691SSudarsana Reddy Kalluru 		qed_mcp_read_ufp_config(p_hwfn, p_ptt);
4341fe56b9e6SYuval Mintz 	}
4342fe56b9e6SYuval Mintz 
4343fe56b9e6SYuval Mintz 	if (qed_mcp_is_init(p_hwfn)) {
4344fe56b9e6SYuval Mintz 		enum qed_pci_personality protocol;
4345fe56b9e6SYuval Mintz 
4346fe56b9e6SYuval Mintz 		protocol = p_hwfn->mcp_info->func_info.protocol;
4347fe56b9e6SYuval Mintz 		p_hwfn->hw_info.personality = protocol;
4348fe56b9e6SYuval Mintz 	}
4349fe56b9e6SYuval Mintz 
435061be82b0SDenis Bolotin 	if (QED_IS_ROCE_PERSONALITY(p_hwfn))
435161be82b0SDenis Bolotin 		p_hwfn->hw_info.multi_tc_roce_en = 1;
435261be82b0SDenis Bolotin 
4353b5a9ee7cSAriel Elior 	p_hwfn->hw_info.num_hw_tc = NUM_PHYS_TCS_4PORT_K2;
4354b5a9ee7cSAriel Elior 	p_hwfn->hw_info.num_active_tc = 1;
4355b5a9ee7cSAriel Elior 
43561408cc1fSYuval Mintz 	qed_get_num_funcs(p_hwfn, p_ptt);
43571408cc1fSYuval Mintz 
43580fefbfbaSSudarsana Kalluru 	if (qed_mcp_is_init(p_hwfn))
43590fefbfbaSSudarsana Kalluru 		p_hwfn->hw_info.mtu = p_hwfn->mcp_info->func_info.mtu;
43600fefbfbaSSudarsana Kalluru 
43619c8517c4STomer Tayar 	return qed_hw_get_resc(p_hwfn, p_ptt);
4362fe56b9e6SYuval Mintz }
4363fe56b9e6SYuval Mintz 
436415582962SRahul Verma static int qed_get_dev_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
4365fe56b9e6SYuval Mintz {
436615582962SRahul Verma 	struct qed_dev *cdev = p_hwfn->cdev;
43679c79ddaaSMintz, Yuval 	u16 device_id_mask;
4368fe56b9e6SYuval Mintz 	u32 tmp;
4369fe56b9e6SYuval Mintz 
4370fc48b7a6SYuval Mintz 	/* Read Vendor Id / Device Id */
43711a635e48SYuval Mintz 	pci_read_config_word(cdev->pdev, PCI_VENDOR_ID, &cdev->vendor_id);
43721a635e48SYuval Mintz 	pci_read_config_word(cdev->pdev, PCI_DEVICE_ID, &cdev->device_id);
43731a635e48SYuval Mintz 
43749c79ddaaSMintz, Yuval 	/* Determine type */
43759c79ddaaSMintz, Yuval 	device_id_mask = cdev->device_id & QED_DEV_ID_MASK;
43769c79ddaaSMintz, Yuval 	switch (device_id_mask) {
43779c79ddaaSMintz, Yuval 	case QED_DEV_ID_MASK_BB:
43789c79ddaaSMintz, Yuval 		cdev->type = QED_DEV_TYPE_BB;
43799c79ddaaSMintz, Yuval 		break;
43809c79ddaaSMintz, Yuval 	case QED_DEV_ID_MASK_AH:
43819c79ddaaSMintz, Yuval 		cdev->type = QED_DEV_TYPE_AH;
43829c79ddaaSMintz, Yuval 		break;
43839c79ddaaSMintz, Yuval 	default:
43849c79ddaaSMintz, Yuval 		DP_NOTICE(p_hwfn, "Unknown device id 0x%x\n", cdev->device_id);
43859c79ddaaSMintz, Yuval 		return -EBUSY;
43869c79ddaaSMintz, Yuval 	}
43879c79ddaaSMintz, Yuval 
438815582962SRahul Verma 	cdev->chip_num = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_NUM);
438915582962SRahul Verma 	cdev->chip_rev = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_REV);
439015582962SRahul Verma 
4391fe56b9e6SYuval Mintz 	MASK_FIELD(CHIP_REV, cdev->chip_rev);
4392fe56b9e6SYuval Mintz 
4393fe56b9e6SYuval Mintz 	/* Learn number of HW-functions */
439415582962SRahul Verma 	tmp = qed_rd(p_hwfn, p_ptt, MISCS_REG_CMT_ENABLED_FOR_PAIR);
4395fe56b9e6SYuval Mintz 
4396fc48b7a6SYuval Mintz 	if (tmp & (1 << p_hwfn->rel_pf_id)) {
4397fe56b9e6SYuval Mintz 		DP_NOTICE(cdev->hwfns, "device in CMT mode\n");
4398fe56b9e6SYuval Mintz 		cdev->num_hwfns = 2;
4399fe56b9e6SYuval Mintz 	} else {
4400fe56b9e6SYuval Mintz 		cdev->num_hwfns = 1;
4401fe56b9e6SYuval Mintz 	}
4402fe56b9e6SYuval Mintz 
440315582962SRahul Verma 	cdev->chip_bond_id = qed_rd(p_hwfn, p_ptt,
4404fe56b9e6SYuval Mintz 				    MISCS_REG_CHIP_TEST_REG) >> 4;
4405fe56b9e6SYuval Mintz 	MASK_FIELD(CHIP_BOND_ID, cdev->chip_bond_id);
440615582962SRahul Verma 	cdev->chip_metal = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_METAL);
4407fe56b9e6SYuval Mintz 	MASK_FIELD(CHIP_METAL, cdev->chip_metal);
4408fe56b9e6SYuval Mintz 
4409fe56b9e6SYuval Mintz 	DP_INFO(cdev->hwfns,
44109c79ddaaSMintz, Yuval 		"Chip details - %s %c%d, Num: %04x Rev: %04x Bond id: %04x Metal: %04x\n",
44119c79ddaaSMintz, Yuval 		QED_IS_BB(cdev) ? "BB" : "AH",
44129c79ddaaSMintz, Yuval 		'A' + cdev->chip_rev,
44139c79ddaaSMintz, Yuval 		(int)cdev->chip_metal,
4414fe56b9e6SYuval Mintz 		cdev->chip_num, cdev->chip_rev,
4415fe56b9e6SYuval Mintz 		cdev->chip_bond_id, cdev->chip_metal);
441612e09c69SYuval Mintz 
441712e09c69SYuval Mintz 	return 0;
4418fe56b9e6SYuval Mintz }
4419fe56b9e6SYuval Mintz 
442043645ce0SSudarsana Reddy Kalluru static void qed_nvm_info_free(struct qed_hwfn *p_hwfn)
442143645ce0SSudarsana Reddy Kalluru {
442243645ce0SSudarsana Reddy Kalluru 	kfree(p_hwfn->nvm_info.image_att);
442343645ce0SSudarsana Reddy Kalluru 	p_hwfn->nvm_info.image_att = NULL;
442443645ce0SSudarsana Reddy Kalluru }
442543645ce0SSudarsana Reddy Kalluru 
4426fe56b9e6SYuval Mintz static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
4427fe56b9e6SYuval Mintz 				 void __iomem *p_regview,
4428fe56b9e6SYuval Mintz 				 void __iomem *p_doorbells,
4429fe56b9e6SYuval Mintz 				 enum qed_pci_personality personality)
4430fe56b9e6SYuval Mintz {
443164515dc8STomer Tayar 	struct qed_dev *cdev = p_hwfn->cdev;
4432fe56b9e6SYuval Mintz 	int rc = 0;
4433fe56b9e6SYuval Mintz 
4434fe56b9e6SYuval Mintz 	/* Split PCI bars evenly between hwfns */
4435fe56b9e6SYuval Mintz 	p_hwfn->regview = p_regview;
4436fe56b9e6SYuval Mintz 	p_hwfn->doorbells = p_doorbells;
4437fe56b9e6SYuval Mintz 
44381408cc1fSYuval Mintz 	if (IS_VF(p_hwfn->cdev))
44391408cc1fSYuval Mintz 		return qed_vf_hw_prepare(p_hwfn);
44401408cc1fSYuval Mintz 
4441fe56b9e6SYuval Mintz 	/* Validate that chip access is feasible */
4442fe56b9e6SYuval Mintz 	if (REG_RD(p_hwfn, PXP_PF_ME_OPAQUE_ADDR) == 0xffffffff) {
4443fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn,
4444fe56b9e6SYuval Mintz 		       "Reading the ME register returns all Fs; Preventing further chip access\n");
4445fe56b9e6SYuval Mintz 		return -EINVAL;
4446fe56b9e6SYuval Mintz 	}
4447fe56b9e6SYuval Mintz 
4448fe56b9e6SYuval Mintz 	get_function_id(p_hwfn);
4449fe56b9e6SYuval Mintz 
445012e09c69SYuval Mintz 	/* Allocate PTT pool */
445112e09c69SYuval Mintz 	rc = qed_ptt_pool_alloc(p_hwfn);
44522591c280SJoe Perches 	if (rc)
4453fe56b9e6SYuval Mintz 		goto err0;
4454fe56b9e6SYuval Mintz 
445512e09c69SYuval Mintz 	/* Allocate the main PTT */
445612e09c69SYuval Mintz 	p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN);
445712e09c69SYuval Mintz 
4458fe56b9e6SYuval Mintz 	/* First hwfn learns basic information, e.g., number of hwfns */
445912e09c69SYuval Mintz 	if (!p_hwfn->my_id) {
446015582962SRahul Verma 		rc = qed_get_dev_info(p_hwfn, p_hwfn->p_main_ptt);
44611a635e48SYuval Mintz 		if (rc)
446212e09c69SYuval Mintz 			goto err1;
446312e09c69SYuval Mintz 	}
446412e09c69SYuval Mintz 
446512e09c69SYuval Mintz 	qed_hw_hwfn_prepare(p_hwfn);
4466fe56b9e6SYuval Mintz 
4467fe56b9e6SYuval Mintz 	/* Initialize MCP structure */
4468fe56b9e6SYuval Mintz 	rc = qed_mcp_cmd_init(p_hwfn, p_hwfn->p_main_ptt);
4469fe56b9e6SYuval Mintz 	if (rc) {
4470fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Failed initializing mcp command\n");
4471fe56b9e6SYuval Mintz 		goto err1;
4472fe56b9e6SYuval Mintz 	}
4473fe56b9e6SYuval Mintz 
4474fe56b9e6SYuval Mintz 	/* Read the device configuration information from the HW and SHMEM */
4475fe56b9e6SYuval Mintz 	rc = qed_get_hw_info(p_hwfn, p_hwfn->p_main_ptt, personality);
4476fe56b9e6SYuval Mintz 	if (rc) {
4477fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Failed to get HW information\n");
4478fe56b9e6SYuval Mintz 		goto err2;
4479fe56b9e6SYuval Mintz 	}
4480fe56b9e6SYuval Mintz 
448118a69e36SMintz, Yuval 	/* Sending a mailbox to the MFW should be done after qed_get_hw_info()
448218a69e36SMintz, Yuval 	 * is called as it sets the ports number in an engine.
448318a69e36SMintz, Yuval 	 */
448464515dc8STomer Tayar 	if (IS_LEAD_HWFN(p_hwfn) && !cdev->recov_in_prog) {
448518a69e36SMintz, Yuval 		rc = qed_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt);
448618a69e36SMintz, Yuval 		if (rc)
448718a69e36SMintz, Yuval 			DP_NOTICE(p_hwfn, "Failed to initiate PF FLR\n");
448818a69e36SMintz, Yuval 	}
448918a69e36SMintz, Yuval 
449043645ce0SSudarsana Reddy Kalluru 	/* NVRAM info initialization and population */
449143645ce0SSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn)) {
449243645ce0SSudarsana Reddy Kalluru 		rc = qed_mcp_nvm_info_populate(p_hwfn);
449343645ce0SSudarsana Reddy Kalluru 		if (rc) {
449443645ce0SSudarsana Reddy Kalluru 			DP_NOTICE(p_hwfn,
449543645ce0SSudarsana Reddy Kalluru 				  "Failed to populate nvm info shadow\n");
449643645ce0SSudarsana Reddy Kalluru 			goto err2;
449743645ce0SSudarsana Reddy Kalluru 		}
449843645ce0SSudarsana Reddy Kalluru 	}
449943645ce0SSudarsana Reddy Kalluru 
4500fe56b9e6SYuval Mintz 	/* Allocate the init RT array and initialize the init-ops engine */
4501fe56b9e6SYuval Mintz 	rc = qed_init_alloc(p_hwfn);
45022591c280SJoe Perches 	if (rc)
450343645ce0SSudarsana Reddy Kalluru 		goto err3;
4504fe56b9e6SYuval Mintz 
4505fe56b9e6SYuval Mintz 	return rc;
450643645ce0SSudarsana Reddy Kalluru err3:
450743645ce0SSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn))
450843645ce0SSudarsana Reddy Kalluru 		qed_nvm_info_free(p_hwfn);
4509fe56b9e6SYuval Mintz err2:
451032a47e72SYuval Mintz 	if (IS_LEAD_HWFN(p_hwfn))
451132a47e72SYuval Mintz 		qed_iov_free_hw_info(p_hwfn->cdev);
4512fe56b9e6SYuval Mintz 	qed_mcp_free(p_hwfn);
4513fe56b9e6SYuval Mintz err1:
4514fe56b9e6SYuval Mintz 	qed_hw_hwfn_free(p_hwfn);
4515fe56b9e6SYuval Mintz err0:
4516fe56b9e6SYuval Mintz 	return rc;
4517fe56b9e6SYuval Mintz }
4518fe56b9e6SYuval Mintz 
4519fe56b9e6SYuval Mintz int qed_hw_prepare(struct qed_dev *cdev,
4520fe56b9e6SYuval Mintz 		   int personality)
4521fe56b9e6SYuval Mintz {
4522c78df14eSAriel Elior 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
4523c78df14eSAriel Elior 	int rc;
4524fe56b9e6SYuval Mintz 
4525fe56b9e6SYuval Mintz 	/* Store the precompiled init data ptrs */
45261408cc1fSYuval Mintz 	if (IS_PF(cdev))
4527fe56b9e6SYuval Mintz 		qed_init_iro_array(cdev);
4528fe56b9e6SYuval Mintz 
4529fe56b9e6SYuval Mintz 	/* Initialize the first hwfn - will learn number of hwfns */
4530c78df14eSAriel Elior 	rc = qed_hw_prepare_single(p_hwfn,
4531c78df14eSAriel Elior 				   cdev->regview,
4532fe56b9e6SYuval Mintz 				   cdev->doorbells, personality);
4533fe56b9e6SYuval Mintz 	if (rc)
4534fe56b9e6SYuval Mintz 		return rc;
4535fe56b9e6SYuval Mintz 
4536c78df14eSAriel Elior 	personality = p_hwfn->hw_info.personality;
4537fe56b9e6SYuval Mintz 
4538fe56b9e6SYuval Mintz 	/* Initialize the rest of the hwfns */
4539c78df14eSAriel Elior 	if (cdev->num_hwfns > 1) {
4540fe56b9e6SYuval Mintz 		void __iomem *p_regview, *p_doorbell;
4541c78df14eSAriel Elior 		u8 __iomem *addr;
4542fe56b9e6SYuval Mintz 
4543c78df14eSAriel Elior 		/* adjust bar offset for second engine */
454415582962SRahul Verma 		addr = cdev->regview +
454515582962SRahul Verma 		       qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
454615582962SRahul Verma 				       BAR_ID_0) / 2;
4547c78df14eSAriel Elior 		p_regview = addr;
4548c78df14eSAriel Elior 
454915582962SRahul Verma 		addr = cdev->doorbells +
455015582962SRahul Verma 		       qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
455115582962SRahul Verma 				       BAR_ID_1) / 2;
4552c78df14eSAriel Elior 		p_doorbell = addr;
4553c78df14eSAriel Elior 
4554c78df14eSAriel Elior 		/* prepare second hw function */
4555c78df14eSAriel Elior 		rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview,
4556fe56b9e6SYuval Mintz 					   p_doorbell, personality);
4557c78df14eSAriel Elior 
4558c78df14eSAriel Elior 		/* in case of error, need to free the previously
4559c78df14eSAriel Elior 		 * initiliazed hwfn 0.
4560c78df14eSAriel Elior 		 */
4561fe56b9e6SYuval Mintz 		if (rc) {
45621408cc1fSYuval Mintz 			if (IS_PF(cdev)) {
4563c78df14eSAriel Elior 				qed_init_free(p_hwfn);
456443645ce0SSudarsana Reddy Kalluru 				qed_nvm_info_free(p_hwfn);
4565c78df14eSAriel Elior 				qed_mcp_free(p_hwfn);
4566c78df14eSAriel Elior 				qed_hw_hwfn_free(p_hwfn);
4567fe56b9e6SYuval Mintz 			}
4568fe56b9e6SYuval Mintz 		}
45691408cc1fSYuval Mintz 	}
4570fe56b9e6SYuval Mintz 
4571c78df14eSAriel Elior 	return rc;
4572fe56b9e6SYuval Mintz }
4573fe56b9e6SYuval Mintz 
4574fe56b9e6SYuval Mintz void qed_hw_remove(struct qed_dev *cdev)
4575fe56b9e6SYuval Mintz {
45760fefbfbaSSudarsana Kalluru 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
4577fe56b9e6SYuval Mintz 	int i;
4578fe56b9e6SYuval Mintz 
45790fefbfbaSSudarsana Kalluru 	if (IS_PF(cdev))
45800fefbfbaSSudarsana Kalluru 		qed_mcp_ov_update_driver_state(p_hwfn, p_hwfn->p_main_ptt,
45810fefbfbaSSudarsana Kalluru 					       QED_OV_DRIVER_STATE_NOT_LOADED);
45820fefbfbaSSudarsana Kalluru 
4583fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
4584fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
4585fe56b9e6SYuval Mintz 
45861408cc1fSYuval Mintz 		if (IS_VF(cdev)) {
45870b55e27dSYuval Mintz 			qed_vf_pf_release(p_hwfn);
45881408cc1fSYuval Mintz 			continue;
45891408cc1fSYuval Mintz 		}
45901408cc1fSYuval Mintz 
4591fe56b9e6SYuval Mintz 		qed_init_free(p_hwfn);
4592fe56b9e6SYuval Mintz 		qed_hw_hwfn_free(p_hwfn);
4593fe56b9e6SYuval Mintz 		qed_mcp_free(p_hwfn);
4594fe56b9e6SYuval Mintz 	}
459532a47e72SYuval Mintz 
459632a47e72SYuval Mintz 	qed_iov_free_hw_info(cdev);
459743645ce0SSudarsana Reddy Kalluru 
459843645ce0SSudarsana Reddy Kalluru 	qed_nvm_info_free(p_hwfn);
4599fe56b9e6SYuval Mintz }
4600fe56b9e6SYuval Mintz 
4601a91eb52aSYuval Mintz static void qed_chain_free_next_ptr(struct qed_dev *cdev,
4602a91eb52aSYuval Mintz 				    struct qed_chain *p_chain)
4603a91eb52aSYuval Mintz {
4604a91eb52aSYuval Mintz 	void *p_virt = p_chain->p_virt_addr, *p_virt_next = NULL;
4605a91eb52aSYuval Mintz 	dma_addr_t p_phys = p_chain->p_phys_addr, p_phys_next = 0;
4606a91eb52aSYuval Mintz 	struct qed_chain_next *p_next;
4607a91eb52aSYuval Mintz 	u32 size, i;
4608a91eb52aSYuval Mintz 
4609a91eb52aSYuval Mintz 	if (!p_virt)
4610a91eb52aSYuval Mintz 		return;
4611a91eb52aSYuval Mintz 
4612a91eb52aSYuval Mintz 	size = p_chain->elem_size * p_chain->usable_per_page;
4613a91eb52aSYuval Mintz 
4614a91eb52aSYuval Mintz 	for (i = 0; i < p_chain->page_cnt; i++) {
4615a91eb52aSYuval Mintz 		if (!p_virt)
4616a91eb52aSYuval Mintz 			break;
4617a91eb52aSYuval Mintz 
4618a91eb52aSYuval Mintz 		p_next = (struct qed_chain_next *)((u8 *)p_virt + size);
4619a91eb52aSYuval Mintz 		p_virt_next = p_next->next_virt;
4620a91eb52aSYuval Mintz 		p_phys_next = HILO_DMA_REGPAIR(p_next->next_phys);
4621a91eb52aSYuval Mintz 
4622a91eb52aSYuval Mintz 		dma_free_coherent(&cdev->pdev->dev,
4623a91eb52aSYuval Mintz 				  QED_CHAIN_PAGE_SIZE, p_virt, p_phys);
4624a91eb52aSYuval Mintz 
4625a91eb52aSYuval Mintz 		p_virt = p_virt_next;
4626a91eb52aSYuval Mintz 		p_phys = p_phys_next;
4627a91eb52aSYuval Mintz 	}
4628a91eb52aSYuval Mintz }
4629a91eb52aSYuval Mintz 
4630a91eb52aSYuval Mintz static void qed_chain_free_single(struct qed_dev *cdev,
4631a91eb52aSYuval Mintz 				  struct qed_chain *p_chain)
4632a91eb52aSYuval Mintz {
4633a91eb52aSYuval Mintz 	if (!p_chain->p_virt_addr)
4634a91eb52aSYuval Mintz 		return;
4635a91eb52aSYuval Mintz 
4636a91eb52aSYuval Mintz 	dma_free_coherent(&cdev->pdev->dev,
4637a91eb52aSYuval Mintz 			  QED_CHAIN_PAGE_SIZE,
4638a91eb52aSYuval Mintz 			  p_chain->p_virt_addr, p_chain->p_phys_addr);
4639a91eb52aSYuval Mintz }
4640a91eb52aSYuval Mintz 
4641a91eb52aSYuval Mintz static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
4642a91eb52aSYuval Mintz {
4643a91eb52aSYuval Mintz 	void **pp_virt_addr_tbl = p_chain->pbl.pp_virt_addr_tbl;
4644a91eb52aSYuval Mintz 	u32 page_cnt = p_chain->page_cnt, i, pbl_size;
46456d937acfSMintz, Yuval 	u8 *p_pbl_virt = p_chain->pbl_sp.p_virt_table;
4646a91eb52aSYuval Mintz 
4647a91eb52aSYuval Mintz 	if (!pp_virt_addr_tbl)
4648a91eb52aSYuval Mintz 		return;
4649a91eb52aSYuval Mintz 
46506d937acfSMintz, Yuval 	if (!p_pbl_virt)
4651a91eb52aSYuval Mintz 		goto out;
4652a91eb52aSYuval Mintz 
4653a91eb52aSYuval Mintz 	for (i = 0; i < page_cnt; i++) {
4654a91eb52aSYuval Mintz 		if (!pp_virt_addr_tbl[i])
4655a91eb52aSYuval Mintz 			break;
4656a91eb52aSYuval Mintz 
4657a91eb52aSYuval Mintz 		dma_free_coherent(&cdev->pdev->dev,
4658a91eb52aSYuval Mintz 				  QED_CHAIN_PAGE_SIZE,
4659a91eb52aSYuval Mintz 				  pp_virt_addr_tbl[i],
4660a91eb52aSYuval Mintz 				  *(dma_addr_t *)p_pbl_virt);
4661a91eb52aSYuval Mintz 
4662a91eb52aSYuval Mintz 		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
4663a91eb52aSYuval Mintz 	}
4664a91eb52aSYuval Mintz 
4665a91eb52aSYuval Mintz 	pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
46661a4a6975SMintz, Yuval 
46671a4a6975SMintz, Yuval 	if (!p_chain->b_external_pbl)
4668a91eb52aSYuval Mintz 		dma_free_coherent(&cdev->pdev->dev,
4669a91eb52aSYuval Mintz 				  pbl_size,
46706d937acfSMintz, Yuval 				  p_chain->pbl_sp.p_virt_table,
46716d937acfSMintz, Yuval 				  p_chain->pbl_sp.p_phys_table);
4672a91eb52aSYuval Mintz out:
4673a91eb52aSYuval Mintz 	vfree(p_chain->pbl.pp_virt_addr_tbl);
46741a4a6975SMintz, Yuval 	p_chain->pbl.pp_virt_addr_tbl = NULL;
4675a91eb52aSYuval Mintz }
4676a91eb52aSYuval Mintz 
4677a91eb52aSYuval Mintz void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain)
4678a91eb52aSYuval Mintz {
4679a91eb52aSYuval Mintz 	switch (p_chain->mode) {
4680a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_NEXT_PTR:
4681a91eb52aSYuval Mintz 		qed_chain_free_next_ptr(cdev, p_chain);
4682a91eb52aSYuval Mintz 		break;
4683a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_SINGLE:
4684a91eb52aSYuval Mintz 		qed_chain_free_single(cdev, p_chain);
4685a91eb52aSYuval Mintz 		break;
4686a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_PBL:
4687a91eb52aSYuval Mintz 		qed_chain_free_pbl(cdev, p_chain);
4688a91eb52aSYuval Mintz 		break;
4689a91eb52aSYuval Mintz 	}
4690a91eb52aSYuval Mintz }
4691a91eb52aSYuval Mintz 
4692a91eb52aSYuval Mintz static int
4693a91eb52aSYuval Mintz qed_chain_alloc_sanity_check(struct qed_dev *cdev,
4694a91eb52aSYuval Mintz 			     enum qed_chain_cnt_type cnt_type,
4695a91eb52aSYuval Mintz 			     size_t elem_size, u32 page_cnt)
4696a91eb52aSYuval Mintz {
4697a91eb52aSYuval Mintz 	u64 chain_size = ELEMS_PER_PAGE(elem_size) * page_cnt;
4698a91eb52aSYuval Mintz 
4699a91eb52aSYuval Mintz 	/* The actual chain size can be larger than the maximal possible value
4700a91eb52aSYuval Mintz 	 * after rounding up the requested elements number to pages, and after
4701a91eb52aSYuval Mintz 	 * taking into acount the unusuable elements (next-ptr elements).
4702a91eb52aSYuval Mintz 	 * The size of a "u16" chain can be (U16_MAX + 1) since the chain
4703a91eb52aSYuval Mintz 	 * size/capacity fields are of a u32 type.
4704a91eb52aSYuval Mintz 	 */
4705a91eb52aSYuval Mintz 	if ((cnt_type == QED_CHAIN_CNT_TYPE_U16 &&
47063ef310a7STomer Tayar 	     chain_size > ((u32)U16_MAX + 1)) ||
47073ef310a7STomer Tayar 	    (cnt_type == QED_CHAIN_CNT_TYPE_U32 && chain_size > U32_MAX)) {
4708a91eb52aSYuval Mintz 		DP_NOTICE(cdev,
4709a91eb52aSYuval Mintz 			  "The actual chain size (0x%llx) is larger than the maximal possible value\n",
4710a91eb52aSYuval Mintz 			  chain_size);
4711a91eb52aSYuval Mintz 		return -EINVAL;
4712a91eb52aSYuval Mintz 	}
4713a91eb52aSYuval Mintz 
4714a91eb52aSYuval Mintz 	return 0;
4715a91eb52aSYuval Mintz }
4716a91eb52aSYuval Mintz 
4717a91eb52aSYuval Mintz static int
4718a91eb52aSYuval Mintz qed_chain_alloc_next_ptr(struct qed_dev *cdev, struct qed_chain *p_chain)
4719a91eb52aSYuval Mintz {
4720a91eb52aSYuval Mintz 	void *p_virt = NULL, *p_virt_prev = NULL;
4721a91eb52aSYuval Mintz 	dma_addr_t p_phys = 0;
4722a91eb52aSYuval Mintz 	u32 i;
4723a91eb52aSYuval Mintz 
4724a91eb52aSYuval Mintz 	for (i = 0; i < p_chain->page_cnt; i++) {
4725a91eb52aSYuval Mintz 		p_virt = dma_alloc_coherent(&cdev->pdev->dev,
4726a91eb52aSYuval Mintz 					    QED_CHAIN_PAGE_SIZE,
4727a91eb52aSYuval Mintz 					    &p_phys, GFP_KERNEL);
47282591c280SJoe Perches 		if (!p_virt)
4729a91eb52aSYuval Mintz 			return -ENOMEM;
4730a91eb52aSYuval Mintz 
4731a91eb52aSYuval Mintz 		if (i == 0) {
4732a91eb52aSYuval Mintz 			qed_chain_init_mem(p_chain, p_virt, p_phys);
4733a91eb52aSYuval Mintz 			qed_chain_reset(p_chain);
4734a91eb52aSYuval Mintz 		} else {
4735a91eb52aSYuval Mintz 			qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
4736a91eb52aSYuval Mintz 						     p_virt, p_phys);
4737a91eb52aSYuval Mintz 		}
4738a91eb52aSYuval Mintz 
4739a91eb52aSYuval Mintz 		p_virt_prev = p_virt;
4740a91eb52aSYuval Mintz 	}
4741a91eb52aSYuval Mintz 	/* Last page's next element should point to the beginning of the
4742a91eb52aSYuval Mintz 	 * chain.
4743a91eb52aSYuval Mintz 	 */
4744a91eb52aSYuval Mintz 	qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
4745a91eb52aSYuval Mintz 				     p_chain->p_virt_addr,
4746a91eb52aSYuval Mintz 				     p_chain->p_phys_addr);
4747a91eb52aSYuval Mintz 
4748a91eb52aSYuval Mintz 	return 0;
4749a91eb52aSYuval Mintz }
4750a91eb52aSYuval Mintz 
4751a91eb52aSYuval Mintz static int
4752a91eb52aSYuval Mintz qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain)
4753a91eb52aSYuval Mintz {
4754a91eb52aSYuval Mintz 	dma_addr_t p_phys = 0;
4755a91eb52aSYuval Mintz 	void *p_virt = NULL;
4756a91eb52aSYuval Mintz 
4757a91eb52aSYuval Mintz 	p_virt = dma_alloc_coherent(&cdev->pdev->dev,
4758a91eb52aSYuval Mintz 				    QED_CHAIN_PAGE_SIZE, &p_phys, GFP_KERNEL);
47592591c280SJoe Perches 	if (!p_virt)
4760a91eb52aSYuval Mintz 		return -ENOMEM;
4761a91eb52aSYuval Mintz 
4762a91eb52aSYuval Mintz 	qed_chain_init_mem(p_chain, p_virt, p_phys);
4763a91eb52aSYuval Mintz 	qed_chain_reset(p_chain);
4764a91eb52aSYuval Mintz 
4765a91eb52aSYuval Mintz 	return 0;
4766a91eb52aSYuval Mintz }
4767a91eb52aSYuval Mintz 
47681a4a6975SMintz, Yuval static int
47691a4a6975SMintz, Yuval qed_chain_alloc_pbl(struct qed_dev *cdev,
47701a4a6975SMintz, Yuval 		    struct qed_chain *p_chain,
47711a4a6975SMintz, Yuval 		    struct qed_chain_ext_pbl *ext_pbl)
4772a91eb52aSYuval Mintz {
4773a91eb52aSYuval Mintz 	u32 page_cnt = p_chain->page_cnt, size, i;
4774a91eb52aSYuval Mintz 	dma_addr_t p_phys = 0, p_pbl_phys = 0;
4775a91eb52aSYuval Mintz 	void **pp_virt_addr_tbl = NULL;
4776a91eb52aSYuval Mintz 	u8 *p_pbl_virt = NULL;
4777a91eb52aSYuval Mintz 	void *p_virt = NULL;
4778a91eb52aSYuval Mintz 
4779a91eb52aSYuval Mintz 	size = page_cnt * sizeof(*pp_virt_addr_tbl);
47802591c280SJoe Perches 	pp_virt_addr_tbl = vzalloc(size);
47812591c280SJoe Perches 	if (!pp_virt_addr_tbl)
4782a91eb52aSYuval Mintz 		return -ENOMEM;
4783a91eb52aSYuval Mintz 
4784a91eb52aSYuval Mintz 	/* The allocation of the PBL table is done with its full size, since it
4785a91eb52aSYuval Mintz 	 * is expected to be successive.
4786a91eb52aSYuval Mintz 	 * qed_chain_init_pbl_mem() is called even in a case of an allocation
4787a91eb52aSYuval Mintz 	 * failure, since pp_virt_addr_tbl was previously allocated, and it
4788a91eb52aSYuval Mintz 	 * should be saved to allow its freeing during the error flow.
4789a91eb52aSYuval Mintz 	 */
4790a91eb52aSYuval Mintz 	size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
47911a4a6975SMintz, Yuval 
47921a4a6975SMintz, Yuval 	if (!ext_pbl) {
4793a91eb52aSYuval Mintz 		p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev,
4794a91eb52aSYuval Mintz 						size, &p_pbl_phys, GFP_KERNEL);
47951a4a6975SMintz, Yuval 	} else {
47961a4a6975SMintz, Yuval 		p_pbl_virt = ext_pbl->p_pbl_virt;
47971a4a6975SMintz, Yuval 		p_pbl_phys = ext_pbl->p_pbl_phys;
47981a4a6975SMintz, Yuval 		p_chain->b_external_pbl = true;
47991a4a6975SMintz, Yuval 	}
48001a4a6975SMintz, Yuval 
4801a91eb52aSYuval Mintz 	qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys,
4802a91eb52aSYuval Mintz 			       pp_virt_addr_tbl);
48032591c280SJoe Perches 	if (!p_pbl_virt)
4804a91eb52aSYuval Mintz 		return -ENOMEM;
4805a91eb52aSYuval Mintz 
4806a91eb52aSYuval Mintz 	for (i = 0; i < page_cnt; i++) {
4807a91eb52aSYuval Mintz 		p_virt = dma_alloc_coherent(&cdev->pdev->dev,
4808a91eb52aSYuval Mintz 					    QED_CHAIN_PAGE_SIZE,
4809a91eb52aSYuval Mintz 					    &p_phys, GFP_KERNEL);
48102591c280SJoe Perches 		if (!p_virt)
4811a91eb52aSYuval Mintz 			return -ENOMEM;
4812a91eb52aSYuval Mintz 
4813a91eb52aSYuval Mintz 		if (i == 0) {
4814a91eb52aSYuval Mintz 			qed_chain_init_mem(p_chain, p_virt, p_phys);
4815a91eb52aSYuval Mintz 			qed_chain_reset(p_chain);
4816a91eb52aSYuval Mintz 		}
4817a91eb52aSYuval Mintz 
4818a91eb52aSYuval Mintz 		/* Fill the PBL table with the physical address of the page */
4819a91eb52aSYuval Mintz 		*(dma_addr_t *)p_pbl_virt = p_phys;
4820a91eb52aSYuval Mintz 		/* Keep the virtual address of the page */
4821a91eb52aSYuval Mintz 		p_chain->pbl.pp_virt_addr_tbl[i] = p_virt;
4822a91eb52aSYuval Mintz 
4823a91eb52aSYuval Mintz 		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
4824a91eb52aSYuval Mintz 	}
4825a91eb52aSYuval Mintz 
4826a91eb52aSYuval Mintz 	return 0;
4827a91eb52aSYuval Mintz }
4828a91eb52aSYuval Mintz 
4829fe56b9e6SYuval Mintz int qed_chain_alloc(struct qed_dev *cdev,
4830fe56b9e6SYuval Mintz 		    enum qed_chain_use_mode intended_use,
4831fe56b9e6SYuval Mintz 		    enum qed_chain_mode mode,
4832a91eb52aSYuval Mintz 		    enum qed_chain_cnt_type cnt_type,
48331a4a6975SMintz, Yuval 		    u32 num_elems,
48341a4a6975SMintz, Yuval 		    size_t elem_size,
48351a4a6975SMintz, Yuval 		    struct qed_chain *p_chain,
48361a4a6975SMintz, Yuval 		    struct qed_chain_ext_pbl *ext_pbl)
4837fe56b9e6SYuval Mintz {
4838a91eb52aSYuval Mintz 	u32 page_cnt;
4839a91eb52aSYuval Mintz 	int rc = 0;
4840fe56b9e6SYuval Mintz 
4841fe56b9e6SYuval Mintz 	if (mode == QED_CHAIN_MODE_SINGLE)
4842fe56b9e6SYuval Mintz 		page_cnt = 1;
4843fe56b9e6SYuval Mintz 	else
4844fe56b9e6SYuval Mintz 		page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode);
4845fe56b9e6SYuval Mintz 
4846a91eb52aSYuval Mintz 	rc = qed_chain_alloc_sanity_check(cdev, cnt_type, elem_size, page_cnt);
4847a91eb52aSYuval Mintz 	if (rc) {
4848a91eb52aSYuval Mintz 		DP_NOTICE(cdev,
48492591c280SJoe Perches 			  "Cannot allocate a chain with the given arguments:\n");
48502591c280SJoe Perches 		DP_NOTICE(cdev,
4851a91eb52aSYuval Mintz 			  "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n",
4852a91eb52aSYuval Mintz 			  intended_use, mode, cnt_type, num_elems, elem_size);
4853a91eb52aSYuval Mintz 		return rc;
4854fe56b9e6SYuval Mintz 	}
4855fe56b9e6SYuval Mintz 
4856a91eb52aSYuval Mintz 	qed_chain_init_params(p_chain, page_cnt, (u8) elem_size, intended_use,
4857a91eb52aSYuval Mintz 			      mode, cnt_type);
4858fe56b9e6SYuval Mintz 
4859a91eb52aSYuval Mintz 	switch (mode) {
4860a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_NEXT_PTR:
4861a91eb52aSYuval Mintz 		rc = qed_chain_alloc_next_ptr(cdev, p_chain);
4862a91eb52aSYuval Mintz 		break;
4863a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_SINGLE:
4864a91eb52aSYuval Mintz 		rc = qed_chain_alloc_single(cdev, p_chain);
4865a91eb52aSYuval Mintz 		break;
4866a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_PBL:
48671a4a6975SMintz, Yuval 		rc = qed_chain_alloc_pbl(cdev, p_chain, ext_pbl);
4868a91eb52aSYuval Mintz 		break;
4869fe56b9e6SYuval Mintz 	}
4870a91eb52aSYuval Mintz 	if (rc)
4871a91eb52aSYuval Mintz 		goto nomem;
4872fe56b9e6SYuval Mintz 
4873fe56b9e6SYuval Mintz 	return 0;
4874fe56b9e6SYuval Mintz 
4875fe56b9e6SYuval Mintz nomem:
4876a91eb52aSYuval Mintz 	qed_chain_free(cdev, p_chain);
4877a91eb52aSYuval Mintz 	return rc;
4878fe56b9e6SYuval Mintz }
4879fe56b9e6SYuval Mintz 
4880a91eb52aSYuval Mintz int qed_fw_l2_queue(struct qed_hwfn *p_hwfn, u16 src_id, u16 *dst_id)
4881cee4d264SManish Chopra {
4882cee4d264SManish Chopra 	if (src_id >= RESC_NUM(p_hwfn, QED_L2_QUEUE)) {
4883cee4d264SManish Chopra 		u16 min, max;
4884cee4d264SManish Chopra 
4885cee4d264SManish Chopra 		min = (u16) RESC_START(p_hwfn, QED_L2_QUEUE);
4886cee4d264SManish Chopra 		max = min + RESC_NUM(p_hwfn, QED_L2_QUEUE);
4887cee4d264SManish Chopra 		DP_NOTICE(p_hwfn,
4888cee4d264SManish Chopra 			  "l2_queue id [%d] is not valid, available indices [%d - %d]\n",
4889cee4d264SManish Chopra 			  src_id, min, max);
4890cee4d264SManish Chopra 
4891cee4d264SManish Chopra 		return -EINVAL;
4892cee4d264SManish Chopra 	}
4893cee4d264SManish Chopra 
4894cee4d264SManish Chopra 	*dst_id = RESC_START(p_hwfn, QED_L2_QUEUE) + src_id;
4895cee4d264SManish Chopra 
4896cee4d264SManish Chopra 	return 0;
4897cee4d264SManish Chopra }
4898cee4d264SManish Chopra 
48991a635e48SYuval Mintz int qed_fw_vport(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id)
4900cee4d264SManish Chopra {
4901cee4d264SManish Chopra 	if (src_id >= RESC_NUM(p_hwfn, QED_VPORT)) {
4902cee4d264SManish Chopra 		u8 min, max;
4903cee4d264SManish Chopra 
4904cee4d264SManish Chopra 		min = (u8)RESC_START(p_hwfn, QED_VPORT);
4905cee4d264SManish Chopra 		max = min + RESC_NUM(p_hwfn, QED_VPORT);
4906cee4d264SManish Chopra 		DP_NOTICE(p_hwfn,
4907cee4d264SManish Chopra 			  "vport id [%d] is not valid, available indices [%d - %d]\n",
4908cee4d264SManish Chopra 			  src_id, min, max);
4909cee4d264SManish Chopra 
4910cee4d264SManish Chopra 		return -EINVAL;
4911cee4d264SManish Chopra 	}
4912cee4d264SManish Chopra 
4913cee4d264SManish Chopra 	*dst_id = RESC_START(p_hwfn, QED_VPORT) + src_id;
4914cee4d264SManish Chopra 
4915cee4d264SManish Chopra 	return 0;
4916cee4d264SManish Chopra }
4917cee4d264SManish Chopra 
49181a635e48SYuval Mintz int qed_fw_rss_eng(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id)
4919cee4d264SManish Chopra {
4920cee4d264SManish Chopra 	if (src_id >= RESC_NUM(p_hwfn, QED_RSS_ENG)) {
4921cee4d264SManish Chopra 		u8 min, max;
4922cee4d264SManish Chopra 
4923cee4d264SManish Chopra 		min = (u8)RESC_START(p_hwfn, QED_RSS_ENG);
4924cee4d264SManish Chopra 		max = min + RESC_NUM(p_hwfn, QED_RSS_ENG);
4925cee4d264SManish Chopra 		DP_NOTICE(p_hwfn,
4926cee4d264SManish Chopra 			  "rss_eng id [%d] is not valid, available indices [%d - %d]\n",
4927cee4d264SManish Chopra 			  src_id, min, max);
4928cee4d264SManish Chopra 
4929cee4d264SManish Chopra 		return -EINVAL;
4930cee4d264SManish Chopra 	}
4931cee4d264SManish Chopra 
4932cee4d264SManish Chopra 	*dst_id = RESC_START(p_hwfn, QED_RSS_ENG) + src_id;
4933cee4d264SManish Chopra 
4934cee4d264SManish Chopra 	return 0;
4935cee4d264SManish Chopra }
4936bcd197c8SManish Chopra 
4937722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
4938722003acSSudarsana Reddy Kalluru 			    u32 hw_addr, void *p_eth_qzone,
4939722003acSSudarsana Reddy Kalluru 			    size_t eth_qzone_size, u8 timeset)
4940722003acSSudarsana Reddy Kalluru {
4941722003acSSudarsana Reddy Kalluru 	struct coalescing_timeset *p_coal_timeset;
4942722003acSSudarsana Reddy Kalluru 
4943722003acSSudarsana Reddy Kalluru 	if (p_hwfn->cdev->int_coalescing_mode != QED_COAL_MODE_ENABLE) {
4944722003acSSudarsana Reddy Kalluru 		DP_NOTICE(p_hwfn, "Coalescing configuration not enabled\n");
4945722003acSSudarsana Reddy Kalluru 		return -EINVAL;
4946722003acSSudarsana Reddy Kalluru 	}
4947722003acSSudarsana Reddy Kalluru 
4948722003acSSudarsana Reddy Kalluru 	p_coal_timeset = p_eth_qzone;
4949477f2d14SRahul Verma 	memset(p_eth_qzone, 0, eth_qzone_size);
4950722003acSSudarsana Reddy Kalluru 	SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset);
4951722003acSSudarsana Reddy Kalluru 	SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1);
4952722003acSSudarsana Reddy Kalluru 	qed_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size);
4953722003acSSudarsana Reddy Kalluru 
4954722003acSSudarsana Reddy Kalluru 	return 0;
4955722003acSSudarsana Reddy Kalluru }
4956722003acSSudarsana Reddy Kalluru 
4957477f2d14SRahul Verma int qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle)
4958477f2d14SRahul Verma {
4959477f2d14SRahul Verma 	struct qed_queue_cid *p_cid = p_handle;
4960477f2d14SRahul Verma 	struct qed_hwfn *p_hwfn;
4961477f2d14SRahul Verma 	struct qed_ptt *p_ptt;
4962477f2d14SRahul Verma 	int rc = 0;
4963477f2d14SRahul Verma 
4964477f2d14SRahul Verma 	p_hwfn = p_cid->p_owner;
4965477f2d14SRahul Verma 
4966477f2d14SRahul Verma 	if (IS_VF(p_hwfn->cdev))
4967477f2d14SRahul Verma 		return qed_vf_pf_set_coalesce(p_hwfn, rx_coal, tx_coal, p_cid);
4968477f2d14SRahul Verma 
4969477f2d14SRahul Verma 	p_ptt = qed_ptt_acquire(p_hwfn);
4970477f2d14SRahul Verma 	if (!p_ptt)
4971477f2d14SRahul Verma 		return -EAGAIN;
4972477f2d14SRahul Verma 
4973477f2d14SRahul Verma 	if (rx_coal) {
4974477f2d14SRahul Verma 		rc = qed_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid);
4975477f2d14SRahul Verma 		if (rc)
4976477f2d14SRahul Verma 			goto out;
4977477f2d14SRahul Verma 		p_hwfn->cdev->rx_coalesce_usecs = rx_coal;
4978477f2d14SRahul Verma 	}
4979477f2d14SRahul Verma 
4980477f2d14SRahul Verma 	if (tx_coal) {
4981477f2d14SRahul Verma 		rc = qed_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, p_cid);
4982477f2d14SRahul Verma 		if (rc)
4983477f2d14SRahul Verma 			goto out;
4984477f2d14SRahul Verma 		p_hwfn->cdev->tx_coalesce_usecs = tx_coal;
4985477f2d14SRahul Verma 	}
4986477f2d14SRahul Verma out:
4987477f2d14SRahul Verma 	qed_ptt_release(p_hwfn, p_ptt);
4988477f2d14SRahul Verma 	return rc;
4989477f2d14SRahul Verma }
4990477f2d14SRahul Verma 
4991477f2d14SRahul Verma int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn,
4992477f2d14SRahul Verma 			 struct qed_ptt *p_ptt,
4993477f2d14SRahul Verma 			 u16 coalesce, struct qed_queue_cid *p_cid)
4994722003acSSudarsana Reddy Kalluru {
4995722003acSSudarsana Reddy Kalluru 	struct ustorm_eth_queue_zone eth_qzone;
4996722003acSSudarsana Reddy Kalluru 	u8 timeset, timer_res;
4997722003acSSudarsana Reddy Kalluru 	u32 address;
4998722003acSSudarsana Reddy Kalluru 	int rc;
4999722003acSSudarsana Reddy Kalluru 
5000722003acSSudarsana Reddy Kalluru 	/* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */
5001722003acSSudarsana Reddy Kalluru 	if (coalesce <= 0x7F) {
5002722003acSSudarsana Reddy Kalluru 		timer_res = 0;
5003722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0xFF) {
5004722003acSSudarsana Reddy Kalluru 		timer_res = 1;
5005722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0x1FF) {
5006722003acSSudarsana Reddy Kalluru 		timer_res = 2;
5007722003acSSudarsana Reddy Kalluru 	} else {
5008722003acSSudarsana Reddy Kalluru 		DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce);
5009722003acSSudarsana Reddy Kalluru 		return -EINVAL;
5010722003acSSudarsana Reddy Kalluru 	}
5011722003acSSudarsana Reddy Kalluru 	timeset = (u8)(coalesce >> timer_res);
5012722003acSSudarsana Reddy Kalluru 
5013477f2d14SRahul Verma 	rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res,
5014477f2d14SRahul Verma 				   p_cid->sb_igu_id, false);
5015722003acSSudarsana Reddy Kalluru 	if (rc)
5016722003acSSudarsana Reddy Kalluru 		goto out;
5017722003acSSudarsana Reddy Kalluru 
5018477f2d14SRahul Verma 	address = BAR0_MAP_REG_USDM_RAM +
5019477f2d14SRahul Verma 		  USTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
5020722003acSSudarsana Reddy Kalluru 
5021722003acSSudarsana Reddy Kalluru 	rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
5022722003acSSudarsana Reddy Kalluru 			      sizeof(struct ustorm_eth_queue_zone), timeset);
5023722003acSSudarsana Reddy Kalluru 	if (rc)
5024722003acSSudarsana Reddy Kalluru 		goto out;
5025722003acSSudarsana Reddy Kalluru 
5026722003acSSudarsana Reddy Kalluru out:
5027722003acSSudarsana Reddy Kalluru 	return rc;
5028722003acSSudarsana Reddy Kalluru }
5029722003acSSudarsana Reddy Kalluru 
5030477f2d14SRahul Verma int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn,
5031477f2d14SRahul Verma 			 struct qed_ptt *p_ptt,
5032477f2d14SRahul Verma 			 u16 coalesce, struct qed_queue_cid *p_cid)
5033722003acSSudarsana Reddy Kalluru {
5034722003acSSudarsana Reddy Kalluru 	struct xstorm_eth_queue_zone eth_qzone;
5035722003acSSudarsana Reddy Kalluru 	u8 timeset, timer_res;
5036722003acSSudarsana Reddy Kalluru 	u32 address;
5037722003acSSudarsana Reddy Kalluru 	int rc;
5038722003acSSudarsana Reddy Kalluru 
5039722003acSSudarsana Reddy Kalluru 	/* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */
5040722003acSSudarsana Reddy Kalluru 	if (coalesce <= 0x7F) {
5041722003acSSudarsana Reddy Kalluru 		timer_res = 0;
5042722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0xFF) {
5043722003acSSudarsana Reddy Kalluru 		timer_res = 1;
5044722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0x1FF) {
5045722003acSSudarsana Reddy Kalluru 		timer_res = 2;
5046722003acSSudarsana Reddy Kalluru 	} else {
5047722003acSSudarsana Reddy Kalluru 		DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce);
5048722003acSSudarsana Reddy Kalluru 		return -EINVAL;
5049722003acSSudarsana Reddy Kalluru 	}
5050722003acSSudarsana Reddy Kalluru 	timeset = (u8)(coalesce >> timer_res);
5051722003acSSudarsana Reddy Kalluru 
5052477f2d14SRahul Verma 	rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res,
5053477f2d14SRahul Verma 				   p_cid->sb_igu_id, true);
5054722003acSSudarsana Reddy Kalluru 	if (rc)
5055722003acSSudarsana Reddy Kalluru 		goto out;
5056722003acSSudarsana Reddy Kalluru 
5057477f2d14SRahul Verma 	address = BAR0_MAP_REG_XSDM_RAM +
5058477f2d14SRahul Verma 		  XSTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
5059722003acSSudarsana Reddy Kalluru 
5060722003acSSudarsana Reddy Kalluru 	rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
5061722003acSSudarsana Reddy Kalluru 			      sizeof(struct xstorm_eth_queue_zone), timeset);
5062722003acSSudarsana Reddy Kalluru out:
5063722003acSSudarsana Reddy Kalluru 	return rc;
5064722003acSSudarsana Reddy Kalluru }
5065722003acSSudarsana Reddy Kalluru 
5066bcd197c8SManish Chopra /* Calculate final WFQ values for all vports and configure them.
5067bcd197c8SManish Chopra  * After this configuration each vport will have
5068bcd197c8SManish Chopra  * approx min rate =  min_pf_rate * (vport_wfq / QED_WFQ_UNIT)
5069bcd197c8SManish Chopra  */
5070bcd197c8SManish Chopra static void qed_configure_wfq_for_all_vports(struct qed_hwfn *p_hwfn,
5071bcd197c8SManish Chopra 					     struct qed_ptt *p_ptt,
5072bcd197c8SManish Chopra 					     u32 min_pf_rate)
5073bcd197c8SManish Chopra {
5074bcd197c8SManish Chopra 	struct init_qm_vport_params *vport_params;
5075bcd197c8SManish Chopra 	int i;
5076bcd197c8SManish Chopra 
5077bcd197c8SManish Chopra 	vport_params = p_hwfn->qm_info.qm_vport_params;
5078bcd197c8SManish Chopra 
5079bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++) {
5080bcd197c8SManish Chopra 		u32 wfq_speed = p_hwfn->qm_info.wfq_data[i].min_speed;
5081bcd197c8SManish Chopra 
5082bcd197c8SManish Chopra 		vport_params[i].vport_wfq = (wfq_speed * QED_WFQ_UNIT) /
5083bcd197c8SManish Chopra 						min_pf_rate;
5084bcd197c8SManish Chopra 		qed_init_vport_wfq(p_hwfn, p_ptt,
5085bcd197c8SManish Chopra 				   vport_params[i].first_tx_pq_id,
5086bcd197c8SManish Chopra 				   vport_params[i].vport_wfq);
5087bcd197c8SManish Chopra 	}
5088bcd197c8SManish Chopra }
5089bcd197c8SManish Chopra 
5090bcd197c8SManish Chopra static void qed_init_wfq_default_param(struct qed_hwfn *p_hwfn,
5091bcd197c8SManish Chopra 				       u32 min_pf_rate)
5092bcd197c8SManish Chopra 
5093bcd197c8SManish Chopra {
5094bcd197c8SManish Chopra 	int i;
5095bcd197c8SManish Chopra 
5096bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++)
5097bcd197c8SManish Chopra 		p_hwfn->qm_info.qm_vport_params[i].vport_wfq = 1;
5098bcd197c8SManish Chopra }
5099bcd197c8SManish Chopra 
5100bcd197c8SManish Chopra static void qed_disable_wfq_for_all_vports(struct qed_hwfn *p_hwfn,
5101bcd197c8SManish Chopra 					   struct qed_ptt *p_ptt,
5102bcd197c8SManish Chopra 					   u32 min_pf_rate)
5103bcd197c8SManish Chopra {
5104bcd197c8SManish Chopra 	struct init_qm_vport_params *vport_params;
5105bcd197c8SManish Chopra 	int i;
5106bcd197c8SManish Chopra 
5107bcd197c8SManish Chopra 	vport_params = p_hwfn->qm_info.qm_vport_params;
5108bcd197c8SManish Chopra 
5109bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++) {
5110bcd197c8SManish Chopra 		qed_init_wfq_default_param(p_hwfn, min_pf_rate);
5111bcd197c8SManish Chopra 		qed_init_vport_wfq(p_hwfn, p_ptt,
5112bcd197c8SManish Chopra 				   vport_params[i].first_tx_pq_id,
5113bcd197c8SManish Chopra 				   vport_params[i].vport_wfq);
5114bcd197c8SManish Chopra 	}
5115bcd197c8SManish Chopra }
5116bcd197c8SManish Chopra 
5117bcd197c8SManish Chopra /* This function performs several validations for WFQ
5118bcd197c8SManish Chopra  * configuration and required min rate for a given vport
5119bcd197c8SManish Chopra  * 1. req_rate must be greater than one percent of min_pf_rate.
5120bcd197c8SManish Chopra  * 2. req_rate should not cause other vports [not configured for WFQ explicitly]
5121bcd197c8SManish Chopra  *    rates to get less than one percent of min_pf_rate.
5122bcd197c8SManish Chopra  * 3. total_req_min_rate [all vports min rate sum] shouldn't exceed min_pf_rate.
5123bcd197c8SManish Chopra  */
5124bcd197c8SManish Chopra static int qed_init_wfq_param(struct qed_hwfn *p_hwfn,
51251a635e48SYuval Mintz 			      u16 vport_id, u32 req_rate, u32 min_pf_rate)
5126bcd197c8SManish Chopra {
5127bcd197c8SManish Chopra 	u32 total_req_min_rate = 0, total_left_rate = 0, left_rate_per_vp = 0;
5128bcd197c8SManish Chopra 	int non_requested_count = 0, req_count = 0, i, num_vports;
5129bcd197c8SManish Chopra 
5130bcd197c8SManish Chopra 	num_vports = p_hwfn->qm_info.num_vports;
5131bcd197c8SManish Chopra 
5132bcd197c8SManish Chopra 	/* Accounting for the vports which are configured for WFQ explicitly */
5133bcd197c8SManish Chopra 	for (i = 0; i < num_vports; i++) {
5134bcd197c8SManish Chopra 		u32 tmp_speed;
5135bcd197c8SManish Chopra 
5136bcd197c8SManish Chopra 		if ((i != vport_id) &&
5137bcd197c8SManish Chopra 		    p_hwfn->qm_info.wfq_data[i].configured) {
5138bcd197c8SManish Chopra 			req_count++;
5139bcd197c8SManish Chopra 			tmp_speed = p_hwfn->qm_info.wfq_data[i].min_speed;
5140bcd197c8SManish Chopra 			total_req_min_rate += tmp_speed;
5141bcd197c8SManish Chopra 		}
5142bcd197c8SManish Chopra 	}
5143bcd197c8SManish Chopra 
5144bcd197c8SManish Chopra 	/* Include current vport data as well */
5145bcd197c8SManish Chopra 	req_count++;
5146bcd197c8SManish Chopra 	total_req_min_rate += req_rate;
5147bcd197c8SManish Chopra 	non_requested_count = num_vports - req_count;
5148bcd197c8SManish Chopra 
5149bcd197c8SManish Chopra 	if (req_rate < min_pf_rate / QED_WFQ_UNIT) {
5150bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5151bcd197c8SManish Chopra 			   "Vport [%d] - Requested rate[%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n",
5152bcd197c8SManish Chopra 			   vport_id, req_rate, min_pf_rate);
5153bcd197c8SManish Chopra 		return -EINVAL;
5154bcd197c8SManish Chopra 	}
5155bcd197c8SManish Chopra 
5156bcd197c8SManish Chopra 	if (num_vports > QED_WFQ_UNIT) {
5157bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5158bcd197c8SManish Chopra 			   "Number of vports is greater than %d\n",
5159bcd197c8SManish Chopra 			   QED_WFQ_UNIT);
5160bcd197c8SManish Chopra 		return -EINVAL;
5161bcd197c8SManish Chopra 	}
5162bcd197c8SManish Chopra 
5163bcd197c8SManish Chopra 	if (total_req_min_rate > min_pf_rate) {
5164bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5165bcd197c8SManish Chopra 			   "Total requested min rate for all vports[%d Mbps] is greater than configured PF min rate[%d Mbps]\n",
5166bcd197c8SManish Chopra 			   total_req_min_rate, min_pf_rate);
5167bcd197c8SManish Chopra 		return -EINVAL;
5168bcd197c8SManish Chopra 	}
5169bcd197c8SManish Chopra 
5170bcd197c8SManish Chopra 	total_left_rate	= min_pf_rate - total_req_min_rate;
5171bcd197c8SManish Chopra 
5172bcd197c8SManish Chopra 	left_rate_per_vp = total_left_rate / non_requested_count;
5173bcd197c8SManish Chopra 	if (left_rate_per_vp <  min_pf_rate / QED_WFQ_UNIT) {
5174bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5175bcd197c8SManish Chopra 			   "Non WFQ configured vports rate [%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n",
5176bcd197c8SManish Chopra 			   left_rate_per_vp, min_pf_rate);
5177bcd197c8SManish Chopra 		return -EINVAL;
5178bcd197c8SManish Chopra 	}
5179bcd197c8SManish Chopra 
5180bcd197c8SManish Chopra 	p_hwfn->qm_info.wfq_data[vport_id].min_speed = req_rate;
5181bcd197c8SManish Chopra 	p_hwfn->qm_info.wfq_data[vport_id].configured = true;
5182bcd197c8SManish Chopra 
5183bcd197c8SManish Chopra 	for (i = 0; i < num_vports; i++) {
5184bcd197c8SManish Chopra 		if (p_hwfn->qm_info.wfq_data[i].configured)
5185bcd197c8SManish Chopra 			continue;
5186bcd197c8SManish Chopra 
5187bcd197c8SManish Chopra 		p_hwfn->qm_info.wfq_data[i].min_speed = left_rate_per_vp;
5188bcd197c8SManish Chopra 	}
5189bcd197c8SManish Chopra 
5190bcd197c8SManish Chopra 	return 0;
5191bcd197c8SManish Chopra }
5192bcd197c8SManish Chopra 
5193733def6aSYuval Mintz static int __qed_configure_vport_wfq(struct qed_hwfn *p_hwfn,
5194733def6aSYuval Mintz 				     struct qed_ptt *p_ptt, u16 vp_id, u32 rate)
5195733def6aSYuval Mintz {
5196733def6aSYuval Mintz 	struct qed_mcp_link_state *p_link;
5197733def6aSYuval Mintz 	int rc = 0;
5198733def6aSYuval Mintz 
5199733def6aSYuval Mintz 	p_link = &p_hwfn->cdev->hwfns[0].mcp_info->link_output;
5200733def6aSYuval Mintz 
5201733def6aSYuval Mintz 	if (!p_link->min_pf_rate) {
5202733def6aSYuval Mintz 		p_hwfn->qm_info.wfq_data[vp_id].min_speed = rate;
5203733def6aSYuval Mintz 		p_hwfn->qm_info.wfq_data[vp_id].configured = true;
5204733def6aSYuval Mintz 		return rc;
5205733def6aSYuval Mintz 	}
5206733def6aSYuval Mintz 
5207733def6aSYuval Mintz 	rc = qed_init_wfq_param(p_hwfn, vp_id, rate, p_link->min_pf_rate);
5208733def6aSYuval Mintz 
52091a635e48SYuval Mintz 	if (!rc)
5210733def6aSYuval Mintz 		qed_configure_wfq_for_all_vports(p_hwfn, p_ptt,
5211733def6aSYuval Mintz 						 p_link->min_pf_rate);
5212733def6aSYuval Mintz 	else
5213733def6aSYuval Mintz 		DP_NOTICE(p_hwfn,
5214733def6aSYuval Mintz 			  "Validation failed while configuring min rate\n");
5215733def6aSYuval Mintz 
5216733def6aSYuval Mintz 	return rc;
5217733def6aSYuval Mintz }
5218733def6aSYuval Mintz 
5219bcd197c8SManish Chopra static int __qed_configure_vp_wfq_on_link_change(struct qed_hwfn *p_hwfn,
5220bcd197c8SManish Chopra 						 struct qed_ptt *p_ptt,
5221bcd197c8SManish Chopra 						 u32 min_pf_rate)
5222bcd197c8SManish Chopra {
5223bcd197c8SManish Chopra 	bool use_wfq = false;
5224bcd197c8SManish Chopra 	int rc = 0;
5225bcd197c8SManish Chopra 	u16 i;
5226bcd197c8SManish Chopra 
5227bcd197c8SManish Chopra 	/* Validate all pre configured vports for wfq */
5228bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++) {
5229bcd197c8SManish Chopra 		u32 rate;
5230bcd197c8SManish Chopra 
5231bcd197c8SManish Chopra 		if (!p_hwfn->qm_info.wfq_data[i].configured)
5232bcd197c8SManish Chopra 			continue;
5233bcd197c8SManish Chopra 
5234bcd197c8SManish Chopra 		rate = p_hwfn->qm_info.wfq_data[i].min_speed;
5235bcd197c8SManish Chopra 		use_wfq = true;
5236bcd197c8SManish Chopra 
5237bcd197c8SManish Chopra 		rc = qed_init_wfq_param(p_hwfn, i, rate, min_pf_rate);
5238bcd197c8SManish Chopra 		if (rc) {
5239bcd197c8SManish Chopra 			DP_NOTICE(p_hwfn,
5240bcd197c8SManish Chopra 				  "WFQ validation failed while configuring min rate\n");
5241bcd197c8SManish Chopra 			break;
5242bcd197c8SManish Chopra 		}
5243bcd197c8SManish Chopra 	}
5244bcd197c8SManish Chopra 
5245bcd197c8SManish Chopra 	if (!rc && use_wfq)
5246bcd197c8SManish Chopra 		qed_configure_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate);
5247bcd197c8SManish Chopra 	else
5248bcd197c8SManish Chopra 		qed_disable_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate);
5249bcd197c8SManish Chopra 
5250bcd197c8SManish Chopra 	return rc;
5251bcd197c8SManish Chopra }
5252bcd197c8SManish Chopra 
5253733def6aSYuval Mintz /* Main API for qed clients to configure vport min rate.
5254733def6aSYuval Mintz  * vp_id - vport id in PF Range[0 - (total_num_vports_per_pf - 1)]
5255733def6aSYuval Mintz  * rate - Speed in Mbps needs to be assigned to a given vport.
5256733def6aSYuval Mintz  */
5257733def6aSYuval Mintz int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate)
5258733def6aSYuval Mintz {
5259733def6aSYuval Mintz 	int i, rc = -EINVAL;
5260733def6aSYuval Mintz 
5261733def6aSYuval Mintz 	/* Currently not supported; Might change in future */
5262733def6aSYuval Mintz 	if (cdev->num_hwfns > 1) {
5263733def6aSYuval Mintz 		DP_NOTICE(cdev,
5264733def6aSYuval Mintz 			  "WFQ configuration is not supported for this device\n");
5265733def6aSYuval Mintz 		return rc;
5266733def6aSYuval Mintz 	}
5267733def6aSYuval Mintz 
5268733def6aSYuval Mintz 	for_each_hwfn(cdev, i) {
5269733def6aSYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
5270733def6aSYuval Mintz 		struct qed_ptt *p_ptt;
5271733def6aSYuval Mintz 
5272733def6aSYuval Mintz 		p_ptt = qed_ptt_acquire(p_hwfn);
5273733def6aSYuval Mintz 		if (!p_ptt)
5274733def6aSYuval Mintz 			return -EBUSY;
5275733def6aSYuval Mintz 
5276733def6aSYuval Mintz 		rc = __qed_configure_vport_wfq(p_hwfn, p_ptt, vp_id, rate);
5277733def6aSYuval Mintz 
5278d572c430SYuval Mintz 		if (rc) {
5279733def6aSYuval Mintz 			qed_ptt_release(p_hwfn, p_ptt);
5280733def6aSYuval Mintz 			return rc;
5281733def6aSYuval Mintz 		}
5282733def6aSYuval Mintz 
5283733def6aSYuval Mintz 		qed_ptt_release(p_hwfn, p_ptt);
5284733def6aSYuval Mintz 	}
5285733def6aSYuval Mintz 
5286733def6aSYuval Mintz 	return rc;
5287733def6aSYuval Mintz }
5288733def6aSYuval Mintz 
5289bcd197c8SManish Chopra /* API to configure WFQ from mcp link change */
52906f437d43SMintz, Yuval void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev,
52916f437d43SMintz, Yuval 					 struct qed_ptt *p_ptt, u32 min_pf_rate)
5292bcd197c8SManish Chopra {
5293bcd197c8SManish Chopra 	int i;
5294bcd197c8SManish Chopra 
52953e7cfce2SYuval Mintz 	if (cdev->num_hwfns > 1) {
52963e7cfce2SYuval Mintz 		DP_VERBOSE(cdev,
52973e7cfce2SYuval Mintz 			   NETIF_MSG_LINK,
52983e7cfce2SYuval Mintz 			   "WFQ configuration is not supported for this device\n");
52993e7cfce2SYuval Mintz 		return;
53003e7cfce2SYuval Mintz 	}
53013e7cfce2SYuval Mintz 
5302bcd197c8SManish Chopra 	for_each_hwfn(cdev, i) {
5303bcd197c8SManish Chopra 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
5304bcd197c8SManish Chopra 
53056f437d43SMintz, Yuval 		__qed_configure_vp_wfq_on_link_change(p_hwfn, p_ptt,
5306bcd197c8SManish Chopra 						      min_pf_rate);
5307bcd197c8SManish Chopra 	}
5308bcd197c8SManish Chopra }
53094b01e519SManish Chopra 
53104b01e519SManish Chopra int __qed_configure_pf_max_bandwidth(struct qed_hwfn *p_hwfn,
53114b01e519SManish Chopra 				     struct qed_ptt *p_ptt,
53124b01e519SManish Chopra 				     struct qed_mcp_link_state *p_link,
53134b01e519SManish Chopra 				     u8 max_bw)
53144b01e519SManish Chopra {
53154b01e519SManish Chopra 	int rc = 0;
53164b01e519SManish Chopra 
53174b01e519SManish Chopra 	p_hwfn->mcp_info->func_info.bandwidth_max = max_bw;
53184b01e519SManish Chopra 
53194b01e519SManish Chopra 	if (!p_link->line_speed && (max_bw != 100))
53204b01e519SManish Chopra 		return rc;
53214b01e519SManish Chopra 
53224b01e519SManish Chopra 	p_link->speed = (p_link->line_speed * max_bw) / 100;
53234b01e519SManish Chopra 	p_hwfn->qm_info.pf_rl = p_link->speed;
53244b01e519SManish Chopra 
53254b01e519SManish Chopra 	/* Since the limiter also affects Tx-switched traffic, we don't want it
53264b01e519SManish Chopra 	 * to limit such traffic in case there's no actual limit.
53274b01e519SManish Chopra 	 * In that case, set limit to imaginary high boundary.
53284b01e519SManish Chopra 	 */
53294b01e519SManish Chopra 	if (max_bw == 100)
53304b01e519SManish Chopra 		p_hwfn->qm_info.pf_rl = 100000;
53314b01e519SManish Chopra 
53324b01e519SManish Chopra 	rc = qed_init_pf_rl(p_hwfn, p_ptt, p_hwfn->rel_pf_id,
53334b01e519SManish Chopra 			    p_hwfn->qm_info.pf_rl);
53344b01e519SManish Chopra 
53354b01e519SManish Chopra 	DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
53364b01e519SManish Chopra 		   "Configured MAX bandwidth to be %08x Mb/sec\n",
53374b01e519SManish Chopra 		   p_link->speed);
53384b01e519SManish Chopra 
53394b01e519SManish Chopra 	return rc;
53404b01e519SManish Chopra }
53414b01e519SManish Chopra 
53424b01e519SManish Chopra /* Main API to configure PF max bandwidth where bw range is [1 - 100] */
53434b01e519SManish Chopra int qed_configure_pf_max_bandwidth(struct qed_dev *cdev, u8 max_bw)
53444b01e519SManish Chopra {
53454b01e519SManish Chopra 	int i, rc = -EINVAL;
53464b01e519SManish Chopra 
53474b01e519SManish Chopra 	if (max_bw < 1 || max_bw > 100) {
53484b01e519SManish Chopra 		DP_NOTICE(cdev, "PF max bw valid range is [1-100]\n");
53494b01e519SManish Chopra 		return rc;
53504b01e519SManish Chopra 	}
53514b01e519SManish Chopra 
53524b01e519SManish Chopra 	for_each_hwfn(cdev, i) {
53534b01e519SManish Chopra 		struct qed_hwfn	*p_hwfn = &cdev->hwfns[i];
53544b01e519SManish Chopra 		struct qed_hwfn *p_lead = QED_LEADING_HWFN(cdev);
53554b01e519SManish Chopra 		struct qed_mcp_link_state *p_link;
53564b01e519SManish Chopra 		struct qed_ptt *p_ptt;
53574b01e519SManish Chopra 
53584b01e519SManish Chopra 		p_link = &p_lead->mcp_info->link_output;
53594b01e519SManish Chopra 
53604b01e519SManish Chopra 		p_ptt = qed_ptt_acquire(p_hwfn);
53614b01e519SManish Chopra 		if (!p_ptt)
53624b01e519SManish Chopra 			return -EBUSY;
53634b01e519SManish Chopra 
53644b01e519SManish Chopra 		rc = __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt,
53654b01e519SManish Chopra 						      p_link, max_bw);
53664b01e519SManish Chopra 
53674b01e519SManish Chopra 		qed_ptt_release(p_hwfn, p_ptt);
53684b01e519SManish Chopra 
53694b01e519SManish Chopra 		if (rc)
53704b01e519SManish Chopra 			break;
53714b01e519SManish Chopra 	}
53724b01e519SManish Chopra 
53734b01e519SManish Chopra 	return rc;
53744b01e519SManish Chopra }
5375a64b02d5SManish Chopra 
5376a64b02d5SManish Chopra int __qed_configure_pf_min_bandwidth(struct qed_hwfn *p_hwfn,
5377a64b02d5SManish Chopra 				     struct qed_ptt *p_ptt,
5378a64b02d5SManish Chopra 				     struct qed_mcp_link_state *p_link,
5379a64b02d5SManish Chopra 				     u8 min_bw)
5380a64b02d5SManish Chopra {
5381a64b02d5SManish Chopra 	int rc = 0;
5382a64b02d5SManish Chopra 
5383a64b02d5SManish Chopra 	p_hwfn->mcp_info->func_info.bandwidth_min = min_bw;
5384a64b02d5SManish Chopra 	p_hwfn->qm_info.pf_wfq = min_bw;
5385a64b02d5SManish Chopra 
5386a64b02d5SManish Chopra 	if (!p_link->line_speed)
5387a64b02d5SManish Chopra 		return rc;
5388a64b02d5SManish Chopra 
5389a64b02d5SManish Chopra 	p_link->min_pf_rate = (p_link->line_speed * min_bw) / 100;
5390a64b02d5SManish Chopra 
5391a64b02d5SManish Chopra 	rc = qed_init_pf_wfq(p_hwfn, p_ptt, p_hwfn->rel_pf_id, min_bw);
5392a64b02d5SManish Chopra 
5393a64b02d5SManish Chopra 	DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5394a64b02d5SManish Chopra 		   "Configured MIN bandwidth to be %d Mb/sec\n",
5395a64b02d5SManish Chopra 		   p_link->min_pf_rate);
5396a64b02d5SManish Chopra 
5397a64b02d5SManish Chopra 	return rc;
5398a64b02d5SManish Chopra }
5399a64b02d5SManish Chopra 
5400a64b02d5SManish Chopra /* Main API to configure PF min bandwidth where bw range is [1-100] */
5401a64b02d5SManish Chopra int qed_configure_pf_min_bandwidth(struct qed_dev *cdev, u8 min_bw)
5402a64b02d5SManish Chopra {
5403a64b02d5SManish Chopra 	int i, rc = -EINVAL;
5404a64b02d5SManish Chopra 
5405a64b02d5SManish Chopra 	if (min_bw < 1 || min_bw > 100) {
5406a64b02d5SManish Chopra 		DP_NOTICE(cdev, "PF min bw valid range is [1-100]\n");
5407a64b02d5SManish Chopra 		return rc;
5408a64b02d5SManish Chopra 	}
5409a64b02d5SManish Chopra 
5410a64b02d5SManish Chopra 	for_each_hwfn(cdev, i) {
5411a64b02d5SManish Chopra 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
5412a64b02d5SManish Chopra 		struct qed_hwfn *p_lead = QED_LEADING_HWFN(cdev);
5413a64b02d5SManish Chopra 		struct qed_mcp_link_state *p_link;
5414a64b02d5SManish Chopra 		struct qed_ptt *p_ptt;
5415a64b02d5SManish Chopra 
5416a64b02d5SManish Chopra 		p_link = &p_lead->mcp_info->link_output;
5417a64b02d5SManish Chopra 
5418a64b02d5SManish Chopra 		p_ptt = qed_ptt_acquire(p_hwfn);
5419a64b02d5SManish Chopra 		if (!p_ptt)
5420a64b02d5SManish Chopra 			return -EBUSY;
5421a64b02d5SManish Chopra 
5422a64b02d5SManish Chopra 		rc = __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt,
5423a64b02d5SManish Chopra 						      p_link, min_bw);
5424a64b02d5SManish Chopra 		if (rc) {
5425a64b02d5SManish Chopra 			qed_ptt_release(p_hwfn, p_ptt);
5426a64b02d5SManish Chopra 			return rc;
5427a64b02d5SManish Chopra 		}
5428a64b02d5SManish Chopra 
5429a64b02d5SManish Chopra 		if (p_link->min_pf_rate) {
5430a64b02d5SManish Chopra 			u32 min_rate = p_link->min_pf_rate;
5431a64b02d5SManish Chopra 
5432a64b02d5SManish Chopra 			rc = __qed_configure_vp_wfq_on_link_change(p_hwfn,
5433a64b02d5SManish Chopra 								   p_ptt,
5434a64b02d5SManish Chopra 								   min_rate);
5435a64b02d5SManish Chopra 		}
5436a64b02d5SManish Chopra 
5437a64b02d5SManish Chopra 		qed_ptt_release(p_hwfn, p_ptt);
5438a64b02d5SManish Chopra 	}
5439a64b02d5SManish Chopra 
5440a64b02d5SManish Chopra 	return rc;
5441a64b02d5SManish Chopra }
5442733def6aSYuval Mintz 
5443733def6aSYuval Mintz void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
5444733def6aSYuval Mintz {
5445733def6aSYuval Mintz 	struct qed_mcp_link_state *p_link;
5446733def6aSYuval Mintz 
5447733def6aSYuval Mintz 	p_link = &p_hwfn->mcp_info->link_output;
5448733def6aSYuval Mintz 
5449733def6aSYuval Mintz 	if (p_link->min_pf_rate)
5450733def6aSYuval Mintz 		qed_disable_wfq_for_all_vports(p_hwfn, p_ptt,
5451733def6aSYuval Mintz 					       p_link->min_pf_rate);
5452733def6aSYuval Mintz 
5453733def6aSYuval Mintz 	memset(p_hwfn->qm_info.wfq_data, 0,
5454733def6aSYuval Mintz 	       sizeof(*p_hwfn->qm_info.wfq_data) * p_hwfn->qm_info.num_vports);
5455733def6aSYuval Mintz }
54569c79ddaaSMintz, Yuval 
54570ebcebbeSSudarsana Reddy Kalluru int qed_device_num_ports(struct qed_dev *cdev)
54589c79ddaaSMintz, Yuval {
54590ebcebbeSSudarsana Reddy Kalluru 	return cdev->num_ports;
5460db82f70eSsudarsana.kalluru@cavium.com }
5461456a5849SKalderon, Michal 
5462456a5849SKalderon, Michal void qed_set_fw_mac_addr(__le16 *fw_msb,
5463456a5849SKalderon, Michal 			 __le16 *fw_mid, __le16 *fw_lsb, u8 *mac)
5464456a5849SKalderon, Michal {
5465456a5849SKalderon, Michal 	((u8 *)fw_msb)[0] = mac[1];
5466456a5849SKalderon, Michal 	((u8 *)fw_msb)[1] = mac[0];
5467456a5849SKalderon, Michal 	((u8 *)fw_mid)[0] = mac[3];
5468456a5849SKalderon, Michal 	((u8 *)fw_mid)[1] = mac[2];
5469456a5849SKalderon, Michal 	((u8 *)fw_lsb)[0] = mac[5];
5470456a5849SKalderon, Michal 	((u8 *)fw_lsb)[1] = mac[4];
5471456a5849SKalderon, Michal }
5472