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);
655815deee0SArnd Bergmann 		*p_abs_ppfid = 0;
65679284adeSMichal Kalderon 		return -EINVAL;
65779284adeSMichal Kalderon 	}
65879284adeSMichal Kalderon 
65979284adeSMichal Kalderon 	*p_abs_ppfid = p_llh_info->ppfid_array[ppfid];
66079284adeSMichal Kalderon 
66179284adeSMichal Kalderon 	return 0;
66279284adeSMichal Kalderon }
66379284adeSMichal Kalderon 
66479284adeSMichal Kalderon static int
66579284adeSMichal Kalderon qed_llh_set_engine_affin(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
66679284adeSMichal Kalderon {
66779284adeSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
66879284adeSMichal Kalderon 	enum qed_eng eng;
66979284adeSMichal Kalderon 	u8 ppfid;
67079284adeSMichal Kalderon 	int rc;
67179284adeSMichal Kalderon 
67279284adeSMichal Kalderon 	rc = qed_mcp_get_engine_config(p_hwfn, p_ptt);
67379284adeSMichal Kalderon 	if (rc != 0 && rc != -EOPNOTSUPP) {
67479284adeSMichal Kalderon 		DP_NOTICE(p_hwfn,
67579284adeSMichal Kalderon 			  "Failed to get the engine affinity configuration\n");
67679284adeSMichal Kalderon 		return rc;
67779284adeSMichal Kalderon 	}
67879284adeSMichal Kalderon 
67979284adeSMichal Kalderon 	/* RoCE PF is bound to a single engine */
68079284adeSMichal Kalderon 	if (QED_IS_ROCE_PERSONALITY(p_hwfn)) {
68179284adeSMichal Kalderon 		eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
68279284adeSMichal Kalderon 		rc = qed_llh_set_roce_affinity(cdev, eng);
68379284adeSMichal Kalderon 		if (rc) {
68479284adeSMichal Kalderon 			DP_NOTICE(cdev,
68579284adeSMichal Kalderon 				  "Failed to set the RoCE engine affinity\n");
68679284adeSMichal Kalderon 			return rc;
68779284adeSMichal Kalderon 		}
68879284adeSMichal Kalderon 
68979284adeSMichal Kalderon 		DP_VERBOSE(cdev,
69079284adeSMichal Kalderon 			   QED_MSG_SP,
69179284adeSMichal Kalderon 			   "LLH: Set the engine affinity of RoCE packets as %d\n",
69279284adeSMichal Kalderon 			   eng);
69379284adeSMichal Kalderon 	}
69479284adeSMichal Kalderon 
69579284adeSMichal Kalderon 	/* Storage PF is bound to a single engine while L2 PF uses both */
69679284adeSMichal Kalderon 	if (QED_IS_FCOE_PERSONALITY(p_hwfn) || QED_IS_ISCSI_PERSONALITY(p_hwfn))
69779284adeSMichal Kalderon 		eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
69879284adeSMichal Kalderon 	else			/* L2_PERSONALITY */
69979284adeSMichal Kalderon 		eng = QED_BOTH_ENG;
70079284adeSMichal Kalderon 
70179284adeSMichal Kalderon 	for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
70279284adeSMichal Kalderon 		rc = qed_llh_set_ppfid_affinity(cdev, ppfid, eng);
70379284adeSMichal Kalderon 		if (rc) {
70479284adeSMichal Kalderon 			DP_NOTICE(cdev,
70579284adeSMichal Kalderon 				  "Failed to set the engine affinity of ppfid %d\n",
70679284adeSMichal Kalderon 				  ppfid);
70779284adeSMichal Kalderon 			return rc;
70879284adeSMichal Kalderon 		}
70979284adeSMichal Kalderon 	}
71079284adeSMichal Kalderon 
71179284adeSMichal Kalderon 	DP_VERBOSE(cdev, QED_MSG_SP,
71279284adeSMichal Kalderon 		   "LLH: Set the engine affinity of non-RoCE packets as %d\n",
71379284adeSMichal Kalderon 		   eng);
71479284adeSMichal Kalderon 
71579284adeSMichal Kalderon 	return 0;
71679284adeSMichal Kalderon }
71779284adeSMichal Kalderon 
71879284adeSMichal Kalderon static int qed_llh_hw_init_pf(struct qed_hwfn *p_hwfn,
71979284adeSMichal Kalderon 			      struct qed_ptt *p_ptt)
72079284adeSMichal Kalderon {
72179284adeSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
72279284adeSMichal Kalderon 	u8 ppfid, abs_ppfid;
72379284adeSMichal Kalderon 	int rc;
72479284adeSMichal Kalderon 
72579284adeSMichal Kalderon 	for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
72679284adeSMichal Kalderon 		u32 addr;
72779284adeSMichal Kalderon 
72879284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
72979284adeSMichal Kalderon 		if (rc)
73079284adeSMichal Kalderon 			return rc;
73179284adeSMichal Kalderon 
73279284adeSMichal Kalderon 		addr = NIG_REG_LLH_PPFID2PFID_TBL_0 + abs_ppfid * 0x4;
73379284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, p_hwfn->rel_pf_id);
73479284adeSMichal Kalderon 	}
73579284adeSMichal Kalderon 
73679284adeSMichal Kalderon 	if (test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) &&
73779284adeSMichal Kalderon 	    !QED_IS_FCOE_PERSONALITY(p_hwfn)) {
73879284adeSMichal Kalderon 		rc = qed_llh_add_mac_filter(cdev, 0,
73979284adeSMichal Kalderon 					    p_hwfn->hw_info.hw_mac_addr);
74079284adeSMichal Kalderon 		if (rc)
74179284adeSMichal Kalderon 			DP_NOTICE(cdev,
74279284adeSMichal Kalderon 				  "Failed to add an LLH filter with the primary MAC\n");
74379284adeSMichal Kalderon 	}
74479284adeSMichal Kalderon 
74579284adeSMichal Kalderon 	if (QED_IS_CMT(cdev)) {
74679284adeSMichal Kalderon 		rc = qed_llh_set_engine_affin(p_hwfn, p_ptt);
74779284adeSMichal Kalderon 		if (rc)
74879284adeSMichal Kalderon 			return rc;
74979284adeSMichal Kalderon 	}
75079284adeSMichal Kalderon 
75179284adeSMichal Kalderon 	return 0;
75279284adeSMichal Kalderon }
75379284adeSMichal Kalderon 
75479284adeSMichal Kalderon u8 qed_llh_get_num_ppfid(struct qed_dev *cdev)
75579284adeSMichal Kalderon {
75679284adeSMichal Kalderon 	return cdev->p_llh_info->num_ppfid;
75779284adeSMichal Kalderon }
75879284adeSMichal Kalderon 
75979284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_MASK             0x3
76079284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_SHIFT            0
76179284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_MASK         0x3
76279284adeSMichal Kalderon #define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_SHIFT        2
76379284adeSMichal Kalderon 
76479284adeSMichal Kalderon int qed_llh_set_ppfid_affinity(struct qed_dev *cdev, u8 ppfid, enum qed_eng eng)
76579284adeSMichal Kalderon {
76679284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
76779284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
76879284adeSMichal Kalderon 	u32 addr, val, eng_sel;
76979284adeSMichal Kalderon 	u8 abs_ppfid;
77079284adeSMichal Kalderon 	int rc = 0;
77179284adeSMichal Kalderon 
77279284adeSMichal Kalderon 	if (!p_ptt)
77379284adeSMichal Kalderon 		return -EAGAIN;
77479284adeSMichal Kalderon 
77579284adeSMichal Kalderon 	if (!QED_IS_CMT(cdev))
77679284adeSMichal Kalderon 		goto out;
77779284adeSMichal Kalderon 
77879284adeSMichal Kalderon 	rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
77979284adeSMichal Kalderon 	if (rc)
78079284adeSMichal Kalderon 		goto out;
78179284adeSMichal Kalderon 
78279284adeSMichal Kalderon 	switch (eng) {
78379284adeSMichal Kalderon 	case QED_ENG0:
78479284adeSMichal Kalderon 		eng_sel = 0;
78579284adeSMichal Kalderon 		break;
78679284adeSMichal Kalderon 	case QED_ENG1:
78779284adeSMichal Kalderon 		eng_sel = 1;
78879284adeSMichal Kalderon 		break;
78979284adeSMichal Kalderon 	case QED_BOTH_ENG:
79079284adeSMichal Kalderon 		eng_sel = 2;
79179284adeSMichal Kalderon 		break;
79279284adeSMichal Kalderon 	default:
79379284adeSMichal Kalderon 		DP_NOTICE(cdev, "Invalid affinity value for ppfid [%d]\n", eng);
79479284adeSMichal Kalderon 		rc = -EINVAL;
79579284adeSMichal Kalderon 		goto out;
79679284adeSMichal Kalderon 	}
79779284adeSMichal Kalderon 
79879284adeSMichal Kalderon 	addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
79979284adeSMichal Kalderon 	val = qed_rd(p_hwfn, p_ptt, addr);
80079284adeSMichal Kalderon 	SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE, eng_sel);
80179284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, val);
80279284adeSMichal Kalderon 
80379284adeSMichal Kalderon 	/* The iWARP affinity is set as the affinity of ppfid 0 */
80479284adeSMichal Kalderon 	if (!ppfid && QED_IS_IWARP_PERSONALITY(p_hwfn))
80579284adeSMichal Kalderon 		cdev->iwarp_affin = (eng == QED_ENG1) ? 1 : 0;
80679284adeSMichal Kalderon out:
80779284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
80879284adeSMichal Kalderon 
80979284adeSMichal Kalderon 	return rc;
81079284adeSMichal Kalderon }
81179284adeSMichal Kalderon 
81279284adeSMichal Kalderon int qed_llh_set_roce_affinity(struct qed_dev *cdev, enum qed_eng eng)
81379284adeSMichal Kalderon {
81479284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
81579284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
81679284adeSMichal Kalderon 	u32 addr, val, eng_sel;
81779284adeSMichal Kalderon 	u8 ppfid, abs_ppfid;
81879284adeSMichal Kalderon 	int rc = 0;
81979284adeSMichal Kalderon 
82079284adeSMichal Kalderon 	if (!p_ptt)
82179284adeSMichal Kalderon 		return -EAGAIN;
82279284adeSMichal Kalderon 
82379284adeSMichal Kalderon 	if (!QED_IS_CMT(cdev))
82479284adeSMichal Kalderon 		goto out;
82579284adeSMichal Kalderon 
82679284adeSMichal Kalderon 	switch (eng) {
82779284adeSMichal Kalderon 	case QED_ENG0:
82879284adeSMichal Kalderon 		eng_sel = 0;
82979284adeSMichal Kalderon 		break;
83079284adeSMichal Kalderon 	case QED_ENG1:
83179284adeSMichal Kalderon 		eng_sel = 1;
83279284adeSMichal Kalderon 		break;
83379284adeSMichal Kalderon 	case QED_BOTH_ENG:
83479284adeSMichal Kalderon 		eng_sel = 2;
83579284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL,
83679284adeSMichal Kalderon 		       0xf);  /* QP bit 15 */
83779284adeSMichal Kalderon 		break;
83879284adeSMichal Kalderon 	default:
83979284adeSMichal Kalderon 		DP_NOTICE(cdev, "Invalid affinity value for RoCE [%d]\n", eng);
84079284adeSMichal Kalderon 		rc = -EINVAL;
84179284adeSMichal Kalderon 		goto out;
84279284adeSMichal Kalderon 	}
84379284adeSMichal Kalderon 
84479284adeSMichal Kalderon 	for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
84579284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
84679284adeSMichal Kalderon 		if (rc)
84779284adeSMichal Kalderon 			goto out;
84879284adeSMichal Kalderon 
84979284adeSMichal Kalderon 		addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
85079284adeSMichal Kalderon 		val = qed_rd(p_hwfn, p_ptt, addr);
85179284adeSMichal Kalderon 		SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_ROCE, eng_sel);
85279284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, val);
85379284adeSMichal Kalderon 	}
85479284adeSMichal Kalderon out:
85579284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
85679284adeSMichal Kalderon 
85779284adeSMichal Kalderon 	return rc;
85879284adeSMichal Kalderon }
85979284adeSMichal Kalderon 
86079284adeSMichal Kalderon struct qed_llh_filter_details {
86179284adeSMichal Kalderon 	u64 value;
86279284adeSMichal Kalderon 	u32 mode;
86379284adeSMichal Kalderon 	u32 protocol_type;
86479284adeSMichal Kalderon 	u32 hdr_sel;
86579284adeSMichal Kalderon 	u32 enable;
86679284adeSMichal Kalderon };
86779284adeSMichal Kalderon 
86879284adeSMichal Kalderon static int
86979284adeSMichal Kalderon qed_llh_access_filter(struct qed_hwfn *p_hwfn,
87079284adeSMichal Kalderon 		      struct qed_ptt *p_ptt,
87179284adeSMichal Kalderon 		      u8 abs_ppfid,
87279284adeSMichal Kalderon 		      u8 filter_idx,
87379284adeSMichal Kalderon 		      struct qed_llh_filter_details *p_details)
87479284adeSMichal Kalderon {
87579284adeSMichal Kalderon 	struct qed_dmae_params params = {0};
87679284adeSMichal Kalderon 	u32 addr;
87779284adeSMichal Kalderon 	u8 pfid;
87879284adeSMichal Kalderon 	int rc;
87979284adeSMichal Kalderon 
88079284adeSMichal Kalderon 	/* The NIG/LLH registers that are accessed in this function have only 16
88179284adeSMichal Kalderon 	 * rows which are exposed to a PF. I.e. only the 16 filters of its
88279284adeSMichal Kalderon 	 * default ppfid. Accessing filters of other ppfids requires pretending
88379284adeSMichal Kalderon 	 * to another PFs.
88479284adeSMichal Kalderon 	 * The calculation of PPFID->PFID in AH is based on the relative index
88579284adeSMichal Kalderon 	 * of a PF on its port.
88679284adeSMichal Kalderon 	 * For BB the pfid is actually the abs_ppfid.
88779284adeSMichal Kalderon 	 */
88879284adeSMichal Kalderon 	if (QED_IS_BB(p_hwfn->cdev))
88979284adeSMichal Kalderon 		pfid = abs_ppfid;
89079284adeSMichal Kalderon 	else
89179284adeSMichal Kalderon 		pfid = abs_ppfid * p_hwfn->cdev->num_ports_in_engine +
89279284adeSMichal Kalderon 		    MFW_PORT(p_hwfn);
89379284adeSMichal Kalderon 
89479284adeSMichal Kalderon 	/* Filter enable - should be done first when removing a filter */
89579284adeSMichal Kalderon 	if (!p_details->enable) {
89679284adeSMichal Kalderon 		qed_fid_pretend(p_hwfn, p_ptt,
89779284adeSMichal Kalderon 				pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
89879284adeSMichal Kalderon 
89979284adeSMichal Kalderon 		addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4;
90079284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, p_details->enable);
90179284adeSMichal Kalderon 
90279284adeSMichal Kalderon 		qed_fid_pretend(p_hwfn, p_ptt,
90379284adeSMichal Kalderon 				p_hwfn->rel_pf_id <<
90479284adeSMichal Kalderon 				PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
90579284adeSMichal Kalderon 	}
90679284adeSMichal Kalderon 
90779284adeSMichal Kalderon 	/* Filter value */
90879284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * filter_idx * 0x4;
90979284adeSMichal Kalderon 
910804c5702SMichal Kalderon 	SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_PF_VALID, 0x1);
91179284adeSMichal Kalderon 	params.dst_pfid = pfid;
91279284adeSMichal Kalderon 	rc = qed_dmae_host2grc(p_hwfn,
91379284adeSMichal Kalderon 			       p_ptt,
91479284adeSMichal Kalderon 			       (u64)(uintptr_t)&p_details->value,
91579284adeSMichal Kalderon 			       addr, 2 /* size_in_dwords */,
91679284adeSMichal Kalderon 			       &params);
91779284adeSMichal Kalderon 	if (rc)
91879284adeSMichal Kalderon 		return rc;
91979284adeSMichal Kalderon 
92079284adeSMichal Kalderon 	qed_fid_pretend(p_hwfn, p_ptt,
92179284adeSMichal Kalderon 			pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
92279284adeSMichal Kalderon 
92379284adeSMichal Kalderon 	/* Filter mode */
92479284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_MODE + filter_idx * 0x4;
92579284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, p_details->mode);
92679284adeSMichal Kalderon 
92779284adeSMichal Kalderon 	/* Filter protocol type */
92879284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + filter_idx * 0x4;
92979284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, p_details->protocol_type);
93079284adeSMichal Kalderon 
93179284adeSMichal Kalderon 	/* Filter header select */
93279284adeSMichal Kalderon 	addr = NIG_REG_LLH_FUNC_FILTER_HDR_SEL + filter_idx * 0x4;
93379284adeSMichal Kalderon 	qed_wr(p_hwfn, p_ptt, addr, p_details->hdr_sel);
93479284adeSMichal Kalderon 
93579284adeSMichal Kalderon 	/* Filter enable - should be done last when adding a filter */
93679284adeSMichal Kalderon 	if (p_details->enable) {
93779284adeSMichal Kalderon 		addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4;
93879284adeSMichal Kalderon 		qed_wr(p_hwfn, p_ptt, addr, p_details->enable);
93979284adeSMichal Kalderon 	}
94079284adeSMichal Kalderon 
94179284adeSMichal Kalderon 	qed_fid_pretend(p_hwfn, p_ptt,
94279284adeSMichal Kalderon 			p_hwfn->rel_pf_id <<
94379284adeSMichal Kalderon 			PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
94479284adeSMichal Kalderon 
94579284adeSMichal Kalderon 	return 0;
94679284adeSMichal Kalderon }
94779284adeSMichal Kalderon 
94879284adeSMichal Kalderon static int
94979284adeSMichal Kalderon qed_llh_add_filter(struct qed_hwfn *p_hwfn,
95079284adeSMichal Kalderon 		   struct qed_ptt *p_ptt,
95179284adeSMichal Kalderon 		   u8 abs_ppfid,
95279284adeSMichal Kalderon 		   u8 filter_idx, u8 filter_prot_type, u32 high, u32 low)
95379284adeSMichal Kalderon {
95479284adeSMichal Kalderon 	struct qed_llh_filter_details filter_details;
95579284adeSMichal Kalderon 
95679284adeSMichal Kalderon 	filter_details.enable = 1;
95779284adeSMichal Kalderon 	filter_details.value = ((u64)high << 32) | low;
95879284adeSMichal Kalderon 	filter_details.hdr_sel = 0;
95979284adeSMichal Kalderon 	filter_details.protocol_type = filter_prot_type;
96079284adeSMichal Kalderon 	/* Mode: 0: MAC-address classification 1: protocol classification */
96179284adeSMichal Kalderon 	filter_details.mode = filter_prot_type ? 1 : 0;
96279284adeSMichal Kalderon 
96379284adeSMichal Kalderon 	return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
96479284adeSMichal Kalderon 				     &filter_details);
96579284adeSMichal Kalderon }
96679284adeSMichal Kalderon 
96779284adeSMichal Kalderon static int
96879284adeSMichal Kalderon qed_llh_remove_filter(struct qed_hwfn *p_hwfn,
96979284adeSMichal Kalderon 		      struct qed_ptt *p_ptt, u8 abs_ppfid, u8 filter_idx)
97079284adeSMichal Kalderon {
97179284adeSMichal Kalderon 	struct qed_llh_filter_details filter_details = {0};
97279284adeSMichal Kalderon 
97379284adeSMichal Kalderon 	return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
97479284adeSMichal Kalderon 				     &filter_details);
97579284adeSMichal Kalderon }
97679284adeSMichal Kalderon 
97779284adeSMichal Kalderon int qed_llh_add_mac_filter(struct qed_dev *cdev,
97879284adeSMichal Kalderon 			   u8 ppfid, u8 mac_addr[ETH_ALEN])
97979284adeSMichal Kalderon {
98079284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
98179284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
98279284adeSMichal Kalderon 	union qed_llh_filter filter = {};
98379284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid;
98479284adeSMichal Kalderon 	u32 high, low, ref_cnt;
98579284adeSMichal Kalderon 	int rc = 0;
98679284adeSMichal Kalderon 
98779284adeSMichal Kalderon 	if (!p_ptt)
98879284adeSMichal Kalderon 		return -EAGAIN;
98979284adeSMichal Kalderon 
99079284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
99179284adeSMichal Kalderon 		goto out;
99279284adeSMichal Kalderon 
99379284adeSMichal Kalderon 	memcpy(filter.mac.addr, mac_addr, ETH_ALEN);
99479284adeSMichal Kalderon 	rc = qed_llh_shadow_add_filter(cdev, ppfid,
99579284adeSMichal Kalderon 				       QED_LLH_FILTER_TYPE_MAC,
99679284adeSMichal Kalderon 				       &filter, &filter_idx, &ref_cnt);
99779284adeSMichal Kalderon 	if (rc)
99879284adeSMichal Kalderon 		goto err;
99979284adeSMichal Kalderon 
100079284adeSMichal Kalderon 	/* Configure the LLH only in case of a new the filter */
100179284adeSMichal Kalderon 	if (ref_cnt == 1) {
100279284adeSMichal Kalderon 		rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
100379284adeSMichal Kalderon 		if (rc)
100479284adeSMichal Kalderon 			goto err;
100579284adeSMichal Kalderon 
100679284adeSMichal Kalderon 		high = mac_addr[1] | (mac_addr[0] << 8);
100779284adeSMichal Kalderon 		low = mac_addr[5] | (mac_addr[4] << 8) | (mac_addr[3] << 16) |
100879284adeSMichal Kalderon 		      (mac_addr[2] << 24);
100979284adeSMichal Kalderon 		rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
101079284adeSMichal Kalderon 					0, high, low);
101179284adeSMichal Kalderon 		if (rc)
101279284adeSMichal Kalderon 			goto err;
101379284adeSMichal Kalderon 	}
101479284adeSMichal Kalderon 
101579284adeSMichal Kalderon 	DP_VERBOSE(cdev,
101679284adeSMichal Kalderon 		   QED_MSG_SP,
101779284adeSMichal Kalderon 		   "LLH: Added MAC filter [%pM] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
101879284adeSMichal Kalderon 		   mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt);
101979284adeSMichal Kalderon 
102079284adeSMichal Kalderon 	goto out;
102179284adeSMichal Kalderon 
102279284adeSMichal Kalderon err:	DP_NOTICE(cdev,
102379284adeSMichal Kalderon 		  "LLH: Failed to add MAC filter [%pM] to ppfid %hhd\n",
102479284adeSMichal Kalderon 		  mac_addr, ppfid);
102579284adeSMichal Kalderon out:
102679284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
102779284adeSMichal Kalderon 
102879284adeSMichal Kalderon 	return rc;
102979284adeSMichal Kalderon }
103079284adeSMichal Kalderon 
103179284adeSMichal Kalderon static int
103279284adeSMichal Kalderon qed_llh_protocol_filter_stringify(struct qed_dev *cdev,
103379284adeSMichal Kalderon 				  enum qed_llh_prot_filter_type_t type,
103479284adeSMichal Kalderon 				  u16 source_port_or_eth_type,
103579284adeSMichal Kalderon 				  u16 dest_port, u8 *str, size_t str_len)
103679284adeSMichal Kalderon {
103779284adeSMichal Kalderon 	switch (type) {
103879284adeSMichal Kalderon 	case QED_LLH_FILTER_ETHERTYPE:
103979284adeSMichal Kalderon 		snprintf(str, str_len, "Ethertype 0x%04x",
104079284adeSMichal Kalderon 			 source_port_or_eth_type);
104179284adeSMichal Kalderon 		break;
104279284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_PORT:
104379284adeSMichal Kalderon 		snprintf(str, str_len, "TCP src port 0x%04x",
104479284adeSMichal Kalderon 			 source_port_or_eth_type);
104579284adeSMichal Kalderon 		break;
104679284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_PORT:
104779284adeSMichal Kalderon 		snprintf(str, str_len, "UDP src port 0x%04x",
104879284adeSMichal Kalderon 			 source_port_or_eth_type);
104979284adeSMichal Kalderon 		break;
105079284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_DEST_PORT:
105179284adeSMichal Kalderon 		snprintf(str, str_len, "TCP dst port 0x%04x", dest_port);
105279284adeSMichal Kalderon 		break;
105379284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_DEST_PORT:
105479284adeSMichal Kalderon 		snprintf(str, str_len, "UDP dst port 0x%04x", dest_port);
105579284adeSMichal Kalderon 		break;
105679284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
105779284adeSMichal Kalderon 		snprintf(str, str_len, "TCP src/dst ports 0x%04x/0x%04x",
105879284adeSMichal Kalderon 			 source_port_or_eth_type, dest_port);
105979284adeSMichal Kalderon 		break;
106079284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
106179284adeSMichal Kalderon 		snprintf(str, str_len, "UDP src/dst ports 0x%04x/0x%04x",
106279284adeSMichal Kalderon 			 source_port_or_eth_type, dest_port);
106379284adeSMichal Kalderon 		break;
106479284adeSMichal Kalderon 	default:
106579284adeSMichal Kalderon 		DP_NOTICE(cdev,
106679284adeSMichal Kalderon 			  "Non valid LLH protocol filter type %d\n", type);
106779284adeSMichal Kalderon 		return -EINVAL;
106879284adeSMichal Kalderon 	}
106979284adeSMichal Kalderon 
107079284adeSMichal Kalderon 	return 0;
107179284adeSMichal Kalderon }
107279284adeSMichal Kalderon 
107379284adeSMichal Kalderon static int
107479284adeSMichal Kalderon qed_llh_protocol_filter_to_hilo(struct qed_dev *cdev,
107579284adeSMichal Kalderon 				enum qed_llh_prot_filter_type_t type,
107679284adeSMichal Kalderon 				u16 source_port_or_eth_type,
107779284adeSMichal Kalderon 				u16 dest_port, u32 *p_high, u32 *p_low)
107879284adeSMichal Kalderon {
107979284adeSMichal Kalderon 	*p_high = 0;
108079284adeSMichal Kalderon 	*p_low = 0;
108179284adeSMichal Kalderon 
108279284adeSMichal Kalderon 	switch (type) {
108379284adeSMichal Kalderon 	case QED_LLH_FILTER_ETHERTYPE:
108479284adeSMichal Kalderon 		*p_high = source_port_or_eth_type;
108579284adeSMichal Kalderon 		break;
108679284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_PORT:
108779284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_PORT:
108879284adeSMichal Kalderon 		*p_low = source_port_or_eth_type << 16;
108979284adeSMichal Kalderon 		break;
109079284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_DEST_PORT:
109179284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_DEST_PORT:
109279284adeSMichal Kalderon 		*p_low = dest_port;
109379284adeSMichal Kalderon 		break;
109479284adeSMichal Kalderon 	case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
109579284adeSMichal Kalderon 	case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
109679284adeSMichal Kalderon 		*p_low = (source_port_or_eth_type << 16) | dest_port;
109779284adeSMichal Kalderon 		break;
109879284adeSMichal Kalderon 	default:
109979284adeSMichal Kalderon 		DP_NOTICE(cdev,
110079284adeSMichal Kalderon 			  "Non valid LLH protocol filter type %d\n", type);
110179284adeSMichal Kalderon 		return -EINVAL;
110279284adeSMichal Kalderon 	}
110379284adeSMichal Kalderon 
110479284adeSMichal Kalderon 	return 0;
110579284adeSMichal Kalderon }
110679284adeSMichal Kalderon 
110779284adeSMichal Kalderon int
110879284adeSMichal Kalderon qed_llh_add_protocol_filter(struct qed_dev *cdev,
110979284adeSMichal Kalderon 			    u8 ppfid,
111079284adeSMichal Kalderon 			    enum qed_llh_prot_filter_type_t type,
111179284adeSMichal Kalderon 			    u16 source_port_or_eth_type, u16 dest_port)
111279284adeSMichal Kalderon {
111379284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
111479284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
111579284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid, str[32], type_bitmap;
111679284adeSMichal Kalderon 	union qed_llh_filter filter = {};
111779284adeSMichal Kalderon 	u32 high, low, ref_cnt;
111879284adeSMichal Kalderon 	int rc = 0;
111979284adeSMichal Kalderon 
112079284adeSMichal Kalderon 	if (!p_ptt)
112179284adeSMichal Kalderon 		return -EAGAIN;
112279284adeSMichal Kalderon 
112379284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits))
112479284adeSMichal Kalderon 		goto out;
112579284adeSMichal Kalderon 
112679284adeSMichal Kalderon 	rc = qed_llh_protocol_filter_stringify(cdev, type,
112779284adeSMichal Kalderon 					       source_port_or_eth_type,
112879284adeSMichal Kalderon 					       dest_port, str, sizeof(str));
112979284adeSMichal Kalderon 	if (rc)
113079284adeSMichal Kalderon 		goto err;
113179284adeSMichal Kalderon 
113279284adeSMichal Kalderon 	filter.protocol.type = type;
113379284adeSMichal Kalderon 	filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
113479284adeSMichal Kalderon 	filter.protocol.dest_port = dest_port;
113579284adeSMichal Kalderon 	rc = qed_llh_shadow_add_filter(cdev,
113679284adeSMichal Kalderon 				       ppfid,
113779284adeSMichal Kalderon 				       QED_LLH_FILTER_TYPE_PROTOCOL,
113879284adeSMichal Kalderon 				       &filter, &filter_idx, &ref_cnt);
113979284adeSMichal Kalderon 	if (rc)
114079284adeSMichal Kalderon 		goto err;
114179284adeSMichal Kalderon 
114279284adeSMichal Kalderon 	rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
114379284adeSMichal Kalderon 	if (rc)
114479284adeSMichal Kalderon 		goto err;
114579284adeSMichal Kalderon 
11468e2ea3eaSMichal Kalderon 	/* Configure the LLH only in case of a new the filter */
11478e2ea3eaSMichal Kalderon 	if (ref_cnt == 1) {
114879284adeSMichal Kalderon 		rc = qed_llh_protocol_filter_to_hilo(cdev, type,
114979284adeSMichal Kalderon 						     source_port_or_eth_type,
115079284adeSMichal Kalderon 						     dest_port, &high, &low);
115179284adeSMichal Kalderon 		if (rc)
115279284adeSMichal Kalderon 			goto err;
115379284adeSMichal Kalderon 
115479284adeSMichal Kalderon 		type_bitmap = 0x1 << type;
115579284adeSMichal Kalderon 		rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid,
115679284adeSMichal Kalderon 					filter_idx, type_bitmap, high, low);
115779284adeSMichal Kalderon 		if (rc)
115879284adeSMichal Kalderon 			goto err;
115979284adeSMichal Kalderon 	}
116079284adeSMichal Kalderon 
116179284adeSMichal Kalderon 	DP_VERBOSE(cdev,
116279284adeSMichal Kalderon 		   QED_MSG_SP,
116379284adeSMichal Kalderon 		   "LLH: Added protocol filter [%s] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
116479284adeSMichal Kalderon 		   str, ppfid, abs_ppfid, filter_idx, ref_cnt);
116579284adeSMichal Kalderon 
116679284adeSMichal Kalderon 	goto out;
116779284adeSMichal Kalderon 
116879284adeSMichal Kalderon err:	DP_NOTICE(p_hwfn,
116979284adeSMichal Kalderon 		  "LLH: Failed to add protocol filter [%s] to ppfid %hhd\n",
117079284adeSMichal Kalderon 		  str, ppfid);
117179284adeSMichal Kalderon out:
117279284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
117379284adeSMichal Kalderon 
117479284adeSMichal Kalderon 	return rc;
117579284adeSMichal Kalderon }
117679284adeSMichal Kalderon 
117779284adeSMichal Kalderon void qed_llh_remove_mac_filter(struct qed_dev *cdev,
117879284adeSMichal Kalderon 			       u8 ppfid, u8 mac_addr[ETH_ALEN])
117979284adeSMichal Kalderon {
118079284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
118179284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
118279284adeSMichal Kalderon 	union qed_llh_filter filter = {};
118379284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid;
118479284adeSMichal Kalderon 	int rc = 0;
118579284adeSMichal Kalderon 	u32 ref_cnt;
118679284adeSMichal Kalderon 
118779284adeSMichal Kalderon 	if (!p_ptt)
118879284adeSMichal Kalderon 		return;
118979284adeSMichal Kalderon 
119079284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
119179284adeSMichal Kalderon 		goto out;
119279284adeSMichal Kalderon 
119379284adeSMichal Kalderon 	ether_addr_copy(filter.mac.addr, mac_addr);
119479284adeSMichal Kalderon 	rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
119579284adeSMichal Kalderon 					  &ref_cnt);
119679284adeSMichal Kalderon 	if (rc)
119779284adeSMichal Kalderon 		goto err;
119879284adeSMichal Kalderon 
119979284adeSMichal Kalderon 	rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
120079284adeSMichal Kalderon 	if (rc)
120179284adeSMichal Kalderon 		goto err;
120279284adeSMichal Kalderon 
12038e2ea3eaSMichal Kalderon 	/* Remove from the LLH in case the filter is not in use */
12048e2ea3eaSMichal Kalderon 	if (!ref_cnt) {
120579284adeSMichal Kalderon 		rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
120679284adeSMichal Kalderon 					   filter_idx);
120779284adeSMichal Kalderon 		if (rc)
120879284adeSMichal Kalderon 			goto err;
120979284adeSMichal Kalderon 	}
121079284adeSMichal Kalderon 
121179284adeSMichal Kalderon 	DP_VERBOSE(cdev,
121279284adeSMichal Kalderon 		   QED_MSG_SP,
121379284adeSMichal Kalderon 		   "LLH: Removed MAC filter [%pM] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
121479284adeSMichal Kalderon 		   mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt);
121579284adeSMichal Kalderon 
121679284adeSMichal Kalderon 	goto out;
121779284adeSMichal Kalderon 
121879284adeSMichal Kalderon err:	DP_NOTICE(cdev,
121979284adeSMichal Kalderon 		  "LLH: Failed to remove MAC filter [%pM] from ppfid %hhd\n",
122079284adeSMichal Kalderon 		  mac_addr, ppfid);
122179284adeSMichal Kalderon out:
122279284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
122379284adeSMichal Kalderon }
122479284adeSMichal Kalderon 
122579284adeSMichal Kalderon void qed_llh_remove_protocol_filter(struct qed_dev *cdev,
122679284adeSMichal Kalderon 				    u8 ppfid,
122779284adeSMichal Kalderon 				    enum qed_llh_prot_filter_type_t type,
122879284adeSMichal Kalderon 				    u16 source_port_or_eth_type, u16 dest_port)
122979284adeSMichal Kalderon {
123079284adeSMichal Kalderon 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
123179284adeSMichal Kalderon 	struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
123279284adeSMichal Kalderon 	u8 filter_idx, abs_ppfid, str[32];
123379284adeSMichal Kalderon 	union qed_llh_filter filter = {};
123479284adeSMichal Kalderon 	int rc = 0;
123579284adeSMichal Kalderon 	u32 ref_cnt;
123679284adeSMichal Kalderon 
123779284adeSMichal Kalderon 	if (!p_ptt)
123879284adeSMichal Kalderon 		return;
123979284adeSMichal Kalderon 
124079284adeSMichal Kalderon 	if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits))
124179284adeSMichal Kalderon 		goto out;
124279284adeSMichal Kalderon 
124379284adeSMichal Kalderon 	rc = qed_llh_protocol_filter_stringify(cdev, type,
124479284adeSMichal Kalderon 					       source_port_or_eth_type,
124579284adeSMichal Kalderon 					       dest_port, str, sizeof(str));
124679284adeSMichal Kalderon 	if (rc)
124779284adeSMichal Kalderon 		goto err;
124879284adeSMichal Kalderon 
124979284adeSMichal Kalderon 	filter.protocol.type = type;
125079284adeSMichal Kalderon 	filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
125179284adeSMichal Kalderon 	filter.protocol.dest_port = dest_port;
125279284adeSMichal Kalderon 	rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
125379284adeSMichal Kalderon 					  &ref_cnt);
125479284adeSMichal Kalderon 	if (rc)
125579284adeSMichal Kalderon 		goto err;
125679284adeSMichal Kalderon 
125779284adeSMichal Kalderon 	rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
125879284adeSMichal Kalderon 	if (rc)
125979284adeSMichal Kalderon 		goto err;
126079284adeSMichal Kalderon 
12618e2ea3eaSMichal Kalderon 	/* Remove from the LLH in case the filter is not in use */
12628e2ea3eaSMichal Kalderon 	if (!ref_cnt) {
126379284adeSMichal Kalderon 		rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
126479284adeSMichal Kalderon 					   filter_idx);
126579284adeSMichal Kalderon 		if (rc)
126679284adeSMichal Kalderon 			goto err;
126779284adeSMichal Kalderon 	}
126879284adeSMichal Kalderon 
126979284adeSMichal Kalderon 	DP_VERBOSE(cdev,
127079284adeSMichal Kalderon 		   QED_MSG_SP,
127179284adeSMichal Kalderon 		   "LLH: Removed protocol filter [%s] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
127279284adeSMichal Kalderon 		   str, ppfid, abs_ppfid, filter_idx, ref_cnt);
127379284adeSMichal Kalderon 
127479284adeSMichal Kalderon 	goto out;
127579284adeSMichal Kalderon 
127679284adeSMichal Kalderon err:	DP_NOTICE(cdev,
127779284adeSMichal Kalderon 		  "LLH: Failed to remove protocol filter [%s] from ppfid %hhd\n",
127879284adeSMichal Kalderon 		  str, ppfid);
127979284adeSMichal Kalderon out:
128079284adeSMichal Kalderon 	qed_ptt_release(p_hwfn, p_ptt);
128179284adeSMichal Kalderon }
128279284adeSMichal Kalderon 
128379284adeSMichal Kalderon /******************************* NIG LLH - End ********************************/
128479284adeSMichal Kalderon 
128551ff1725SRam Amrani #define QED_MIN_DPIS            (4)
128651ff1725SRam Amrani #define QED_MIN_PWM_REGION      (QED_WID_SIZE * QED_MIN_DPIS)
128751ff1725SRam Amrani 
128815582962SRahul Verma static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
128915582962SRahul Verma 			   struct qed_ptt *p_ptt, enum BAR_ID bar_id)
1290c2035eeaSRam Amrani {
1291c2035eeaSRam Amrani 	u32 bar_reg = (bar_id == BAR_ID_0 ?
1292c2035eeaSRam Amrani 		       PGLUE_B_REG_PF_BAR0_SIZE : PGLUE_B_REG_PF_BAR1_SIZE);
12931408cc1fSYuval Mintz 	u32 val;
1294c2035eeaSRam Amrani 
12951408cc1fSYuval Mintz 	if (IS_VF(p_hwfn->cdev))
12961a850bfcSMintz, Yuval 		return qed_vf_hw_bar_size(p_hwfn, bar_id);
12971408cc1fSYuval Mintz 
129815582962SRahul Verma 	val = qed_rd(p_hwfn, p_ptt, bar_reg);
1299c2035eeaSRam Amrani 	if (val)
1300c2035eeaSRam Amrani 		return 1 << (val + 15);
1301c2035eeaSRam Amrani 
1302c2035eeaSRam Amrani 	/* Old MFW initialized above registered only conditionally */
1303c2035eeaSRam Amrani 	if (p_hwfn->cdev->num_hwfns > 1) {
1304c2035eeaSRam Amrani 		DP_INFO(p_hwfn,
1305c2035eeaSRam Amrani 			"BAR size not configured. Assuming BAR size of 256kB for GRC and 512kB for DB\n");
1306c2035eeaSRam Amrani 			return BAR_ID_0 ? 256 * 1024 : 512 * 1024;
1307c2035eeaSRam Amrani 	} else {
1308c2035eeaSRam Amrani 		DP_INFO(p_hwfn,
1309c2035eeaSRam Amrani 			"BAR size not configured. Assuming BAR size of 512kB for GRC and 512kB for DB\n");
1310c2035eeaSRam Amrani 			return 512 * 1024;
1311c2035eeaSRam Amrani 	}
1312c2035eeaSRam Amrani }
1313c2035eeaSRam Amrani 
13141a635e48SYuval Mintz void qed_init_dp(struct qed_dev *cdev, u32 dp_module, u8 dp_level)
1315fe56b9e6SYuval Mintz {
1316fe56b9e6SYuval Mintz 	u32 i;
1317fe56b9e6SYuval Mintz 
1318fe56b9e6SYuval Mintz 	cdev->dp_level = dp_level;
1319fe56b9e6SYuval Mintz 	cdev->dp_module = dp_module;
1320fe56b9e6SYuval Mintz 	for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) {
1321fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1322fe56b9e6SYuval Mintz 
1323fe56b9e6SYuval Mintz 		p_hwfn->dp_level = dp_level;
1324fe56b9e6SYuval Mintz 		p_hwfn->dp_module = dp_module;
1325fe56b9e6SYuval Mintz 	}
1326fe56b9e6SYuval Mintz }
1327fe56b9e6SYuval Mintz 
1328fe56b9e6SYuval Mintz void qed_init_struct(struct qed_dev *cdev)
1329fe56b9e6SYuval Mintz {
1330fe56b9e6SYuval Mintz 	u8 i;
1331fe56b9e6SYuval Mintz 
1332fe56b9e6SYuval Mintz 	for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) {
1333fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1334fe56b9e6SYuval Mintz 
1335fe56b9e6SYuval Mintz 		p_hwfn->cdev = cdev;
1336fe56b9e6SYuval Mintz 		p_hwfn->my_id = i;
1337fe56b9e6SYuval Mintz 		p_hwfn->b_active = false;
1338fe56b9e6SYuval Mintz 
1339fe56b9e6SYuval Mintz 		mutex_init(&p_hwfn->dmae_info.mutex);
1340fe56b9e6SYuval Mintz 	}
1341fe56b9e6SYuval Mintz 
1342fe56b9e6SYuval Mintz 	/* hwfn 0 is always active */
1343fe56b9e6SYuval Mintz 	cdev->hwfns[0].b_active = true;
1344fe56b9e6SYuval Mintz 
1345fe56b9e6SYuval Mintz 	/* set the default cache alignment to 128 */
1346fe56b9e6SYuval Mintz 	cdev->cache_shift = 7;
1347fe56b9e6SYuval Mintz }
1348fe56b9e6SYuval Mintz 
1349fe56b9e6SYuval Mintz static void qed_qm_info_free(struct qed_hwfn *p_hwfn)
1350fe56b9e6SYuval Mintz {
1351fe56b9e6SYuval Mintz 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1352fe56b9e6SYuval Mintz 
1353fe56b9e6SYuval Mintz 	kfree(qm_info->qm_pq_params);
1354fe56b9e6SYuval Mintz 	qm_info->qm_pq_params = NULL;
1355fe56b9e6SYuval Mintz 	kfree(qm_info->qm_vport_params);
1356fe56b9e6SYuval Mintz 	qm_info->qm_vport_params = NULL;
1357fe56b9e6SYuval Mintz 	kfree(qm_info->qm_port_params);
1358fe56b9e6SYuval Mintz 	qm_info->qm_port_params = NULL;
1359bcd197c8SManish Chopra 	kfree(qm_info->wfq_data);
1360bcd197c8SManish Chopra 	qm_info->wfq_data = NULL;
1361fe56b9e6SYuval Mintz }
1362fe56b9e6SYuval Mintz 
1363a3f72307SDenis Bolotin static void qed_dbg_user_data_free(struct qed_hwfn *p_hwfn)
1364a3f72307SDenis Bolotin {
1365a3f72307SDenis Bolotin 	kfree(p_hwfn->dbg_user_info);
1366a3f72307SDenis Bolotin 	p_hwfn->dbg_user_info = NULL;
1367a3f72307SDenis Bolotin }
1368a3f72307SDenis Bolotin 
1369fe56b9e6SYuval Mintz void qed_resc_free(struct qed_dev *cdev)
1370fe56b9e6SYuval Mintz {
1371fe56b9e6SYuval Mintz 	int i;
1372fe56b9e6SYuval Mintz 
13730db711bbSMintz, Yuval 	if (IS_VF(cdev)) {
13740db711bbSMintz, Yuval 		for_each_hwfn(cdev, i)
13750db711bbSMintz, Yuval 			qed_l2_free(&cdev->hwfns[i]);
13761408cc1fSYuval Mintz 		return;
13770db711bbSMintz, Yuval 	}
13781408cc1fSYuval Mintz 
1379fe56b9e6SYuval Mintz 	kfree(cdev->fw_data);
1380fe56b9e6SYuval Mintz 	cdev->fw_data = NULL;
1381fe56b9e6SYuval Mintz 
1382fe56b9e6SYuval Mintz 	kfree(cdev->reset_stats);
13833587cb87STomer Tayar 	cdev->reset_stats = NULL;
1384fe56b9e6SYuval Mintz 
138579284adeSMichal Kalderon 	qed_llh_free(cdev);
138679284adeSMichal Kalderon 
1387fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
1388fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
1389fe56b9e6SYuval Mintz 
1390fe56b9e6SYuval Mintz 		qed_cxt_mngr_free(p_hwfn);
1391fe56b9e6SYuval Mintz 		qed_qm_info_free(p_hwfn);
1392fe56b9e6SYuval Mintz 		qed_spq_free(p_hwfn);
13933587cb87STomer Tayar 		qed_eq_free(p_hwfn);
13943587cb87STomer Tayar 		qed_consq_free(p_hwfn);
1395fe56b9e6SYuval Mintz 		qed_int_free(p_hwfn);
13960a7fb11cSYuval Mintz #ifdef CONFIG_QED_LL2
13973587cb87STomer Tayar 		qed_ll2_free(p_hwfn);
13980a7fb11cSYuval Mintz #endif
13991e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
14003587cb87STomer Tayar 			qed_fcoe_free(p_hwfn);
14011e128c81SArun Easi 
14021d6cff4fSYuval Mintz 		if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
14033587cb87STomer Tayar 			qed_iscsi_free(p_hwfn);
14043587cb87STomer Tayar 			qed_ooo_free(p_hwfn);
14051d6cff4fSYuval Mintz 		}
1406291d57f6SMichal Kalderon 
1407291d57f6SMichal Kalderon 		if (QED_IS_RDMA_PERSONALITY(p_hwfn))
1408291d57f6SMichal Kalderon 			qed_rdma_info_free(p_hwfn);
1409291d57f6SMichal Kalderon 
141032a47e72SYuval Mintz 		qed_iov_free(p_hwfn);
14110db711bbSMintz, Yuval 		qed_l2_free(p_hwfn);
1412fe56b9e6SYuval Mintz 		qed_dmae_info_free(p_hwfn);
1413270837b3Ssudarsana.kalluru@cavium.com 		qed_dcbx_info_free(p_hwfn);
1414a3f72307SDenis Bolotin 		qed_dbg_user_data_free(p_hwfn);
141530d5f858SMichal Kalderon 		qed_fw_overlay_mem_free(p_hwfn, p_hwfn->fw_overlay_mem);
141636907cd5SAriel Elior 
141736907cd5SAriel Elior 		/* Destroy doorbell recovery mechanism */
141836907cd5SAriel Elior 		qed_db_recovery_teardown(p_hwfn);
1419fe56b9e6SYuval Mintz 	}
1420fe56b9e6SYuval Mintz }
1421fe56b9e6SYuval Mintz 
1422b5a9ee7cSAriel Elior /******************** QM initialization *******************/
1423b5a9ee7cSAriel Elior #define ACTIVE_TCS_BMAP 0x9f
1424b5a9ee7cSAriel Elior #define ACTIVE_TCS_BMAP_4PORT_K2 0xf
1425b5a9ee7cSAriel Elior 
1426b5a9ee7cSAriel Elior /* determines the physical queue flags for a given PF. */
1427b5a9ee7cSAriel Elior static u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn)
1428fe56b9e6SYuval Mintz {
1429b5a9ee7cSAriel Elior 	u32 flags;
1430fe56b9e6SYuval Mintz 
1431b5a9ee7cSAriel Elior 	/* common flags */
1432b5a9ee7cSAriel Elior 	flags = PQ_FLAGS_LB;
1433fe56b9e6SYuval Mintz 
1434b5a9ee7cSAriel Elior 	/* feature flags */
1435b5a9ee7cSAriel Elior 	if (IS_QED_SRIOV(p_hwfn->cdev))
1436b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_VFS;
1437fe56b9e6SYuval Mintz 
1438b5a9ee7cSAriel Elior 	/* protocol flags */
1439b5a9ee7cSAriel Elior 	switch (p_hwfn->hw_info.personality) {
1440b5a9ee7cSAriel Elior 	case QED_PCI_ETH:
1441b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_MCOS;
1442b5a9ee7cSAriel Elior 		break;
1443b5a9ee7cSAriel Elior 	case QED_PCI_FCOE:
1444b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_OFLD;
1445b5a9ee7cSAriel Elior 		break;
1446b5a9ee7cSAriel Elior 	case QED_PCI_ISCSI:
1447b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_ACK | PQ_FLAGS_OOO | PQ_FLAGS_OFLD;
1448b5a9ee7cSAriel Elior 		break;
1449b5a9ee7cSAriel Elior 	case QED_PCI_ETH_ROCE:
1450b5a9ee7cSAriel Elior 		flags |= PQ_FLAGS_MCOS | PQ_FLAGS_OFLD | PQ_FLAGS_LLT;
145161be82b0SDenis Bolotin 		if (IS_QED_MULTI_TC_ROCE(p_hwfn))
145261be82b0SDenis Bolotin 			flags |= PQ_FLAGS_MTC;
1453b5a9ee7cSAriel Elior 		break;
145493c45984SKalderon, Michal 	case QED_PCI_ETH_IWARP:
145593c45984SKalderon, Michal 		flags |= PQ_FLAGS_MCOS | PQ_FLAGS_ACK | PQ_FLAGS_OOO |
145693c45984SKalderon, Michal 		    PQ_FLAGS_OFLD;
145793c45984SKalderon, Michal 		break;
1458b5a9ee7cSAriel Elior 	default:
1459fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn,
1460b5a9ee7cSAriel Elior 		       "unknown personality %d\n", p_hwfn->hw_info.personality);
1461b5a9ee7cSAriel Elior 		return 0;
1462fe56b9e6SYuval Mintz 	}
1463fe56b9e6SYuval Mintz 
1464b5a9ee7cSAriel Elior 	return flags;
1465b5a9ee7cSAriel Elior }
1466b5a9ee7cSAriel Elior 
1467b5a9ee7cSAriel Elior /* Getters for resource amounts necessary for qm initialization */
1468bf774d14SYueHaibing static u8 qed_init_qm_get_num_tcs(struct qed_hwfn *p_hwfn)
1469b5a9ee7cSAriel Elior {
1470b5a9ee7cSAriel Elior 	return p_hwfn->hw_info.num_hw_tc;
1471b5a9ee7cSAriel Elior }
1472b5a9ee7cSAriel Elior 
1473bf774d14SYueHaibing static u16 qed_init_qm_get_num_vfs(struct qed_hwfn *p_hwfn)
1474b5a9ee7cSAriel Elior {
1475b5a9ee7cSAriel Elior 	return IS_QED_SRIOV(p_hwfn->cdev) ?
1476b5a9ee7cSAriel Elior 	       p_hwfn->cdev->p_iov_info->total_vfs : 0;
1477b5a9ee7cSAriel Elior }
1478b5a9ee7cSAriel Elior 
147961be82b0SDenis Bolotin static u8 qed_init_qm_get_num_mtc_tcs(struct qed_hwfn *p_hwfn)
148061be82b0SDenis Bolotin {
148161be82b0SDenis Bolotin 	u32 pq_flags = qed_get_pq_flags(p_hwfn);
148261be82b0SDenis Bolotin 
148361be82b0SDenis Bolotin 	if (!(PQ_FLAGS_MTC & pq_flags))
148461be82b0SDenis Bolotin 		return 1;
148561be82b0SDenis Bolotin 
148661be82b0SDenis Bolotin 	return qed_init_qm_get_num_tcs(p_hwfn);
148761be82b0SDenis Bolotin }
148861be82b0SDenis Bolotin 
1489b5a9ee7cSAriel Elior #define NUM_DEFAULT_RLS 1
1490b5a9ee7cSAriel Elior 
1491bf774d14SYueHaibing static u16 qed_init_qm_get_num_pf_rls(struct qed_hwfn *p_hwfn)
1492b5a9ee7cSAriel Elior {
1493b5a9ee7cSAriel Elior 	u16 num_pf_rls, num_vfs = qed_init_qm_get_num_vfs(p_hwfn);
1494b5a9ee7cSAriel Elior 
1495b5a9ee7cSAriel Elior 	/* num RLs can't exceed resource amount of rls or vports */
1496b5a9ee7cSAriel Elior 	num_pf_rls = (u16) min_t(u32, RESC_NUM(p_hwfn, QED_RL),
1497b5a9ee7cSAriel Elior 				 RESC_NUM(p_hwfn, QED_VPORT));
1498b5a9ee7cSAriel Elior 
1499b5a9ee7cSAriel Elior 	/* Make sure after we reserve there's something left */
1500b5a9ee7cSAriel Elior 	if (num_pf_rls < num_vfs + NUM_DEFAULT_RLS)
1501b5a9ee7cSAriel Elior 		return 0;
1502b5a9ee7cSAriel Elior 
1503b5a9ee7cSAriel Elior 	/* subtract rls necessary for VFs and one default one for the PF */
1504b5a9ee7cSAriel Elior 	num_pf_rls -= num_vfs + NUM_DEFAULT_RLS;
1505b5a9ee7cSAriel Elior 
1506b5a9ee7cSAriel Elior 	return num_pf_rls;
1507b5a9ee7cSAriel Elior }
1508b5a9ee7cSAriel Elior 
1509bf774d14SYueHaibing static u16 qed_init_qm_get_num_vports(struct qed_hwfn *p_hwfn)
1510b5a9ee7cSAriel Elior {
1511b5a9ee7cSAriel Elior 	u32 pq_flags = qed_get_pq_flags(p_hwfn);
1512b5a9ee7cSAriel Elior 
1513b5a9ee7cSAriel Elior 	/* all pqs share the same vport, except for vfs and pf_rl pqs */
1514b5a9ee7cSAriel Elior 	return (!!(PQ_FLAGS_RLS & pq_flags)) *
1515b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_pf_rls(p_hwfn) +
1516b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_VFS & pq_flags)) *
1517b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_vfs(p_hwfn) + 1;
1518b5a9ee7cSAriel Elior }
1519b5a9ee7cSAriel Elior 
1520b5a9ee7cSAriel Elior /* calc amount of PQs according to the requested flags */
1521bf774d14SYueHaibing static u16 qed_init_qm_get_num_pqs(struct qed_hwfn *p_hwfn)
1522b5a9ee7cSAriel Elior {
1523b5a9ee7cSAriel Elior 	u32 pq_flags = qed_get_pq_flags(p_hwfn);
1524b5a9ee7cSAriel Elior 
1525b5a9ee7cSAriel Elior 	return (!!(PQ_FLAGS_RLS & pq_flags)) *
1526b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_pf_rls(p_hwfn) +
1527b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_MCOS & pq_flags)) *
1528b5a9ee7cSAriel Elior 	       qed_init_qm_get_num_tcs(p_hwfn) +
1529b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_LB & pq_flags)) + (!!(PQ_FLAGS_OOO & pq_flags)) +
153061be82b0SDenis Bolotin 	       (!!(PQ_FLAGS_ACK & pq_flags)) +
153161be82b0SDenis Bolotin 	       (!!(PQ_FLAGS_OFLD & pq_flags)) *
153261be82b0SDenis Bolotin 	       qed_init_qm_get_num_mtc_tcs(p_hwfn) +
153361be82b0SDenis Bolotin 	       (!!(PQ_FLAGS_LLT & pq_flags)) *
153461be82b0SDenis Bolotin 	       qed_init_qm_get_num_mtc_tcs(p_hwfn) +
1535b5a9ee7cSAriel Elior 	       (!!(PQ_FLAGS_VFS & pq_flags)) * qed_init_qm_get_num_vfs(p_hwfn);
1536b5a9ee7cSAriel Elior }
1537b5a9ee7cSAriel Elior 
1538b5a9ee7cSAriel Elior /* initialize the top level QM params */
1539b5a9ee7cSAriel Elior static void qed_init_qm_params(struct qed_hwfn *p_hwfn)
1540b5a9ee7cSAriel Elior {
1541b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1542b5a9ee7cSAriel Elior 	bool four_port;
1543b5a9ee7cSAriel Elior 
1544b5a9ee7cSAriel Elior 	/* pq and vport bases for this PF */
1545b5a9ee7cSAriel Elior 	qm_info->start_pq = (u16) RESC_START(p_hwfn, QED_PQ);
1546b5a9ee7cSAriel Elior 	qm_info->start_vport = (u8) RESC_START(p_hwfn, QED_VPORT);
1547b5a9ee7cSAriel Elior 
1548b5a9ee7cSAriel Elior 	/* rate limiting and weighted fair queueing are always enabled */
1549c7281d59SGustavo A. R. Silva 	qm_info->vport_rl_en = true;
1550c7281d59SGustavo A. R. Silva 	qm_info->vport_wfq_en = true;
1551b5a9ee7cSAriel Elior 
1552b5a9ee7cSAriel Elior 	/* TC config is different for AH 4 port */
155378cea9ffSTomer Tayar 	four_port = p_hwfn->cdev->num_ports_in_engine == MAX_NUM_PORTS_K2;
1554b5a9ee7cSAriel Elior 
1555b5a9ee7cSAriel Elior 	/* in AH 4 port we have fewer TCs per port */
1556b5a9ee7cSAriel Elior 	qm_info->max_phys_tcs_per_port = four_port ? NUM_PHYS_TCS_4PORT_K2 :
1557b5a9ee7cSAriel Elior 						     NUM_OF_PHYS_TCS;
1558b5a9ee7cSAriel Elior 
1559b5a9ee7cSAriel Elior 	/* unless MFW indicated otherwise, ooo_tc == 3 for
1560b5a9ee7cSAriel Elior 	 * AH 4-port and 4 otherwise.
1561fe56b9e6SYuval Mintz 	 */
1562b5a9ee7cSAriel Elior 	if (!qm_info->ooo_tc)
1563b5a9ee7cSAriel Elior 		qm_info->ooo_tc = four_port ? DCBX_TCP_OOO_K2_4PORT_TC :
1564b5a9ee7cSAriel Elior 					      DCBX_TCP_OOO_TC;
1565dbb799c3SYuval Mintz }
1566dbb799c3SYuval Mintz 
1567b5a9ee7cSAriel Elior /* initialize qm vport params */
1568b5a9ee7cSAriel Elior static void qed_init_qm_vport_params(struct qed_hwfn *p_hwfn)
1569b5a9ee7cSAriel Elior {
1570b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1571b5a9ee7cSAriel Elior 	u8 i;
1572fe56b9e6SYuval Mintz 
1573b5a9ee7cSAriel Elior 	/* all vports participate in weighted fair queueing */
1574b5a9ee7cSAriel Elior 	for (i = 0; i < qed_init_qm_get_num_vports(p_hwfn); i++)
157592fae6fbSMichal Kalderon 		qm_info->qm_vport_params[i].wfq = 1;
1576fe56b9e6SYuval Mintz }
1577fe56b9e6SYuval Mintz 
1578b5a9ee7cSAriel Elior /* initialize qm port params */
1579b5a9ee7cSAriel Elior static void qed_init_qm_port_params(struct qed_hwfn *p_hwfn)
1580b5a9ee7cSAriel Elior {
1581fe56b9e6SYuval Mintz 	/* Initialize qm port parameters */
158278cea9ffSTomer Tayar 	u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engine;
15831392d19fSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
1584b5a9ee7cSAriel Elior 
1585b5a9ee7cSAriel Elior 	/* indicate how ooo and high pri traffic is dealt with */
1586b5a9ee7cSAriel Elior 	active_phys_tcs = num_ports == MAX_NUM_PORTS_K2 ?
1587b5a9ee7cSAriel Elior 			  ACTIVE_TCS_BMAP_4PORT_K2 :
1588b5a9ee7cSAriel Elior 			  ACTIVE_TCS_BMAP;
1589b5a9ee7cSAriel Elior 
1590fe56b9e6SYuval Mintz 	for (i = 0; i < num_ports; i++) {
1591b5a9ee7cSAriel Elior 		struct init_qm_port_params *p_qm_port =
1592b5a9ee7cSAriel Elior 		    &p_hwfn->qm_info.qm_port_params[i];
15931392d19fSMichal Kalderon 		u16 pbf_max_cmd_lines;
1594b5a9ee7cSAriel Elior 
1595fe56b9e6SYuval Mintz 		p_qm_port->active = 1;
1596b5a9ee7cSAriel Elior 		p_qm_port->active_phys_tcs = active_phys_tcs;
15971392d19fSMichal Kalderon 		pbf_max_cmd_lines = (u16)NUM_OF_PBF_CMD_LINES(cdev);
15981392d19fSMichal Kalderon 		p_qm_port->num_pbf_cmd_lines = pbf_max_cmd_lines / num_ports;
15991392d19fSMichal Kalderon 		p_qm_port->num_btb_blocks = NUM_OF_BTB_BLOCKS(cdev) / num_ports;
1600fe56b9e6SYuval Mintz 	}
1601b5a9ee7cSAriel Elior }
1602fe56b9e6SYuval Mintz 
1603b5a9ee7cSAriel Elior /* Reset the params which must be reset for qm init. QM init may be called as
1604b5a9ee7cSAriel Elior  * a result of flows other than driver load (e.g. dcbx renegotiation). Other
1605b5a9ee7cSAriel Elior  * params may be affected by the init but would simply recalculate to the same
1606b5a9ee7cSAriel Elior  * values. The allocations made for QM init, ports, vports, pqs and vfqs are not
1607b5a9ee7cSAriel Elior  * affected as these amounts stay the same.
1608b5a9ee7cSAriel Elior  */
1609b5a9ee7cSAriel Elior static void qed_init_qm_reset_params(struct qed_hwfn *p_hwfn)
1610b5a9ee7cSAriel Elior {
1611b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1612fe56b9e6SYuval Mintz 
1613b5a9ee7cSAriel Elior 	qm_info->num_pqs = 0;
1614b5a9ee7cSAriel Elior 	qm_info->num_vports = 0;
1615b5a9ee7cSAriel Elior 	qm_info->num_pf_rls = 0;
1616b5a9ee7cSAriel Elior 	qm_info->num_vf_pqs = 0;
1617b5a9ee7cSAriel Elior 	qm_info->first_vf_pq = 0;
1618b5a9ee7cSAriel Elior 	qm_info->first_mcos_pq = 0;
1619b5a9ee7cSAriel Elior 	qm_info->first_rl_pq = 0;
1620b5a9ee7cSAriel Elior }
1621fe56b9e6SYuval Mintz 
1622b5a9ee7cSAriel Elior static void qed_init_qm_advance_vport(struct qed_hwfn *p_hwfn)
1623b5a9ee7cSAriel Elior {
1624b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1625b5a9ee7cSAriel Elior 
1626b5a9ee7cSAriel Elior 	qm_info->num_vports++;
1627b5a9ee7cSAriel Elior 
1628b5a9ee7cSAriel Elior 	if (qm_info->num_vports > qed_init_qm_get_num_vports(p_hwfn))
1629b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1630b5a9ee7cSAriel Elior 		       "vport overflow! qm_info->num_vports %d, qm_init_get_num_vports() %d\n",
1631b5a9ee7cSAriel Elior 		       qm_info->num_vports, qed_init_qm_get_num_vports(p_hwfn));
1632b5a9ee7cSAriel Elior }
1633b5a9ee7cSAriel Elior 
1634b5a9ee7cSAriel Elior /* initialize a single pq and manage qm_info resources accounting.
1635b5a9ee7cSAriel Elior  * The pq_init_flags param determines whether the PQ is rate limited
1636b5a9ee7cSAriel Elior  * (for VF or PF) and whether a new vport is allocated to the pq or not
1637b5a9ee7cSAriel Elior  * (i.e. vport will be shared).
1638b5a9ee7cSAriel Elior  */
1639b5a9ee7cSAriel Elior 
1640b5a9ee7cSAriel Elior /* flags for pq init */
1641b5a9ee7cSAriel Elior #define PQ_INIT_SHARE_VPORT     (1 << 0)
1642b5a9ee7cSAriel Elior #define PQ_INIT_PF_RL           (1 << 1)
1643b5a9ee7cSAriel Elior #define PQ_INIT_VF_RL           (1 << 2)
1644b5a9ee7cSAriel Elior 
1645b5a9ee7cSAriel Elior /* defines for pq init */
1646b5a9ee7cSAriel Elior #define PQ_INIT_DEFAULT_WRR_GROUP       1
1647b5a9ee7cSAriel Elior #define PQ_INIT_DEFAULT_TC              0
1648c4259ddaSDenis Bolotin 
1649c4259ddaSDenis Bolotin void qed_hw_info_set_offload_tc(struct qed_hw_info *p_info, u8 tc)
1650c4259ddaSDenis Bolotin {
1651c4259ddaSDenis Bolotin 	p_info->offload_tc = tc;
1652c4259ddaSDenis Bolotin 	p_info->offload_tc_set = true;
1653c4259ddaSDenis Bolotin }
1654c4259ddaSDenis Bolotin 
1655c4259ddaSDenis Bolotin static bool qed_is_offload_tc_set(struct qed_hwfn *p_hwfn)
1656c4259ddaSDenis Bolotin {
1657c4259ddaSDenis Bolotin 	return p_hwfn->hw_info.offload_tc_set;
1658c4259ddaSDenis Bolotin }
1659c4259ddaSDenis Bolotin 
1660c4259ddaSDenis Bolotin static u32 qed_get_offload_tc(struct qed_hwfn *p_hwfn)
1661c4259ddaSDenis Bolotin {
1662c4259ddaSDenis Bolotin 	if (qed_is_offload_tc_set(p_hwfn))
1663c4259ddaSDenis Bolotin 		return p_hwfn->hw_info.offload_tc;
1664c4259ddaSDenis Bolotin 
1665c4259ddaSDenis Bolotin 	return PQ_INIT_DEFAULT_TC;
1666c4259ddaSDenis Bolotin }
1667b5a9ee7cSAriel Elior 
1668b5a9ee7cSAriel Elior static void qed_init_qm_pq(struct qed_hwfn *p_hwfn,
1669b5a9ee7cSAriel Elior 			   struct qed_qm_info *qm_info,
1670b5a9ee7cSAriel Elior 			   u8 tc, u32 pq_init_flags)
1671b5a9ee7cSAriel Elior {
1672b5a9ee7cSAriel Elior 	u16 pq_idx = qm_info->num_pqs, max_pq = qed_init_qm_get_num_pqs(p_hwfn);
1673b5a9ee7cSAriel Elior 
1674b5a9ee7cSAriel Elior 	if (pq_idx > max_pq)
1675b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1676b5a9ee7cSAriel Elior 		       "pq overflow! pq %d, max pq %d\n", pq_idx, max_pq);
1677b5a9ee7cSAriel Elior 
1678b5a9ee7cSAriel Elior 	/* init pq params */
167950bc60cbSMichal Kalderon 	qm_info->qm_pq_params[pq_idx].port_id = p_hwfn->port_id;
1680b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].vport_id = qm_info->start_vport +
1681b5a9ee7cSAriel Elior 	    qm_info->num_vports;
1682b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].tc_id = tc;
1683b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].wrr_group = PQ_INIT_DEFAULT_WRR_GROUP;
1684b5a9ee7cSAriel Elior 	qm_info->qm_pq_params[pq_idx].rl_valid =
1685b5a9ee7cSAriel Elior 	    (pq_init_flags & PQ_INIT_PF_RL || pq_init_flags & PQ_INIT_VF_RL);
1686b5a9ee7cSAriel Elior 
1687b5a9ee7cSAriel Elior 	/* qm params accounting */
1688b5a9ee7cSAriel Elior 	qm_info->num_pqs++;
1689b5a9ee7cSAriel Elior 	if (!(pq_init_flags & PQ_INIT_SHARE_VPORT))
1690b5a9ee7cSAriel Elior 		qm_info->num_vports++;
1691b5a9ee7cSAriel Elior 
1692b5a9ee7cSAriel Elior 	if (pq_init_flags & PQ_INIT_PF_RL)
1693b5a9ee7cSAriel Elior 		qm_info->num_pf_rls++;
1694b5a9ee7cSAriel Elior 
1695b5a9ee7cSAriel Elior 	if (qm_info->num_vports > qed_init_qm_get_num_vports(p_hwfn))
1696b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1697b5a9ee7cSAriel Elior 		       "vport overflow! qm_info->num_vports %d, qm_init_get_num_vports() %d\n",
1698b5a9ee7cSAriel Elior 		       qm_info->num_vports, qed_init_qm_get_num_vports(p_hwfn));
1699b5a9ee7cSAriel Elior 
1700b5a9ee7cSAriel Elior 	if (qm_info->num_pf_rls > qed_init_qm_get_num_pf_rls(p_hwfn))
1701b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn,
1702b5a9ee7cSAriel Elior 		       "rl overflow! qm_info->num_pf_rls %d, qm_init_get_num_pf_rls() %d\n",
1703b5a9ee7cSAriel Elior 		       qm_info->num_pf_rls, qed_init_qm_get_num_pf_rls(p_hwfn));
1704b5a9ee7cSAriel Elior }
1705b5a9ee7cSAriel Elior 
1706b5a9ee7cSAriel Elior /* get pq index according to PQ_FLAGS */
1707b5a9ee7cSAriel Elior static u16 *qed_init_qm_get_idx_from_flags(struct qed_hwfn *p_hwfn,
1708ffb057f9SManish Chopra 					   unsigned long pq_flags)
1709b5a9ee7cSAriel Elior {
1710b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1711b5a9ee7cSAriel Elior 
1712b5a9ee7cSAriel Elior 	/* Can't have multiple flags set here */
1713ffb057f9SManish Chopra 	if (bitmap_weight(&pq_flags,
1714276d43f0SDenis Bolotin 			  sizeof(pq_flags) * BITS_PER_BYTE) > 1) {
1715ffb057f9SManish Chopra 		DP_ERR(p_hwfn, "requested multiple pq flags 0x%lx\n", pq_flags);
1716b5a9ee7cSAriel Elior 		goto err;
1717276d43f0SDenis Bolotin 	}
1718b5a9ee7cSAriel Elior 
1719eb62cca9SDenis Bolotin 	if (!(qed_get_pq_flags(p_hwfn) & pq_flags)) {
1720ffb057f9SManish Chopra 		DP_ERR(p_hwfn, "pq flag 0x%lx is not set\n", pq_flags);
1721eb62cca9SDenis Bolotin 		goto err;
1722eb62cca9SDenis Bolotin 	}
1723eb62cca9SDenis Bolotin 
1724b5a9ee7cSAriel Elior 	switch (pq_flags) {
1725b5a9ee7cSAriel Elior 	case PQ_FLAGS_RLS:
1726b5a9ee7cSAriel Elior 		return &qm_info->first_rl_pq;
1727b5a9ee7cSAriel Elior 	case PQ_FLAGS_MCOS:
1728b5a9ee7cSAriel Elior 		return &qm_info->first_mcos_pq;
1729b5a9ee7cSAriel Elior 	case PQ_FLAGS_LB:
1730b5a9ee7cSAriel Elior 		return &qm_info->pure_lb_pq;
1731b5a9ee7cSAriel Elior 	case PQ_FLAGS_OOO:
1732b5a9ee7cSAriel Elior 		return &qm_info->ooo_pq;
1733b5a9ee7cSAriel Elior 	case PQ_FLAGS_ACK:
1734b5a9ee7cSAriel Elior 		return &qm_info->pure_ack_pq;
1735b5a9ee7cSAriel Elior 	case PQ_FLAGS_OFLD:
173661be82b0SDenis Bolotin 		return &qm_info->first_ofld_pq;
1737b5a9ee7cSAriel Elior 	case PQ_FLAGS_LLT:
173861be82b0SDenis Bolotin 		return &qm_info->first_llt_pq;
1739b5a9ee7cSAriel Elior 	case PQ_FLAGS_VFS:
1740b5a9ee7cSAriel Elior 		return &qm_info->first_vf_pq;
1741b5a9ee7cSAriel Elior 	default:
1742b5a9ee7cSAriel Elior 		goto err;
1743b5a9ee7cSAriel Elior 	}
1744b5a9ee7cSAriel Elior 
1745b5a9ee7cSAriel Elior err:
1746eb62cca9SDenis Bolotin 	return &qm_info->start_pq;
1747b5a9ee7cSAriel Elior }
1748b5a9ee7cSAriel Elior 
1749b5a9ee7cSAriel Elior /* save pq index in qm info */
1750b5a9ee7cSAriel Elior static void qed_init_qm_set_idx(struct qed_hwfn *p_hwfn,
1751b5a9ee7cSAriel Elior 				u32 pq_flags, u16 pq_val)
1752b5a9ee7cSAriel Elior {
1753b5a9ee7cSAriel Elior 	u16 *base_pq_idx = qed_init_qm_get_idx_from_flags(p_hwfn, pq_flags);
1754b5a9ee7cSAriel Elior 
1755b5a9ee7cSAriel Elior 	*base_pq_idx = p_hwfn->qm_info.start_pq + pq_val;
1756b5a9ee7cSAriel Elior }
1757b5a9ee7cSAriel Elior 
1758b5a9ee7cSAriel Elior /* get tx pq index, with the PQ TX base already set (ready for context init) */
1759b5a9ee7cSAriel Elior u16 qed_get_cm_pq_idx(struct qed_hwfn *p_hwfn, u32 pq_flags)
1760b5a9ee7cSAriel Elior {
1761b5a9ee7cSAriel Elior 	u16 *base_pq_idx = qed_init_qm_get_idx_from_flags(p_hwfn, pq_flags);
1762b5a9ee7cSAriel Elior 
1763b5a9ee7cSAriel Elior 	return *base_pq_idx + CM_TX_PQ_BASE;
1764b5a9ee7cSAriel Elior }
1765b5a9ee7cSAriel Elior 
1766b5a9ee7cSAriel Elior u16 qed_get_cm_pq_idx_mcos(struct qed_hwfn *p_hwfn, u8 tc)
1767b5a9ee7cSAriel Elior {
1768b5a9ee7cSAriel Elior 	u8 max_tc = qed_init_qm_get_num_tcs(p_hwfn);
1769b5a9ee7cSAriel Elior 
1770eb62cca9SDenis Bolotin 	if (max_tc == 0) {
1771eb62cca9SDenis Bolotin 		DP_ERR(p_hwfn, "pq with flag 0x%lx do not exist\n",
1772eb62cca9SDenis Bolotin 		       PQ_FLAGS_MCOS);
1773eb62cca9SDenis Bolotin 		return p_hwfn->qm_info.start_pq;
1774eb62cca9SDenis Bolotin 	}
1775eb62cca9SDenis Bolotin 
1776b5a9ee7cSAriel Elior 	if (tc > max_tc)
1777b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn, "tc %d must be smaller than %d\n", tc, max_tc);
1778b5a9ee7cSAriel Elior 
1779eb62cca9SDenis Bolotin 	return qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_MCOS) + (tc % max_tc);
1780b5a9ee7cSAriel Elior }
1781b5a9ee7cSAriel Elior 
1782b5a9ee7cSAriel Elior u16 qed_get_cm_pq_idx_vf(struct qed_hwfn *p_hwfn, u16 vf)
1783b5a9ee7cSAriel Elior {
1784b5a9ee7cSAriel Elior 	u16 max_vf = qed_init_qm_get_num_vfs(p_hwfn);
1785b5a9ee7cSAriel Elior 
1786eb62cca9SDenis Bolotin 	if (max_vf == 0) {
1787eb62cca9SDenis Bolotin 		DP_ERR(p_hwfn, "pq with flag 0x%lx do not exist\n",
1788eb62cca9SDenis Bolotin 		       PQ_FLAGS_VFS);
1789eb62cca9SDenis Bolotin 		return p_hwfn->qm_info.start_pq;
1790eb62cca9SDenis Bolotin 	}
1791eb62cca9SDenis Bolotin 
1792b5a9ee7cSAriel Elior 	if (vf > max_vf)
1793b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn, "vf %d must be smaller than %d\n", vf, max_vf);
1794b5a9ee7cSAriel Elior 
1795eb62cca9SDenis Bolotin 	return qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_VFS) + (vf % max_vf);
1796b5a9ee7cSAriel Elior }
1797b5a9ee7cSAriel Elior 
179861be82b0SDenis Bolotin u16 qed_get_cm_pq_idx_ofld_mtc(struct qed_hwfn *p_hwfn, u8 tc)
179961be82b0SDenis Bolotin {
180061be82b0SDenis Bolotin 	u16 first_ofld_pq, pq_offset;
180161be82b0SDenis Bolotin 
180261be82b0SDenis Bolotin 	first_ofld_pq = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD);
180361be82b0SDenis Bolotin 	pq_offset = (tc < qed_init_qm_get_num_mtc_tcs(p_hwfn)) ?
180461be82b0SDenis Bolotin 		    tc : PQ_INIT_DEFAULT_TC;
180561be82b0SDenis Bolotin 
180661be82b0SDenis Bolotin 	return first_ofld_pq + pq_offset;
180761be82b0SDenis Bolotin }
180861be82b0SDenis Bolotin 
180961be82b0SDenis Bolotin u16 qed_get_cm_pq_idx_llt_mtc(struct qed_hwfn *p_hwfn, u8 tc)
181061be82b0SDenis Bolotin {
181161be82b0SDenis Bolotin 	u16 first_llt_pq, pq_offset;
181261be82b0SDenis Bolotin 
181361be82b0SDenis Bolotin 	first_llt_pq = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LLT);
181461be82b0SDenis Bolotin 	pq_offset = (tc < qed_init_qm_get_num_mtc_tcs(p_hwfn)) ?
181561be82b0SDenis Bolotin 		    tc : PQ_INIT_DEFAULT_TC;
181661be82b0SDenis Bolotin 
181761be82b0SDenis Bolotin 	return first_llt_pq + pq_offset;
181861be82b0SDenis Bolotin }
181961be82b0SDenis Bolotin 
1820b5a9ee7cSAriel Elior /* Functions for creating specific types of pqs */
1821b5a9ee7cSAriel Elior static void qed_init_qm_lb_pq(struct qed_hwfn *p_hwfn)
1822b5a9ee7cSAriel Elior {
1823b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1824b5a9ee7cSAriel Elior 
1825b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_LB))
1826b5a9ee7cSAriel Elior 		return;
1827b5a9ee7cSAriel Elior 
1828b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_LB, qm_info->num_pqs);
1829b5a9ee7cSAriel Elior 	qed_init_qm_pq(p_hwfn, qm_info, PURE_LB_TC, PQ_INIT_SHARE_VPORT);
1830b5a9ee7cSAriel Elior }
1831b5a9ee7cSAriel Elior 
1832b5a9ee7cSAriel Elior static void qed_init_qm_ooo_pq(struct qed_hwfn *p_hwfn)
1833b5a9ee7cSAriel Elior {
1834b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1835b5a9ee7cSAriel Elior 
1836b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_OOO))
1837b5a9ee7cSAriel Elior 		return;
1838b5a9ee7cSAriel Elior 
1839b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_OOO, qm_info->num_pqs);
1840b5a9ee7cSAriel Elior 	qed_init_qm_pq(p_hwfn, qm_info, qm_info->ooo_tc, PQ_INIT_SHARE_VPORT);
1841b5a9ee7cSAriel Elior }
1842b5a9ee7cSAriel Elior 
1843b5a9ee7cSAriel Elior static void qed_init_qm_pure_ack_pq(struct qed_hwfn *p_hwfn)
1844b5a9ee7cSAriel Elior {
1845b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1846b5a9ee7cSAriel Elior 
1847b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_ACK))
1848b5a9ee7cSAriel Elior 		return;
1849b5a9ee7cSAriel Elior 
1850b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_ACK, qm_info->num_pqs);
1851c4259ddaSDenis Bolotin 	qed_init_qm_pq(p_hwfn, qm_info, qed_get_offload_tc(p_hwfn),
1852c4259ddaSDenis Bolotin 		       PQ_INIT_SHARE_VPORT);
1853b5a9ee7cSAriel Elior }
1854b5a9ee7cSAriel Elior 
185561be82b0SDenis Bolotin static void qed_init_qm_mtc_pqs(struct qed_hwfn *p_hwfn)
185661be82b0SDenis Bolotin {
185761be82b0SDenis Bolotin 	u8 num_tcs = qed_init_qm_get_num_mtc_tcs(p_hwfn);
185861be82b0SDenis Bolotin 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
185961be82b0SDenis Bolotin 	u8 tc;
186061be82b0SDenis Bolotin 
186161be82b0SDenis Bolotin 	/* override pq's TC if offload TC is set */
186261be82b0SDenis Bolotin 	for (tc = 0; tc < num_tcs; tc++)
186361be82b0SDenis Bolotin 		qed_init_qm_pq(p_hwfn, qm_info,
186461be82b0SDenis Bolotin 			       qed_is_offload_tc_set(p_hwfn) ?
186561be82b0SDenis Bolotin 			       p_hwfn->hw_info.offload_tc : tc,
186661be82b0SDenis Bolotin 			       PQ_INIT_SHARE_VPORT);
186761be82b0SDenis Bolotin }
186861be82b0SDenis Bolotin 
1869b5a9ee7cSAriel Elior static void qed_init_qm_offload_pq(struct qed_hwfn *p_hwfn)
1870b5a9ee7cSAriel Elior {
1871b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1872b5a9ee7cSAriel Elior 
1873b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_OFLD))
1874b5a9ee7cSAriel Elior 		return;
1875b5a9ee7cSAriel Elior 
1876b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_OFLD, qm_info->num_pqs);
187761be82b0SDenis Bolotin 	qed_init_qm_mtc_pqs(p_hwfn);
1878b5a9ee7cSAriel Elior }
1879b5a9ee7cSAriel Elior 
1880b5a9ee7cSAriel Elior static void qed_init_qm_low_latency_pq(struct qed_hwfn *p_hwfn)
1881b5a9ee7cSAriel Elior {
1882b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1883b5a9ee7cSAriel Elior 
1884b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_LLT))
1885b5a9ee7cSAriel Elior 		return;
1886b5a9ee7cSAriel Elior 
1887b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_LLT, qm_info->num_pqs);
188861be82b0SDenis Bolotin 	qed_init_qm_mtc_pqs(p_hwfn);
1889b5a9ee7cSAriel Elior }
1890b5a9ee7cSAriel Elior 
1891b5a9ee7cSAriel Elior static void qed_init_qm_mcos_pqs(struct qed_hwfn *p_hwfn)
1892b5a9ee7cSAriel Elior {
1893b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1894b5a9ee7cSAriel Elior 	u8 tc_idx;
1895b5a9ee7cSAriel Elior 
1896b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_MCOS))
1897b5a9ee7cSAriel Elior 		return;
1898b5a9ee7cSAriel Elior 
1899b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_MCOS, qm_info->num_pqs);
1900b5a9ee7cSAriel Elior 	for (tc_idx = 0; tc_idx < qed_init_qm_get_num_tcs(p_hwfn); tc_idx++)
1901b5a9ee7cSAriel Elior 		qed_init_qm_pq(p_hwfn, qm_info, tc_idx, PQ_INIT_SHARE_VPORT);
1902b5a9ee7cSAriel Elior }
1903b5a9ee7cSAriel Elior 
1904b5a9ee7cSAriel Elior static void qed_init_qm_vf_pqs(struct qed_hwfn *p_hwfn)
1905b5a9ee7cSAriel Elior {
1906b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1907b5a9ee7cSAriel Elior 	u16 vf_idx, num_vfs = qed_init_qm_get_num_vfs(p_hwfn);
1908b5a9ee7cSAriel Elior 
1909b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_VFS))
1910b5a9ee7cSAriel Elior 		return;
1911b5a9ee7cSAriel Elior 
1912b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_VFS, qm_info->num_pqs);
19131408cc1fSYuval Mintz 	qm_info->num_vf_pqs = num_vfs;
1914b5a9ee7cSAriel Elior 	for (vf_idx = 0; vf_idx < num_vfs; vf_idx++)
1915b5a9ee7cSAriel Elior 		qed_init_qm_pq(p_hwfn,
1916b5a9ee7cSAriel Elior 			       qm_info, PQ_INIT_DEFAULT_TC, PQ_INIT_VF_RL);
1917b5a9ee7cSAriel Elior }
1918fe56b9e6SYuval Mintz 
1919b5a9ee7cSAriel Elior static void qed_init_qm_rl_pqs(struct qed_hwfn *p_hwfn)
1920b5a9ee7cSAriel Elior {
1921b5a9ee7cSAriel Elior 	u16 pf_rls_idx, num_pf_rls = qed_init_qm_get_num_pf_rls(p_hwfn);
1922b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1923a64b02d5SManish Chopra 
1924b5a9ee7cSAriel Elior 	if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_RLS))
1925b5a9ee7cSAriel Elior 		return;
1926b5a9ee7cSAriel Elior 
1927b5a9ee7cSAriel Elior 	qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_RLS, qm_info->num_pqs);
1928b5a9ee7cSAriel Elior 	for (pf_rls_idx = 0; pf_rls_idx < num_pf_rls; pf_rls_idx++)
1929c4259ddaSDenis Bolotin 		qed_init_qm_pq(p_hwfn, qm_info, qed_get_offload_tc(p_hwfn),
1930c4259ddaSDenis Bolotin 			       PQ_INIT_PF_RL);
1931b5a9ee7cSAriel Elior }
1932b5a9ee7cSAriel Elior 
1933b5a9ee7cSAriel Elior static void qed_init_qm_pq_params(struct qed_hwfn *p_hwfn)
1934b5a9ee7cSAriel Elior {
1935b5a9ee7cSAriel Elior 	/* rate limited pqs, must come first (FW assumption) */
1936b5a9ee7cSAriel Elior 	qed_init_qm_rl_pqs(p_hwfn);
1937b5a9ee7cSAriel Elior 
1938b5a9ee7cSAriel Elior 	/* pqs for multi cos */
1939b5a9ee7cSAriel Elior 	qed_init_qm_mcos_pqs(p_hwfn);
1940b5a9ee7cSAriel Elior 
1941b5a9ee7cSAriel Elior 	/* pure loopback pq */
1942b5a9ee7cSAriel Elior 	qed_init_qm_lb_pq(p_hwfn);
1943b5a9ee7cSAriel Elior 
1944b5a9ee7cSAriel Elior 	/* out of order pq */
1945b5a9ee7cSAriel Elior 	qed_init_qm_ooo_pq(p_hwfn);
1946b5a9ee7cSAriel Elior 
1947b5a9ee7cSAriel Elior 	/* pure ack pq */
1948b5a9ee7cSAriel Elior 	qed_init_qm_pure_ack_pq(p_hwfn);
1949b5a9ee7cSAriel Elior 
1950b5a9ee7cSAriel Elior 	/* pq for offloaded protocol */
1951b5a9ee7cSAriel Elior 	qed_init_qm_offload_pq(p_hwfn);
1952b5a9ee7cSAriel Elior 
1953b5a9ee7cSAriel Elior 	/* low latency pq */
1954b5a9ee7cSAriel Elior 	qed_init_qm_low_latency_pq(p_hwfn);
1955b5a9ee7cSAriel Elior 
1956b5a9ee7cSAriel Elior 	/* done sharing vports */
1957b5a9ee7cSAriel Elior 	qed_init_qm_advance_vport(p_hwfn);
1958b5a9ee7cSAriel Elior 
1959b5a9ee7cSAriel Elior 	/* pqs for vfs */
1960b5a9ee7cSAriel Elior 	qed_init_qm_vf_pqs(p_hwfn);
1961b5a9ee7cSAriel Elior }
1962b5a9ee7cSAriel Elior 
1963b5a9ee7cSAriel Elior /* compare values of getters against resources amounts */
1964b5a9ee7cSAriel Elior static int qed_init_qm_sanity(struct qed_hwfn *p_hwfn)
1965b5a9ee7cSAriel Elior {
1966b5a9ee7cSAriel Elior 	if (qed_init_qm_get_num_vports(p_hwfn) > RESC_NUM(p_hwfn, QED_VPORT)) {
1967b5a9ee7cSAriel Elior 		DP_ERR(p_hwfn, "requested amount of vports exceeds resource\n");
1968b5a9ee7cSAriel Elior 		return -EINVAL;
1969b5a9ee7cSAriel Elior 	}
1970b5a9ee7cSAriel Elior 
197161be82b0SDenis Bolotin 	if (qed_init_qm_get_num_pqs(p_hwfn) <= RESC_NUM(p_hwfn, QED_PQ))
197261be82b0SDenis Bolotin 		return 0;
197361be82b0SDenis Bolotin 
197461be82b0SDenis Bolotin 	if (QED_IS_ROCE_PERSONALITY(p_hwfn)) {
197582ebc889SJason Yan 		p_hwfn->hw_info.multi_tc_roce_en = false;
197661be82b0SDenis Bolotin 		DP_NOTICE(p_hwfn,
197761be82b0SDenis Bolotin 			  "multi-tc roce was disabled to reduce requested amount of pqs\n");
197861be82b0SDenis Bolotin 		if (qed_init_qm_get_num_pqs(p_hwfn) <= RESC_NUM(p_hwfn, QED_PQ))
197961be82b0SDenis Bolotin 			return 0;
1980b5a9ee7cSAriel Elior 	}
1981fe56b9e6SYuval Mintz 
198261be82b0SDenis Bolotin 	DP_ERR(p_hwfn, "requested amount of pqs exceeds resource\n");
198361be82b0SDenis Bolotin 	return -EINVAL;
1984b5a9ee7cSAriel Elior }
1985fe56b9e6SYuval Mintz 
1986b5a9ee7cSAriel Elior static void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn)
1987b5a9ee7cSAriel Elior {
1988b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
1989b5a9ee7cSAriel Elior 	struct init_qm_vport_params *vport;
1990b5a9ee7cSAriel Elior 	struct init_qm_port_params *port;
1991b5a9ee7cSAriel Elior 	struct init_qm_pq_params *pq;
1992b5a9ee7cSAriel Elior 	int i, tc;
1993b5a9ee7cSAriel Elior 
1994b5a9ee7cSAriel Elior 	/* top level params */
1995b5a9ee7cSAriel Elior 	DP_VERBOSE(p_hwfn,
1996b5a9ee7cSAriel Elior 		   NETIF_MSG_HW,
199761be82b0SDenis 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",
1998b5a9ee7cSAriel Elior 		   qm_info->start_pq,
1999b5a9ee7cSAriel Elior 		   qm_info->start_vport,
2000b5a9ee7cSAriel Elior 		   qm_info->pure_lb_pq,
200161be82b0SDenis Bolotin 		   qm_info->first_ofld_pq,
200261be82b0SDenis Bolotin 		   qm_info->first_llt_pq,
200361be82b0SDenis Bolotin 		   qm_info->pure_ack_pq);
2004b5a9ee7cSAriel Elior 	DP_VERBOSE(p_hwfn,
2005b5a9ee7cSAriel Elior 		   NETIF_MSG_HW,
2006b5a9ee7cSAriel 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",
2007b5a9ee7cSAriel Elior 		   qm_info->ooo_pq,
2008b5a9ee7cSAriel Elior 		   qm_info->first_vf_pq,
2009b5a9ee7cSAriel Elior 		   qm_info->num_pqs,
2010b5a9ee7cSAriel Elior 		   qm_info->num_vf_pqs,
2011b5a9ee7cSAriel Elior 		   qm_info->num_vports, qm_info->max_phys_tcs_per_port);
2012b5a9ee7cSAriel Elior 	DP_VERBOSE(p_hwfn,
2013b5a9ee7cSAriel Elior 		   NETIF_MSG_HW,
2014b5a9ee7cSAriel 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",
2015b5a9ee7cSAriel Elior 		   qm_info->pf_rl_en,
2016b5a9ee7cSAriel Elior 		   qm_info->pf_wfq_en,
2017b5a9ee7cSAriel Elior 		   qm_info->vport_rl_en,
2018b5a9ee7cSAriel Elior 		   qm_info->vport_wfq_en,
2019b5a9ee7cSAriel Elior 		   qm_info->pf_wfq,
2020b5a9ee7cSAriel Elior 		   qm_info->pf_rl,
2021b5a9ee7cSAriel Elior 		   qm_info->num_pf_rls, qed_get_pq_flags(p_hwfn));
2022b5a9ee7cSAriel Elior 
2023b5a9ee7cSAriel Elior 	/* port table */
202478cea9ffSTomer Tayar 	for (i = 0; i < p_hwfn->cdev->num_ports_in_engine; i++) {
2025b5a9ee7cSAriel Elior 		port = &(qm_info->qm_port_params[i]);
2026b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn,
2027b5a9ee7cSAriel Elior 			   NETIF_MSG_HW,
2028b5a9ee7cSAriel Elior 			   "port idx %d, active %d, active_phys_tcs %d, num_pbf_cmd_lines %d, num_btb_blocks %d, reserved %d\n",
2029b5a9ee7cSAriel Elior 			   i,
2030b5a9ee7cSAriel Elior 			   port->active,
2031b5a9ee7cSAriel Elior 			   port->active_phys_tcs,
2032b5a9ee7cSAriel Elior 			   port->num_pbf_cmd_lines,
2033b5a9ee7cSAriel Elior 			   port->num_btb_blocks, port->reserved);
2034b5a9ee7cSAriel Elior 	}
2035b5a9ee7cSAriel Elior 
2036b5a9ee7cSAriel Elior 	/* vport table */
2037b5a9ee7cSAriel Elior 	for (i = 0; i < qm_info->num_vports; i++) {
2038b5a9ee7cSAriel Elior 		vport = &(qm_info->qm_vport_params[i]);
2039b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn,
2040b5a9ee7cSAriel Elior 			   NETIF_MSG_HW,
204192fae6fbSMichal Kalderon 			   "vport idx %d, wfq %d, first_tx_pq_id [ ",
204292fae6fbSMichal Kalderon 			   qm_info->start_vport + i, vport->wfq);
2043b5a9ee7cSAriel Elior 		for (tc = 0; tc < NUM_OF_TCS; tc++)
2044b5a9ee7cSAriel Elior 			DP_VERBOSE(p_hwfn,
2045b5a9ee7cSAriel Elior 				   NETIF_MSG_HW,
2046b5a9ee7cSAriel Elior 				   "%d ", vport->first_tx_pq_id[tc]);
2047b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "]\n");
2048b5a9ee7cSAriel Elior 	}
2049b5a9ee7cSAriel Elior 
2050b5a9ee7cSAriel Elior 	/* pq table */
2051b5a9ee7cSAriel Elior 	for (i = 0; i < qm_info->num_pqs; i++) {
2052b5a9ee7cSAriel Elior 		pq = &(qm_info->qm_pq_params[i]);
2053b5a9ee7cSAriel Elior 		DP_VERBOSE(p_hwfn,
2054b5a9ee7cSAriel Elior 			   NETIF_MSG_HW,
205592fae6fbSMichal Kalderon 			   "pq idx %d, port %d, vport_id %d, tc %d, wrr_grp %d, rl_valid %d rl_id %d\n",
2056b5a9ee7cSAriel Elior 			   qm_info->start_pq + i,
205750bc60cbSMichal Kalderon 			   pq->port_id,
2058b5a9ee7cSAriel Elior 			   pq->vport_id,
205992fae6fbSMichal Kalderon 			   pq->tc_id, pq->wrr_group, pq->rl_valid, pq->rl_id);
2060b5a9ee7cSAriel Elior 	}
2061b5a9ee7cSAriel Elior }
2062b5a9ee7cSAriel Elior 
2063b5a9ee7cSAriel Elior static void qed_init_qm_info(struct qed_hwfn *p_hwfn)
2064b5a9ee7cSAriel Elior {
2065b5a9ee7cSAriel Elior 	/* reset params required for init run */
2066b5a9ee7cSAriel Elior 	qed_init_qm_reset_params(p_hwfn);
2067b5a9ee7cSAriel Elior 
2068b5a9ee7cSAriel Elior 	/* init QM top level params */
2069b5a9ee7cSAriel Elior 	qed_init_qm_params(p_hwfn);
2070b5a9ee7cSAriel Elior 
2071b5a9ee7cSAriel Elior 	/* init QM port params */
2072b5a9ee7cSAriel Elior 	qed_init_qm_port_params(p_hwfn);
2073b5a9ee7cSAriel Elior 
2074b5a9ee7cSAriel Elior 	/* init QM vport params */
2075b5a9ee7cSAriel Elior 	qed_init_qm_vport_params(p_hwfn);
2076b5a9ee7cSAriel Elior 
2077b5a9ee7cSAriel Elior 	/* init QM physical queue params */
2078b5a9ee7cSAriel Elior 	qed_init_qm_pq_params(p_hwfn);
2079b5a9ee7cSAriel Elior 
2080b5a9ee7cSAriel Elior 	/* display all that init */
2081b5a9ee7cSAriel Elior 	qed_dp_init_qm_params(p_hwfn);
2082fe56b9e6SYuval Mintz }
2083fe56b9e6SYuval Mintz 
208439651abdSSudarsana Reddy Kalluru /* This function reconfigures the QM pf on the fly.
208539651abdSSudarsana Reddy Kalluru  * For this purpose we:
208639651abdSSudarsana Reddy Kalluru  * 1. reconfigure the QM database
2087a2e7699eSTomer Tayar  * 2. set new values to runtime array
208839651abdSSudarsana Reddy Kalluru  * 3. send an sdm_qm_cmd through the rbc interface to stop the QM
208939651abdSSudarsana Reddy Kalluru  * 4. activate init tool in QM_PF stage
209039651abdSSudarsana Reddy Kalluru  * 5. send an sdm_qm_cmd through rbc interface to release the QM
209139651abdSSudarsana Reddy Kalluru  */
209239651abdSSudarsana Reddy Kalluru int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
209339651abdSSudarsana Reddy Kalluru {
209439651abdSSudarsana Reddy Kalluru 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
209539651abdSSudarsana Reddy Kalluru 	bool b_rc;
209639651abdSSudarsana Reddy Kalluru 	int rc;
209739651abdSSudarsana Reddy Kalluru 
209839651abdSSudarsana Reddy Kalluru 	/* initialize qed's qm data structure */
2099b5a9ee7cSAriel Elior 	qed_init_qm_info(p_hwfn);
210039651abdSSudarsana Reddy Kalluru 
210139651abdSSudarsana Reddy Kalluru 	/* stop PF's qm queues */
210239651abdSSudarsana Reddy Kalluru 	spin_lock_bh(&qm_lock);
210339651abdSSudarsana Reddy Kalluru 	b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, false, true,
210439651abdSSudarsana Reddy Kalluru 				    qm_info->start_pq, qm_info->num_pqs);
210539651abdSSudarsana Reddy Kalluru 	spin_unlock_bh(&qm_lock);
210639651abdSSudarsana Reddy Kalluru 	if (!b_rc)
210739651abdSSudarsana Reddy Kalluru 		return -EINVAL;
210839651abdSSudarsana Reddy Kalluru 
210939651abdSSudarsana Reddy Kalluru 	/* prepare QM portion of runtime array */
2110da090917STomer Tayar 	qed_qm_init_pf(p_hwfn, p_ptt, false);
211139651abdSSudarsana Reddy Kalluru 
211239651abdSSudarsana Reddy Kalluru 	/* activate init tool on runtime array */
211339651abdSSudarsana Reddy Kalluru 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, p_hwfn->rel_pf_id,
211439651abdSSudarsana Reddy Kalluru 			  p_hwfn->hw_info.hw_mode);
211539651abdSSudarsana Reddy Kalluru 	if (rc)
211639651abdSSudarsana Reddy Kalluru 		return rc;
211739651abdSSudarsana Reddy Kalluru 
211839651abdSSudarsana Reddy Kalluru 	/* start PF's qm queues */
211939651abdSSudarsana Reddy Kalluru 	spin_lock_bh(&qm_lock);
212039651abdSSudarsana Reddy Kalluru 	b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, true, true,
212139651abdSSudarsana Reddy Kalluru 				    qm_info->start_pq, qm_info->num_pqs);
212239651abdSSudarsana Reddy Kalluru 	spin_unlock_bh(&qm_lock);
212339651abdSSudarsana Reddy Kalluru 	if (!b_rc)
212439651abdSSudarsana Reddy Kalluru 		return -EINVAL;
212539651abdSSudarsana Reddy Kalluru 
212639651abdSSudarsana Reddy Kalluru 	return 0;
212739651abdSSudarsana Reddy Kalluru }
212839651abdSSudarsana Reddy Kalluru 
2129b5a9ee7cSAriel Elior static int qed_alloc_qm_data(struct qed_hwfn *p_hwfn)
2130b5a9ee7cSAriel Elior {
2131b5a9ee7cSAriel Elior 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
2132b5a9ee7cSAriel Elior 	int rc;
2133b5a9ee7cSAriel Elior 
2134b5a9ee7cSAriel Elior 	rc = qed_init_qm_sanity(p_hwfn);
2135b5a9ee7cSAriel Elior 	if (rc)
2136b5a9ee7cSAriel Elior 		goto alloc_err;
2137b5a9ee7cSAriel Elior 
21386396bb22SKees Cook 	qm_info->qm_pq_params = kcalloc(qed_init_qm_get_num_pqs(p_hwfn),
21396396bb22SKees Cook 					sizeof(*qm_info->qm_pq_params),
2140b5a9ee7cSAriel Elior 					GFP_KERNEL);
2141b5a9ee7cSAriel Elior 	if (!qm_info->qm_pq_params)
2142b5a9ee7cSAriel Elior 		goto alloc_err;
2143b5a9ee7cSAriel Elior 
21446396bb22SKees Cook 	qm_info->qm_vport_params = kcalloc(qed_init_qm_get_num_vports(p_hwfn),
21456396bb22SKees Cook 					   sizeof(*qm_info->qm_vport_params),
2146b5a9ee7cSAriel Elior 					   GFP_KERNEL);
2147b5a9ee7cSAriel Elior 	if (!qm_info->qm_vport_params)
2148b5a9ee7cSAriel Elior 		goto alloc_err;
2149b5a9ee7cSAriel Elior 
21506396bb22SKees Cook 	qm_info->qm_port_params = kcalloc(p_hwfn->cdev->num_ports_in_engine,
21516396bb22SKees Cook 					  sizeof(*qm_info->qm_port_params),
2152b5a9ee7cSAriel Elior 					  GFP_KERNEL);
2153b5a9ee7cSAriel Elior 	if (!qm_info->qm_port_params)
2154b5a9ee7cSAriel Elior 		goto alloc_err;
2155b5a9ee7cSAriel Elior 
21566396bb22SKees Cook 	qm_info->wfq_data = kcalloc(qed_init_qm_get_num_vports(p_hwfn),
21576396bb22SKees Cook 				    sizeof(*qm_info->wfq_data),
2158b5a9ee7cSAriel Elior 				    GFP_KERNEL);
2159b5a9ee7cSAriel Elior 	if (!qm_info->wfq_data)
2160b5a9ee7cSAriel Elior 		goto alloc_err;
2161b5a9ee7cSAriel Elior 
2162b5a9ee7cSAriel Elior 	return 0;
2163b5a9ee7cSAriel Elior 
2164b5a9ee7cSAriel Elior alloc_err:
2165b5a9ee7cSAriel Elior 	DP_NOTICE(p_hwfn, "Failed to allocate memory for QM params\n");
2166b5a9ee7cSAriel Elior 	qed_qm_info_free(p_hwfn);
2167b5a9ee7cSAriel Elior 	return -ENOMEM;
2168b5a9ee7cSAriel Elior }
2169b5a9ee7cSAriel Elior 
2170fe56b9e6SYuval Mintz int qed_resc_alloc(struct qed_dev *cdev)
2171fe56b9e6SYuval Mintz {
2172f9dc4d1fSRam Amrani 	u32 rdma_tasks, excess_tasks;
2173f9dc4d1fSRam Amrani 	u32 line_count;
2174fe56b9e6SYuval Mintz 	int i, rc = 0;
2175fe56b9e6SYuval Mintz 
21760db711bbSMintz, Yuval 	if (IS_VF(cdev)) {
21770db711bbSMintz, Yuval 		for_each_hwfn(cdev, i) {
21780db711bbSMintz, Yuval 			rc = qed_l2_alloc(&cdev->hwfns[i]);
21790db711bbSMintz, Yuval 			if (rc)
21801408cc1fSYuval Mintz 				return rc;
21810db711bbSMintz, Yuval 		}
21820db711bbSMintz, Yuval 		return rc;
21830db711bbSMintz, Yuval 	}
21841408cc1fSYuval Mintz 
2185fe56b9e6SYuval Mintz 	cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL);
2186fe56b9e6SYuval Mintz 	if (!cdev->fw_data)
2187fe56b9e6SYuval Mintz 		return -ENOMEM;
2188fe56b9e6SYuval Mintz 
2189fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2190fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
2191dbb799c3SYuval Mintz 		u32 n_eqes, num_cons;
2192fe56b9e6SYuval Mintz 
219336907cd5SAriel Elior 		/* Initialize the doorbell recovery mechanism */
219436907cd5SAriel Elior 		rc = qed_db_recovery_setup(p_hwfn);
219536907cd5SAriel Elior 		if (rc)
219636907cd5SAriel Elior 			goto alloc_err;
219736907cd5SAriel Elior 
2198fe56b9e6SYuval Mintz 		/* First allocate the context manager structure */
2199fe56b9e6SYuval Mintz 		rc = qed_cxt_mngr_alloc(p_hwfn);
2200fe56b9e6SYuval Mintz 		if (rc)
2201fe56b9e6SYuval Mintz 			goto alloc_err;
2202fe56b9e6SYuval Mintz 
2203fe56b9e6SYuval Mintz 		/* Set the HW cid/tid numbers (in the contest manager)
2204fe56b9e6SYuval Mintz 		 * Must be done prior to any further computations.
2205fe56b9e6SYuval Mintz 		 */
2206f9dc4d1fSRam Amrani 		rc = qed_cxt_set_pf_params(p_hwfn, RDMA_MAX_TIDS);
2207fe56b9e6SYuval Mintz 		if (rc)
2208fe56b9e6SYuval Mintz 			goto alloc_err;
2209fe56b9e6SYuval Mintz 
2210b5a9ee7cSAriel Elior 		rc = qed_alloc_qm_data(p_hwfn);
2211fe56b9e6SYuval Mintz 		if (rc)
2212fe56b9e6SYuval Mintz 			goto alloc_err;
2213fe56b9e6SYuval Mintz 
2214b5a9ee7cSAriel Elior 		/* init qm info */
2215b5a9ee7cSAriel Elior 		qed_init_qm_info(p_hwfn);
2216b5a9ee7cSAriel Elior 
2217fe56b9e6SYuval Mintz 		/* Compute the ILT client partition */
2218f9dc4d1fSRam Amrani 		rc = qed_cxt_cfg_ilt_compute(p_hwfn, &line_count);
2219f9dc4d1fSRam Amrani 		if (rc) {
2220f9dc4d1fSRam Amrani 			DP_NOTICE(p_hwfn,
2221f9dc4d1fSRam Amrani 				  "too many ILT lines; re-computing with less lines\n");
2222f9dc4d1fSRam Amrani 			/* In case there are not enough ILT lines we reduce the
2223f9dc4d1fSRam Amrani 			 * number of RDMA tasks and re-compute.
2224f9dc4d1fSRam Amrani 			 */
2225f9dc4d1fSRam Amrani 			excess_tasks =
2226f9dc4d1fSRam Amrani 			    qed_cxt_cfg_ilt_compute_excess(p_hwfn, line_count);
2227f9dc4d1fSRam Amrani 			if (!excess_tasks)
2228f9dc4d1fSRam Amrani 				goto alloc_err;
2229f9dc4d1fSRam Amrani 
2230f9dc4d1fSRam Amrani 			rdma_tasks = RDMA_MAX_TIDS - excess_tasks;
2231f9dc4d1fSRam Amrani 			rc = qed_cxt_set_pf_params(p_hwfn, rdma_tasks);
2232fe56b9e6SYuval Mintz 			if (rc)
2233fe56b9e6SYuval Mintz 				goto alloc_err;
2234fe56b9e6SYuval Mintz 
2235f9dc4d1fSRam Amrani 			rc = qed_cxt_cfg_ilt_compute(p_hwfn, &line_count);
2236f9dc4d1fSRam Amrani 			if (rc) {
2237f9dc4d1fSRam Amrani 				DP_ERR(p_hwfn,
2238f9dc4d1fSRam Amrani 				       "failed ILT compute. Requested too many lines: %u\n",
2239f9dc4d1fSRam Amrani 				       line_count);
2240f9dc4d1fSRam Amrani 
2241f9dc4d1fSRam Amrani 				goto alloc_err;
2242f9dc4d1fSRam Amrani 			}
2243f9dc4d1fSRam Amrani 		}
2244f9dc4d1fSRam Amrani 
2245fe56b9e6SYuval Mintz 		/* CID map / ILT shadow table / T2
2246fe56b9e6SYuval Mintz 		 * The talbes sizes are determined by the computations above
2247fe56b9e6SYuval Mintz 		 */
2248fe56b9e6SYuval Mintz 		rc = qed_cxt_tables_alloc(p_hwfn);
2249fe56b9e6SYuval Mintz 		if (rc)
2250fe56b9e6SYuval Mintz 			goto alloc_err;
2251fe56b9e6SYuval Mintz 
2252fe56b9e6SYuval Mintz 		/* SPQ, must follow ILT because initializes SPQ context */
2253fe56b9e6SYuval Mintz 		rc = qed_spq_alloc(p_hwfn);
2254fe56b9e6SYuval Mintz 		if (rc)
2255fe56b9e6SYuval Mintz 			goto alloc_err;
2256fe56b9e6SYuval Mintz 
2257fe56b9e6SYuval Mintz 		/* SP status block allocation */
2258fe56b9e6SYuval Mintz 		p_hwfn->p_dpc_ptt = qed_get_reserved_ptt(p_hwfn,
2259fe56b9e6SYuval Mintz 							 RESERVED_PTT_DPC);
2260fe56b9e6SYuval Mintz 
2261fe56b9e6SYuval Mintz 		rc = qed_int_alloc(p_hwfn, p_hwfn->p_main_ptt);
2262fe56b9e6SYuval Mintz 		if (rc)
2263fe56b9e6SYuval Mintz 			goto alloc_err;
2264fe56b9e6SYuval Mintz 
226532a47e72SYuval Mintz 		rc = qed_iov_alloc(p_hwfn);
226632a47e72SYuval Mintz 		if (rc)
226732a47e72SYuval Mintz 			goto alloc_err;
226832a47e72SYuval Mintz 
2269fe56b9e6SYuval Mintz 		/* EQ */
2270dbb799c3SYuval Mintz 		n_eqes = qed_chain_get_capacity(&p_hwfn->p_spq->chain);
2271c851a9dcSKalderon, Michal 		if (QED_IS_RDMA_PERSONALITY(p_hwfn)) {
2272b8204ad8SYuval Basson 			u32 n_srq = qed_cxt_get_total_srq_count(p_hwfn);
227367b40dccSKalderon, Michal 			enum protocol_type rdma_proto;
227467b40dccSKalderon, Michal 
227567b40dccSKalderon, Michal 			if (QED_IS_ROCE_PERSONALITY(p_hwfn))
227667b40dccSKalderon, Michal 				rdma_proto = PROTOCOLID_ROCE;
227767b40dccSKalderon, Michal 			else
227867b40dccSKalderon, Michal 				rdma_proto = PROTOCOLID_IWARP;
227967b40dccSKalderon, Michal 
2280dbb799c3SYuval Mintz 			num_cons = qed_cxt_get_proto_cid_count(p_hwfn,
228167b40dccSKalderon, Michal 							       rdma_proto,
22828c93beafSYuval Mintz 							       NULL) * 2;
2283b8204ad8SYuval Basson 			/* EQ should be able to get events from all SRQ's
2284b8204ad8SYuval Basson 			 * at the same time
2285b8204ad8SYuval Basson 			 */
2286b8204ad8SYuval Basson 			n_eqes += num_cons + 2 * MAX_NUM_VFS_BB + n_srq;
2287dbb799c3SYuval Mintz 		} else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
2288dbb799c3SYuval Mintz 			num_cons =
2289dbb799c3SYuval Mintz 			    qed_cxt_get_proto_cid_count(p_hwfn,
22908c93beafSYuval Mintz 							PROTOCOLID_ISCSI,
22918c93beafSYuval Mintz 							NULL);
2292dbb799c3SYuval Mintz 			n_eqes += 2 * num_cons;
2293dbb799c3SYuval Mintz 		}
2294dbb799c3SYuval Mintz 
2295dbb799c3SYuval Mintz 		if (n_eqes > 0xFFFF) {
2296dbb799c3SYuval Mintz 			DP_ERR(p_hwfn,
2297dbb799c3SYuval Mintz 			       "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n",
2298dbb799c3SYuval Mintz 			       n_eqes, 0xFFFF);
22993587cb87STomer Tayar 			goto alloc_no_mem;
23009b15acbfSDan Carpenter 		}
2301dbb799c3SYuval Mintz 
23023587cb87STomer Tayar 		rc = qed_eq_alloc(p_hwfn, (u16) n_eqes);
23033587cb87STomer Tayar 		if (rc)
23043587cb87STomer Tayar 			goto alloc_err;
2305fe56b9e6SYuval Mintz 
23063587cb87STomer Tayar 		rc = qed_consq_alloc(p_hwfn);
23073587cb87STomer Tayar 		if (rc)
23083587cb87STomer Tayar 			goto alloc_err;
2309fe56b9e6SYuval Mintz 
23100db711bbSMintz, Yuval 		rc = qed_l2_alloc(p_hwfn);
23110db711bbSMintz, Yuval 		if (rc)
23120db711bbSMintz, Yuval 			goto alloc_err;
23130db711bbSMintz, Yuval 
23140a7fb11cSYuval Mintz #ifdef CONFIG_QED_LL2
23150a7fb11cSYuval Mintz 		if (p_hwfn->using_ll2) {
23163587cb87STomer Tayar 			rc = qed_ll2_alloc(p_hwfn);
23173587cb87STomer Tayar 			if (rc)
23183587cb87STomer Tayar 				goto alloc_err;
23190a7fb11cSYuval Mintz 		}
23200a7fb11cSYuval Mintz #endif
23211e128c81SArun Easi 
23221e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE) {
23233587cb87STomer Tayar 			rc = qed_fcoe_alloc(p_hwfn);
23243587cb87STomer Tayar 			if (rc)
23253587cb87STomer Tayar 				goto alloc_err;
23261e128c81SArun Easi 		}
23271e128c81SArun Easi 
2328fc831825SYuval Mintz 		if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
23293587cb87STomer Tayar 			rc = qed_iscsi_alloc(p_hwfn);
23303587cb87STomer Tayar 			if (rc)
23313587cb87STomer Tayar 				goto alloc_err;
23323587cb87STomer Tayar 			rc = qed_ooo_alloc(p_hwfn);
23333587cb87STomer Tayar 			if (rc)
23343587cb87STomer Tayar 				goto alloc_err;
2335fc831825SYuval Mintz 		}
23360a7fb11cSYuval Mintz 
2337291d57f6SMichal Kalderon 		if (QED_IS_RDMA_PERSONALITY(p_hwfn)) {
2338291d57f6SMichal Kalderon 			rc = qed_rdma_info_alloc(p_hwfn);
2339291d57f6SMichal Kalderon 			if (rc)
2340291d57f6SMichal Kalderon 				goto alloc_err;
2341291d57f6SMichal Kalderon 		}
2342291d57f6SMichal Kalderon 
2343fe56b9e6SYuval Mintz 		/* DMA info initialization */
2344fe56b9e6SYuval Mintz 		rc = qed_dmae_info_alloc(p_hwfn);
23452591c280SJoe Perches 		if (rc)
2346fe56b9e6SYuval Mintz 			goto alloc_err;
234739651abdSSudarsana Reddy Kalluru 
234839651abdSSudarsana Reddy Kalluru 		/* DCBX initialization */
234939651abdSSudarsana Reddy Kalluru 		rc = qed_dcbx_info_alloc(p_hwfn);
23502591c280SJoe Perches 		if (rc)
235139651abdSSudarsana Reddy Kalluru 			goto alloc_err;
2352a3f72307SDenis Bolotin 
23532d22bc83SMichal Kalderon 		rc = qed_dbg_alloc_user_data(p_hwfn, &p_hwfn->dbg_user_info);
2354a3f72307SDenis Bolotin 		if (rc)
2355a3f72307SDenis Bolotin 			goto alloc_err;
235639651abdSSudarsana Reddy Kalluru 	}
2357fe56b9e6SYuval Mintz 
235879284adeSMichal Kalderon 	rc = qed_llh_alloc(cdev);
235979284adeSMichal Kalderon 	if (rc) {
236079284adeSMichal Kalderon 		DP_NOTICE(cdev,
236179284adeSMichal Kalderon 			  "Failed to allocate memory for the llh_info structure\n");
236279284adeSMichal Kalderon 		goto alloc_err;
236379284adeSMichal Kalderon 	}
236479284adeSMichal Kalderon 
2365fe56b9e6SYuval Mintz 	cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
23662591c280SJoe Perches 	if (!cdev->reset_stats)
236783aeb933SYuval Mintz 		goto alloc_no_mem;
2368fe56b9e6SYuval Mintz 
2369fe56b9e6SYuval Mintz 	return 0;
2370fe56b9e6SYuval Mintz 
2371dbb799c3SYuval Mintz alloc_no_mem:
2372dbb799c3SYuval Mintz 	rc = -ENOMEM;
2373fe56b9e6SYuval Mintz alloc_err:
2374fe56b9e6SYuval Mintz 	qed_resc_free(cdev);
2375fe56b9e6SYuval Mintz 	return rc;
2376fe56b9e6SYuval Mintz }
2377fe56b9e6SYuval Mintz 
2378fe56b9e6SYuval Mintz void qed_resc_setup(struct qed_dev *cdev)
2379fe56b9e6SYuval Mintz {
2380fe56b9e6SYuval Mintz 	int i;
2381fe56b9e6SYuval Mintz 
23820db711bbSMintz, Yuval 	if (IS_VF(cdev)) {
23830db711bbSMintz, Yuval 		for_each_hwfn(cdev, i)
23840db711bbSMintz, Yuval 			qed_l2_setup(&cdev->hwfns[i]);
23851408cc1fSYuval Mintz 		return;
23860db711bbSMintz, Yuval 	}
23871408cc1fSYuval Mintz 
2388fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2389fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
2390fe56b9e6SYuval Mintz 
2391fe56b9e6SYuval Mintz 		qed_cxt_mngr_setup(p_hwfn);
2392fe56b9e6SYuval Mintz 		qed_spq_setup(p_hwfn);
23933587cb87STomer Tayar 		qed_eq_setup(p_hwfn);
23943587cb87STomer Tayar 		qed_consq_setup(p_hwfn);
2395fe56b9e6SYuval Mintz 
2396fe56b9e6SYuval Mintz 		/* Read shadow of current MFW mailbox */
2397fe56b9e6SYuval Mintz 		qed_mcp_read_mb(p_hwfn, p_hwfn->p_main_ptt);
2398fe56b9e6SYuval Mintz 		memcpy(p_hwfn->mcp_info->mfw_mb_shadow,
2399fe56b9e6SYuval Mintz 		       p_hwfn->mcp_info->mfw_mb_cur,
2400fe56b9e6SYuval Mintz 		       p_hwfn->mcp_info->mfw_mb_length);
2401fe56b9e6SYuval Mintz 
2402fe56b9e6SYuval Mintz 		qed_int_setup(p_hwfn, p_hwfn->p_main_ptt);
240332a47e72SYuval Mintz 
24040db711bbSMintz, Yuval 		qed_l2_setup(p_hwfn);
24051ee240e3SMintz, Yuval 		qed_iov_setup(p_hwfn);
24060a7fb11cSYuval Mintz #ifdef CONFIG_QED_LL2
24070a7fb11cSYuval Mintz 		if (p_hwfn->using_ll2)
24083587cb87STomer Tayar 			qed_ll2_setup(p_hwfn);
24090a7fb11cSYuval Mintz #endif
24101e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
24113587cb87STomer Tayar 			qed_fcoe_setup(p_hwfn);
24121e128c81SArun Easi 
24131d6cff4fSYuval Mintz 		if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
24143587cb87STomer Tayar 			qed_iscsi_setup(p_hwfn);
24153587cb87STomer Tayar 			qed_ooo_setup(p_hwfn);
24161d6cff4fSYuval Mintz 		}
2417fe56b9e6SYuval Mintz 	}
2418fe56b9e6SYuval Mintz }
2419fe56b9e6SYuval Mintz 
2420fe56b9e6SYuval Mintz #define FINAL_CLEANUP_POLL_CNT          (100)
2421fe56b9e6SYuval Mintz #define FINAL_CLEANUP_POLL_TIME         (10)
2422fe56b9e6SYuval Mintz int qed_final_cleanup(struct qed_hwfn *p_hwfn,
24230b55e27dSYuval Mintz 		      struct qed_ptt *p_ptt, u16 id, bool is_vf)
2424fe56b9e6SYuval Mintz {
2425fe56b9e6SYuval Mintz 	u32 command = 0, addr, count = FINAL_CLEANUP_POLL_CNT;
2426fe56b9e6SYuval Mintz 	int rc = -EBUSY;
2427fe56b9e6SYuval Mintz 
2428fc48b7a6SYuval Mintz 	addr = GTT_BAR0_MAP_REG_USDM_RAM +
2429fc48b7a6SYuval Mintz 		USTORM_FLR_FINAL_ACK_OFFSET(p_hwfn->rel_pf_id);
2430fe56b9e6SYuval Mintz 
24310b55e27dSYuval Mintz 	if (is_vf)
24320b55e27dSYuval Mintz 		id += 0x10;
24330b55e27dSYuval Mintz 
2434fc48b7a6SYuval Mintz 	command |= X_FINAL_CLEANUP_AGG_INT <<
2435fc48b7a6SYuval Mintz 		SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT;
2436fc48b7a6SYuval Mintz 	command |= 1 << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT;
2437fc48b7a6SYuval Mintz 	command |= id << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT;
2438fc48b7a6SYuval Mintz 	command |= SDM_COMP_TYPE_AGG_INT << SDM_OP_GEN_COMP_TYPE_SHIFT;
2439fe56b9e6SYuval Mintz 
2440fe56b9e6SYuval Mintz 	/* Make sure notification is not set before initiating final cleanup */
2441fe56b9e6SYuval Mintz 	if (REG_RD(p_hwfn, addr)) {
24421a635e48SYuval Mintz 		DP_NOTICE(p_hwfn,
2443fe56b9e6SYuval Mintz 			  "Unexpected; Found final cleanup notification before initiating final cleanup\n");
2444fe56b9e6SYuval Mintz 		REG_WR(p_hwfn, addr, 0);
2445fe56b9e6SYuval Mintz 	}
2446fe56b9e6SYuval Mintz 
2447fe56b9e6SYuval Mintz 	DP_VERBOSE(p_hwfn, QED_MSG_IOV,
2448d602de8eSJoe Perches 		   "Sending final cleanup for PFVF[%d] [Command %08x]\n",
2449fe56b9e6SYuval Mintz 		   id, command);
2450fe56b9e6SYuval Mintz 
2451fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, XSDM_REG_OPERATION_GEN, command);
2452fe56b9e6SYuval Mintz 
2453fe56b9e6SYuval Mintz 	/* Poll until completion */
2454fe56b9e6SYuval Mintz 	while (!REG_RD(p_hwfn, addr) && count--)
2455fe56b9e6SYuval Mintz 		msleep(FINAL_CLEANUP_POLL_TIME);
2456fe56b9e6SYuval Mintz 
2457fe56b9e6SYuval Mintz 	if (REG_RD(p_hwfn, addr))
2458fe56b9e6SYuval Mintz 		rc = 0;
2459fe56b9e6SYuval Mintz 	else
2460fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn,
2461fe56b9e6SYuval Mintz 			  "Failed to receive FW final cleanup notification\n");
2462fe56b9e6SYuval Mintz 
2463fe56b9e6SYuval Mintz 	/* Cleanup afterwards */
2464fe56b9e6SYuval Mintz 	REG_WR(p_hwfn, addr, 0);
2465fe56b9e6SYuval Mintz 
2466fe56b9e6SYuval Mintz 	return rc;
2467fe56b9e6SYuval Mintz }
2468fe56b9e6SYuval Mintz 
24699c79ddaaSMintz, Yuval static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn)
2470fe56b9e6SYuval Mintz {
2471fe56b9e6SYuval Mintz 	int hw_mode = 0;
2472fe56b9e6SYuval Mintz 
24739c79ddaaSMintz, Yuval 	if (QED_IS_BB_B0(p_hwfn->cdev)) {
24749c79ddaaSMintz, Yuval 		hw_mode |= 1 << MODE_BB;
24759c79ddaaSMintz, Yuval 	} else if (QED_IS_AH(p_hwfn->cdev)) {
24769c79ddaaSMintz, Yuval 		hw_mode |= 1 << MODE_K2;
24779c79ddaaSMintz, Yuval 	} else {
24789c79ddaaSMintz, Yuval 		DP_NOTICE(p_hwfn, "Unknown chip type %#x\n",
24799c79ddaaSMintz, Yuval 			  p_hwfn->cdev->type);
24809c79ddaaSMintz, Yuval 		return -EINVAL;
24819c79ddaaSMintz, Yuval 	}
2482fe56b9e6SYuval Mintz 
248378cea9ffSTomer Tayar 	switch (p_hwfn->cdev->num_ports_in_engine) {
2484fe56b9e6SYuval Mintz 	case 1:
2485fe56b9e6SYuval Mintz 		hw_mode |= 1 << MODE_PORTS_PER_ENG_1;
2486fe56b9e6SYuval Mintz 		break;
2487fe56b9e6SYuval Mintz 	case 2:
2488fe56b9e6SYuval Mintz 		hw_mode |= 1 << MODE_PORTS_PER_ENG_2;
2489fe56b9e6SYuval Mintz 		break;
2490fe56b9e6SYuval Mintz 	case 4:
2491fe56b9e6SYuval Mintz 		hw_mode |= 1 << MODE_PORTS_PER_ENG_4;
2492fe56b9e6SYuval Mintz 		break;
2493fe56b9e6SYuval Mintz 	default:
2494fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "num_ports_in_engine = %d not supported\n",
249578cea9ffSTomer Tayar 			  p_hwfn->cdev->num_ports_in_engine);
24969c79ddaaSMintz, Yuval 		return -EINVAL;
2497fe56b9e6SYuval Mintz 	}
2498fe56b9e6SYuval Mintz 
24990bc5fe85SSudarsana Reddy Kalluru 	if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits))
2500fc48b7a6SYuval Mintz 		hw_mode |= 1 << MODE_MF_SD;
25010bc5fe85SSudarsana Reddy Kalluru 	else
2502fc48b7a6SYuval Mintz 		hw_mode |= 1 << MODE_MF_SI;
2503fe56b9e6SYuval Mintz 
2504fe56b9e6SYuval Mintz 	hw_mode |= 1 << MODE_ASIC;
2505fe56b9e6SYuval Mintz 
25061af9dcf7SYuval Mintz 	if (p_hwfn->cdev->num_hwfns > 1)
25071af9dcf7SYuval Mintz 		hw_mode |= 1 << MODE_100G;
25081af9dcf7SYuval Mintz 
2509fe56b9e6SYuval Mintz 	p_hwfn->hw_info.hw_mode = hw_mode;
25101af9dcf7SYuval Mintz 
25111af9dcf7SYuval Mintz 	DP_VERBOSE(p_hwfn, (NETIF_MSG_PROBE | NETIF_MSG_IFUP),
25121af9dcf7SYuval Mintz 		   "Configuring function for hw_mode: 0x%08x\n",
25131af9dcf7SYuval Mintz 		   p_hwfn->hw_info.hw_mode);
25149c79ddaaSMintz, Yuval 
25159c79ddaaSMintz, Yuval 	return 0;
2516fe56b9e6SYuval Mintz }
2517fe56b9e6SYuval Mintz 
2518fe56b9e6SYuval Mintz /* Init run time data for all PFs on an engine. */
2519fe56b9e6SYuval Mintz static void qed_init_cau_rt_data(struct qed_dev *cdev)
2520fe56b9e6SYuval Mintz {
2521fe56b9e6SYuval Mintz 	u32 offset = CAU_REG_SB_VAR_MEMORY_RT_OFFSET;
2522d031548eSMintz, Yuval 	int i, igu_sb_id;
2523fe56b9e6SYuval Mintz 
2524fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
2525fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
2526fe56b9e6SYuval Mintz 		struct qed_igu_info *p_igu_info;
2527fe56b9e6SYuval Mintz 		struct qed_igu_block *p_block;
2528fe56b9e6SYuval Mintz 		struct cau_sb_entry sb_entry;
2529fe56b9e6SYuval Mintz 
2530fe56b9e6SYuval Mintz 		p_igu_info = p_hwfn->hw_info.p_igu_info;
2531fe56b9e6SYuval Mintz 
2532d031548eSMintz, Yuval 		for (igu_sb_id = 0;
2533d031548eSMintz, Yuval 		     igu_sb_id < QED_MAPPING_MEMORY_SIZE(cdev); igu_sb_id++) {
2534d031548eSMintz, Yuval 			p_block = &p_igu_info->entry[igu_sb_id];
2535d031548eSMintz, Yuval 
2536fe56b9e6SYuval Mintz 			if (!p_block->is_pf)
2537fe56b9e6SYuval Mintz 				continue;
2538fe56b9e6SYuval Mintz 
2539fe56b9e6SYuval Mintz 			qed_init_cau_sb_entry(p_hwfn, &sb_entry,
25401a635e48SYuval Mintz 					      p_block->function_id, 0, 0);
2541d031548eSMintz, Yuval 			STORE_RT_REG_AGG(p_hwfn, offset + igu_sb_id * 2,
2542d031548eSMintz, Yuval 					 sb_entry);
2543fe56b9e6SYuval Mintz 		}
2544fe56b9e6SYuval Mintz 	}
2545fe56b9e6SYuval Mintz }
2546fe56b9e6SYuval Mintz 
254760afed72STomer Tayar static void qed_init_cache_line_size(struct qed_hwfn *p_hwfn,
254860afed72STomer Tayar 				     struct qed_ptt *p_ptt)
254960afed72STomer Tayar {
255060afed72STomer Tayar 	u32 val, wr_mbs, cache_line_size;
255160afed72STomer Tayar 
255260afed72STomer Tayar 	val = qed_rd(p_hwfn, p_ptt, PSWRQ2_REG_WR_MBS0);
255360afed72STomer Tayar 	switch (val) {
255460afed72STomer Tayar 	case 0:
255560afed72STomer Tayar 		wr_mbs = 128;
255660afed72STomer Tayar 		break;
255760afed72STomer Tayar 	case 1:
255860afed72STomer Tayar 		wr_mbs = 256;
255960afed72STomer Tayar 		break;
256060afed72STomer Tayar 	case 2:
256160afed72STomer Tayar 		wr_mbs = 512;
256260afed72STomer Tayar 		break;
256360afed72STomer Tayar 	default:
256460afed72STomer Tayar 		DP_INFO(p_hwfn,
256560afed72STomer Tayar 			"Unexpected value of PSWRQ2_REG_WR_MBS0 [0x%x]. Avoid configuring PGLUE_B_REG_CACHE_LINE_SIZE.\n",
256660afed72STomer Tayar 			val);
256760afed72STomer Tayar 		return;
256860afed72STomer Tayar 	}
256960afed72STomer Tayar 
257060afed72STomer Tayar 	cache_line_size = min_t(u32, L1_CACHE_BYTES, wr_mbs);
257160afed72STomer Tayar 	switch (cache_line_size) {
257260afed72STomer Tayar 	case 32:
257360afed72STomer Tayar 		val = 0;
257460afed72STomer Tayar 		break;
257560afed72STomer Tayar 	case 64:
257660afed72STomer Tayar 		val = 1;
257760afed72STomer Tayar 		break;
257860afed72STomer Tayar 	case 128:
257960afed72STomer Tayar 		val = 2;
258060afed72STomer Tayar 		break;
258160afed72STomer Tayar 	case 256:
258260afed72STomer Tayar 		val = 3;
258360afed72STomer Tayar 		break;
258460afed72STomer Tayar 	default:
258560afed72STomer Tayar 		DP_INFO(p_hwfn,
258660afed72STomer Tayar 			"Unexpected value of cache line size [0x%x]. Avoid configuring PGLUE_B_REG_CACHE_LINE_SIZE.\n",
258760afed72STomer Tayar 			cache_line_size);
258860afed72STomer Tayar 	}
258960afed72STomer Tayar 
259060afed72STomer Tayar 	if (L1_CACHE_BYTES > wr_mbs)
259160afed72STomer Tayar 		DP_INFO(p_hwfn,
259260afed72STomer Tayar 			"The cache line size for padding is suboptimal for performance [OS cache line size 0x%x, wr mbs 0x%x]\n",
259360afed72STomer Tayar 			L1_CACHE_BYTES, wr_mbs);
259460afed72STomer Tayar 
259560afed72STomer Tayar 	STORE_RT_REG(p_hwfn, PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET, val);
2596fc6575bcSMintz, Yuval 	if (val > 0) {
2597fc6575bcSMintz, Yuval 		STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET, val);
2598fc6575bcSMintz, Yuval 		STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET, val);
2599fc6575bcSMintz, Yuval 	}
260060afed72STomer Tayar }
260160afed72STomer Tayar 
2602fe56b9e6SYuval Mintz static int qed_hw_init_common(struct qed_hwfn *p_hwfn,
26031a635e48SYuval Mintz 			      struct qed_ptt *p_ptt, int hw_mode)
2604fe56b9e6SYuval Mintz {
2605fe56b9e6SYuval Mintz 	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
2606fe56b9e6SYuval Mintz 	struct qed_qm_common_rt_init_params params;
2607fe56b9e6SYuval Mintz 	struct qed_dev *cdev = p_hwfn->cdev;
26089c79ddaaSMintz, Yuval 	u8 vf_id, max_num_vfs;
2609dbb799c3SYuval Mintz 	u16 num_pfs, pf_id;
26101408cc1fSYuval Mintz 	u32 concrete_fid;
2611fe56b9e6SYuval Mintz 	int rc = 0;
2612fe56b9e6SYuval Mintz 
2613fe56b9e6SYuval Mintz 	qed_init_cau_rt_data(cdev);
2614fe56b9e6SYuval Mintz 
2615fe56b9e6SYuval Mintz 	/* Program GTT windows */
2616fe56b9e6SYuval Mintz 	qed_gtt_init(p_hwfn);
2617fe56b9e6SYuval Mintz 
2618fe56b9e6SYuval Mintz 	if (p_hwfn->mcp_info) {
2619fe56b9e6SYuval Mintz 		if (p_hwfn->mcp_info->func_info.bandwidth_max)
2620c7281d59SGustavo A. R. Silva 			qm_info->pf_rl_en = true;
2621fe56b9e6SYuval Mintz 		if (p_hwfn->mcp_info->func_info.bandwidth_min)
2622c7281d59SGustavo A. R. Silva 			qm_info->pf_wfq_en = true;
2623fe56b9e6SYuval Mintz 	}
2624fe56b9e6SYuval Mintz 
2625fe56b9e6SYuval Mintz 	memset(&params, 0, sizeof(params));
262678cea9ffSTomer Tayar 	params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engine;
2627fe56b9e6SYuval Mintz 	params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port;
2628fe56b9e6SYuval Mintz 	params.pf_rl_en = qm_info->pf_rl_en;
2629fe56b9e6SYuval Mintz 	params.pf_wfq_en = qm_info->pf_wfq_en;
263092fae6fbSMichal Kalderon 	params.global_rl_en = qm_info->vport_rl_en;
2631fe56b9e6SYuval Mintz 	params.vport_wfq_en = qm_info->vport_wfq_en;
2632fe56b9e6SYuval Mintz 	params.port_params = qm_info->qm_port_params;
2633fe56b9e6SYuval Mintz 
2634fe56b9e6SYuval Mintz 	qed_qm_common_rt_init(p_hwfn, &params);
2635fe56b9e6SYuval Mintz 
2636fe56b9e6SYuval Mintz 	qed_cxt_hw_init_common(p_hwfn);
2637fe56b9e6SYuval Mintz 
263860afed72STomer Tayar 	qed_init_cache_line_size(p_hwfn, p_ptt);
263960afed72STomer Tayar 
2640fe56b9e6SYuval Mintz 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_ENGINE, ANY_PHASE_ID, hw_mode);
26411a635e48SYuval Mintz 	if (rc)
2642fe56b9e6SYuval Mintz 		return rc;
2643fe56b9e6SYuval Mintz 
2644fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, PSWRQ2_REG_L2P_VALIDATE_VFID, 0);
2645fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_USE_CLIENTID_IN_TAG, 1);
2646fe56b9e6SYuval Mintz 
2647dbb799c3SYuval Mintz 	if (QED_IS_BB(p_hwfn->cdev)) {
2648dbb799c3SYuval Mintz 		num_pfs = NUM_OF_ENG_PFS(p_hwfn->cdev);
2649dbb799c3SYuval Mintz 		for (pf_id = 0; pf_id < num_pfs; pf_id++) {
2650dbb799c3SYuval Mintz 			qed_fid_pretend(p_hwfn, p_ptt, pf_id);
2651dbb799c3SYuval Mintz 			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
2652dbb799c3SYuval Mintz 			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
2653dbb799c3SYuval Mintz 		}
2654dbb799c3SYuval Mintz 		/* pretend to original PF */
2655dbb799c3SYuval Mintz 		qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id);
2656dbb799c3SYuval Mintz 	}
2657fe56b9e6SYuval Mintz 
26589c79ddaaSMintz, Yuval 	max_num_vfs = QED_IS_AH(cdev) ? MAX_NUM_VFS_K2 : MAX_NUM_VFS_BB;
26599c79ddaaSMintz, Yuval 	for (vf_id = 0; vf_id < max_num_vfs; vf_id++) {
26601408cc1fSYuval Mintz 		concrete_fid = qed_vfid_to_concrete(p_hwfn, vf_id);
26611408cc1fSYuval Mintz 		qed_fid_pretend(p_hwfn, p_ptt, (u16) concrete_fid);
26621408cc1fSYuval Mintz 		qed_wr(p_hwfn, p_ptt, CCFC_REG_STRONG_ENABLE_VF, 0x1);
266305fafbfbSYuval Mintz 		qed_wr(p_hwfn, p_ptt, CCFC_REG_WEAK_ENABLE_VF, 0x0);
266405fafbfbSYuval Mintz 		qed_wr(p_hwfn, p_ptt, TCFC_REG_STRONG_ENABLE_VF, 0x1);
266505fafbfbSYuval Mintz 		qed_wr(p_hwfn, p_ptt, TCFC_REG_WEAK_ENABLE_VF, 0x0);
26661408cc1fSYuval Mintz 	}
26671408cc1fSYuval Mintz 	/* pretend to original PF */
26681408cc1fSYuval Mintz 	qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id);
26691408cc1fSYuval Mintz 
2670fe56b9e6SYuval Mintz 	return rc;
2671fe56b9e6SYuval Mintz }
2672fe56b9e6SYuval Mintz 
267351ff1725SRam Amrani static int
267451ff1725SRam Amrani qed_hw_init_dpi_size(struct qed_hwfn *p_hwfn,
267551ff1725SRam Amrani 		     struct qed_ptt *p_ptt, u32 pwm_region_size, u32 n_cpus)
267651ff1725SRam Amrani {
2677107392b7SRam Amrani 	u32 dpi_bit_shift, dpi_count, dpi_page_size;
267851ff1725SRam Amrani 	u32 min_dpis;
2679107392b7SRam Amrani 	u32 n_wids;
268051ff1725SRam Amrani 
268151ff1725SRam Amrani 	/* Calculate DPI size */
2682107392b7SRam Amrani 	n_wids = max_t(u32, QED_MIN_WIDS, n_cpus);
2683107392b7SRam Amrani 	dpi_page_size = QED_WID_SIZE * roundup_pow_of_two(n_wids);
2684107392b7SRam Amrani 	dpi_page_size = (dpi_page_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
268551ff1725SRam Amrani 	dpi_bit_shift = ilog2(dpi_page_size / 4096);
268651ff1725SRam Amrani 	dpi_count = pwm_region_size / dpi_page_size;
268751ff1725SRam Amrani 
268851ff1725SRam Amrani 	min_dpis = p_hwfn->pf_params.rdma_pf_params.min_dpis;
268951ff1725SRam Amrani 	min_dpis = max_t(u32, QED_MIN_DPIS, min_dpis);
269051ff1725SRam Amrani 
269151ff1725SRam Amrani 	p_hwfn->dpi_size = dpi_page_size;
269251ff1725SRam Amrani 	p_hwfn->dpi_count = dpi_count;
269351ff1725SRam Amrani 
269451ff1725SRam Amrani 	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPI_BIT_SHIFT, dpi_bit_shift);
269551ff1725SRam Amrani 
269651ff1725SRam Amrani 	if (dpi_count < min_dpis)
269751ff1725SRam Amrani 		return -EINVAL;
269851ff1725SRam Amrani 
269951ff1725SRam Amrani 	return 0;
270051ff1725SRam Amrani }
270151ff1725SRam Amrani 
270251ff1725SRam Amrani enum QED_ROCE_EDPM_MODE {
270351ff1725SRam Amrani 	QED_ROCE_EDPM_MODE_ENABLE = 0,
270451ff1725SRam Amrani 	QED_ROCE_EDPM_MODE_FORCE_ON = 1,
270551ff1725SRam Amrani 	QED_ROCE_EDPM_MODE_DISABLE = 2,
270651ff1725SRam Amrani };
270751ff1725SRam Amrani 
2708a1b469b8SAriel Elior bool qed_edpm_enabled(struct qed_hwfn *p_hwfn)
2709a1b469b8SAriel Elior {
2710a1b469b8SAriel Elior 	if (p_hwfn->dcbx_no_edpm || p_hwfn->db_bar_no_edpm)
2711a1b469b8SAriel Elior 		return false;
2712a1b469b8SAriel Elior 
2713a1b469b8SAriel Elior 	return true;
2714a1b469b8SAriel Elior }
2715a1b469b8SAriel Elior 
271651ff1725SRam Amrani static int
271751ff1725SRam Amrani qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
271851ff1725SRam Amrani {
271951ff1725SRam Amrani 	u32 pwm_regsize, norm_regsize;
272051ff1725SRam Amrani 	u32 non_pwm_conn, min_addr_reg1;
272120b1bd96SRam Amrani 	u32 db_bar_size, n_cpus = 1;
272251ff1725SRam Amrani 	u32 roce_edpm_mode;
272351ff1725SRam Amrani 	u32 pf_dems_shift;
272451ff1725SRam Amrani 	int rc = 0;
272551ff1725SRam Amrani 	u8 cond;
272651ff1725SRam Amrani 
272715582962SRahul Verma 	db_bar_size = qed_hw_bar_size(p_hwfn, p_ptt, BAR_ID_1);
272851ff1725SRam Amrani 	if (p_hwfn->cdev->num_hwfns > 1)
272951ff1725SRam Amrani 		db_bar_size /= 2;
273051ff1725SRam Amrani 
273151ff1725SRam Amrani 	/* Calculate doorbell regions */
273251ff1725SRam Amrani 	non_pwm_conn = qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_CORE) +
273351ff1725SRam Amrani 		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_CORE,
273451ff1725SRam Amrani 						   NULL) +
273551ff1725SRam Amrani 		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
273651ff1725SRam Amrani 						   NULL);
2737a82dadbcSRam Amrani 	norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE);
273851ff1725SRam Amrani 	min_addr_reg1 = norm_regsize / 4096;
273951ff1725SRam Amrani 	pwm_regsize = db_bar_size - norm_regsize;
274051ff1725SRam Amrani 
274151ff1725SRam Amrani 	/* Check that the normal and PWM sizes are valid */
274251ff1725SRam Amrani 	if (db_bar_size < norm_regsize) {
274351ff1725SRam Amrani 		DP_ERR(p_hwfn->cdev,
274451ff1725SRam Amrani 		       "Doorbell BAR size 0x%x is too small (normal region is 0x%0x )\n",
274551ff1725SRam Amrani 		       db_bar_size, norm_regsize);
274651ff1725SRam Amrani 		return -EINVAL;
274751ff1725SRam Amrani 	}
274851ff1725SRam Amrani 
274951ff1725SRam Amrani 	if (pwm_regsize < QED_MIN_PWM_REGION) {
275051ff1725SRam Amrani 		DP_ERR(p_hwfn->cdev,
275151ff1725SRam 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",
275251ff1725SRam Amrani 		       pwm_regsize,
275351ff1725SRam Amrani 		       QED_MIN_PWM_REGION, db_bar_size, norm_regsize);
275451ff1725SRam Amrani 		return -EINVAL;
275551ff1725SRam Amrani 	}
275651ff1725SRam Amrani 
275751ff1725SRam Amrani 	/* Calculate number of DPIs */
275851ff1725SRam Amrani 	roce_edpm_mode = p_hwfn->pf_params.rdma_pf_params.roce_edpm_mode;
275951ff1725SRam Amrani 	if ((roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE) ||
276051ff1725SRam Amrani 	    ((roce_edpm_mode == QED_ROCE_EDPM_MODE_FORCE_ON))) {
276151ff1725SRam Amrani 		/* Either EDPM is mandatory, or we are attempting to allocate a
276251ff1725SRam Amrani 		 * WID per CPU.
276351ff1725SRam Amrani 		 */
2764c2dedf87SRam Amrani 		n_cpus = num_present_cpus();
276551ff1725SRam Amrani 		rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus);
276651ff1725SRam Amrani 	}
276751ff1725SRam Amrani 
276851ff1725SRam Amrani 	cond = (rc && (roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE)) ||
276951ff1725SRam Amrani 	       (roce_edpm_mode == QED_ROCE_EDPM_MODE_DISABLE);
277051ff1725SRam Amrani 	if (cond || p_hwfn->dcbx_no_edpm) {
277151ff1725SRam Amrani 		/* Either EDPM is disabled from user configuration, or it is
277251ff1725SRam Amrani 		 * disabled via DCBx, or it is not mandatory and we failed to
277351ff1725SRam Amrani 		 * allocated a WID per CPU.
277451ff1725SRam Amrani 		 */
277551ff1725SRam Amrani 		n_cpus = 1;
277651ff1725SRam Amrani 		rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus);
277751ff1725SRam Amrani 
277851ff1725SRam Amrani 		if (cond)
277951ff1725SRam Amrani 			qed_rdma_dpm_bar(p_hwfn, p_ptt);
278051ff1725SRam Amrani 	}
278151ff1725SRam Amrani 
278220b1bd96SRam Amrani 	p_hwfn->wid_count = (u16) n_cpus;
278320b1bd96SRam Amrani 
278451ff1725SRam Amrani 	DP_INFO(p_hwfn,
2785a1b469b8SAriel Elior 		"doorbell bar: normal_region_size=%d, pwm_region_size=%d, dpi_size=%d, dpi_count=%d, roce_edpm=%s, page_size=%lu\n",
278651ff1725SRam Amrani 		norm_regsize,
278751ff1725SRam Amrani 		pwm_regsize,
278851ff1725SRam Amrani 		p_hwfn->dpi_size,
278951ff1725SRam Amrani 		p_hwfn->dpi_count,
2790a1b469b8SAriel Elior 		(!qed_edpm_enabled(p_hwfn)) ?
2791a1b469b8SAriel Elior 		"disabled" : "enabled", PAGE_SIZE);
279251ff1725SRam Amrani 
279351ff1725SRam Amrani 	if (rc) {
279451ff1725SRam Amrani 		DP_ERR(p_hwfn,
279551ff1725SRam Amrani 		       "Failed to allocate enough DPIs. Allocated %d but the current minimum is %d.\n",
279651ff1725SRam Amrani 		       p_hwfn->dpi_count,
279751ff1725SRam Amrani 		       p_hwfn->pf_params.rdma_pf_params.min_dpis);
279851ff1725SRam Amrani 		return -EINVAL;
279951ff1725SRam Amrani 	}
280051ff1725SRam Amrani 
280151ff1725SRam Amrani 	p_hwfn->dpi_start_offset = norm_regsize;
280251ff1725SRam Amrani 
280351ff1725SRam Amrani 	/* DEMS size is configured log2 of DWORDs, hence the division by 4 */
280451ff1725SRam Amrani 	pf_dems_shift = ilog2(QED_PF_DEMS_SIZE / 4);
280551ff1725SRam Amrani 	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_ICID_BIT_SHIFT_NORM, pf_dems_shift);
280651ff1725SRam Amrani 	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_MIN_ADDR_REG1, min_addr_reg1);
280751ff1725SRam Amrani 
280851ff1725SRam Amrani 	return 0;
280951ff1725SRam Amrani }
281051ff1725SRam Amrani 
2811fe56b9e6SYuval Mintz static int qed_hw_init_port(struct qed_hwfn *p_hwfn,
28121a635e48SYuval Mintz 			    struct qed_ptt *p_ptt, int hw_mode)
2813fe56b9e6SYuval Mintz {
2814fc6575bcSMintz, Yuval 	int rc = 0;
2815fc6575bcSMintz, Yuval 
281679284adeSMichal Kalderon 	/* In CMT the gate should be cleared by the 2nd hwfn */
281779284adeSMichal Kalderon 	if (!QED_IS_CMT(p_hwfn->cdev) || !IS_LEAD_HWFN(p_hwfn))
281879284adeSMichal Kalderon 		STORE_RT_REG(p_hwfn, NIG_REG_BRB_GATE_DNTFWD_PORT_RT_OFFSET, 0);
281979284adeSMichal Kalderon 
2820fc6575bcSMintz, Yuval 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode);
2821fc6575bcSMintz, Yuval 	if (rc)
2822fc6575bcSMintz, Yuval 		return rc;
2823fc6575bcSMintz, Yuval 
2824fc6575bcSMintz, Yuval 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE, 0);
2825fc6575bcSMintz, Yuval 
2826fc6575bcSMintz, Yuval 	return 0;
2827fe56b9e6SYuval Mintz }
2828fe56b9e6SYuval Mintz 
2829fe56b9e6SYuval Mintz static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
2830fe56b9e6SYuval Mintz 			  struct qed_ptt *p_ptt,
283119968430SChopra, Manish 			  struct qed_tunnel_info *p_tunn,
2832fe56b9e6SYuval Mintz 			  int hw_mode,
2833fe56b9e6SYuval Mintz 			  bool b_hw_start,
2834fe56b9e6SYuval Mintz 			  enum qed_int_mode int_mode,
2835fe56b9e6SYuval Mintz 			  bool allow_npar_tx_switch)
2836fe56b9e6SYuval Mintz {
2837fe56b9e6SYuval Mintz 	u8 rel_pf_id = p_hwfn->rel_pf_id;
2838fe56b9e6SYuval Mintz 	int rc = 0;
2839fe56b9e6SYuval Mintz 
2840fe56b9e6SYuval Mintz 	if (p_hwfn->mcp_info) {
2841fe56b9e6SYuval Mintz 		struct qed_mcp_function_info *p_info;
2842fe56b9e6SYuval Mintz 
2843fe56b9e6SYuval Mintz 		p_info = &p_hwfn->mcp_info->func_info;
2844fe56b9e6SYuval Mintz 		if (p_info->bandwidth_min)
2845fe56b9e6SYuval Mintz 			p_hwfn->qm_info.pf_wfq = p_info->bandwidth_min;
2846fe56b9e6SYuval Mintz 
2847fe56b9e6SYuval Mintz 		/* Update rate limit once we'll actually have a link */
28484b01e519SManish Chopra 		p_hwfn->qm_info.pf_rl = 100000;
2849fe56b9e6SYuval Mintz 	}
2850fe56b9e6SYuval Mintz 
285115582962SRahul Verma 	qed_cxt_hw_init_pf(p_hwfn, p_ptt);
2852fe56b9e6SYuval Mintz 
2853fe56b9e6SYuval Mintz 	qed_int_igu_init_rt(p_hwfn);
2854fe56b9e6SYuval Mintz 
2855fe56b9e6SYuval Mintz 	/* Set VLAN in NIG if needed */
28561a635e48SYuval Mintz 	if (hw_mode & BIT(MODE_MF_SD)) {
2857fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Configuring LLH_FUNC_TAG\n");
2858fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET, 1);
2859fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET,
2860fe56b9e6SYuval Mintz 			     p_hwfn->hw_info.ovlan);
2861cac6f691SSudarsana Reddy Kalluru 
2862cac6f691SSudarsana Reddy Kalluru 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
2863cac6f691SSudarsana Reddy Kalluru 			   "Configuring LLH_FUNC_FILTER_HDR_SEL\n");
2864cac6f691SSudarsana Reddy Kalluru 		STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET,
2865cac6f691SSudarsana Reddy Kalluru 			     1);
2866fe56b9e6SYuval Mintz 	}
2867fe56b9e6SYuval Mintz 
2868fe56b9e6SYuval Mintz 	/* Enable classification by MAC if needed */
28691a635e48SYuval Mintz 	if (hw_mode & BIT(MODE_MF_SI)) {
2870fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
2871fe56b9e6SYuval Mintz 			   "Configuring TAGMAC_CLS_TYPE\n");
2872fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn,
2873fe56b9e6SYuval Mintz 			     NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET, 1);
2874fe56b9e6SYuval Mintz 	}
2875fe56b9e6SYuval Mintz 
2876a2e7699eSTomer Tayar 	/* Protocol Configuration */
2877dbb799c3SYuval Mintz 	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET,
2878dbb799c3SYuval Mintz 		     (p_hwfn->hw_info.personality == QED_PCI_ISCSI) ? 1 : 0);
28791e128c81SArun Easi 	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET,
28801e128c81SArun Easi 		     (p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0);
2881fe56b9e6SYuval Mintz 	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0);
2882fe56b9e6SYuval Mintz 
2883da090917STomer Tayar 	/* Sanity check before the PF init sequence that uses DMAE */
2884da090917STomer Tayar 	rc = qed_dmae_sanity(p_hwfn, p_ptt, "pf_phase");
2885da090917STomer Tayar 	if (rc)
2886da090917STomer Tayar 		return rc;
2887da090917STomer Tayar 
2888fe56b9e6SYuval Mintz 	/* PF Init sequence */
2889fe56b9e6SYuval Mintz 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_PF, rel_pf_id, hw_mode);
2890fe56b9e6SYuval Mintz 	if (rc)
2891fe56b9e6SYuval Mintz 		return rc;
2892fe56b9e6SYuval Mintz 
2893fe56b9e6SYuval Mintz 	/* QM_PF Init sequence (may be invoked separately e.g. for DCB) */
2894fe56b9e6SYuval Mintz 	rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, rel_pf_id, hw_mode);
2895fe56b9e6SYuval Mintz 	if (rc)
2896fe56b9e6SYuval Mintz 		return rc;
2897fe56b9e6SYuval Mintz 
289830d5f858SMichal Kalderon 	qed_fw_overlay_init_ram(p_hwfn, p_ptt, p_hwfn->fw_overlay_mem);
289930d5f858SMichal Kalderon 
2900fe56b9e6SYuval Mintz 	/* Pure runtime initializations - directly to the HW  */
2901fe56b9e6SYuval Mintz 	qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true);
2902fe56b9e6SYuval Mintz 
290351ff1725SRam Amrani 	rc = qed_hw_init_pf_doorbell_bar(p_hwfn, p_ptt);
290451ff1725SRam Amrani 	if (rc)
290551ff1725SRam Amrani 		return rc;
290651ff1725SRam Amrani 
290779284adeSMichal Kalderon 	/* Use the leading hwfn since in CMT only NIG #0 is operational */
290879284adeSMichal Kalderon 	if (IS_LEAD_HWFN(p_hwfn)) {
290979284adeSMichal Kalderon 		rc = qed_llh_hw_init_pf(p_hwfn, p_ptt);
291079284adeSMichal Kalderon 		if (rc)
291179284adeSMichal Kalderon 			return rc;
291279284adeSMichal Kalderon 	}
291379284adeSMichal Kalderon 
2914fe56b9e6SYuval Mintz 	if (b_hw_start) {
2915fe56b9e6SYuval Mintz 		/* enable interrupts */
2916fe56b9e6SYuval Mintz 		qed_int_igu_enable(p_hwfn, p_ptt, int_mode);
2917fe56b9e6SYuval Mintz 
2918fe56b9e6SYuval Mintz 		/* send function start command */
29194f64675fSManish Chopra 		rc = qed_sp_pf_start(p_hwfn, p_ptt, p_tunn,
2920831bfb0eSYuval Mintz 				     allow_npar_tx_switch);
29211e128c81SArun Easi 		if (rc) {
2922fe56b9e6SYuval Mintz 			DP_NOTICE(p_hwfn, "Function start ramrod failed\n");
29231e128c81SArun Easi 			return rc;
29241e128c81SArun Easi 		}
29251e128c81SArun Easi 		if (p_hwfn->hw_info.personality == QED_PCI_FCOE) {
29261e128c81SArun Easi 			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TAG1, BIT(2));
29271e128c81SArun Easi 			qed_wr(p_hwfn, p_ptt,
29281e128c81SArun Easi 			       PRS_REG_PKT_LEN_STAT_TAGS_NOT_COUNTED_FIRST,
29291e128c81SArun Easi 			       0x100);
29301e128c81SArun Easi 		}
2931fe56b9e6SYuval Mintz 	}
2932fe56b9e6SYuval Mintz 	return rc;
2933fe56b9e6SYuval Mintz }
2934fe56b9e6SYuval Mintz 
2935666db486STomer Tayar int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn,
2936666db486STomer Tayar 			       struct qed_ptt *p_ptt, bool b_enable)
2937fe56b9e6SYuval Mintz {
2938666db486STomer Tayar 	u32 delay_idx = 0, val, set_val = b_enable ? 1 : 0;
2939fe56b9e6SYuval Mintz 
2940666db486STomer Tayar 	/* Configure the PF's internal FID_enable for master transactions */
2941666db486STomer Tayar 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val);
2942fe56b9e6SYuval Mintz 
2943666db486STomer Tayar 	/* Wait until value is set - try for 1 second every 50us */
2944fe56b9e6SYuval Mintz 	for (delay_idx = 0; delay_idx < 20000; delay_idx++) {
2945fe56b9e6SYuval Mintz 		val = qed_rd(p_hwfn, p_ptt,
2946fe56b9e6SYuval Mintz 			     PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
2947fe56b9e6SYuval Mintz 		if (val == set_val)
2948fe56b9e6SYuval Mintz 			break;
2949fe56b9e6SYuval Mintz 
2950fe56b9e6SYuval Mintz 		usleep_range(50, 60);
2951fe56b9e6SYuval Mintz 	}
2952fe56b9e6SYuval Mintz 
2953fe56b9e6SYuval Mintz 	if (val != set_val) {
2954fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn,
2955fe56b9e6SYuval Mintz 			  "PFID_ENABLE_MASTER wasn't changed after a second\n");
2956fe56b9e6SYuval Mintz 		return -EAGAIN;
2957fe56b9e6SYuval Mintz 	}
2958fe56b9e6SYuval Mintz 
2959fe56b9e6SYuval Mintz 	return 0;
2960fe56b9e6SYuval Mintz }
2961fe56b9e6SYuval Mintz 
2962fe56b9e6SYuval Mintz static void qed_reset_mb_shadow(struct qed_hwfn *p_hwfn,
2963fe56b9e6SYuval Mintz 				struct qed_ptt *p_main_ptt)
2964fe56b9e6SYuval Mintz {
2965fe56b9e6SYuval Mintz 	/* Read shadow of current MFW mailbox */
2966fe56b9e6SYuval Mintz 	qed_mcp_read_mb(p_hwfn, p_main_ptt);
2967fe56b9e6SYuval Mintz 	memcpy(p_hwfn->mcp_info->mfw_mb_shadow,
29681a635e48SYuval Mintz 	       p_hwfn->mcp_info->mfw_mb_cur, p_hwfn->mcp_info->mfw_mb_length);
2969fe56b9e6SYuval Mintz }
2970fe56b9e6SYuval Mintz 
29715d24bcf1STomer Tayar static void
29725d24bcf1STomer Tayar qed_fill_load_req_params(struct qed_load_req_params *p_load_req,
29735d24bcf1STomer Tayar 			 struct qed_drv_load_params *p_drv_load)
29745d24bcf1STomer Tayar {
29755d24bcf1STomer Tayar 	memset(p_load_req, 0, sizeof(*p_load_req));
29765d24bcf1STomer Tayar 
29775d24bcf1STomer Tayar 	p_load_req->drv_role = p_drv_load->is_crash_kernel ?
29785d24bcf1STomer Tayar 			       QED_DRV_ROLE_KDUMP : QED_DRV_ROLE_OS;
29795d24bcf1STomer Tayar 	p_load_req->timeout_val = p_drv_load->mfw_timeout_val;
29805d24bcf1STomer Tayar 	p_load_req->avoid_eng_reset = p_drv_load->avoid_eng_reset;
29815d24bcf1STomer Tayar 	p_load_req->override_force_load = p_drv_load->override_force_load;
29825d24bcf1STomer Tayar }
29835d24bcf1STomer Tayar 
2984eaf3c0c6SChopra, Manish static int qed_vf_start(struct qed_hwfn *p_hwfn,
2985eaf3c0c6SChopra, Manish 			struct qed_hw_init_params *p_params)
2986eaf3c0c6SChopra, Manish {
2987eaf3c0c6SChopra, Manish 	if (p_params->p_tunn) {
2988eaf3c0c6SChopra, Manish 		qed_vf_set_vf_start_tunn_update_param(p_params->p_tunn);
2989eaf3c0c6SChopra, Manish 		qed_vf_pf_tunnel_param_update(p_hwfn, p_params->p_tunn);
2990eaf3c0c6SChopra, Manish 	}
2991eaf3c0c6SChopra, Manish 
2992c7281d59SGustavo A. R. Silva 	p_hwfn->b_int_enabled = true;
2993eaf3c0c6SChopra, Manish 
2994eaf3c0c6SChopra, Manish 	return 0;
2995eaf3c0c6SChopra, Manish }
2996eaf3c0c6SChopra, Manish 
2997666db486STomer Tayar static void qed_pglueb_clear_err(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
2998666db486STomer Tayar {
2999666db486STomer Tayar 	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR,
3000666db486STomer Tayar 	       BIT(p_hwfn->abs_pf_id));
3001666db486STomer Tayar }
3002666db486STomer Tayar 
3003c0c2d0b4SMintz, Yuval int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
3004fe56b9e6SYuval Mintz {
30055d24bcf1STomer Tayar 	struct qed_load_req_params load_req_params;
300650fdf601SSudarsana Reddy Kalluru 	u32 load_code, resp, param, drv_mb_param;
30070fefbfbaSSudarsana Kalluru 	bool b_default_mtu = true;
30080fefbfbaSSudarsana Kalluru 	struct qed_hwfn *p_hwfn;
300930d5f858SMichal Kalderon 	const u32 *fw_overlays;
301030d5f858SMichal Kalderon 	u32 fw_overlays_len;
3011cac6f691SSudarsana Reddy Kalluru 	u16 ether_type;
301230d5f858SMichal Kalderon 	int rc = 0, i;
3013fe56b9e6SYuval Mintz 
3014c0c2d0b4SMintz, Yuval 	if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) {
3015bb13ace7SSudarsana Reddy Kalluru 		DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n");
3016bb13ace7SSudarsana Reddy Kalluru 		return -EINVAL;
3017bb13ace7SSudarsana Reddy Kalluru 	}
3018bb13ace7SSudarsana Reddy Kalluru 
30191408cc1fSYuval Mintz 	if (IS_PF(cdev)) {
3020c0c2d0b4SMintz, Yuval 		rc = qed_init_fw_data(cdev, p_params->bin_fw_data);
30211a635e48SYuval Mintz 		if (rc)
3022fe56b9e6SYuval Mintz 			return rc;
30231408cc1fSYuval Mintz 	}
3024fe56b9e6SYuval Mintz 
3025fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
3026666db486STomer Tayar 		p_hwfn = &cdev->hwfns[i];
3027fe56b9e6SYuval Mintz 
30280fefbfbaSSudarsana Kalluru 		/* If management didn't provide a default, set one of our own */
30290fefbfbaSSudarsana Kalluru 		if (!p_hwfn->hw_info.mtu) {
30300fefbfbaSSudarsana Kalluru 			p_hwfn->hw_info.mtu = 1500;
30310fefbfbaSSudarsana Kalluru 			b_default_mtu = false;
30320fefbfbaSSudarsana Kalluru 		}
30330fefbfbaSSudarsana Kalluru 
30341408cc1fSYuval Mintz 		if (IS_VF(cdev)) {
3035eaf3c0c6SChopra, Manish 			qed_vf_start(p_hwfn, p_params);
30361408cc1fSYuval Mintz 			continue;
30371408cc1fSYuval Mintz 		}
30381408cc1fSYuval Mintz 
30399c79ddaaSMintz, Yuval 		rc = qed_calc_hw_mode(p_hwfn);
30409c79ddaaSMintz, Yuval 		if (rc)
30419c79ddaaSMintz, Yuval 			return rc;
3042fe56b9e6SYuval Mintz 
3043cac6f691SSudarsana Reddy Kalluru 		if (IS_PF(cdev) && (test_bit(QED_MF_8021Q_TAGGING,
3044cac6f691SSudarsana Reddy Kalluru 					     &cdev->mf_bits) ||
3045cac6f691SSudarsana Reddy Kalluru 				    test_bit(QED_MF_8021AD_TAGGING,
3046cac6f691SSudarsana Reddy Kalluru 					     &cdev->mf_bits))) {
3047cac6f691SSudarsana Reddy Kalluru 			if (test_bit(QED_MF_8021Q_TAGGING, &cdev->mf_bits))
3048cac6f691SSudarsana Reddy Kalluru 				ether_type = ETH_P_8021Q;
3049cac6f691SSudarsana Reddy Kalluru 			else
3050cac6f691SSudarsana Reddy Kalluru 				ether_type = ETH_P_8021AD;
3051b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, PRS_REG_TAG_ETHERTYPE_0_RT_OFFSET,
3052cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3053b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET,
3054cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3055b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET,
3056cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3057b51bdfb9SSudarsana Reddy Kalluru 			STORE_RT_REG(p_hwfn, DORQ_REG_TAG1_ETHERTYPE_RT_OFFSET,
3058cac6f691SSudarsana Reddy Kalluru 				     ether_type);
3059b51bdfb9SSudarsana Reddy Kalluru 		}
3060b51bdfb9SSudarsana Reddy Kalluru 
30615d24bcf1STomer Tayar 		qed_fill_load_req_params(&load_req_params,
30625d24bcf1STomer Tayar 					 p_params->p_drv_load_params);
30635d24bcf1STomer Tayar 		rc = qed_mcp_load_req(p_hwfn, p_hwfn->p_main_ptt,
30645d24bcf1STomer Tayar 				      &load_req_params);
3065fe56b9e6SYuval Mintz 		if (rc) {
30665d24bcf1STomer Tayar 			DP_NOTICE(p_hwfn, "Failed sending a LOAD_REQ command\n");
3067fe56b9e6SYuval Mintz 			return rc;
3068fe56b9e6SYuval Mintz 		}
3069fe56b9e6SYuval Mintz 
30705d24bcf1STomer Tayar 		load_code = load_req_params.load_code;
3071fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, QED_MSG_SP,
30725d24bcf1STomer Tayar 			   "Load request was sent. Load code: 0x%x\n",
30735d24bcf1STomer Tayar 			   load_code);
30745d24bcf1STomer Tayar 
307564515dc8STomer Tayar 		/* Only relevant for recovery:
307664515dc8STomer Tayar 		 * Clear the indication after LOAD_REQ is responded by the MFW.
307764515dc8STomer Tayar 		 */
307864515dc8STomer Tayar 		cdev->recov_in_prog = false;
307964515dc8STomer Tayar 
3080645874e5SSudarsana Reddy Kalluru 		qed_mcp_set_capabilities(p_hwfn, p_hwfn->p_main_ptt);
3081645874e5SSudarsana Reddy Kalluru 
30825d24bcf1STomer Tayar 		qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt);
3083fe56b9e6SYuval Mintz 
3084666db486STomer Tayar 		/* Clean up chip from previous driver if such remains exist.
3085666db486STomer Tayar 		 * This is not needed when the PF is the first one on the
3086666db486STomer Tayar 		 * engine, since afterwards we are going to init the FW.
3087666db486STomer Tayar 		 */
3088666db486STomer Tayar 		if (load_code != FW_MSG_CODE_DRV_LOAD_ENGINE) {
3089666db486STomer Tayar 			rc = qed_final_cleanup(p_hwfn, p_hwfn->p_main_ptt,
3090666db486STomer Tayar 					       p_hwfn->rel_pf_id, false);
3091666db486STomer Tayar 			if (rc) {
30922ec276d5SIgor Russkikh 				qed_hw_err_notify(p_hwfn, p_hwfn->p_main_ptt,
30932ec276d5SIgor Russkikh 						  QED_HW_ERR_RAMROD_FAIL,
30942ec276d5SIgor Russkikh 						  "Final cleanup failed\n");
3095666db486STomer Tayar 				goto load_err;
3096666db486STomer Tayar 			}
3097666db486STomer Tayar 		}
3098666db486STomer Tayar 
3099666db486STomer Tayar 		/* Log and clear previous pglue_b errors if such exist */
3100666db486STomer Tayar 		qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt);
3101666db486STomer Tayar 
3102666db486STomer Tayar 		/* Enable the PF's internal FID_enable in the PXP */
3103666db486STomer Tayar 		rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt,
3104666db486STomer Tayar 						true);
3105666db486STomer Tayar 		if (rc)
3106666db486STomer Tayar 			goto load_err;
3107666db486STomer Tayar 
3108666db486STomer Tayar 		/* Clear the pglue_b was_error indication.
3109666db486STomer Tayar 		 * In E4 it must be done after the BME and the internal
3110666db486STomer Tayar 		 * FID_enable for the PF are set, since VDMs may cause the
3111666db486STomer Tayar 		 * indication to be set again.
3112666db486STomer Tayar 		 */
3113666db486STomer Tayar 		qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt);
3114fe56b9e6SYuval Mintz 
311530d5f858SMichal Kalderon 		fw_overlays = cdev->fw_data->fw_overlays;
311630d5f858SMichal Kalderon 		fw_overlays_len = cdev->fw_data->fw_overlays_len;
311730d5f858SMichal Kalderon 		p_hwfn->fw_overlay_mem =
311830d5f858SMichal Kalderon 		    qed_fw_overlay_mem_alloc(p_hwfn, fw_overlays,
311930d5f858SMichal Kalderon 					     fw_overlays_len);
312030d5f858SMichal Kalderon 		if (!p_hwfn->fw_overlay_mem) {
312130d5f858SMichal Kalderon 			DP_NOTICE(p_hwfn,
312230d5f858SMichal Kalderon 				  "Failed to allocate fw overlay memory\n");
3123d32a06f5SDan Carpenter 			rc = -ENOMEM;
312430d5f858SMichal Kalderon 			goto load_err;
312530d5f858SMichal Kalderon 		}
312630d5f858SMichal Kalderon 
3127fe56b9e6SYuval Mintz 		switch (load_code) {
3128fe56b9e6SYuval Mintz 		case FW_MSG_CODE_DRV_LOAD_ENGINE:
3129fe56b9e6SYuval Mintz 			rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt,
3130fe56b9e6SYuval Mintz 						p_hwfn->hw_info.hw_mode);
3131fe56b9e6SYuval Mintz 			if (rc)
3132fe56b9e6SYuval Mintz 				break;
313353a42286SGustavo A. R. Silva 		/* Fall through */
3134fe56b9e6SYuval Mintz 		case FW_MSG_CODE_DRV_LOAD_PORT:
3135fe56b9e6SYuval Mintz 			rc = qed_hw_init_port(p_hwfn, p_hwfn->p_main_ptt,
3136fe56b9e6SYuval Mintz 					      p_hwfn->hw_info.hw_mode);
3137fe56b9e6SYuval Mintz 			if (rc)
3138fe56b9e6SYuval Mintz 				break;
3139fe56b9e6SYuval Mintz 
314053a42286SGustavo A. R. Silva 		/* Fall through */
3141fe56b9e6SYuval Mintz 		case FW_MSG_CODE_DRV_LOAD_FUNCTION:
3142fe56b9e6SYuval Mintz 			rc = qed_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt,
3143c0c2d0b4SMintz, Yuval 					    p_params->p_tunn,
3144c0c2d0b4SMintz, Yuval 					    p_hwfn->hw_info.hw_mode,
3145c0c2d0b4SMintz, Yuval 					    p_params->b_hw_start,
3146c0c2d0b4SMintz, Yuval 					    p_params->int_mode,
3147c0c2d0b4SMintz, Yuval 					    p_params->allow_npar_tx_switch);
3148fe56b9e6SYuval Mintz 			break;
3149fe56b9e6SYuval Mintz 		default:
3150c0c2d0b4SMintz, Yuval 			DP_NOTICE(p_hwfn,
3151c0c2d0b4SMintz, Yuval 				  "Unexpected load code [0x%08x]", load_code);
3152fe56b9e6SYuval Mintz 			rc = -EINVAL;
3153fe56b9e6SYuval Mintz 			break;
3154fe56b9e6SYuval Mintz 		}
3155fe56b9e6SYuval Mintz 
3156666db486STomer Tayar 		if (rc) {
3157fe56b9e6SYuval Mintz 			DP_NOTICE(p_hwfn,
3158fe56b9e6SYuval Mintz 				  "init phase failed for loadcode 0x%x (rc %d)\n",
3159fe56b9e6SYuval Mintz 				  load_code, rc);
3160666db486STomer Tayar 			goto load_err;
3161fe56b9e6SYuval Mintz 		}
3162fe56b9e6SYuval Mintz 
3163666db486STomer Tayar 		rc = qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt);
3164666db486STomer Tayar 		if (rc)
3165666db486STomer Tayar 			return rc;
3166fc561c8bSTomer Tayar 
316739651abdSSudarsana Reddy Kalluru 		/* send DCBX attention request command */
316839651abdSSudarsana Reddy Kalluru 		DP_VERBOSE(p_hwfn,
316939651abdSSudarsana Reddy Kalluru 			   QED_MSG_DCB,
317039651abdSSudarsana Reddy Kalluru 			   "sending phony dcbx set command to trigger DCBx attention handling\n");
3171666db486STomer Tayar 		rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
317239651abdSSudarsana Reddy Kalluru 				 DRV_MSG_CODE_SET_DCBX,
317339651abdSSudarsana Reddy Kalluru 				 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT,
3174666db486STomer Tayar 				 &resp, &param);
3175666db486STomer Tayar 		if (rc) {
317639651abdSSudarsana Reddy Kalluru 			DP_NOTICE(p_hwfn,
317739651abdSSudarsana Reddy Kalluru 				  "Failed to send DCBX attention request\n");
3178666db486STomer Tayar 			return rc;
317939651abdSSudarsana Reddy Kalluru 		}
318039651abdSSudarsana Reddy Kalluru 
3181fe56b9e6SYuval Mintz 		p_hwfn->hw_init_done = true;
3182fe56b9e6SYuval Mintz 	}
3183fe56b9e6SYuval Mintz 
31840fefbfbaSSudarsana Kalluru 	if (IS_PF(cdev)) {
31850fefbfbaSSudarsana Kalluru 		p_hwfn = QED_LEADING_HWFN(cdev);
318650fdf601SSudarsana Reddy Kalluru 
318750fdf601SSudarsana Reddy Kalluru 		/* Get pre-negotiated values for stag, bandwidth etc. */
318850fdf601SSudarsana Reddy Kalluru 		DP_VERBOSE(p_hwfn,
318950fdf601SSudarsana Reddy Kalluru 			   QED_MSG_SPQ,
319050fdf601SSudarsana Reddy Kalluru 			   "Sending GET_OEM_UPDATES command to trigger stag/bandwidth attention handling\n");
319150fdf601SSudarsana Reddy Kalluru 		drv_mb_param = 1 << DRV_MB_PARAM_DUMMY_OEM_UPDATES_OFFSET;
319250fdf601SSudarsana Reddy Kalluru 		rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
319350fdf601SSudarsana Reddy Kalluru 				 DRV_MSG_CODE_GET_OEM_UPDATES,
319450fdf601SSudarsana Reddy Kalluru 				 drv_mb_param, &resp, &param);
319550fdf601SSudarsana Reddy Kalluru 		if (rc)
319650fdf601SSudarsana Reddy Kalluru 			DP_NOTICE(p_hwfn,
319750fdf601SSudarsana Reddy Kalluru 				  "Failed to send GET_OEM_UPDATES attention request\n");
319850fdf601SSudarsana Reddy Kalluru 
31995d24bcf1STomer Tayar 		drv_mb_param = STORM_FW_VERSION;
32000fefbfbaSSudarsana Kalluru 		rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
32010fefbfbaSSudarsana Kalluru 				 DRV_MSG_CODE_OV_UPDATE_STORM_FW_VER,
32020fefbfbaSSudarsana Kalluru 				 drv_mb_param, &load_code, &param);
32030fefbfbaSSudarsana Kalluru 		if (rc)
32040fefbfbaSSudarsana Kalluru 			DP_INFO(p_hwfn, "Failed to update firmware version\n");
32050fefbfbaSSudarsana Kalluru 
32060fefbfbaSSudarsana Kalluru 		if (!b_default_mtu) {
32070fefbfbaSSudarsana Kalluru 			rc = qed_mcp_ov_update_mtu(p_hwfn, p_hwfn->p_main_ptt,
32080fefbfbaSSudarsana Kalluru 						   p_hwfn->hw_info.mtu);
32090fefbfbaSSudarsana Kalluru 			if (rc)
32100fefbfbaSSudarsana Kalluru 				DP_INFO(p_hwfn,
32110fefbfbaSSudarsana Kalluru 					"Failed to update default mtu\n");
32120fefbfbaSSudarsana Kalluru 		}
32130fefbfbaSSudarsana Kalluru 
32140fefbfbaSSudarsana Kalluru 		rc = qed_mcp_ov_update_driver_state(p_hwfn,
32150fefbfbaSSudarsana Kalluru 						    p_hwfn->p_main_ptt,
32160fefbfbaSSudarsana Kalluru 						  QED_OV_DRIVER_STATE_DISABLED);
32170fefbfbaSSudarsana Kalluru 		if (rc)
32180fefbfbaSSudarsana Kalluru 			DP_INFO(p_hwfn, "Failed to update driver state\n");
32190fefbfbaSSudarsana Kalluru 
32200fefbfbaSSudarsana Kalluru 		rc = qed_mcp_ov_update_eswitch(p_hwfn, p_hwfn->p_main_ptt,
3221538f8d00SSudarsana Reddy Kalluru 					       QED_OV_ESWITCH_NONE);
32220fefbfbaSSudarsana Kalluru 		if (rc)
32230fefbfbaSSudarsana Kalluru 			DP_INFO(p_hwfn, "Failed to update eswitch mode\n");
32240fefbfbaSSudarsana Kalluru 	}
32250fefbfbaSSudarsana Kalluru 
3226fe56b9e6SYuval Mintz 	return 0;
3227666db486STomer Tayar 
3228666db486STomer Tayar load_err:
3229666db486STomer Tayar 	/* The MFW load lock should be released also when initialization fails.
3230666db486STomer Tayar 	 */
3231666db486STomer Tayar 	qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt);
3232666db486STomer Tayar 	return rc;
3233fe56b9e6SYuval Mintz }
3234fe56b9e6SYuval Mintz 
3235fe56b9e6SYuval Mintz #define QED_HW_STOP_RETRY_LIMIT (10)
32361a635e48SYuval Mintz static void qed_hw_timers_stop(struct qed_dev *cdev,
32371a635e48SYuval Mintz 			       struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
32388c925c44SYuval Mintz {
32398c925c44SYuval Mintz 	int i;
32408c925c44SYuval Mintz 
32418c925c44SYuval Mintz 	/* close timers */
32428c925c44SYuval Mintz 	qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
32438c925c44SYuval Mintz 	qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
32448c925c44SYuval Mintz 
324564515dc8STomer Tayar 	if (cdev->recov_in_prog)
324664515dc8STomer Tayar 		return;
324764515dc8STomer Tayar 
32488c925c44SYuval Mintz 	for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
32498c925c44SYuval Mintz 		if ((!qed_rd(p_hwfn, p_ptt,
32508c925c44SYuval Mintz 			     TM_REG_PF_SCAN_ACTIVE_CONN)) &&
32511a635e48SYuval Mintz 		    (!qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK)))
32528c925c44SYuval Mintz 			break;
32538c925c44SYuval Mintz 
32548c925c44SYuval Mintz 		/* Dependent on number of connection/tasks, possibly
32558c925c44SYuval Mintz 		 * 1ms sleep is required between polls
32568c925c44SYuval Mintz 		 */
32578c925c44SYuval Mintz 		usleep_range(1000, 2000);
32588c925c44SYuval Mintz 	}
32598c925c44SYuval Mintz 
32608c925c44SYuval Mintz 	if (i < QED_HW_STOP_RETRY_LIMIT)
32618c925c44SYuval Mintz 		return;
32628c925c44SYuval Mintz 
32638c925c44SYuval Mintz 	DP_NOTICE(p_hwfn,
32648c925c44SYuval Mintz 		  "Timers linear scans are not over [Connection %02x Tasks %02x]\n",
32658c925c44SYuval Mintz 		  (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN),
32668c925c44SYuval Mintz 		  (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK));
32678c925c44SYuval Mintz }
32688c925c44SYuval Mintz 
32698c925c44SYuval Mintz void qed_hw_timers_stop_all(struct qed_dev *cdev)
32708c925c44SYuval Mintz {
32718c925c44SYuval Mintz 	int j;
32728c925c44SYuval Mintz 
32738c925c44SYuval Mintz 	for_each_hwfn(cdev, j) {
32748c925c44SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
32758c925c44SYuval Mintz 		struct qed_ptt *p_ptt = p_hwfn->p_main_ptt;
32768c925c44SYuval Mintz 
32778c925c44SYuval Mintz 		qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
32788c925c44SYuval Mintz 	}
32798c925c44SYuval Mintz }
32808c925c44SYuval Mintz 
3281fe56b9e6SYuval Mintz int qed_hw_stop(struct qed_dev *cdev)
3282fe56b9e6SYuval Mintz {
32831226337aSTomer Tayar 	struct qed_hwfn *p_hwfn;
32841226337aSTomer Tayar 	struct qed_ptt *p_ptt;
32851226337aSTomer Tayar 	int rc, rc2 = 0;
32868c925c44SYuval Mintz 	int j;
3287fe56b9e6SYuval Mintz 
3288fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, j) {
32891226337aSTomer Tayar 		p_hwfn = &cdev->hwfns[j];
32901226337aSTomer Tayar 		p_ptt = p_hwfn->p_main_ptt;
3291fe56b9e6SYuval Mintz 
3292fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_IFDOWN, "Stopping hw/fw\n");
3293fe56b9e6SYuval Mintz 
32941408cc1fSYuval Mintz 		if (IS_VF(cdev)) {
32950b55e27dSYuval Mintz 			qed_vf_pf_int_cleanup(p_hwfn);
32961226337aSTomer Tayar 			rc = qed_vf_pf_reset(p_hwfn);
32971226337aSTomer Tayar 			if (rc) {
32981226337aSTomer Tayar 				DP_NOTICE(p_hwfn,
32991226337aSTomer Tayar 					  "qed_vf_pf_reset failed. rc = %d.\n",
33001226337aSTomer Tayar 					  rc);
33011226337aSTomer Tayar 				rc2 = -EINVAL;
33021226337aSTomer Tayar 			}
33031408cc1fSYuval Mintz 			continue;
33041408cc1fSYuval Mintz 		}
33051408cc1fSYuval Mintz 
3306fe56b9e6SYuval Mintz 		/* mark the hw as uninitialized... */
3307fe56b9e6SYuval Mintz 		p_hwfn->hw_init_done = false;
3308fe56b9e6SYuval Mintz 
33091226337aSTomer Tayar 		/* Send unload command to MCP */
331064515dc8STomer Tayar 		if (!cdev->recov_in_prog) {
33111226337aSTomer Tayar 			rc = qed_mcp_unload_req(p_hwfn, p_ptt);
33121226337aSTomer Tayar 			if (rc) {
33138c925c44SYuval Mintz 				DP_NOTICE(p_hwfn,
33141226337aSTomer Tayar 					  "Failed sending a UNLOAD_REQ command. rc = %d.\n",
33151226337aSTomer Tayar 					  rc);
33161226337aSTomer Tayar 				rc2 = -EINVAL;
33171226337aSTomer Tayar 			}
331864515dc8STomer Tayar 		}
33191226337aSTomer Tayar 
33201226337aSTomer Tayar 		qed_slowpath_irq_sync(p_hwfn);
33211226337aSTomer Tayar 
33221226337aSTomer Tayar 		/* After this point no MFW attentions are expected, e.g. prevent
33231226337aSTomer Tayar 		 * race between pf stop and dcbx pf update.
33241226337aSTomer Tayar 		 */
33251226337aSTomer Tayar 		rc = qed_sp_pf_stop(p_hwfn);
33261226337aSTomer Tayar 		if (rc) {
33271226337aSTomer Tayar 			DP_NOTICE(p_hwfn,
33281226337aSTomer Tayar 				  "Failed to close PF against FW [rc = %d]. Continue to stop HW to prevent illegal host access by the device.\n",
33291226337aSTomer Tayar 				  rc);
33301226337aSTomer Tayar 			rc2 = -EINVAL;
33311226337aSTomer Tayar 		}
3332fe56b9e6SYuval Mintz 
3333fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt,
3334fe56b9e6SYuval Mintz 		       NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1);
3335fe56b9e6SYuval Mintz 
3336fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
3337fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0);
3338fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0);
3339fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
3340fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
3341fe56b9e6SYuval Mintz 
33428c925c44SYuval Mintz 		qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
3343fe56b9e6SYuval Mintz 
3344fe56b9e6SYuval Mintz 		/* Disable Attention Generation */
3345fe56b9e6SYuval Mintz 		qed_int_igu_disable_int(p_hwfn, p_ptt);
3346fe56b9e6SYuval Mintz 
3347fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0);
3348fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0);
3349fe56b9e6SYuval Mintz 
3350fe56b9e6SYuval Mintz 		qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, true);
3351fe56b9e6SYuval Mintz 
3352fe56b9e6SYuval Mintz 		/* Need to wait 1ms to guarantee SBs are cleared */
3353fe56b9e6SYuval Mintz 		usleep_range(1000, 2000);
33541226337aSTomer Tayar 
33551226337aSTomer Tayar 		/* Disable PF in HW blocks */
33561226337aSTomer Tayar 		qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DB_ENABLE, 0);
33571226337aSTomer Tayar 		qed_wr(p_hwfn, p_ptt, QM_REG_PF_EN, 0);
33581226337aSTomer Tayar 
335979284adeSMichal Kalderon 		if (IS_LEAD_HWFN(p_hwfn) &&
336079284adeSMichal Kalderon 		    test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) &&
336179284adeSMichal Kalderon 		    !QED_IS_FCOE_PERSONALITY(p_hwfn))
336279284adeSMichal Kalderon 			qed_llh_remove_mac_filter(cdev, 0,
336379284adeSMichal Kalderon 						  p_hwfn->hw_info.hw_mac_addr);
336479284adeSMichal Kalderon 
336564515dc8STomer Tayar 		if (!cdev->recov_in_prog) {
336664515dc8STomer Tayar 			rc = qed_mcp_unload_done(p_hwfn, p_ptt);
33671226337aSTomer Tayar 			if (rc) {
33681226337aSTomer Tayar 				DP_NOTICE(p_hwfn,
33691226337aSTomer Tayar 					  "Failed sending a UNLOAD_DONE command. rc = %d.\n",
33701226337aSTomer Tayar 					  rc);
33711226337aSTomer Tayar 				rc2 = -EINVAL;
33721226337aSTomer Tayar 			}
3373fe56b9e6SYuval Mintz 		}
337464515dc8STomer Tayar 	}
3375fe56b9e6SYuval Mintz 
337664515dc8STomer Tayar 	if (IS_PF(cdev) && !cdev->recov_in_prog) {
33771226337aSTomer Tayar 		p_hwfn = QED_LEADING_HWFN(cdev);
33781226337aSTomer Tayar 		p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt;
33791226337aSTomer Tayar 
3380666db486STomer Tayar 		/* Clear the PF's internal FID_enable in the PXP.
3381666db486STomer Tayar 		 * In CMT this should only be done for first hw-function, and
3382666db486STomer Tayar 		 * only after all transactions have stopped for all active
3383666db486STomer Tayar 		 * hw-functions.
3384fe56b9e6SYuval Mintz 		 */
3385666db486STomer Tayar 		rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false);
33861226337aSTomer Tayar 		if (rc) {
33871226337aSTomer Tayar 			DP_NOTICE(p_hwfn,
3388666db486STomer Tayar 				  "qed_pglueb_set_pfid_enable() failed. rc = %d.\n",
3389666db486STomer Tayar 				  rc);
33901226337aSTomer Tayar 			rc2 = -EINVAL;
33911226337aSTomer Tayar 		}
33921408cc1fSYuval Mintz 	}
3393fe56b9e6SYuval Mintz 
33941226337aSTomer Tayar 	return rc2;
3395fe56b9e6SYuval Mintz }
3396fe56b9e6SYuval Mintz 
339715582962SRahul Verma int qed_hw_stop_fastpath(struct qed_dev *cdev)
3398cee4d264SManish Chopra {
33998c925c44SYuval Mintz 	int j;
3400cee4d264SManish Chopra 
3401cee4d264SManish Chopra 	for_each_hwfn(cdev, j) {
3402cee4d264SManish Chopra 		struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
340315582962SRahul Verma 		struct qed_ptt *p_ptt;
3404cee4d264SManish Chopra 
3405dacd88d6SYuval Mintz 		if (IS_VF(cdev)) {
3406dacd88d6SYuval Mintz 			qed_vf_pf_int_cleanup(p_hwfn);
3407dacd88d6SYuval Mintz 			continue;
3408dacd88d6SYuval Mintz 		}
340915582962SRahul Verma 		p_ptt = qed_ptt_acquire(p_hwfn);
341015582962SRahul Verma 		if (!p_ptt)
341115582962SRahul Verma 			return -EAGAIN;
3412dacd88d6SYuval Mintz 
3413cee4d264SManish Chopra 		DP_VERBOSE(p_hwfn,
34141a635e48SYuval Mintz 			   NETIF_MSG_IFDOWN, "Shutting down the fastpath\n");
3415cee4d264SManish Chopra 
3416cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt,
3417cee4d264SManish Chopra 		       NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1);
3418cee4d264SManish Chopra 
3419cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
3420cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0);
3421cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0);
3422cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
3423cee4d264SManish Chopra 		qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
3424cee4d264SManish Chopra 
3425cee4d264SManish Chopra 		qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, false);
3426cee4d264SManish Chopra 
3427cee4d264SManish Chopra 		/* Need to wait 1ms to guarantee SBs are cleared */
3428cee4d264SManish Chopra 		usleep_range(1000, 2000);
342915582962SRahul Verma 		qed_ptt_release(p_hwfn, p_ptt);
3430cee4d264SManish Chopra 	}
3431cee4d264SManish Chopra 
343215582962SRahul Verma 	return 0;
343315582962SRahul Verma }
343415582962SRahul Verma 
343515582962SRahul Verma int qed_hw_start_fastpath(struct qed_hwfn *p_hwfn)
3436cee4d264SManish Chopra {
343715582962SRahul Verma 	struct qed_ptt *p_ptt;
343815582962SRahul Verma 
3439dacd88d6SYuval Mintz 	if (IS_VF(p_hwfn->cdev))
344015582962SRahul Verma 		return 0;
344115582962SRahul Verma 
344215582962SRahul Verma 	p_ptt = qed_ptt_acquire(p_hwfn);
344315582962SRahul Verma 	if (!p_ptt)
344415582962SRahul Verma 		return -EAGAIN;
3445dacd88d6SYuval Mintz 
3446f855df22SMichal Kalderon 	if (p_hwfn->p_rdma_info &&
3447291d57f6SMichal Kalderon 	    p_hwfn->p_rdma_info->active && p_hwfn->b_rdma_enabled_in_prs)
3448f855df22SMichal Kalderon 		qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0x1);
3449f855df22SMichal Kalderon 
3450cee4d264SManish Chopra 	/* Re-open incoming traffic */
345115582962SRahul Verma 	qed_wr(p_hwfn, p_ptt, NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x0);
345215582962SRahul Verma 	qed_ptt_release(p_hwfn, p_ptt);
345315582962SRahul Verma 
345415582962SRahul Verma 	return 0;
3455cee4d264SManish Chopra }
3456cee4d264SManish Chopra 
3457fe56b9e6SYuval Mintz /* Free hwfn memory and resources acquired in hw_hwfn_prepare */
3458fe56b9e6SYuval Mintz static void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn)
3459fe56b9e6SYuval Mintz {
3460fe56b9e6SYuval Mintz 	qed_ptt_pool_free(p_hwfn);
3461fe56b9e6SYuval Mintz 	kfree(p_hwfn->hw_info.p_igu_info);
34623587cb87STomer Tayar 	p_hwfn->hw_info.p_igu_info = NULL;
3463fe56b9e6SYuval Mintz }
3464fe56b9e6SYuval Mintz 
3465fe56b9e6SYuval Mintz /* Setup bar access */
346612e09c69SYuval Mintz static void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn)
3467fe56b9e6SYuval Mintz {
3468fe56b9e6SYuval Mintz 	/* clear indirect access */
34699c79ddaaSMintz, Yuval 	if (QED_IS_AH(p_hwfn->cdev)) {
34709c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34719c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_E8_F0_K2, 0);
34729c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34739c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_EC_F0_K2, 0);
34749c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34759c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_F0_F0_K2, 0);
34769c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34779c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_F4_F0_K2, 0);
34789c79ddaaSMintz, Yuval 	} else {
34799c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34809c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_88_F0_BB, 0);
34819c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34829c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_8C_F0_BB, 0);
34839c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34849c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_90_F0_BB, 0);
34859c79ddaaSMintz, Yuval 		qed_wr(p_hwfn, p_hwfn->p_main_ptt,
34869c79ddaaSMintz, Yuval 		       PGLUE_B_REG_PGL_ADDR_94_F0_BB, 0);
34879c79ddaaSMintz, Yuval 	}
3488fe56b9e6SYuval Mintz 
3489666db486STomer Tayar 	/* Clean previous pglue_b errors if such exist */
3490666db486STomer Tayar 	qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt);
3491fe56b9e6SYuval Mintz 
3492fe56b9e6SYuval Mintz 	/* enable internal target-read */
3493fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_hwfn->p_main_ptt,
3494fe56b9e6SYuval Mintz 	       PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
3495fe56b9e6SYuval Mintz }
3496fe56b9e6SYuval Mintz 
3497fe56b9e6SYuval Mintz static void get_function_id(struct qed_hwfn *p_hwfn)
3498fe56b9e6SYuval Mintz {
3499fe56b9e6SYuval Mintz 	/* ME Register */
35001a635e48SYuval Mintz 	p_hwfn->hw_info.opaque_fid = (u16) REG_RD(p_hwfn,
35011a635e48SYuval Mintz 						  PXP_PF_ME_OPAQUE_ADDR);
3502fe56b9e6SYuval Mintz 
3503fe56b9e6SYuval Mintz 	p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, PXP_PF_ME_CONCRETE_ADDR);
3504fe56b9e6SYuval Mintz 
3505fe56b9e6SYuval Mintz 	p_hwfn->abs_pf_id = (p_hwfn->hw_info.concrete_fid >> 16) & 0xf;
3506fe56b9e6SYuval Mintz 	p_hwfn->rel_pf_id = GET_FIELD(p_hwfn->hw_info.concrete_fid,
3507fe56b9e6SYuval Mintz 				      PXP_CONCRETE_FID_PFID);
3508fe56b9e6SYuval Mintz 	p_hwfn->port_id = GET_FIELD(p_hwfn->hw_info.concrete_fid,
3509fe56b9e6SYuval Mintz 				    PXP_CONCRETE_FID_PORT);
3510525ef5c0SYuval Mintz 
3511525ef5c0SYuval Mintz 	DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE,
3512525ef5c0SYuval Mintz 		   "Read ME register: Concrete 0x%08x Opaque 0x%04x\n",
3513525ef5c0SYuval Mintz 		   p_hwfn->hw_info.concrete_fid, p_hwfn->hw_info.opaque_fid);
3514fe56b9e6SYuval Mintz }
3515fe56b9e6SYuval Mintz 
351625c089d7SYuval Mintz static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
351725c089d7SYuval Mintz {
351825c089d7SYuval Mintz 	u32 *feat_num = p_hwfn->hw_info.feat_num;
3519ebbdcc66SMintz, Yuval 	struct qed_sb_cnt_info sb_cnt;
3520810bb1f0SMintz, Yuval 	u32 non_l2_sbs = 0;
352125c089d7SYuval Mintz 
3522ebbdcc66SMintz, Yuval 	memset(&sb_cnt, 0, sizeof(sb_cnt));
3523ebbdcc66SMintz, Yuval 	qed_int_get_num_sbs(p_hwfn, &sb_cnt);
3524ebbdcc66SMintz, Yuval 
35250189efb8SYuval Mintz 	if (IS_ENABLED(CONFIG_QED_RDMA) &&
3526c851a9dcSKalderon, Michal 	    QED_IS_RDMA_PERSONALITY(p_hwfn)) {
35270189efb8SYuval Mintz 		/* Roce CNQ each requires: 1 status block + 1 CNQ. We divide
35280189efb8SYuval Mintz 		 * the status blocks equally between L2 / RoCE but with
35290189efb8SYuval Mintz 		 * consideration as to how many l2 queues / cnqs we have.
353051ff1725SRam Amrani 		 */
353151ff1725SRam Amrani 		feat_num[QED_RDMA_CNQ] =
3532ebbdcc66SMintz, Yuval 			min_t(u32, sb_cnt.cnt / 2,
353351ff1725SRam Amrani 			      RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM));
3534810bb1f0SMintz, Yuval 
3535810bb1f0SMintz, Yuval 		non_l2_sbs = feat_num[QED_RDMA_CNQ];
353651ff1725SRam Amrani 	}
3537c851a9dcSKalderon, Michal 	if (QED_IS_L2_PERSONALITY(p_hwfn)) {
3538dec26533SMintz, Yuval 		/* Start by allocating VF queues, then PF's */
3539dec26533SMintz, Yuval 		feat_num[QED_VF_L2_QUE] = min_t(u32,
3540dec26533SMintz, Yuval 						RESC_NUM(p_hwfn, QED_L2_QUEUE),
3541ebbdcc66SMintz, Yuval 						sb_cnt.iov_cnt);
3542810bb1f0SMintz, Yuval 		feat_num[QED_PF_L2_QUE] = min_t(u32,
3543ebbdcc66SMintz, Yuval 						sb_cnt.cnt - non_l2_sbs,
3544dec26533SMintz, Yuval 						RESC_NUM(p_hwfn,
3545dec26533SMintz, Yuval 							 QED_L2_QUEUE) -
3546dec26533SMintz, Yuval 						FEAT_NUM(p_hwfn,
3547dec26533SMintz, Yuval 							 QED_VF_L2_QUE));
3548dec26533SMintz, Yuval 	}
35495a1f965aSMintz, Yuval 
3550c851a9dcSKalderon, Michal 	if (QED_IS_FCOE_PERSONALITY(p_hwfn))
35513c5da942SMintz, Yuval 		feat_num[QED_FCOE_CQ] =  min_t(u32, sb_cnt.cnt,
35523c5da942SMintz, Yuval 					       RESC_NUM(p_hwfn,
35533c5da942SMintz, Yuval 							QED_CMDQS_CQS));
35543c5da942SMintz, Yuval 
3555c851a9dcSKalderon, Michal 	if (QED_IS_ISCSI_PERSONALITY(p_hwfn))
3556ebbdcc66SMintz, Yuval 		feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt,
355708737a3fSMintz, Yuval 					       RESC_NUM(p_hwfn,
355808737a3fSMintz, Yuval 							QED_CMDQS_CQS));
35595a1f965aSMintz, Yuval 	DP_VERBOSE(p_hwfn,
35605a1f965aSMintz, Yuval 		   NETIF_MSG_PROBE,
35613c5da942SMintz, Yuval 		   "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d #SBS=%d\n",
35625a1f965aSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE),
35635a1f965aSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE),
35645a1f965aSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ),
35653c5da942SMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_FCOE_CQ),
356608737a3fSMintz, Yuval 		   (int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ),
3567ebbdcc66SMintz, Yuval 		   (int)sb_cnt.cnt);
356825c089d7SYuval Mintz }
356925c089d7SYuval Mintz 
35709c8517c4STomer Tayar const char *qed_hw_get_resc_name(enum qed_resources res_id)
35712edbff8dSTomer Tayar {
35722edbff8dSTomer Tayar 	switch (res_id) {
35732edbff8dSTomer Tayar 	case QED_L2_QUEUE:
35742edbff8dSTomer Tayar 		return "L2_QUEUE";
35752edbff8dSTomer Tayar 	case QED_VPORT:
35762edbff8dSTomer Tayar 		return "VPORT";
35772edbff8dSTomer Tayar 	case QED_RSS_ENG:
35782edbff8dSTomer Tayar 		return "RSS_ENG";
35792edbff8dSTomer Tayar 	case QED_PQ:
35802edbff8dSTomer Tayar 		return "PQ";
35812edbff8dSTomer Tayar 	case QED_RL:
35822edbff8dSTomer Tayar 		return "RL";
35832edbff8dSTomer Tayar 	case QED_MAC:
35842edbff8dSTomer Tayar 		return "MAC";
35852edbff8dSTomer Tayar 	case QED_VLAN:
35862edbff8dSTomer Tayar 		return "VLAN";
35872edbff8dSTomer Tayar 	case QED_RDMA_CNQ_RAM:
35882edbff8dSTomer Tayar 		return "RDMA_CNQ_RAM";
35892edbff8dSTomer Tayar 	case QED_ILT:
35902edbff8dSTomer Tayar 		return "ILT";
3591997af5dfSMichal Kalderon 	case QED_LL2_RAM_QUEUE:
3592997af5dfSMichal Kalderon 		return "LL2_RAM_QUEUE";
3593997af5dfSMichal Kalderon 	case QED_LL2_CTX_QUEUE:
3594997af5dfSMichal Kalderon 		return "LL2_CTX_QUEUE";
35952edbff8dSTomer Tayar 	case QED_CMDQS_CQS:
35962edbff8dSTomer Tayar 		return "CMDQS_CQS";
35972edbff8dSTomer Tayar 	case QED_RDMA_STATS_QUEUE:
35982edbff8dSTomer Tayar 		return "RDMA_STATS_QUEUE";
35999c8517c4STomer Tayar 	case QED_BDQ:
36009c8517c4STomer Tayar 		return "BDQ";
36019c8517c4STomer Tayar 	case QED_SB:
36029c8517c4STomer Tayar 		return "SB";
36032edbff8dSTomer Tayar 	default:
36042edbff8dSTomer Tayar 		return "UNKNOWN_RESOURCE";
36052edbff8dSTomer Tayar 	}
36062edbff8dSTomer Tayar }
36072edbff8dSTomer Tayar 
36089c8517c4STomer Tayar static int
36099c8517c4STomer Tayar __qed_hw_set_soft_resc_size(struct qed_hwfn *p_hwfn,
36109c8517c4STomer Tayar 			    struct qed_ptt *p_ptt,
36119c8517c4STomer Tayar 			    enum qed_resources res_id,
36129c8517c4STomer Tayar 			    u32 resc_max_val, u32 *p_mcp_resp)
36139c8517c4STomer Tayar {
36149c8517c4STomer Tayar 	int rc;
36159c8517c4STomer Tayar 
36169c8517c4STomer Tayar 	rc = qed_mcp_set_resc_max_val(p_hwfn, p_ptt, res_id,
36179c8517c4STomer Tayar 				      resc_max_val, p_mcp_resp);
36189c8517c4STomer Tayar 	if (rc) {
36199c8517c4STomer Tayar 		DP_NOTICE(p_hwfn,
36209c8517c4STomer Tayar 			  "MFW response failure for a max value setting of resource %d [%s]\n",
36219c8517c4STomer Tayar 			  res_id, qed_hw_get_resc_name(res_id));
36229c8517c4STomer Tayar 		return rc;
36239c8517c4STomer Tayar 	}
36249c8517c4STomer Tayar 
36259c8517c4STomer Tayar 	if (*p_mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK)
36269c8517c4STomer Tayar 		DP_INFO(p_hwfn,
36279c8517c4STomer Tayar 			"Failed to set the max value of resource %d [%s]. mcp_resp = 0x%08x.\n",
36289c8517c4STomer Tayar 			res_id, qed_hw_get_resc_name(res_id), *p_mcp_resp);
36299c8517c4STomer Tayar 
36309c8517c4STomer Tayar 	return 0;
36319c8517c4STomer Tayar }
36329c8517c4STomer Tayar 
36331392d19fSMichal Kalderon static u32 qed_hsi_def_val[][MAX_CHIP_IDS] = {
36341392d19fSMichal Kalderon 	{MAX_NUM_VFS_BB, MAX_NUM_VFS_K2},
36351392d19fSMichal Kalderon 	{MAX_NUM_L2_QUEUES_BB, MAX_NUM_L2_QUEUES_K2},
36361392d19fSMichal Kalderon 	{MAX_NUM_PORTS_BB, MAX_NUM_PORTS_K2},
36371392d19fSMichal Kalderon 	{MAX_SB_PER_PATH_BB, MAX_SB_PER_PATH_K2,},
36381392d19fSMichal Kalderon 	{MAX_NUM_PFS_BB, MAX_NUM_PFS_K2},
36391392d19fSMichal Kalderon 	{MAX_NUM_VPORTS_BB, MAX_NUM_VPORTS_K2},
36401392d19fSMichal Kalderon 	{ETH_RSS_ENGINE_NUM_BB, ETH_RSS_ENGINE_NUM_K2},
36411392d19fSMichal Kalderon 	{MAX_QM_TX_QUEUES_BB, MAX_QM_TX_QUEUES_K2},
36421392d19fSMichal Kalderon 	{PXP_NUM_ILT_RECORDS_BB, PXP_NUM_ILT_RECORDS_K2},
36431392d19fSMichal Kalderon 	{RDMA_NUM_STATISTIC_COUNTERS_BB, RDMA_NUM_STATISTIC_COUNTERS_K2},
36441392d19fSMichal Kalderon 	{MAX_QM_GLOBAL_RLS, MAX_QM_GLOBAL_RLS},
36451392d19fSMichal Kalderon 	{PBF_MAX_CMD_LINES, PBF_MAX_CMD_LINES},
36461392d19fSMichal Kalderon 	{BTB_MAX_BLOCKS_BB, BTB_MAX_BLOCKS_K2},
36471392d19fSMichal Kalderon };
36481392d19fSMichal Kalderon 
36491392d19fSMichal Kalderon u32 qed_get_hsi_def_val(struct qed_dev *cdev, enum qed_hsi_def_type type)
36501392d19fSMichal Kalderon {
36511392d19fSMichal Kalderon 	enum chip_ids chip_id = QED_IS_BB(cdev) ? CHIP_BB : CHIP_K2;
36521392d19fSMichal Kalderon 
36531392d19fSMichal Kalderon 	if (type >= QED_NUM_HSI_DEFS) {
36541392d19fSMichal Kalderon 		DP_ERR(cdev, "Unexpected HSI definition type [%d]\n", type);
36551392d19fSMichal Kalderon 		return 0;
36561392d19fSMichal Kalderon 	}
36571392d19fSMichal Kalderon 
36581392d19fSMichal Kalderon 	return qed_hsi_def_val[type][chip_id];
36591392d19fSMichal Kalderon }
36609c8517c4STomer Tayar static int
36619c8517c4STomer Tayar qed_hw_set_soft_resc_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
36629c8517c4STomer Tayar {
36639c8517c4STomer Tayar 	u32 resc_max_val, mcp_resp;
36649c8517c4STomer Tayar 	u8 res_id;
36659c8517c4STomer Tayar 	int rc;
36669c8517c4STomer Tayar 	for (res_id = 0; res_id < QED_MAX_RESC; res_id++) {
36679c8517c4STomer Tayar 		switch (res_id) {
3668997af5dfSMichal Kalderon 		case QED_LL2_RAM_QUEUE:
3669997af5dfSMichal Kalderon 			resc_max_val = MAX_NUM_LL2_RX_RAM_QUEUES;
3670997af5dfSMichal Kalderon 			break;
3671997af5dfSMichal Kalderon 		case QED_LL2_CTX_QUEUE:
3672997af5dfSMichal Kalderon 			resc_max_val = MAX_NUM_LL2_RX_CTX_QUEUES;
36739c8517c4STomer Tayar 			break;
36749c8517c4STomer Tayar 		case QED_RDMA_CNQ_RAM:
36759c8517c4STomer Tayar 			/* No need for a case for QED_CMDQS_CQS since
36769c8517c4STomer Tayar 			 * CNQ/CMDQS are the same resource.
36779c8517c4STomer Tayar 			 */
3678da090917STomer Tayar 			resc_max_val = NUM_OF_GLOBAL_QUEUES;
36799c8517c4STomer Tayar 			break;
36809c8517c4STomer Tayar 		case QED_RDMA_STATS_QUEUE:
36811392d19fSMichal Kalderon 			resc_max_val =
36821392d19fSMichal Kalderon 			    NUM_OF_RDMA_STATISTIC_COUNTERS(p_hwfn->cdev);
36839c8517c4STomer Tayar 			break;
36849c8517c4STomer Tayar 		case QED_BDQ:
36859c8517c4STomer Tayar 			resc_max_val = BDQ_NUM_RESOURCES;
36869c8517c4STomer Tayar 			break;
36879c8517c4STomer Tayar 		default:
36889c8517c4STomer Tayar 			continue;
36899c8517c4STomer Tayar 		}
36909c8517c4STomer Tayar 
36919c8517c4STomer Tayar 		rc = __qed_hw_set_soft_resc_size(p_hwfn, p_ptt, res_id,
36929c8517c4STomer Tayar 						 resc_max_val, &mcp_resp);
36939c8517c4STomer Tayar 		if (rc)
36949c8517c4STomer Tayar 			return rc;
36959c8517c4STomer Tayar 
36969c8517c4STomer Tayar 		/* There's no point to continue to the next resource if the
36979c8517c4STomer Tayar 		 * command is not supported by the MFW.
36989c8517c4STomer Tayar 		 * We do continue if the command is supported but the resource
36999c8517c4STomer Tayar 		 * is unknown to the MFW. Such a resource will be later
37009c8517c4STomer Tayar 		 * configured with the default allocation values.
37019c8517c4STomer Tayar 		 */
37029c8517c4STomer Tayar 		if (mcp_resp == FW_MSG_CODE_UNSUPPORTED)
37039c8517c4STomer Tayar 			return -EINVAL;
37049c8517c4STomer Tayar 	}
37059c8517c4STomer Tayar 
37069c8517c4STomer Tayar 	return 0;
37079c8517c4STomer Tayar }
37089c8517c4STomer Tayar 
37099c8517c4STomer Tayar static
37109c8517c4STomer Tayar int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn,
37119c8517c4STomer Tayar 			 enum qed_resources res_id,
37129c8517c4STomer Tayar 			 u32 *p_resc_num, u32 *p_resc_start)
37139c8517c4STomer Tayar {
37149c8517c4STomer Tayar 	u8 num_funcs = p_hwfn->num_funcs_on_engine;
37151392d19fSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
37169c8517c4STomer Tayar 
37179c8517c4STomer Tayar 	switch (res_id) {
37189c8517c4STomer Tayar 	case QED_L2_QUEUE:
37191392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_L2_QUEUES(cdev) / num_funcs;
37209c8517c4STomer Tayar 		break;
37219c8517c4STomer Tayar 	case QED_VPORT:
37221392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_VPORTS(cdev) / num_funcs;
37239c8517c4STomer Tayar 		break;
37249c8517c4STomer Tayar 	case QED_RSS_ENG:
37251392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_RSS_ENGINES(cdev) / num_funcs;
37269c8517c4STomer Tayar 		break;
37279c8517c4STomer Tayar 	case QED_PQ:
37281392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_QM_TX_QUEUES(cdev) / num_funcs;
37299c8517c4STomer Tayar 		*p_resc_num &= ~0x7;	/* The granularity of the PQs is 8 */
37309c8517c4STomer Tayar 		break;
37319c8517c4STomer Tayar 	case QED_RL:
37321392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_QM_GLOBAL_RLS(cdev) / num_funcs;
37339c8517c4STomer Tayar 		break;
37349c8517c4STomer Tayar 	case QED_MAC:
37359c8517c4STomer Tayar 	case QED_VLAN:
37369c8517c4STomer Tayar 		/* Each VFC resource can accommodate both a MAC and a VLAN */
37379c8517c4STomer Tayar 		*p_resc_num = ETH_NUM_MAC_FILTERS / num_funcs;
37389c8517c4STomer Tayar 		break;
37399c8517c4STomer Tayar 	case QED_ILT:
37401392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_PXP_ILT_RECORDS(cdev) / num_funcs;
37419c8517c4STomer Tayar 		break;
3742997af5dfSMichal Kalderon 	case QED_LL2_RAM_QUEUE:
3743997af5dfSMichal Kalderon 		*p_resc_num = MAX_NUM_LL2_RX_RAM_QUEUES / num_funcs;
3744997af5dfSMichal Kalderon 		break;
3745997af5dfSMichal Kalderon 	case QED_LL2_CTX_QUEUE:
3746997af5dfSMichal Kalderon 		*p_resc_num = MAX_NUM_LL2_RX_CTX_QUEUES / num_funcs;
37479c8517c4STomer Tayar 		break;
37489c8517c4STomer Tayar 	case QED_RDMA_CNQ_RAM:
37499c8517c4STomer Tayar 	case QED_CMDQS_CQS:
37509c8517c4STomer Tayar 		/* CNQ/CMDQS are the same resource */
3751da090917STomer Tayar 		*p_resc_num = NUM_OF_GLOBAL_QUEUES / num_funcs;
37529c8517c4STomer Tayar 		break;
37539c8517c4STomer Tayar 	case QED_RDMA_STATS_QUEUE:
37541392d19fSMichal Kalderon 		*p_resc_num = NUM_OF_RDMA_STATISTIC_COUNTERS(cdev) / num_funcs;
37559c8517c4STomer Tayar 		break;
37569c8517c4STomer Tayar 	case QED_BDQ:
37579c8517c4STomer Tayar 		if (p_hwfn->hw_info.personality != QED_PCI_ISCSI &&
37589c8517c4STomer Tayar 		    p_hwfn->hw_info.personality != QED_PCI_FCOE)
37599c8517c4STomer Tayar 			*p_resc_num = 0;
37609c8517c4STomer Tayar 		else
37619c8517c4STomer Tayar 			*p_resc_num = 1;
37629c8517c4STomer Tayar 		break;
37639c8517c4STomer Tayar 	case QED_SB:
3764ebbdcc66SMintz, Yuval 		/* Since we want its value to reflect whether MFW supports
3765ebbdcc66SMintz, Yuval 		 * the new scheme, have a default of 0.
3766ebbdcc66SMintz, Yuval 		 */
3767ebbdcc66SMintz, Yuval 		*p_resc_num = 0;
37689c8517c4STomer Tayar 		break;
37699c8517c4STomer Tayar 	default:
37709c8517c4STomer Tayar 		return -EINVAL;
37719c8517c4STomer Tayar 	}
37729c8517c4STomer Tayar 
37739c8517c4STomer Tayar 	switch (res_id) {
37749c8517c4STomer Tayar 	case QED_BDQ:
37759c8517c4STomer Tayar 		if (!*p_resc_num)
37769c8517c4STomer Tayar 			*p_resc_start = 0;
377778cea9ffSTomer Tayar 		else if (p_hwfn->cdev->num_ports_in_engine == 4)
37789c8517c4STomer Tayar 			*p_resc_start = p_hwfn->port_id;
37799c8517c4STomer Tayar 		else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI)
37809c8517c4STomer Tayar 			*p_resc_start = p_hwfn->port_id;
37819c8517c4STomer Tayar 		else if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
37829c8517c4STomer Tayar 			*p_resc_start = p_hwfn->port_id + 2;
37839c8517c4STomer Tayar 		break;
37849c8517c4STomer Tayar 	default:
37859c8517c4STomer Tayar 		*p_resc_start = *p_resc_num * p_hwfn->enabled_func_idx;
37869c8517c4STomer Tayar 		break;
37879c8517c4STomer Tayar 	}
37889c8517c4STomer Tayar 
37899c8517c4STomer Tayar 	return 0;
37909c8517c4STomer Tayar }
37919c8517c4STomer Tayar 
37929c8517c4STomer Tayar static int __qed_hw_set_resc_info(struct qed_hwfn *p_hwfn,
37932edbff8dSTomer Tayar 				  enum qed_resources res_id)
37942edbff8dSTomer Tayar {
37959c8517c4STomer Tayar 	u32 dflt_resc_num = 0, dflt_resc_start = 0;
37969c8517c4STomer Tayar 	u32 mcp_resp, *p_resc_num, *p_resc_start;
37972edbff8dSTomer Tayar 	int rc;
37982edbff8dSTomer Tayar 
37992edbff8dSTomer Tayar 	p_resc_num = &RESC_NUM(p_hwfn, res_id);
38002edbff8dSTomer Tayar 	p_resc_start = &RESC_START(p_hwfn, res_id);
38012edbff8dSTomer Tayar 
38029c8517c4STomer Tayar 	rc = qed_hw_get_dflt_resc(p_hwfn, res_id, &dflt_resc_num,
38039c8517c4STomer Tayar 				  &dflt_resc_start);
38049c8517c4STomer Tayar 	if (rc) {
38052edbff8dSTomer Tayar 		DP_ERR(p_hwfn,
38062edbff8dSTomer Tayar 		       "Failed to get default amount for resource %d [%s]\n",
38072edbff8dSTomer Tayar 		       res_id, qed_hw_get_resc_name(res_id));
38089c8517c4STomer Tayar 		return rc;
38092edbff8dSTomer Tayar 	}
38102edbff8dSTomer Tayar 
38119c8517c4STomer Tayar 	rc = qed_mcp_get_resc_info(p_hwfn, p_hwfn->p_main_ptt, res_id,
38129c8517c4STomer Tayar 				   &mcp_resp, p_resc_num, p_resc_start);
38132edbff8dSTomer Tayar 	if (rc) {
38142edbff8dSTomer Tayar 		DP_NOTICE(p_hwfn,
38152edbff8dSTomer Tayar 			  "MFW response failure for an allocation request for resource %d [%s]\n",
38162edbff8dSTomer Tayar 			  res_id, qed_hw_get_resc_name(res_id));
38172edbff8dSTomer Tayar 		return rc;
38182edbff8dSTomer Tayar 	}
38192edbff8dSTomer Tayar 
38202edbff8dSTomer Tayar 	/* Default driver values are applied in the following cases:
38212edbff8dSTomer Tayar 	 * - The resource allocation MB command is not supported by the MFW
38222edbff8dSTomer Tayar 	 * - There is an internal error in the MFW while processing the request
38232edbff8dSTomer Tayar 	 * - The resource ID is unknown to the MFW
38242edbff8dSTomer Tayar 	 */
38259c8517c4STomer Tayar 	if (mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK) {
38269c8517c4STomer Tayar 		DP_INFO(p_hwfn,
38279c8517c4STomer Tayar 			"Failed to receive allocation info for resource %d [%s]. mcp_resp = 0x%x. Applying default values [%d,%d].\n",
38282edbff8dSTomer Tayar 			res_id,
38292edbff8dSTomer Tayar 			qed_hw_get_resc_name(res_id),
38302edbff8dSTomer Tayar 			mcp_resp, dflt_resc_num, dflt_resc_start);
38312edbff8dSTomer Tayar 		*p_resc_num = dflt_resc_num;
38322edbff8dSTomer Tayar 		*p_resc_start = dflt_resc_start;
38332edbff8dSTomer Tayar 		goto out;
38342edbff8dSTomer Tayar 	}
38352edbff8dSTomer Tayar 
38362edbff8dSTomer Tayar out:
38372edbff8dSTomer Tayar 	/* PQs have to divide by 8 [that's the HW granularity].
38382edbff8dSTomer Tayar 	 * Reduce number so it would fit.
38392edbff8dSTomer Tayar 	 */
38402edbff8dSTomer Tayar 	if ((res_id == QED_PQ) && ((*p_resc_num % 8) || (*p_resc_start % 8))) {
38412edbff8dSTomer Tayar 		DP_INFO(p_hwfn,
38422edbff8dSTomer Tayar 			"PQs need to align by 8; Number %08x --> %08x, Start %08x --> %08x\n",
38432edbff8dSTomer Tayar 			*p_resc_num,
38442edbff8dSTomer Tayar 			(*p_resc_num) & ~0x7,
38452edbff8dSTomer Tayar 			*p_resc_start, (*p_resc_start) & ~0x7);
38462edbff8dSTomer Tayar 		*p_resc_num &= ~0x7;
38472edbff8dSTomer Tayar 		*p_resc_start &= ~0x7;
38482edbff8dSTomer Tayar 	}
38492edbff8dSTomer Tayar 
38502edbff8dSTomer Tayar 	return 0;
38512edbff8dSTomer Tayar }
38522edbff8dSTomer Tayar 
38539c8517c4STomer Tayar static int qed_hw_set_resc_info(struct qed_hwfn *p_hwfn)
3854fe56b9e6SYuval Mintz {
38559c8517c4STomer Tayar 	int rc;
38569c8517c4STomer Tayar 	u8 res_id;
38579c8517c4STomer Tayar 
38589c8517c4STomer Tayar 	for (res_id = 0; res_id < QED_MAX_RESC; res_id++) {
38599c8517c4STomer Tayar 		rc = __qed_hw_set_resc_info(p_hwfn, res_id);
38609c8517c4STomer Tayar 		if (rc)
38619c8517c4STomer Tayar 			return rc;
38629c8517c4STomer Tayar 	}
38639c8517c4STomer Tayar 
38649c8517c4STomer Tayar 	return 0;
38659c8517c4STomer Tayar }
38669c8517c4STomer Tayar 
386779284adeSMichal Kalderon static int qed_hw_get_ppfid_bitmap(struct qed_hwfn *p_hwfn,
386879284adeSMichal Kalderon 				   struct qed_ptt *p_ptt)
386979284adeSMichal Kalderon {
387079284adeSMichal Kalderon 	struct qed_dev *cdev = p_hwfn->cdev;
387179284adeSMichal Kalderon 	u8 native_ppfid_idx;
387279284adeSMichal Kalderon 	int rc;
387379284adeSMichal Kalderon 
387479284adeSMichal Kalderon 	/* Calculation of BB/AH is different for native_ppfid_idx */
387579284adeSMichal Kalderon 	if (QED_IS_BB(cdev))
387679284adeSMichal Kalderon 		native_ppfid_idx = p_hwfn->rel_pf_id;
387779284adeSMichal Kalderon 	else
387879284adeSMichal Kalderon 		native_ppfid_idx = p_hwfn->rel_pf_id /
387979284adeSMichal Kalderon 		    cdev->num_ports_in_engine;
388079284adeSMichal Kalderon 
388179284adeSMichal Kalderon 	rc = qed_mcp_get_ppfid_bitmap(p_hwfn, p_ptt);
388279284adeSMichal Kalderon 	if (rc != 0 && rc != -EOPNOTSUPP)
388379284adeSMichal Kalderon 		return rc;
388479284adeSMichal Kalderon 	else if (rc == -EOPNOTSUPP)
388579284adeSMichal Kalderon 		cdev->ppfid_bitmap = 0x1 << native_ppfid_idx;
388679284adeSMichal Kalderon 
388779284adeSMichal Kalderon 	if (!(cdev->ppfid_bitmap & (0x1 << native_ppfid_idx))) {
388879284adeSMichal Kalderon 		DP_INFO(p_hwfn,
38891b3855abSColin Ian King 			"Fix the PPFID bitmap to include the native PPFID [native_ppfid_idx %hhd, orig_bitmap 0x%hhx]\n",
389079284adeSMichal Kalderon 			native_ppfid_idx, cdev->ppfid_bitmap);
389179284adeSMichal Kalderon 		cdev->ppfid_bitmap = 0x1 << native_ppfid_idx;
389279284adeSMichal Kalderon 	}
389379284adeSMichal Kalderon 
389479284adeSMichal Kalderon 	return 0;
389579284adeSMichal Kalderon }
389679284adeSMichal Kalderon 
38979c8517c4STomer Tayar static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
38989c8517c4STomer Tayar {
38999c8517c4STomer Tayar 	struct qed_resc_unlock_params resc_unlock_params;
39009c8517c4STomer Tayar 	struct qed_resc_lock_params resc_lock_params;
39019c79ddaaSMintz, Yuval 	bool b_ah = QED_IS_AH(p_hwfn->cdev);
39022edbff8dSTomer Tayar 	u8 res_id;
39032edbff8dSTomer Tayar 	int rc;
3904fe56b9e6SYuval Mintz 
39059c8517c4STomer Tayar 	/* Setting the max values of the soft resources and the following
39069c8517c4STomer Tayar 	 * resources allocation queries should be atomic. Since several PFs can
39079c8517c4STomer Tayar 	 * run in parallel - a resource lock is needed.
39089c8517c4STomer Tayar 	 * If either the resource lock or resource set value commands are not
39099c8517c4STomer Tayar 	 * supported - skip the the max values setting, release the lock if
39109c8517c4STomer Tayar 	 * needed, and proceed to the queries. Other failures, including a
39119c8517c4STomer Tayar 	 * failure to acquire the lock, will cause this function to fail.
39129c8517c4STomer Tayar 	 */
3913f470f22cSsudarsana.kalluru@cavium.com 	qed_mcp_resc_lock_default_init(&resc_lock_params, &resc_unlock_params,
3914f470f22cSsudarsana.kalluru@cavium.com 				       QED_RESC_LOCK_RESC_ALLOC, false);
39159c8517c4STomer Tayar 
39169c8517c4STomer Tayar 	rc = qed_mcp_resc_lock(p_hwfn, p_ptt, &resc_lock_params);
39179c8517c4STomer Tayar 	if (rc && rc != -EINVAL) {
39182edbff8dSTomer Tayar 		return rc;
39199c8517c4STomer Tayar 	} else if (rc == -EINVAL) {
39209c8517c4STomer Tayar 		DP_INFO(p_hwfn,
39219c8517c4STomer Tayar 			"Skip the max values setting of the soft resources since the resource lock is not supported by the MFW\n");
39229c8517c4STomer Tayar 	} else if (!rc && !resc_lock_params.b_granted) {
39239c8517c4STomer Tayar 		DP_NOTICE(p_hwfn,
39249c8517c4STomer Tayar 			  "Failed to acquire the resource lock for the resource allocation commands\n");
39259c8517c4STomer Tayar 		return -EBUSY;
39269c8517c4STomer Tayar 	} else {
39279c8517c4STomer Tayar 		rc = qed_hw_set_soft_resc_size(p_hwfn, p_ptt);
39289c8517c4STomer Tayar 		if (rc && rc != -EINVAL) {
39299c8517c4STomer Tayar 			DP_NOTICE(p_hwfn,
39309c8517c4STomer Tayar 				  "Failed to set the max values of the soft resources\n");
39319c8517c4STomer Tayar 			goto unlock_and_exit;
39329c8517c4STomer Tayar 		} else if (rc == -EINVAL) {
39339c8517c4STomer Tayar 			DP_INFO(p_hwfn,
39349c8517c4STomer Tayar 				"Skip the max values setting of the soft resources since it is not supported by the MFW\n");
39359c8517c4STomer Tayar 			rc = qed_mcp_resc_unlock(p_hwfn, p_ptt,
39369c8517c4STomer Tayar 						 &resc_unlock_params);
39379c8517c4STomer Tayar 			if (rc)
39389c8517c4STomer Tayar 				DP_INFO(p_hwfn,
39399c8517c4STomer Tayar 					"Failed to release the resource lock for the resource allocation commands\n");
39409c8517c4STomer Tayar 		}
39419c8517c4STomer Tayar 	}
39429c8517c4STomer Tayar 
39439c8517c4STomer Tayar 	rc = qed_hw_set_resc_info(p_hwfn);
39449c8517c4STomer Tayar 	if (rc)
39459c8517c4STomer Tayar 		goto unlock_and_exit;
39469c8517c4STomer Tayar 
39479c8517c4STomer Tayar 	if (resc_lock_params.b_granted && !resc_unlock_params.b_released) {
39489c8517c4STomer Tayar 		rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, &resc_unlock_params);
39499c8517c4STomer Tayar 		if (rc)
39509c8517c4STomer Tayar 			DP_INFO(p_hwfn,
39519c8517c4STomer Tayar 				"Failed to release the resource lock for the resource allocation commands\n");
39522edbff8dSTomer Tayar 	}
3953dbb799c3SYuval Mintz 
395479284adeSMichal Kalderon 	/* PPFID bitmap */
395579284adeSMichal Kalderon 	if (IS_LEAD_HWFN(p_hwfn)) {
395679284adeSMichal Kalderon 		rc = qed_hw_get_ppfid_bitmap(p_hwfn, p_ptt);
395779284adeSMichal Kalderon 		if (rc)
395879284adeSMichal Kalderon 			return rc;
395979284adeSMichal Kalderon 	}
396079284adeSMichal Kalderon 
3961dbb799c3SYuval Mintz 	/* Sanity for ILT */
39629c79ddaaSMintz, Yuval 	if ((b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_K2)) ||
39639c79ddaaSMintz, Yuval 	    (!b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_BB))) {
3964dbb799c3SYuval Mintz 		DP_NOTICE(p_hwfn, "Can't assign ILT pages [%08x,...,%08x]\n",
3965dbb799c3SYuval Mintz 			  RESC_START(p_hwfn, QED_ILT),
3966dbb799c3SYuval Mintz 			  RESC_END(p_hwfn, QED_ILT) - 1);
3967dbb799c3SYuval Mintz 		return -EINVAL;
3968dbb799c3SYuval Mintz 	}
3969fe56b9e6SYuval Mintz 
3970ebbdcc66SMintz, Yuval 	/* This will also learn the number of SBs from MFW */
3971ebbdcc66SMintz, Yuval 	if (qed_int_igu_reset_cam(p_hwfn, p_ptt))
3972ebbdcc66SMintz, Yuval 		return -EINVAL;
3973ebbdcc66SMintz, Yuval 
397425c089d7SYuval Mintz 	qed_hw_set_feat(p_hwfn);
397525c089d7SYuval Mintz 
39762edbff8dSTomer Tayar 	for (res_id = 0; res_id < QED_MAX_RESC; res_id++)
39772edbff8dSTomer Tayar 		DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, "%s = %d start = %d\n",
39782edbff8dSTomer Tayar 			   qed_hw_get_resc_name(res_id),
39792edbff8dSTomer Tayar 			   RESC_NUM(p_hwfn, res_id),
39802edbff8dSTomer Tayar 			   RESC_START(p_hwfn, res_id));
3981dbb799c3SYuval Mintz 
3982dbb799c3SYuval Mintz 	return 0;
39839c8517c4STomer Tayar 
39849c8517c4STomer Tayar unlock_and_exit:
39859c8517c4STomer Tayar 	if (resc_lock_params.b_granted && !resc_unlock_params.b_released)
39869c8517c4STomer Tayar 		qed_mcp_resc_unlock(p_hwfn, p_ptt, &resc_unlock_params);
39879c8517c4STomer Tayar 	return rc;
3988fe56b9e6SYuval Mintz }
3989fe56b9e6SYuval Mintz 
39901a635e48SYuval Mintz static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
3991fe56b9e6SYuval Mintz {
3992fc48b7a6SYuval Mintz 	u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities;
39931e128c81SArun Easi 	u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
3994645874e5SSudarsana Reddy Kalluru 	struct qed_mcp_link_capabilities *p_caps;
3995cc875c2eSYuval Mintz 	struct qed_mcp_link_params *link;
3996fe56b9e6SYuval Mintz 
3997fe56b9e6SYuval Mintz 	/* Read global nvm_cfg address */
3998fe56b9e6SYuval Mintz 	nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0);
3999fe56b9e6SYuval Mintz 
4000fe56b9e6SYuval Mintz 	/* Verify MCP has initialized it */
4001fe56b9e6SYuval Mintz 	if (!nvm_cfg_addr) {
4002fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Shared memory not initialized\n");
4003fe56b9e6SYuval Mintz 		return -EINVAL;
4004fe56b9e6SYuval Mintz 	}
4005fe56b9e6SYuval Mintz 
4006fe56b9e6SYuval Mintz 	/* Read nvm_cfg1  (Notice this is just offset, and not offsize (TBD) */
4007fe56b9e6SYuval Mintz 	nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4);
4008fe56b9e6SYuval Mintz 
4009cc875c2eSYuval Mintz 	addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4010cc875c2eSYuval Mintz 	       offsetof(struct nvm_cfg1, glob) +
4011cc875c2eSYuval Mintz 	       offsetof(struct nvm_cfg1_glob, core_cfg);
4012cc875c2eSYuval Mintz 
4013cc875c2eSYuval Mintz 	core_cfg = qed_rd(p_hwfn, p_ptt, addr);
4014cc875c2eSYuval Mintz 
4015cc875c2eSYuval Mintz 	switch ((core_cfg & NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK) >>
4016cc875c2eSYuval Mintz 		NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET) {
4017351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G:
4018cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X40G;
4019cc875c2eSYuval Mintz 		break;
4020351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G:
4021cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X50G;
4022cc875c2eSYuval Mintz 		break;
4023351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G:
4024cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X100G;
4025cc875c2eSYuval Mintz 		break;
4026351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F:
4027cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X10G_F;
4028cc875c2eSYuval Mintz 		break;
4029351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E:
4030cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X10G_E;
4031cc875c2eSYuval Mintz 		break;
4032351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G:
4033cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X20G;
4034cc875c2eSYuval Mintz 		break;
4035351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G:
4036cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X40G;
4037cc875c2eSYuval Mintz 		break;
4038351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G:
4039cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X25G;
4040cc875c2eSYuval Mintz 		break;
40419c79ddaaSMintz, Yuval 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X10G:
40429c79ddaaSMintz, Yuval 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X10G;
40439c79ddaaSMintz, Yuval 		break;
4044351a4dedSYuval Mintz 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G:
4045cc875c2eSYuval Mintz 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X25G;
4046cc875c2eSYuval Mintz 		break;
40479c79ddaaSMintz, Yuval 	case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X25G:
40489c79ddaaSMintz, Yuval 		p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X25G;
40499c79ddaaSMintz, Yuval 		break;
4050cc875c2eSYuval Mintz 	default:
40511a635e48SYuval Mintz 		DP_NOTICE(p_hwfn, "Unknown port mode in 0x%08x\n", core_cfg);
4052cc875c2eSYuval Mintz 		break;
4053cc875c2eSYuval Mintz 	}
4054cc875c2eSYuval Mintz 
4055cc875c2eSYuval Mintz 	/* Read default link configuration */
4056cc875c2eSYuval Mintz 	link = &p_hwfn->mcp_info->link_input;
4057645874e5SSudarsana Reddy Kalluru 	p_caps = &p_hwfn->mcp_info->link_capabilities;
4058cc875c2eSYuval Mintz 	port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4059cc875c2eSYuval Mintz 			offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]);
4060cc875c2eSYuval Mintz 	link_temp = qed_rd(p_hwfn, p_ptt,
4061cc875c2eSYuval Mintz 			   port_cfg_addr +
4062cc875c2eSYuval Mintz 			   offsetof(struct nvm_cfg1_port, speed_cap_mask));
406383aeb933SYuval Mintz 	link_temp &= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_MASK;
406483aeb933SYuval Mintz 	link->speed.advertised_speeds = link_temp;
4065cc875c2eSYuval Mintz 
406683aeb933SYuval Mintz 	link_temp = link->speed.advertised_speeds;
406783aeb933SYuval Mintz 	p_hwfn->mcp_info->link_capabilities.speed_capabilities = link_temp;
4068cc875c2eSYuval Mintz 
4069cc875c2eSYuval Mintz 	link_temp = qed_rd(p_hwfn, p_ptt,
4070cc875c2eSYuval Mintz 			   port_cfg_addr +
4071cc875c2eSYuval Mintz 			   offsetof(struct nvm_cfg1_port, link_settings));
4072cc875c2eSYuval Mintz 	switch ((link_temp & NVM_CFG1_PORT_DRV_LINK_SPEED_MASK) >>
4073cc875c2eSYuval Mintz 		NVM_CFG1_PORT_DRV_LINK_SPEED_OFFSET) {
4074cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG:
4075cc875c2eSYuval Mintz 		link->speed.autoneg = true;
4076cc875c2eSYuval Mintz 		break;
4077cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_1G:
4078cc875c2eSYuval Mintz 		link->speed.forced_speed = 1000;
4079cc875c2eSYuval Mintz 		break;
4080cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_10G:
4081cc875c2eSYuval Mintz 		link->speed.forced_speed = 10000;
4082cc875c2eSYuval Mintz 		break;
40835bf0961cSSudarsana Reddy Kalluru 	case NVM_CFG1_PORT_DRV_LINK_SPEED_20G:
40845bf0961cSSudarsana Reddy Kalluru 		link->speed.forced_speed = 20000;
40855bf0961cSSudarsana Reddy Kalluru 		break;
4086cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_25G:
4087cc875c2eSYuval Mintz 		link->speed.forced_speed = 25000;
4088cc875c2eSYuval Mintz 		break;
4089cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_40G:
4090cc875c2eSYuval Mintz 		link->speed.forced_speed = 40000;
4091cc875c2eSYuval Mintz 		break;
4092cc875c2eSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_50G:
4093cc875c2eSYuval Mintz 		link->speed.forced_speed = 50000;
4094cc875c2eSYuval Mintz 		break;
4095351a4dedSYuval Mintz 	case NVM_CFG1_PORT_DRV_LINK_SPEED_BB_100G:
4096cc875c2eSYuval Mintz 		link->speed.forced_speed = 100000;
4097cc875c2eSYuval Mintz 		break;
4098cc875c2eSYuval Mintz 	default:
40991a635e48SYuval Mintz 		DP_NOTICE(p_hwfn, "Unknown Speed in 0x%08x\n", link_temp);
4100cc875c2eSYuval Mintz 	}
4101cc875c2eSYuval Mintz 
410234f9199cSsudarsana.kalluru@cavium.com 	p_hwfn->mcp_info->link_capabilities.default_speed_autoneg =
410334f9199cSsudarsana.kalluru@cavium.com 		link->speed.autoneg;
410434f9199cSsudarsana.kalluru@cavium.com 
4105cc875c2eSYuval Mintz 	link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK;
4106cc875c2eSYuval Mintz 	link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET;
4107cc875c2eSYuval Mintz 	link->pause.autoneg = !!(link_temp &
4108cc875c2eSYuval Mintz 				 NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG);
4109cc875c2eSYuval Mintz 	link->pause.forced_rx = !!(link_temp &
4110cc875c2eSYuval Mintz 				   NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX);
4111cc875c2eSYuval Mintz 	link->pause.forced_tx = !!(link_temp &
4112cc875c2eSYuval Mintz 				   NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
4113cc875c2eSYuval Mintz 	link->loopback_mode = 0;
4114cc875c2eSYuval Mintz 
4115645874e5SSudarsana Reddy Kalluru 	if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
4116645874e5SSudarsana Reddy Kalluru 		link_temp = qed_rd(p_hwfn, p_ptt, port_cfg_addr +
4117645874e5SSudarsana Reddy Kalluru 				   offsetof(struct nvm_cfg1_port, ext_phy));
4118645874e5SSudarsana Reddy Kalluru 		link_temp &= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK;
4119645874e5SSudarsana Reddy Kalluru 		link_temp >>= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET;
4120645874e5SSudarsana Reddy Kalluru 		p_caps->default_eee = QED_MCP_EEE_ENABLED;
4121645874e5SSudarsana Reddy Kalluru 		link->eee.enable = true;
4122645874e5SSudarsana Reddy Kalluru 		switch (link_temp) {
4123645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED:
4124645874e5SSudarsana Reddy Kalluru 			p_caps->default_eee = QED_MCP_EEE_DISABLED;
4125645874e5SSudarsana Reddy Kalluru 			link->eee.enable = false;
4126645874e5SSudarsana Reddy Kalluru 			break;
4127645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED:
4128645874e5SSudarsana Reddy Kalluru 			p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_BALANCED_TIME;
4129645874e5SSudarsana Reddy Kalluru 			break;
4130645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE:
4131645874e5SSudarsana Reddy Kalluru 			p_caps->eee_lpi_timer =
4132645874e5SSudarsana Reddy Kalluru 			    EEE_TX_TIMER_USEC_AGGRESSIVE_TIME;
4133645874e5SSudarsana Reddy Kalluru 			break;
4134645874e5SSudarsana Reddy Kalluru 		case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY:
4135645874e5SSudarsana Reddy Kalluru 			p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_LATENCY_TIME;
4136645874e5SSudarsana Reddy Kalluru 			break;
4137645874e5SSudarsana Reddy Kalluru 		}
4138645874e5SSudarsana Reddy Kalluru 
4139645874e5SSudarsana Reddy Kalluru 		link->eee.tx_lpi_timer = p_caps->eee_lpi_timer;
4140645874e5SSudarsana Reddy Kalluru 		link->eee.tx_lpi_enable = link->eee.enable;
4141645874e5SSudarsana Reddy Kalluru 		link->eee.adv_caps = QED_EEE_1G_ADV | QED_EEE_10G_ADV;
4142645874e5SSudarsana Reddy Kalluru 	} else {
4143645874e5SSudarsana Reddy Kalluru 		p_caps->default_eee = QED_MCP_EEE_UNSUPPORTED;
4144645874e5SSudarsana Reddy Kalluru 	}
4145645874e5SSudarsana Reddy Kalluru 
4146645874e5SSudarsana Reddy Kalluru 	DP_VERBOSE(p_hwfn,
4147645874e5SSudarsana Reddy Kalluru 		   NETIF_MSG_LINK,
4148645874e5SSudarsana Reddy Kalluru 		   "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x EEE: %02x [%08x usec]\n",
4149645874e5SSudarsana Reddy Kalluru 		   link->speed.forced_speed,
4150645874e5SSudarsana Reddy Kalluru 		   link->speed.advertised_speeds,
4151645874e5SSudarsana Reddy Kalluru 		   link->speed.autoneg,
4152645874e5SSudarsana Reddy Kalluru 		   link->pause.autoneg,
4153645874e5SSudarsana Reddy Kalluru 		   p_caps->default_eee, p_caps->eee_lpi_timer);
4154cc875c2eSYuval Mintz 
4155b51bdfb9SSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn)) {
4156b51bdfb9SSudarsana Reddy Kalluru 		struct qed_dev *cdev = p_hwfn->cdev;
4157b51bdfb9SSudarsana Reddy Kalluru 
4158fe56b9e6SYuval Mintz 		/* Read Multi-function information from shmem */
4159fe56b9e6SYuval Mintz 		addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4160fe56b9e6SYuval Mintz 		       offsetof(struct nvm_cfg1, glob) +
4161fe56b9e6SYuval Mintz 		       offsetof(struct nvm_cfg1_glob, generic_cont0);
4162fe56b9e6SYuval Mintz 
4163fe56b9e6SYuval Mintz 		generic_cont0 = qed_rd(p_hwfn, p_ptt, addr);
4164fe56b9e6SYuval Mintz 
4165fe56b9e6SYuval Mintz 		mf_mode = (generic_cont0 & NVM_CFG1_GLOB_MF_MODE_MASK) >>
4166fe56b9e6SYuval Mintz 			  NVM_CFG1_GLOB_MF_MODE_OFFSET;
4167fe56b9e6SYuval Mintz 
4168fe56b9e6SYuval Mintz 		switch (mf_mode) {
4169fe56b9e6SYuval Mintz 		case NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED:
4170b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS);
4171b51bdfb9SSudarsana Reddy Kalluru 			break;
4172cac6f691SSudarsana Reddy Kalluru 		case NVM_CFG1_GLOB_MF_MODE_UFP:
4173cac6f691SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS) |
4174cac6f691SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
4175cac6f691SSudarsana Reddy Kalluru 					BIT(QED_MF_UFP_SPECIFIC) |
41761a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_8021Q_TAGGING) |
41771a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_DONT_ADD_VLAN0_TAG);
4178cac6f691SSudarsana Reddy Kalluru 			break;
4179b51bdfb9SSudarsana Reddy Kalluru 		case NVM_CFG1_GLOB_MF_MODE_BD:
4180b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS) |
4181b51bdfb9SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
41821a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_8021AD_TAGGING) |
41831a3ca250SSudarsana Reddy Kalluru 					BIT(QED_MF_DONT_ADD_VLAN0_TAG);
4184fe56b9e6SYuval Mintz 			break;
4185fe56b9e6SYuval Mintz 		case NVM_CFG1_GLOB_MF_MODE_NPAR1_0:
4186b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
41870bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
41880bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LL2_NON_UNICAST) |
41890bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_INTER_PF_SWITCH);
4190fe56b9e6SYuval Mintz 			break;
4191fc48b7a6SYuval Mintz 		case NVM_CFG1_GLOB_MF_MODE_DEFAULT:
4192b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
41930bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LLH_PROTO_CLSS) |
41940bc5fe85SSudarsana Reddy Kalluru 					BIT(QED_MF_LL2_NON_UNICAST);
41950bc5fe85SSudarsana Reddy Kalluru 			if (QED_IS_BB(p_hwfn->cdev))
4196b51bdfb9SSudarsana Reddy Kalluru 				cdev->mf_bits |= BIT(QED_MF_NEED_DEF_PF);
4197fe56b9e6SYuval Mintz 			break;
4198fe56b9e6SYuval Mintz 		}
41990bc5fe85SSudarsana Reddy Kalluru 
42000bc5fe85SSudarsana Reddy Kalluru 		DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
4201b51bdfb9SSudarsana Reddy Kalluru 			cdev->mf_bits);
4202b51bdfb9SSudarsana Reddy Kalluru 	}
4203b51bdfb9SSudarsana Reddy Kalluru 
4204b51bdfb9SSudarsana Reddy Kalluru 	DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
42050bc5fe85SSudarsana Reddy Kalluru 		p_hwfn->cdev->mf_bits);
4206fe56b9e6SYuval Mintz 
4207b51bdfb9SSudarsana Reddy Kalluru 	/* Read device capabilities information from shmem */
4208fc48b7a6SYuval Mintz 	addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
4209fc48b7a6SYuval Mintz 		offsetof(struct nvm_cfg1, glob) +
4210fc48b7a6SYuval Mintz 		offsetof(struct nvm_cfg1_glob, device_capabilities);
4211fc48b7a6SYuval Mintz 
4212fc48b7a6SYuval Mintz 	device_capabilities = qed_rd(p_hwfn, p_ptt, addr);
4213fc48b7a6SYuval Mintz 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET)
4214fc48b7a6SYuval Mintz 		__set_bit(QED_DEV_CAP_ETH,
4215fc48b7a6SYuval Mintz 			  &p_hwfn->hw_info.device_capabilities);
42161e128c81SArun Easi 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_FCOE)
42171e128c81SArun Easi 		__set_bit(QED_DEV_CAP_FCOE,
42181e128c81SArun Easi 			  &p_hwfn->hw_info.device_capabilities);
4219c5ac9319SYuval Mintz 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI)
4220c5ac9319SYuval Mintz 		__set_bit(QED_DEV_CAP_ISCSI,
4221c5ac9319SYuval Mintz 			  &p_hwfn->hw_info.device_capabilities);
4222c5ac9319SYuval Mintz 	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE)
4223c5ac9319SYuval Mintz 		__set_bit(QED_DEV_CAP_ROCE,
4224c5ac9319SYuval Mintz 			  &p_hwfn->hw_info.device_capabilities);
4225fc48b7a6SYuval Mintz 
4226fe56b9e6SYuval Mintz 	return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt);
4227fe56b9e6SYuval Mintz }
4228fe56b9e6SYuval Mintz 
42291408cc1fSYuval Mintz static void qed_get_num_funcs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
42301408cc1fSYuval Mintz {
4231dbb799c3SYuval Mintz 	u8 num_funcs, enabled_func_idx = p_hwfn->rel_pf_id;
4232dbb799c3SYuval Mintz 	u32 reg_function_hide, tmp, eng_mask, low_pfs_mask;
42339c79ddaaSMintz, Yuval 	struct qed_dev *cdev = p_hwfn->cdev;
42341408cc1fSYuval Mintz 
42359c79ddaaSMintz, Yuval 	num_funcs = QED_IS_AH(cdev) ? MAX_NUM_PFS_K2 : MAX_NUM_PFS_BB;
42361408cc1fSYuval Mintz 
42371408cc1fSYuval Mintz 	/* Bit 0 of MISCS_REG_FUNCTION_HIDE indicates whether the bypass values
42381408cc1fSYuval Mintz 	 * in the other bits are selected.
42391408cc1fSYuval Mintz 	 * Bits 1-15 are for functions 1-15, respectively, and their value is
42401408cc1fSYuval Mintz 	 * '0' only for enabled functions (function 0 always exists and
42411408cc1fSYuval Mintz 	 * enabled).
42421408cc1fSYuval Mintz 	 * In case of CMT, only the "even" functions are enabled, and thus the
42431408cc1fSYuval Mintz 	 * number of functions for both hwfns is learnt from the same bits.
42441408cc1fSYuval Mintz 	 */
42451408cc1fSYuval Mintz 	reg_function_hide = qed_rd(p_hwfn, p_ptt, MISCS_REG_FUNCTION_HIDE);
42461408cc1fSYuval Mintz 
42471408cc1fSYuval Mintz 	if (reg_function_hide & 0x1) {
42489c79ddaaSMintz, Yuval 		if (QED_IS_BB(cdev)) {
42499c79ddaaSMintz, Yuval 			if (QED_PATH_ID(p_hwfn) && cdev->num_hwfns == 1) {
42501408cc1fSYuval Mintz 				num_funcs = 0;
42511408cc1fSYuval Mintz 				eng_mask = 0xaaaa;
42521408cc1fSYuval Mintz 			} else {
42531408cc1fSYuval Mintz 				num_funcs = 1;
42541408cc1fSYuval Mintz 				eng_mask = 0x5554;
42551408cc1fSYuval Mintz 			}
42569c79ddaaSMintz, Yuval 		} else {
42579c79ddaaSMintz, Yuval 			num_funcs = 1;
42589c79ddaaSMintz, Yuval 			eng_mask = 0xfffe;
42599c79ddaaSMintz, Yuval 		}
42601408cc1fSYuval Mintz 
42611408cc1fSYuval Mintz 		/* Get the number of the enabled functions on the engine */
42621408cc1fSYuval Mintz 		tmp = (reg_function_hide ^ 0xffffffff) & eng_mask;
42631408cc1fSYuval Mintz 		while (tmp) {
42641408cc1fSYuval Mintz 			if (tmp & 0x1)
42651408cc1fSYuval Mintz 				num_funcs++;
42661408cc1fSYuval Mintz 			tmp >>= 0x1;
42671408cc1fSYuval Mintz 		}
4268dbb799c3SYuval Mintz 
4269dbb799c3SYuval Mintz 		/* Get the PF index within the enabled functions */
4270dbb799c3SYuval Mintz 		low_pfs_mask = (0x1 << p_hwfn->abs_pf_id) - 1;
4271dbb799c3SYuval Mintz 		tmp = reg_function_hide & eng_mask & low_pfs_mask;
4272dbb799c3SYuval Mintz 		while (tmp) {
4273dbb799c3SYuval Mintz 			if (tmp & 0x1)
4274dbb799c3SYuval Mintz 				enabled_func_idx--;
4275dbb799c3SYuval Mintz 			tmp >>= 0x1;
4276dbb799c3SYuval Mintz 		}
42771408cc1fSYuval Mintz 	}
42781408cc1fSYuval Mintz 
42791408cc1fSYuval Mintz 	p_hwfn->num_funcs_on_engine = num_funcs;
4280dbb799c3SYuval Mintz 	p_hwfn->enabled_func_idx = enabled_func_idx;
42811408cc1fSYuval Mintz 
42821408cc1fSYuval Mintz 	DP_VERBOSE(p_hwfn,
42831408cc1fSYuval Mintz 		   NETIF_MSG_PROBE,
4284525ef5c0SYuval Mintz 		   "PF [rel_id %d, abs_id %d] occupies index %d within the %d enabled functions on the engine\n",
42851408cc1fSYuval Mintz 		   p_hwfn->rel_pf_id,
42861408cc1fSYuval Mintz 		   p_hwfn->abs_pf_id,
4287525ef5c0SYuval Mintz 		   p_hwfn->enabled_func_idx, p_hwfn->num_funcs_on_engine);
42881408cc1fSYuval Mintz }
42891408cc1fSYuval Mintz 
42909c79ddaaSMintz, Yuval static void qed_hw_info_port_num(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
42919c79ddaaSMintz, Yuval {
42920ebcebbeSSudarsana Reddy Kalluru 	u32 addr, global_offsize, global_addr, port_mode;
42930ebcebbeSSudarsana Reddy Kalluru 	struct qed_dev *cdev = p_hwfn->cdev;
42940ebcebbeSSudarsana Reddy Kalluru 
42950ebcebbeSSudarsana Reddy Kalluru 	/* In CMT there is always only one port */
42960ebcebbeSSudarsana Reddy Kalluru 	if (cdev->num_hwfns > 1) {
42970ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 1;
42980ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports = 1;
42990ebcebbeSSudarsana Reddy Kalluru 		return;
43000ebcebbeSSudarsana Reddy Kalluru 	}
43010ebcebbeSSudarsana Reddy Kalluru 
43020ebcebbeSSudarsana Reddy Kalluru 	/* Determine the number of ports per engine */
43030ebcebbeSSudarsana Reddy Kalluru 	port_mode = qed_rd(p_hwfn, p_ptt, MISC_REG_PORT_MODE);
43040ebcebbeSSudarsana Reddy Kalluru 	switch (port_mode) {
43050ebcebbeSSudarsana Reddy Kalluru 	case 0x0:
43060ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 1;
43070ebcebbeSSudarsana Reddy Kalluru 		break;
43080ebcebbeSSudarsana Reddy Kalluru 	case 0x1:
43090ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 2;
43100ebcebbeSSudarsana Reddy Kalluru 		break;
43110ebcebbeSSudarsana Reddy Kalluru 	case 0x2:
43120ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 4;
43130ebcebbeSSudarsana Reddy Kalluru 		break;
43140ebcebbeSSudarsana Reddy Kalluru 	default:
43150ebcebbeSSudarsana Reddy Kalluru 		DP_NOTICE(p_hwfn, "Unknown port mode 0x%08x\n", port_mode);
43160ebcebbeSSudarsana Reddy Kalluru 		cdev->num_ports_in_engine = 1;	/* Default to something */
43170ebcebbeSSudarsana Reddy Kalluru 		break;
43180ebcebbeSSudarsana Reddy Kalluru 	}
43190ebcebbeSSudarsana Reddy Kalluru 
43200ebcebbeSSudarsana Reddy Kalluru 	/* Get the total number of ports of the device */
43210ebcebbeSSudarsana Reddy Kalluru 	addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
43220ebcebbeSSudarsana Reddy Kalluru 				    PUBLIC_GLOBAL);
43230ebcebbeSSudarsana Reddy Kalluru 	global_offsize = qed_rd(p_hwfn, p_ptt, addr);
43240ebcebbeSSudarsana Reddy Kalluru 	global_addr = SECTION_ADDR(global_offsize, 0);
43250ebcebbeSSudarsana Reddy Kalluru 	addr = global_addr + offsetof(struct public_global, max_ports);
43260ebcebbeSSudarsana Reddy Kalluru 	cdev->num_ports = (u8)qed_rd(p_hwfn, p_ptt, addr);
43279c79ddaaSMintz, Yuval }
43289c79ddaaSMintz, Yuval 
4329645874e5SSudarsana Reddy Kalluru static void qed_get_eee_caps(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
4330645874e5SSudarsana Reddy Kalluru {
4331645874e5SSudarsana Reddy Kalluru 	struct qed_mcp_link_capabilities *p_caps;
4332645874e5SSudarsana Reddy Kalluru 	u32 eee_status;
4333645874e5SSudarsana Reddy Kalluru 
4334645874e5SSudarsana Reddy Kalluru 	p_caps = &p_hwfn->mcp_info->link_capabilities;
4335645874e5SSudarsana Reddy Kalluru 	if (p_caps->default_eee == QED_MCP_EEE_UNSUPPORTED)
4336645874e5SSudarsana Reddy Kalluru 		return;
4337645874e5SSudarsana Reddy Kalluru 
4338645874e5SSudarsana Reddy Kalluru 	p_caps->eee_speed_caps = 0;
4339645874e5SSudarsana Reddy Kalluru 	eee_status = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
4340645874e5SSudarsana Reddy Kalluru 			    offsetof(struct public_port, eee_status));
4341645874e5SSudarsana Reddy Kalluru 	eee_status = (eee_status & EEE_SUPPORTED_SPEED_MASK) >>
4342645874e5SSudarsana Reddy Kalluru 			EEE_SUPPORTED_SPEED_OFFSET;
4343645874e5SSudarsana Reddy Kalluru 
4344645874e5SSudarsana Reddy Kalluru 	if (eee_status & EEE_1G_SUPPORTED)
4345645874e5SSudarsana Reddy Kalluru 		p_caps->eee_speed_caps |= QED_EEE_1G_ADV;
4346645874e5SSudarsana Reddy Kalluru 	if (eee_status & EEE_10G_ADV)
4347645874e5SSudarsana Reddy Kalluru 		p_caps->eee_speed_caps |= QED_EEE_10G_ADV;
4348645874e5SSudarsana Reddy Kalluru }
4349645874e5SSudarsana Reddy Kalluru 
43509c79ddaaSMintz, Yuval static int
43519c79ddaaSMintz, Yuval qed_get_hw_info(struct qed_hwfn *p_hwfn,
43529c79ddaaSMintz, Yuval 		struct qed_ptt *p_ptt,
43539c79ddaaSMintz, Yuval 		enum qed_pci_personality personality)
43549c79ddaaSMintz, Yuval {
43559c79ddaaSMintz, Yuval 	int rc;
43569c79ddaaSMintz, Yuval 
43579c79ddaaSMintz, Yuval 	/* Since all information is common, only first hwfns should do this */
43589c79ddaaSMintz, Yuval 	if (IS_LEAD_HWFN(p_hwfn)) {
43599c79ddaaSMintz, Yuval 		rc = qed_iov_hw_info(p_hwfn);
43609c79ddaaSMintz, Yuval 		if (rc)
43619c79ddaaSMintz, Yuval 			return rc;
43629c79ddaaSMintz, Yuval 	}
43639c79ddaaSMintz, Yuval 
43640ebcebbeSSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn))
43659c79ddaaSMintz, Yuval 		qed_hw_info_port_num(p_hwfn, p_ptt);
4366fe56b9e6SYuval Mintz 
4367645874e5SSudarsana Reddy Kalluru 	qed_mcp_get_capabilities(p_hwfn, p_ptt);
4368645874e5SSudarsana Reddy Kalluru 
4369fe56b9e6SYuval Mintz 	qed_hw_get_nvm_info(p_hwfn, p_ptt);
4370fe56b9e6SYuval Mintz 
4371fe56b9e6SYuval Mintz 	rc = qed_int_igu_read_cam(p_hwfn, p_ptt);
4372fe56b9e6SYuval Mintz 	if (rc)
4373fe56b9e6SYuval Mintz 		return rc;
4374fe56b9e6SYuval Mintz 
4375fe56b9e6SYuval Mintz 	if (qed_mcp_is_init(p_hwfn))
4376fe56b9e6SYuval Mintz 		ether_addr_copy(p_hwfn->hw_info.hw_mac_addr,
4377fe56b9e6SYuval Mintz 				p_hwfn->mcp_info->func_info.mac);
4378fe56b9e6SYuval Mintz 	else
4379fe56b9e6SYuval Mintz 		eth_random_addr(p_hwfn->hw_info.hw_mac_addr);
4380fe56b9e6SYuval Mintz 
4381fe56b9e6SYuval Mintz 	if (qed_mcp_is_init(p_hwfn)) {
4382fe56b9e6SYuval Mintz 		if (p_hwfn->mcp_info->func_info.ovlan != QED_MCP_VLAN_UNSET)
4383fe56b9e6SYuval Mintz 			p_hwfn->hw_info.ovlan =
4384fe56b9e6SYuval Mintz 				p_hwfn->mcp_info->func_info.ovlan;
4385fe56b9e6SYuval Mintz 
4386fe56b9e6SYuval Mintz 		qed_mcp_cmd_port_init(p_hwfn, p_ptt);
4387645874e5SSudarsana Reddy Kalluru 
4388645874e5SSudarsana Reddy Kalluru 		qed_get_eee_caps(p_hwfn, p_ptt);
4389cac6f691SSudarsana Reddy Kalluru 
4390cac6f691SSudarsana Reddy Kalluru 		qed_mcp_read_ufp_config(p_hwfn, p_ptt);
4391fe56b9e6SYuval Mintz 	}
4392fe56b9e6SYuval Mintz 
4393fe56b9e6SYuval Mintz 	if (qed_mcp_is_init(p_hwfn)) {
4394fe56b9e6SYuval Mintz 		enum qed_pci_personality protocol;
4395fe56b9e6SYuval Mintz 
4396fe56b9e6SYuval Mintz 		protocol = p_hwfn->mcp_info->func_info.protocol;
4397fe56b9e6SYuval Mintz 		p_hwfn->hw_info.personality = protocol;
4398fe56b9e6SYuval Mintz 	}
4399fe56b9e6SYuval Mintz 
440061be82b0SDenis Bolotin 	if (QED_IS_ROCE_PERSONALITY(p_hwfn))
440182ebc889SJason Yan 		p_hwfn->hw_info.multi_tc_roce_en = true;
440261be82b0SDenis Bolotin 
4403b5a9ee7cSAriel Elior 	p_hwfn->hw_info.num_hw_tc = NUM_PHYS_TCS_4PORT_K2;
4404b5a9ee7cSAriel Elior 	p_hwfn->hw_info.num_active_tc = 1;
4405b5a9ee7cSAriel Elior 
44061408cc1fSYuval Mintz 	qed_get_num_funcs(p_hwfn, p_ptt);
44071408cc1fSYuval Mintz 
44080fefbfbaSSudarsana Kalluru 	if (qed_mcp_is_init(p_hwfn))
44090fefbfbaSSudarsana Kalluru 		p_hwfn->hw_info.mtu = p_hwfn->mcp_info->func_info.mtu;
44100fefbfbaSSudarsana Kalluru 
44119c8517c4STomer Tayar 	return qed_hw_get_resc(p_hwfn, p_ptt);
4412fe56b9e6SYuval Mintz }
4413fe56b9e6SYuval Mintz 
441415582962SRahul Verma static int qed_get_dev_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
4415fe56b9e6SYuval Mintz {
441615582962SRahul Verma 	struct qed_dev *cdev = p_hwfn->cdev;
44179c79ddaaSMintz, Yuval 	u16 device_id_mask;
4418fe56b9e6SYuval Mintz 	u32 tmp;
4419fe56b9e6SYuval Mintz 
4420fc48b7a6SYuval Mintz 	/* Read Vendor Id / Device Id */
44211a635e48SYuval Mintz 	pci_read_config_word(cdev->pdev, PCI_VENDOR_ID, &cdev->vendor_id);
44221a635e48SYuval Mintz 	pci_read_config_word(cdev->pdev, PCI_DEVICE_ID, &cdev->device_id);
44231a635e48SYuval Mintz 
44249c79ddaaSMintz, Yuval 	/* Determine type */
44259c79ddaaSMintz, Yuval 	device_id_mask = cdev->device_id & QED_DEV_ID_MASK;
44269c79ddaaSMintz, Yuval 	switch (device_id_mask) {
44279c79ddaaSMintz, Yuval 	case QED_DEV_ID_MASK_BB:
44289c79ddaaSMintz, Yuval 		cdev->type = QED_DEV_TYPE_BB;
44299c79ddaaSMintz, Yuval 		break;
44309c79ddaaSMintz, Yuval 	case QED_DEV_ID_MASK_AH:
44319c79ddaaSMintz, Yuval 		cdev->type = QED_DEV_TYPE_AH;
44329c79ddaaSMintz, Yuval 		break;
44339c79ddaaSMintz, Yuval 	default:
44349c79ddaaSMintz, Yuval 		DP_NOTICE(p_hwfn, "Unknown device id 0x%x\n", cdev->device_id);
44359c79ddaaSMintz, Yuval 		return -EBUSY;
44369c79ddaaSMintz, Yuval 	}
44379c79ddaaSMintz, Yuval 
443815582962SRahul Verma 	cdev->chip_num = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_NUM);
443915582962SRahul Verma 	cdev->chip_rev = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_REV);
444015582962SRahul Verma 
4441fe56b9e6SYuval Mintz 	MASK_FIELD(CHIP_REV, cdev->chip_rev);
4442fe56b9e6SYuval Mintz 
4443fe56b9e6SYuval Mintz 	/* Learn number of HW-functions */
444415582962SRahul Verma 	tmp = qed_rd(p_hwfn, p_ptt, MISCS_REG_CMT_ENABLED_FOR_PAIR);
4445fe56b9e6SYuval Mintz 
4446fc48b7a6SYuval Mintz 	if (tmp & (1 << p_hwfn->rel_pf_id)) {
4447fe56b9e6SYuval Mintz 		DP_NOTICE(cdev->hwfns, "device in CMT mode\n");
4448fe56b9e6SYuval Mintz 		cdev->num_hwfns = 2;
4449fe56b9e6SYuval Mintz 	} else {
4450fe56b9e6SYuval Mintz 		cdev->num_hwfns = 1;
4451fe56b9e6SYuval Mintz 	}
4452fe56b9e6SYuval Mintz 
445315582962SRahul Verma 	cdev->chip_bond_id = qed_rd(p_hwfn, p_ptt,
4454fe56b9e6SYuval Mintz 				    MISCS_REG_CHIP_TEST_REG) >> 4;
4455fe56b9e6SYuval Mintz 	MASK_FIELD(CHIP_BOND_ID, cdev->chip_bond_id);
445615582962SRahul Verma 	cdev->chip_metal = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_METAL);
4457fe56b9e6SYuval Mintz 	MASK_FIELD(CHIP_METAL, cdev->chip_metal);
4458fe56b9e6SYuval Mintz 
4459fe56b9e6SYuval Mintz 	DP_INFO(cdev->hwfns,
44609c79ddaaSMintz, Yuval 		"Chip details - %s %c%d, Num: %04x Rev: %04x Bond id: %04x Metal: %04x\n",
44619c79ddaaSMintz, Yuval 		QED_IS_BB(cdev) ? "BB" : "AH",
44629c79ddaaSMintz, Yuval 		'A' + cdev->chip_rev,
44639c79ddaaSMintz, Yuval 		(int)cdev->chip_metal,
4464fe56b9e6SYuval Mintz 		cdev->chip_num, cdev->chip_rev,
4465fe56b9e6SYuval Mintz 		cdev->chip_bond_id, cdev->chip_metal);
446612e09c69SYuval Mintz 
446712e09c69SYuval Mintz 	return 0;
4468fe56b9e6SYuval Mintz }
4469fe56b9e6SYuval Mintz 
447043645ce0SSudarsana Reddy Kalluru static void qed_nvm_info_free(struct qed_hwfn *p_hwfn)
447143645ce0SSudarsana Reddy Kalluru {
447243645ce0SSudarsana Reddy Kalluru 	kfree(p_hwfn->nvm_info.image_att);
447343645ce0SSudarsana Reddy Kalluru 	p_hwfn->nvm_info.image_att = NULL;
447443645ce0SSudarsana Reddy Kalluru }
447543645ce0SSudarsana Reddy Kalluru 
4476fe56b9e6SYuval Mintz static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
4477fe56b9e6SYuval Mintz 				 void __iomem *p_regview,
4478fe56b9e6SYuval Mintz 				 void __iomem *p_doorbells,
44798366d520SMichal Kalderon 				 u64 db_phys_addr,
4480fe56b9e6SYuval Mintz 				 enum qed_pci_personality personality)
4481fe56b9e6SYuval Mintz {
448264515dc8STomer Tayar 	struct qed_dev *cdev = p_hwfn->cdev;
4483fe56b9e6SYuval Mintz 	int rc = 0;
4484fe56b9e6SYuval Mintz 
4485fe56b9e6SYuval Mintz 	/* Split PCI bars evenly between hwfns */
4486fe56b9e6SYuval Mintz 	p_hwfn->regview = p_regview;
4487fe56b9e6SYuval Mintz 	p_hwfn->doorbells = p_doorbells;
44888366d520SMichal Kalderon 	p_hwfn->db_phys_addr = db_phys_addr;
4489fe56b9e6SYuval Mintz 
44901408cc1fSYuval Mintz 	if (IS_VF(p_hwfn->cdev))
44911408cc1fSYuval Mintz 		return qed_vf_hw_prepare(p_hwfn);
44921408cc1fSYuval Mintz 
4493fe56b9e6SYuval Mintz 	/* Validate that chip access is feasible */
4494fe56b9e6SYuval Mintz 	if (REG_RD(p_hwfn, PXP_PF_ME_OPAQUE_ADDR) == 0xffffffff) {
4495fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn,
4496fe56b9e6SYuval Mintz 		       "Reading the ME register returns all Fs; Preventing further chip access\n");
4497fe56b9e6SYuval Mintz 		return -EINVAL;
4498fe56b9e6SYuval Mintz 	}
4499fe56b9e6SYuval Mintz 
4500fe56b9e6SYuval Mintz 	get_function_id(p_hwfn);
4501fe56b9e6SYuval Mintz 
450212e09c69SYuval Mintz 	/* Allocate PTT pool */
450312e09c69SYuval Mintz 	rc = qed_ptt_pool_alloc(p_hwfn);
45042591c280SJoe Perches 	if (rc)
4505fe56b9e6SYuval Mintz 		goto err0;
4506fe56b9e6SYuval Mintz 
450712e09c69SYuval Mintz 	/* Allocate the main PTT */
450812e09c69SYuval Mintz 	p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN);
450912e09c69SYuval Mintz 
4510fe56b9e6SYuval Mintz 	/* First hwfn learns basic information, e.g., number of hwfns */
451112e09c69SYuval Mintz 	if (!p_hwfn->my_id) {
451215582962SRahul Verma 		rc = qed_get_dev_info(p_hwfn, p_hwfn->p_main_ptt);
45131a635e48SYuval Mintz 		if (rc)
451412e09c69SYuval Mintz 			goto err1;
451512e09c69SYuval Mintz 	}
451612e09c69SYuval Mintz 
451712e09c69SYuval Mintz 	qed_hw_hwfn_prepare(p_hwfn);
4518fe56b9e6SYuval Mintz 
4519fe56b9e6SYuval Mintz 	/* Initialize MCP structure */
4520fe56b9e6SYuval Mintz 	rc = qed_mcp_cmd_init(p_hwfn, p_hwfn->p_main_ptt);
4521fe56b9e6SYuval Mintz 	if (rc) {
4522fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Failed initializing mcp command\n");
4523fe56b9e6SYuval Mintz 		goto err1;
4524fe56b9e6SYuval Mintz 	}
4525fe56b9e6SYuval Mintz 
4526fe56b9e6SYuval Mintz 	/* Read the device configuration information from the HW and SHMEM */
4527fe56b9e6SYuval Mintz 	rc = qed_get_hw_info(p_hwfn, p_hwfn->p_main_ptt, personality);
4528fe56b9e6SYuval Mintz 	if (rc) {
4529fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Failed to get HW information\n");
4530fe56b9e6SYuval Mintz 		goto err2;
4531fe56b9e6SYuval Mintz 	}
4532fe56b9e6SYuval Mintz 
453318a69e36SMintz, Yuval 	/* Sending a mailbox to the MFW should be done after qed_get_hw_info()
453418a69e36SMintz, Yuval 	 * is called as it sets the ports number in an engine.
453518a69e36SMintz, Yuval 	 */
453664515dc8STomer Tayar 	if (IS_LEAD_HWFN(p_hwfn) && !cdev->recov_in_prog) {
453718a69e36SMintz, Yuval 		rc = qed_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt);
453818a69e36SMintz, Yuval 		if (rc)
453918a69e36SMintz, Yuval 			DP_NOTICE(p_hwfn, "Failed to initiate PF FLR\n");
454018a69e36SMintz, Yuval 	}
454118a69e36SMintz, Yuval 
454243645ce0SSudarsana Reddy Kalluru 	/* NVRAM info initialization and population */
454343645ce0SSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn)) {
454443645ce0SSudarsana Reddy Kalluru 		rc = qed_mcp_nvm_info_populate(p_hwfn);
454543645ce0SSudarsana Reddy Kalluru 		if (rc) {
454643645ce0SSudarsana Reddy Kalluru 			DP_NOTICE(p_hwfn,
454743645ce0SSudarsana Reddy Kalluru 				  "Failed to populate nvm info shadow\n");
454843645ce0SSudarsana Reddy Kalluru 			goto err2;
454943645ce0SSudarsana Reddy Kalluru 		}
455043645ce0SSudarsana Reddy Kalluru 	}
455143645ce0SSudarsana Reddy Kalluru 
4552fe56b9e6SYuval Mintz 	/* Allocate the init RT array and initialize the init-ops engine */
4553fe56b9e6SYuval Mintz 	rc = qed_init_alloc(p_hwfn);
45542591c280SJoe Perches 	if (rc)
455543645ce0SSudarsana Reddy Kalluru 		goto err3;
4556fe56b9e6SYuval Mintz 
4557fe56b9e6SYuval Mintz 	return rc;
455843645ce0SSudarsana Reddy Kalluru err3:
455943645ce0SSudarsana Reddy Kalluru 	if (IS_LEAD_HWFN(p_hwfn))
456043645ce0SSudarsana Reddy Kalluru 		qed_nvm_info_free(p_hwfn);
4561fe56b9e6SYuval Mintz err2:
456232a47e72SYuval Mintz 	if (IS_LEAD_HWFN(p_hwfn))
456332a47e72SYuval Mintz 		qed_iov_free_hw_info(p_hwfn->cdev);
4564fe56b9e6SYuval Mintz 	qed_mcp_free(p_hwfn);
4565fe56b9e6SYuval Mintz err1:
4566fe56b9e6SYuval Mintz 	qed_hw_hwfn_free(p_hwfn);
4567fe56b9e6SYuval Mintz err0:
4568fe56b9e6SYuval Mintz 	return rc;
4569fe56b9e6SYuval Mintz }
4570fe56b9e6SYuval Mintz 
4571fe56b9e6SYuval Mintz int qed_hw_prepare(struct qed_dev *cdev,
4572fe56b9e6SYuval Mintz 		   int personality)
4573fe56b9e6SYuval Mintz {
4574c78df14eSAriel Elior 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
4575c78df14eSAriel Elior 	int rc;
4576fe56b9e6SYuval Mintz 
4577fe56b9e6SYuval Mintz 	/* Store the precompiled init data ptrs */
45781408cc1fSYuval Mintz 	if (IS_PF(cdev))
4579fe56b9e6SYuval Mintz 		qed_init_iro_array(cdev);
4580fe56b9e6SYuval Mintz 
4581fe56b9e6SYuval Mintz 	/* Initialize the first hwfn - will learn number of hwfns */
4582c78df14eSAriel Elior 	rc = qed_hw_prepare_single(p_hwfn,
4583c78df14eSAriel Elior 				   cdev->regview,
45848366d520SMichal Kalderon 				   cdev->doorbells,
45858366d520SMichal Kalderon 				   cdev->db_phys_addr,
45868366d520SMichal Kalderon 				   personality);
4587fe56b9e6SYuval Mintz 	if (rc)
4588fe56b9e6SYuval Mintz 		return rc;
4589fe56b9e6SYuval Mintz 
4590c78df14eSAriel Elior 	personality = p_hwfn->hw_info.personality;
4591fe56b9e6SYuval Mintz 
4592fe56b9e6SYuval Mintz 	/* Initialize the rest of the hwfns */
4593c78df14eSAriel Elior 	if (cdev->num_hwfns > 1) {
4594fe56b9e6SYuval Mintz 		void __iomem *p_regview, *p_doorbell;
45958366d520SMichal Kalderon 		u64 db_phys_addr;
45968366d520SMichal Kalderon 		u32 offset;
4597fe56b9e6SYuval Mintz 
4598c78df14eSAriel Elior 		/* adjust bar offset for second engine */
45998366d520SMichal Kalderon 		offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
460015582962SRahul Verma 					 BAR_ID_0) / 2;
46018366d520SMichal Kalderon 		p_regview = cdev->regview + offset;
4602c78df14eSAriel Elior 
46038366d520SMichal Kalderon 		offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
460415582962SRahul Verma 					 BAR_ID_1) / 2;
46058366d520SMichal Kalderon 
46068366d520SMichal Kalderon 		p_doorbell = cdev->doorbells + offset;
46078366d520SMichal Kalderon 
46088366d520SMichal Kalderon 		db_phys_addr = cdev->db_phys_addr + offset;
4609c78df14eSAriel Elior 
4610c78df14eSAriel Elior 		/* prepare second hw function */
4611c78df14eSAriel Elior 		rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview,
46128366d520SMichal Kalderon 					   p_doorbell, db_phys_addr,
46138366d520SMichal Kalderon 					   personality);
4614c78df14eSAriel Elior 
4615c78df14eSAriel Elior 		/* in case of error, need to free the previously
4616c78df14eSAriel Elior 		 * initiliazed hwfn 0.
4617c78df14eSAriel Elior 		 */
4618fe56b9e6SYuval Mintz 		if (rc) {
46191408cc1fSYuval Mintz 			if (IS_PF(cdev)) {
4620c78df14eSAriel Elior 				qed_init_free(p_hwfn);
462143645ce0SSudarsana Reddy Kalluru 				qed_nvm_info_free(p_hwfn);
4622c78df14eSAriel Elior 				qed_mcp_free(p_hwfn);
4623c78df14eSAriel Elior 				qed_hw_hwfn_free(p_hwfn);
4624fe56b9e6SYuval Mintz 			}
4625fe56b9e6SYuval Mintz 		}
46261408cc1fSYuval Mintz 	}
4627fe56b9e6SYuval Mintz 
4628c78df14eSAriel Elior 	return rc;
4629fe56b9e6SYuval Mintz }
4630fe56b9e6SYuval Mintz 
4631fe56b9e6SYuval Mintz void qed_hw_remove(struct qed_dev *cdev)
4632fe56b9e6SYuval Mintz {
46330fefbfbaSSudarsana Kalluru 	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
4634fe56b9e6SYuval Mintz 	int i;
4635fe56b9e6SYuval Mintz 
46360fefbfbaSSudarsana Kalluru 	if (IS_PF(cdev))
46370fefbfbaSSudarsana Kalluru 		qed_mcp_ov_update_driver_state(p_hwfn, p_hwfn->p_main_ptt,
46380fefbfbaSSudarsana Kalluru 					       QED_OV_DRIVER_STATE_NOT_LOADED);
46390fefbfbaSSudarsana Kalluru 
4640fe56b9e6SYuval Mintz 	for_each_hwfn(cdev, i) {
4641fe56b9e6SYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
4642fe56b9e6SYuval Mintz 
46431408cc1fSYuval Mintz 		if (IS_VF(cdev)) {
46440b55e27dSYuval Mintz 			qed_vf_pf_release(p_hwfn);
46451408cc1fSYuval Mintz 			continue;
46461408cc1fSYuval Mintz 		}
46471408cc1fSYuval Mintz 
4648fe56b9e6SYuval Mintz 		qed_init_free(p_hwfn);
4649fe56b9e6SYuval Mintz 		qed_hw_hwfn_free(p_hwfn);
4650fe56b9e6SYuval Mintz 		qed_mcp_free(p_hwfn);
4651fe56b9e6SYuval Mintz 	}
465232a47e72SYuval Mintz 
465332a47e72SYuval Mintz 	qed_iov_free_hw_info(cdev);
465443645ce0SSudarsana Reddy Kalluru 
465543645ce0SSudarsana Reddy Kalluru 	qed_nvm_info_free(p_hwfn);
4656fe56b9e6SYuval Mintz }
4657fe56b9e6SYuval Mintz 
4658a91eb52aSYuval Mintz static void qed_chain_free_next_ptr(struct qed_dev *cdev,
4659a91eb52aSYuval Mintz 				    struct qed_chain *p_chain)
4660a91eb52aSYuval Mintz {
4661a91eb52aSYuval Mintz 	void *p_virt = p_chain->p_virt_addr, *p_virt_next = NULL;
4662a91eb52aSYuval Mintz 	dma_addr_t p_phys = p_chain->p_phys_addr, p_phys_next = 0;
4663a91eb52aSYuval Mintz 	struct qed_chain_next *p_next;
4664a91eb52aSYuval Mintz 	u32 size, i;
4665a91eb52aSYuval Mintz 
4666a91eb52aSYuval Mintz 	if (!p_virt)
4667a91eb52aSYuval Mintz 		return;
4668a91eb52aSYuval Mintz 
4669a91eb52aSYuval Mintz 	size = p_chain->elem_size * p_chain->usable_per_page;
4670a91eb52aSYuval Mintz 
4671a91eb52aSYuval Mintz 	for (i = 0; i < p_chain->page_cnt; i++) {
4672a91eb52aSYuval Mintz 		if (!p_virt)
4673a91eb52aSYuval Mintz 			break;
4674a91eb52aSYuval Mintz 
4675a91eb52aSYuval Mintz 		p_next = (struct qed_chain_next *)((u8 *)p_virt + size);
4676a91eb52aSYuval Mintz 		p_virt_next = p_next->next_virt;
4677a91eb52aSYuval Mintz 		p_phys_next = HILO_DMA_REGPAIR(p_next->next_phys);
4678a91eb52aSYuval Mintz 
4679a91eb52aSYuval Mintz 		dma_free_coherent(&cdev->pdev->dev,
4680a91eb52aSYuval Mintz 				  QED_CHAIN_PAGE_SIZE, p_virt, p_phys);
4681a91eb52aSYuval Mintz 
4682a91eb52aSYuval Mintz 		p_virt = p_virt_next;
4683a91eb52aSYuval Mintz 		p_phys = p_phys_next;
4684a91eb52aSYuval Mintz 	}
4685a91eb52aSYuval Mintz }
4686a91eb52aSYuval Mintz 
4687a91eb52aSYuval Mintz static void qed_chain_free_single(struct qed_dev *cdev,
4688a91eb52aSYuval Mintz 				  struct qed_chain *p_chain)
4689a91eb52aSYuval Mintz {
4690a91eb52aSYuval Mintz 	if (!p_chain->p_virt_addr)
4691a91eb52aSYuval Mintz 		return;
4692a91eb52aSYuval Mintz 
4693a91eb52aSYuval Mintz 	dma_free_coherent(&cdev->pdev->dev,
4694a91eb52aSYuval Mintz 			  QED_CHAIN_PAGE_SIZE,
4695a91eb52aSYuval Mintz 			  p_chain->p_virt_addr, p_chain->p_phys_addr);
4696a91eb52aSYuval Mintz }
4697a91eb52aSYuval Mintz 
4698a91eb52aSYuval Mintz static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
4699a91eb52aSYuval Mintz {
47008063f761SYuval Basson 	struct addr_tbl_entry *pp_addr_tbl = p_chain->pbl.pp_addr_tbl;
4701a91eb52aSYuval Mintz 	u32 page_cnt = p_chain->page_cnt, i, pbl_size;
4702a91eb52aSYuval Mintz 
47038063f761SYuval Basson 	if (!pp_addr_tbl)
4704a91eb52aSYuval Mintz 		return;
4705a91eb52aSYuval Mintz 
4706a91eb52aSYuval Mintz 	for (i = 0; i < page_cnt; i++) {
47078063f761SYuval Basson 		if (!pp_addr_tbl[i].virt_addr || !pp_addr_tbl[i].dma_map)
4708a91eb52aSYuval Mintz 			break;
4709a91eb52aSYuval Mintz 
4710a91eb52aSYuval Mintz 		dma_free_coherent(&cdev->pdev->dev,
4711a91eb52aSYuval Mintz 				  QED_CHAIN_PAGE_SIZE,
47128063f761SYuval Basson 				  pp_addr_tbl[i].virt_addr,
47138063f761SYuval Basson 				  pp_addr_tbl[i].dma_map);
4714a91eb52aSYuval Mintz 	}
4715a91eb52aSYuval Mintz 
4716a91eb52aSYuval Mintz 	pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
47171a4a6975SMintz, Yuval 
47181a4a6975SMintz, Yuval 	if (!p_chain->b_external_pbl)
4719a91eb52aSYuval Mintz 		dma_free_coherent(&cdev->pdev->dev,
4720a91eb52aSYuval Mintz 				  pbl_size,
47216d937acfSMintz, Yuval 				  p_chain->pbl_sp.p_virt_table,
47226d937acfSMintz, Yuval 				  p_chain->pbl_sp.p_phys_table);
47238063f761SYuval Basson 
47248063f761SYuval Basson 	vfree(p_chain->pbl.pp_addr_tbl);
47258063f761SYuval Basson 	p_chain->pbl.pp_addr_tbl = NULL;
4726a91eb52aSYuval Mintz }
4727a91eb52aSYuval Mintz 
4728a91eb52aSYuval Mintz void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain)
4729a91eb52aSYuval Mintz {
4730a91eb52aSYuval Mintz 	switch (p_chain->mode) {
4731a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_NEXT_PTR:
4732a91eb52aSYuval Mintz 		qed_chain_free_next_ptr(cdev, p_chain);
4733a91eb52aSYuval Mintz 		break;
4734a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_SINGLE:
4735a91eb52aSYuval Mintz 		qed_chain_free_single(cdev, p_chain);
4736a91eb52aSYuval Mintz 		break;
4737a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_PBL:
4738a91eb52aSYuval Mintz 		qed_chain_free_pbl(cdev, p_chain);
4739a91eb52aSYuval Mintz 		break;
4740a91eb52aSYuval Mintz 	}
4741a91eb52aSYuval Mintz }
4742a91eb52aSYuval Mintz 
4743a91eb52aSYuval Mintz static int
4744a91eb52aSYuval Mintz qed_chain_alloc_sanity_check(struct qed_dev *cdev,
4745a91eb52aSYuval Mintz 			     enum qed_chain_cnt_type cnt_type,
4746a91eb52aSYuval Mintz 			     size_t elem_size, u32 page_cnt)
4747a91eb52aSYuval Mintz {
4748a91eb52aSYuval Mintz 	u64 chain_size = ELEMS_PER_PAGE(elem_size) * page_cnt;
4749a91eb52aSYuval Mintz 
4750a91eb52aSYuval Mintz 	/* The actual chain size can be larger than the maximal possible value
4751a91eb52aSYuval Mintz 	 * after rounding up the requested elements number to pages, and after
4752a91eb52aSYuval Mintz 	 * taking into acount the unusuable elements (next-ptr elements).
4753a91eb52aSYuval Mintz 	 * The size of a "u16" chain can be (U16_MAX + 1) since the chain
4754a91eb52aSYuval Mintz 	 * size/capacity fields are of a u32 type.
4755a91eb52aSYuval Mintz 	 */
4756a91eb52aSYuval Mintz 	if ((cnt_type == QED_CHAIN_CNT_TYPE_U16 &&
47573ef310a7STomer Tayar 	     chain_size > ((u32)U16_MAX + 1)) ||
47583ef310a7STomer Tayar 	    (cnt_type == QED_CHAIN_CNT_TYPE_U32 && chain_size > U32_MAX)) {
4759a91eb52aSYuval Mintz 		DP_NOTICE(cdev,
4760a91eb52aSYuval Mintz 			  "The actual chain size (0x%llx) is larger than the maximal possible value\n",
4761a91eb52aSYuval Mintz 			  chain_size);
4762a91eb52aSYuval Mintz 		return -EINVAL;
4763a91eb52aSYuval Mintz 	}
4764a91eb52aSYuval Mintz 
4765a91eb52aSYuval Mintz 	return 0;
4766a91eb52aSYuval Mintz }
4767a91eb52aSYuval Mintz 
4768a91eb52aSYuval Mintz static int
4769a91eb52aSYuval Mintz qed_chain_alloc_next_ptr(struct qed_dev *cdev, struct qed_chain *p_chain)
4770a91eb52aSYuval Mintz {
4771a91eb52aSYuval Mintz 	void *p_virt = NULL, *p_virt_prev = NULL;
4772a91eb52aSYuval Mintz 	dma_addr_t p_phys = 0;
4773a91eb52aSYuval Mintz 	u32 i;
4774a91eb52aSYuval Mintz 
4775a91eb52aSYuval Mintz 	for (i = 0; i < p_chain->page_cnt; i++) {
4776a91eb52aSYuval Mintz 		p_virt = dma_alloc_coherent(&cdev->pdev->dev,
4777a91eb52aSYuval Mintz 					    QED_CHAIN_PAGE_SIZE,
4778a91eb52aSYuval Mintz 					    &p_phys, GFP_KERNEL);
47792591c280SJoe Perches 		if (!p_virt)
4780a91eb52aSYuval Mintz 			return -ENOMEM;
4781a91eb52aSYuval Mintz 
4782a91eb52aSYuval Mintz 		if (i == 0) {
4783a91eb52aSYuval Mintz 			qed_chain_init_mem(p_chain, p_virt, p_phys);
4784a91eb52aSYuval Mintz 			qed_chain_reset(p_chain);
4785a91eb52aSYuval Mintz 		} else {
4786a91eb52aSYuval Mintz 			qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
4787a91eb52aSYuval Mintz 						     p_virt, p_phys);
4788a91eb52aSYuval Mintz 		}
4789a91eb52aSYuval Mintz 
4790a91eb52aSYuval Mintz 		p_virt_prev = p_virt;
4791a91eb52aSYuval Mintz 	}
4792a91eb52aSYuval Mintz 	/* Last page's next element should point to the beginning of the
4793a91eb52aSYuval Mintz 	 * chain.
4794a91eb52aSYuval Mintz 	 */
4795a91eb52aSYuval Mintz 	qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
4796a91eb52aSYuval Mintz 				     p_chain->p_virt_addr,
4797a91eb52aSYuval Mintz 				     p_chain->p_phys_addr);
4798a91eb52aSYuval Mintz 
4799a91eb52aSYuval Mintz 	return 0;
4800a91eb52aSYuval Mintz }
4801a91eb52aSYuval Mintz 
4802a91eb52aSYuval Mintz static int
4803a91eb52aSYuval Mintz qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain)
4804a91eb52aSYuval Mintz {
4805a91eb52aSYuval Mintz 	dma_addr_t p_phys = 0;
4806a91eb52aSYuval Mintz 	void *p_virt = NULL;
4807a91eb52aSYuval Mintz 
4808a91eb52aSYuval Mintz 	p_virt = dma_alloc_coherent(&cdev->pdev->dev,
4809a91eb52aSYuval Mintz 				    QED_CHAIN_PAGE_SIZE, &p_phys, GFP_KERNEL);
48102591c280SJoe Perches 	if (!p_virt)
4811a91eb52aSYuval Mintz 		return -ENOMEM;
4812a91eb52aSYuval Mintz 
4813a91eb52aSYuval Mintz 	qed_chain_init_mem(p_chain, p_virt, p_phys);
4814a91eb52aSYuval Mintz 	qed_chain_reset(p_chain);
4815a91eb52aSYuval Mintz 
4816a91eb52aSYuval Mintz 	return 0;
4817a91eb52aSYuval Mintz }
4818a91eb52aSYuval Mintz 
48191a4a6975SMintz, Yuval static int
48201a4a6975SMintz, Yuval qed_chain_alloc_pbl(struct qed_dev *cdev,
48211a4a6975SMintz, Yuval 		    struct qed_chain *p_chain,
48221a4a6975SMintz, Yuval 		    struct qed_chain_ext_pbl *ext_pbl)
4823a91eb52aSYuval Mintz {
4824a91eb52aSYuval Mintz 	u32 page_cnt = p_chain->page_cnt, size, i;
4825a91eb52aSYuval Mintz 	dma_addr_t p_phys = 0, p_pbl_phys = 0;
48268063f761SYuval Basson 	struct addr_tbl_entry *pp_addr_tbl;
4827a91eb52aSYuval Mintz 	u8 *p_pbl_virt = NULL;
4828a91eb52aSYuval Mintz 	void *p_virt = NULL;
4829a91eb52aSYuval Mintz 
48308063f761SYuval Basson 	size = page_cnt * sizeof(*pp_addr_tbl);
48318063f761SYuval Basson 	pp_addr_tbl =  vzalloc(size);
48328063f761SYuval Basson 	if (!pp_addr_tbl)
4833a91eb52aSYuval Mintz 		return -ENOMEM;
4834a91eb52aSYuval Mintz 
4835a91eb52aSYuval Mintz 	/* The allocation of the PBL table is done with its full size, since it
4836a91eb52aSYuval Mintz 	 * is expected to be successive.
4837a91eb52aSYuval Mintz 	 * qed_chain_init_pbl_mem() is called even in a case of an allocation
48388063f761SYuval Basson 	 * failure, since tbl was previously allocated, and it
4839a91eb52aSYuval Mintz 	 * should be saved to allow its freeing during the error flow.
4840a91eb52aSYuval Mintz 	 */
4841a91eb52aSYuval Mintz 	size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
48421a4a6975SMintz, Yuval 
48431a4a6975SMintz, Yuval 	if (!ext_pbl) {
4844a91eb52aSYuval Mintz 		p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev,
4845a91eb52aSYuval Mintz 						size, &p_pbl_phys, GFP_KERNEL);
48461a4a6975SMintz, Yuval 	} else {
48471a4a6975SMintz, Yuval 		p_pbl_virt = ext_pbl->p_pbl_virt;
48481a4a6975SMintz, Yuval 		p_pbl_phys = ext_pbl->p_pbl_phys;
48491a4a6975SMintz, Yuval 		p_chain->b_external_pbl = true;
48501a4a6975SMintz, Yuval 	}
48511a4a6975SMintz, Yuval 
48528063f761SYuval Basson 	qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, pp_addr_tbl);
48532591c280SJoe Perches 	if (!p_pbl_virt)
4854a91eb52aSYuval Mintz 		return -ENOMEM;
4855a91eb52aSYuval Mintz 
4856a91eb52aSYuval Mintz 	for (i = 0; i < page_cnt; i++) {
4857a91eb52aSYuval Mintz 		p_virt = dma_alloc_coherent(&cdev->pdev->dev,
4858a91eb52aSYuval Mintz 					    QED_CHAIN_PAGE_SIZE,
4859a91eb52aSYuval Mintz 					    &p_phys, GFP_KERNEL);
48602591c280SJoe Perches 		if (!p_virt)
4861a91eb52aSYuval Mintz 			return -ENOMEM;
4862a91eb52aSYuval Mintz 
4863a91eb52aSYuval Mintz 		if (i == 0) {
4864a91eb52aSYuval Mintz 			qed_chain_init_mem(p_chain, p_virt, p_phys);
4865a91eb52aSYuval Mintz 			qed_chain_reset(p_chain);
4866a91eb52aSYuval Mintz 		}
4867a91eb52aSYuval Mintz 
4868a91eb52aSYuval Mintz 		/* Fill the PBL table with the physical address of the page */
4869a91eb52aSYuval Mintz 		*(dma_addr_t *)p_pbl_virt = p_phys;
4870a91eb52aSYuval Mintz 		/* Keep the virtual address of the page */
48718063f761SYuval Basson 		p_chain->pbl.pp_addr_tbl[i].virt_addr = p_virt;
48728063f761SYuval Basson 		p_chain->pbl.pp_addr_tbl[i].dma_map = p_phys;
4873a91eb52aSYuval Mintz 
4874a91eb52aSYuval Mintz 		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
4875a91eb52aSYuval Mintz 	}
4876a91eb52aSYuval Mintz 
4877a91eb52aSYuval Mintz 	return 0;
4878a91eb52aSYuval Mintz }
4879a91eb52aSYuval Mintz 
4880fe56b9e6SYuval Mintz int qed_chain_alloc(struct qed_dev *cdev,
4881fe56b9e6SYuval Mintz 		    enum qed_chain_use_mode intended_use,
4882fe56b9e6SYuval Mintz 		    enum qed_chain_mode mode,
4883a91eb52aSYuval Mintz 		    enum qed_chain_cnt_type cnt_type,
48841a4a6975SMintz, Yuval 		    u32 num_elems,
48851a4a6975SMintz, Yuval 		    size_t elem_size,
48861a4a6975SMintz, Yuval 		    struct qed_chain *p_chain,
48871a4a6975SMintz, Yuval 		    struct qed_chain_ext_pbl *ext_pbl)
4888fe56b9e6SYuval Mintz {
4889a91eb52aSYuval Mintz 	u32 page_cnt;
4890a91eb52aSYuval Mintz 	int rc = 0;
4891fe56b9e6SYuval Mintz 
4892fe56b9e6SYuval Mintz 	if (mode == QED_CHAIN_MODE_SINGLE)
4893fe56b9e6SYuval Mintz 		page_cnt = 1;
4894fe56b9e6SYuval Mintz 	else
4895fe56b9e6SYuval Mintz 		page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode);
4896fe56b9e6SYuval Mintz 
4897a91eb52aSYuval Mintz 	rc = qed_chain_alloc_sanity_check(cdev, cnt_type, elem_size, page_cnt);
4898a91eb52aSYuval Mintz 	if (rc) {
4899a91eb52aSYuval Mintz 		DP_NOTICE(cdev,
49002591c280SJoe Perches 			  "Cannot allocate a chain with the given arguments:\n");
49012591c280SJoe Perches 		DP_NOTICE(cdev,
4902a91eb52aSYuval Mintz 			  "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n",
4903a91eb52aSYuval Mintz 			  intended_use, mode, cnt_type, num_elems, elem_size);
4904a91eb52aSYuval Mintz 		return rc;
4905fe56b9e6SYuval Mintz 	}
4906fe56b9e6SYuval Mintz 
4907a91eb52aSYuval Mintz 	qed_chain_init_params(p_chain, page_cnt, (u8) elem_size, intended_use,
4908a91eb52aSYuval Mintz 			      mode, cnt_type);
4909fe56b9e6SYuval Mintz 
4910a91eb52aSYuval Mintz 	switch (mode) {
4911a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_NEXT_PTR:
4912a91eb52aSYuval Mintz 		rc = qed_chain_alloc_next_ptr(cdev, p_chain);
4913a91eb52aSYuval Mintz 		break;
4914a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_SINGLE:
4915a91eb52aSYuval Mintz 		rc = qed_chain_alloc_single(cdev, p_chain);
4916a91eb52aSYuval Mintz 		break;
4917a91eb52aSYuval Mintz 	case QED_CHAIN_MODE_PBL:
49181a4a6975SMintz, Yuval 		rc = qed_chain_alloc_pbl(cdev, p_chain, ext_pbl);
4919a91eb52aSYuval Mintz 		break;
4920fe56b9e6SYuval Mintz 	}
4921a91eb52aSYuval Mintz 	if (rc)
4922a91eb52aSYuval Mintz 		goto nomem;
4923fe56b9e6SYuval Mintz 
4924fe56b9e6SYuval Mintz 	return 0;
4925fe56b9e6SYuval Mintz 
4926fe56b9e6SYuval Mintz nomem:
4927a91eb52aSYuval Mintz 	qed_chain_free(cdev, p_chain);
4928a91eb52aSYuval Mintz 	return rc;
4929fe56b9e6SYuval Mintz }
4930fe56b9e6SYuval Mintz 
4931a91eb52aSYuval Mintz int qed_fw_l2_queue(struct qed_hwfn *p_hwfn, u16 src_id, u16 *dst_id)
4932cee4d264SManish Chopra {
4933cee4d264SManish Chopra 	if (src_id >= RESC_NUM(p_hwfn, QED_L2_QUEUE)) {
4934cee4d264SManish Chopra 		u16 min, max;
4935cee4d264SManish Chopra 
4936cee4d264SManish Chopra 		min = (u16) RESC_START(p_hwfn, QED_L2_QUEUE);
4937cee4d264SManish Chopra 		max = min + RESC_NUM(p_hwfn, QED_L2_QUEUE);
4938cee4d264SManish Chopra 		DP_NOTICE(p_hwfn,
4939cee4d264SManish Chopra 			  "l2_queue id [%d] is not valid, available indices [%d - %d]\n",
4940cee4d264SManish Chopra 			  src_id, min, max);
4941cee4d264SManish Chopra 
4942cee4d264SManish Chopra 		return -EINVAL;
4943cee4d264SManish Chopra 	}
4944cee4d264SManish Chopra 
4945cee4d264SManish Chopra 	*dst_id = RESC_START(p_hwfn, QED_L2_QUEUE) + src_id;
4946cee4d264SManish Chopra 
4947cee4d264SManish Chopra 	return 0;
4948cee4d264SManish Chopra }
4949cee4d264SManish Chopra 
49501a635e48SYuval Mintz int qed_fw_vport(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id)
4951cee4d264SManish Chopra {
4952cee4d264SManish Chopra 	if (src_id >= RESC_NUM(p_hwfn, QED_VPORT)) {
4953cee4d264SManish Chopra 		u8 min, max;
4954cee4d264SManish Chopra 
4955cee4d264SManish Chopra 		min = (u8)RESC_START(p_hwfn, QED_VPORT);
4956cee4d264SManish Chopra 		max = min + RESC_NUM(p_hwfn, QED_VPORT);
4957cee4d264SManish Chopra 		DP_NOTICE(p_hwfn,
4958cee4d264SManish Chopra 			  "vport id [%d] is not valid, available indices [%d - %d]\n",
4959cee4d264SManish Chopra 			  src_id, min, max);
4960cee4d264SManish Chopra 
4961cee4d264SManish Chopra 		return -EINVAL;
4962cee4d264SManish Chopra 	}
4963cee4d264SManish Chopra 
4964cee4d264SManish Chopra 	*dst_id = RESC_START(p_hwfn, QED_VPORT) + src_id;
4965cee4d264SManish Chopra 
4966cee4d264SManish Chopra 	return 0;
4967cee4d264SManish Chopra }
4968cee4d264SManish Chopra 
49691a635e48SYuval Mintz int qed_fw_rss_eng(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id)
4970cee4d264SManish Chopra {
4971cee4d264SManish Chopra 	if (src_id >= RESC_NUM(p_hwfn, QED_RSS_ENG)) {
4972cee4d264SManish Chopra 		u8 min, max;
4973cee4d264SManish Chopra 
4974cee4d264SManish Chopra 		min = (u8)RESC_START(p_hwfn, QED_RSS_ENG);
4975cee4d264SManish Chopra 		max = min + RESC_NUM(p_hwfn, QED_RSS_ENG);
4976cee4d264SManish Chopra 		DP_NOTICE(p_hwfn,
4977cee4d264SManish Chopra 			  "rss_eng id [%d] is not valid, available indices [%d - %d]\n",
4978cee4d264SManish Chopra 			  src_id, min, max);
4979cee4d264SManish Chopra 
4980cee4d264SManish Chopra 		return -EINVAL;
4981cee4d264SManish Chopra 	}
4982cee4d264SManish Chopra 
4983cee4d264SManish Chopra 	*dst_id = RESC_START(p_hwfn, QED_RSS_ENG) + src_id;
4984cee4d264SManish Chopra 
4985cee4d264SManish Chopra 	return 0;
4986cee4d264SManish Chopra }
4987bcd197c8SManish Chopra 
4988722003acSSudarsana Reddy Kalluru static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
4989722003acSSudarsana Reddy Kalluru 			    u32 hw_addr, void *p_eth_qzone,
4990722003acSSudarsana Reddy Kalluru 			    size_t eth_qzone_size, u8 timeset)
4991722003acSSudarsana Reddy Kalluru {
4992722003acSSudarsana Reddy Kalluru 	struct coalescing_timeset *p_coal_timeset;
4993722003acSSudarsana Reddy Kalluru 
4994722003acSSudarsana Reddy Kalluru 	if (p_hwfn->cdev->int_coalescing_mode != QED_COAL_MODE_ENABLE) {
4995722003acSSudarsana Reddy Kalluru 		DP_NOTICE(p_hwfn, "Coalescing configuration not enabled\n");
4996722003acSSudarsana Reddy Kalluru 		return -EINVAL;
4997722003acSSudarsana Reddy Kalluru 	}
4998722003acSSudarsana Reddy Kalluru 
4999722003acSSudarsana Reddy Kalluru 	p_coal_timeset = p_eth_qzone;
5000477f2d14SRahul Verma 	memset(p_eth_qzone, 0, eth_qzone_size);
5001722003acSSudarsana Reddy Kalluru 	SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset);
5002722003acSSudarsana Reddy Kalluru 	SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1);
5003722003acSSudarsana Reddy Kalluru 	qed_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size);
5004722003acSSudarsana Reddy Kalluru 
5005722003acSSudarsana Reddy Kalluru 	return 0;
5006722003acSSudarsana Reddy Kalluru }
5007722003acSSudarsana Reddy Kalluru 
5008477f2d14SRahul Verma int qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle)
5009477f2d14SRahul Verma {
5010477f2d14SRahul Verma 	struct qed_queue_cid *p_cid = p_handle;
5011477f2d14SRahul Verma 	struct qed_hwfn *p_hwfn;
5012477f2d14SRahul Verma 	struct qed_ptt *p_ptt;
5013477f2d14SRahul Verma 	int rc = 0;
5014477f2d14SRahul Verma 
5015477f2d14SRahul Verma 	p_hwfn = p_cid->p_owner;
5016477f2d14SRahul Verma 
5017477f2d14SRahul Verma 	if (IS_VF(p_hwfn->cdev))
5018477f2d14SRahul Verma 		return qed_vf_pf_set_coalesce(p_hwfn, rx_coal, tx_coal, p_cid);
5019477f2d14SRahul Verma 
5020477f2d14SRahul Verma 	p_ptt = qed_ptt_acquire(p_hwfn);
5021477f2d14SRahul Verma 	if (!p_ptt)
5022477f2d14SRahul Verma 		return -EAGAIN;
5023477f2d14SRahul Verma 
5024477f2d14SRahul Verma 	if (rx_coal) {
5025477f2d14SRahul Verma 		rc = qed_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid);
5026477f2d14SRahul Verma 		if (rc)
5027477f2d14SRahul Verma 			goto out;
5028477f2d14SRahul Verma 		p_hwfn->cdev->rx_coalesce_usecs = rx_coal;
5029477f2d14SRahul Verma 	}
5030477f2d14SRahul Verma 
5031477f2d14SRahul Verma 	if (tx_coal) {
5032477f2d14SRahul Verma 		rc = qed_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, p_cid);
5033477f2d14SRahul Verma 		if (rc)
5034477f2d14SRahul Verma 			goto out;
5035477f2d14SRahul Verma 		p_hwfn->cdev->tx_coalesce_usecs = tx_coal;
5036477f2d14SRahul Verma 	}
5037477f2d14SRahul Verma out:
5038477f2d14SRahul Verma 	qed_ptt_release(p_hwfn, p_ptt);
5039477f2d14SRahul Verma 	return rc;
5040477f2d14SRahul Verma }
5041477f2d14SRahul Verma 
5042477f2d14SRahul Verma int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn,
5043477f2d14SRahul Verma 			 struct qed_ptt *p_ptt,
5044477f2d14SRahul Verma 			 u16 coalesce, struct qed_queue_cid *p_cid)
5045722003acSSudarsana Reddy Kalluru {
5046722003acSSudarsana Reddy Kalluru 	struct ustorm_eth_queue_zone eth_qzone;
5047722003acSSudarsana Reddy Kalluru 	u8 timeset, timer_res;
5048722003acSSudarsana Reddy Kalluru 	u32 address;
5049722003acSSudarsana Reddy Kalluru 	int rc;
5050722003acSSudarsana Reddy Kalluru 
5051722003acSSudarsana Reddy Kalluru 	/* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */
5052722003acSSudarsana Reddy Kalluru 	if (coalesce <= 0x7F) {
5053722003acSSudarsana Reddy Kalluru 		timer_res = 0;
5054722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0xFF) {
5055722003acSSudarsana Reddy Kalluru 		timer_res = 1;
5056722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0x1FF) {
5057722003acSSudarsana Reddy Kalluru 		timer_res = 2;
5058722003acSSudarsana Reddy Kalluru 	} else {
5059722003acSSudarsana Reddy Kalluru 		DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce);
5060722003acSSudarsana Reddy Kalluru 		return -EINVAL;
5061722003acSSudarsana Reddy Kalluru 	}
5062722003acSSudarsana Reddy Kalluru 	timeset = (u8)(coalesce >> timer_res);
5063722003acSSudarsana Reddy Kalluru 
5064477f2d14SRahul Verma 	rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res,
5065477f2d14SRahul Verma 				   p_cid->sb_igu_id, false);
5066722003acSSudarsana Reddy Kalluru 	if (rc)
5067722003acSSudarsana Reddy Kalluru 		goto out;
5068722003acSSudarsana Reddy Kalluru 
5069477f2d14SRahul Verma 	address = BAR0_MAP_REG_USDM_RAM +
5070477f2d14SRahul Verma 		  USTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
5071722003acSSudarsana Reddy Kalluru 
5072722003acSSudarsana Reddy Kalluru 	rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
5073722003acSSudarsana Reddy Kalluru 			      sizeof(struct ustorm_eth_queue_zone), timeset);
5074722003acSSudarsana Reddy Kalluru 	if (rc)
5075722003acSSudarsana Reddy Kalluru 		goto out;
5076722003acSSudarsana Reddy Kalluru 
5077722003acSSudarsana Reddy Kalluru out:
5078722003acSSudarsana Reddy Kalluru 	return rc;
5079722003acSSudarsana Reddy Kalluru }
5080722003acSSudarsana Reddy Kalluru 
5081477f2d14SRahul Verma int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn,
5082477f2d14SRahul Verma 			 struct qed_ptt *p_ptt,
5083477f2d14SRahul Verma 			 u16 coalesce, struct qed_queue_cid *p_cid)
5084722003acSSudarsana Reddy Kalluru {
5085722003acSSudarsana Reddy Kalluru 	struct xstorm_eth_queue_zone eth_qzone;
5086722003acSSudarsana Reddy Kalluru 	u8 timeset, timer_res;
5087722003acSSudarsana Reddy Kalluru 	u32 address;
5088722003acSSudarsana Reddy Kalluru 	int rc;
5089722003acSSudarsana Reddy Kalluru 
5090722003acSSudarsana Reddy Kalluru 	/* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */
5091722003acSSudarsana Reddy Kalluru 	if (coalesce <= 0x7F) {
5092722003acSSudarsana Reddy Kalluru 		timer_res = 0;
5093722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0xFF) {
5094722003acSSudarsana Reddy Kalluru 		timer_res = 1;
5095722003acSSudarsana Reddy Kalluru 	} else if (coalesce <= 0x1FF) {
5096722003acSSudarsana Reddy Kalluru 		timer_res = 2;
5097722003acSSudarsana Reddy Kalluru 	} else {
5098722003acSSudarsana Reddy Kalluru 		DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce);
5099722003acSSudarsana Reddy Kalluru 		return -EINVAL;
5100722003acSSudarsana Reddy Kalluru 	}
5101722003acSSudarsana Reddy Kalluru 	timeset = (u8)(coalesce >> timer_res);
5102722003acSSudarsana Reddy Kalluru 
5103477f2d14SRahul Verma 	rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res,
5104477f2d14SRahul Verma 				   p_cid->sb_igu_id, true);
5105722003acSSudarsana Reddy Kalluru 	if (rc)
5106722003acSSudarsana Reddy Kalluru 		goto out;
5107722003acSSudarsana Reddy Kalluru 
5108477f2d14SRahul Verma 	address = BAR0_MAP_REG_XSDM_RAM +
5109477f2d14SRahul Verma 		  XSTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id);
5110722003acSSudarsana Reddy Kalluru 
5111722003acSSudarsana Reddy Kalluru 	rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
5112722003acSSudarsana Reddy Kalluru 			      sizeof(struct xstorm_eth_queue_zone), timeset);
5113722003acSSudarsana Reddy Kalluru out:
5114722003acSSudarsana Reddy Kalluru 	return rc;
5115722003acSSudarsana Reddy Kalluru }
5116722003acSSudarsana Reddy Kalluru 
5117bcd197c8SManish Chopra /* Calculate final WFQ values for all vports and configure them.
5118bcd197c8SManish Chopra  * After this configuration each vport will have
5119bcd197c8SManish Chopra  * approx min rate =  min_pf_rate * (vport_wfq / QED_WFQ_UNIT)
5120bcd197c8SManish Chopra  */
5121bcd197c8SManish Chopra static void qed_configure_wfq_for_all_vports(struct qed_hwfn *p_hwfn,
5122bcd197c8SManish Chopra 					     struct qed_ptt *p_ptt,
5123bcd197c8SManish Chopra 					     u32 min_pf_rate)
5124bcd197c8SManish Chopra {
5125bcd197c8SManish Chopra 	struct init_qm_vport_params *vport_params;
5126bcd197c8SManish Chopra 	int i;
5127bcd197c8SManish Chopra 
5128bcd197c8SManish Chopra 	vport_params = p_hwfn->qm_info.qm_vport_params;
5129bcd197c8SManish Chopra 
5130bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++) {
5131bcd197c8SManish Chopra 		u32 wfq_speed = p_hwfn->qm_info.wfq_data[i].min_speed;
5132bcd197c8SManish Chopra 
513392fae6fbSMichal Kalderon 		vport_params[i].wfq = (wfq_speed * QED_WFQ_UNIT) /
5134bcd197c8SManish Chopra 						min_pf_rate;
5135bcd197c8SManish Chopra 		qed_init_vport_wfq(p_hwfn, p_ptt,
5136bcd197c8SManish Chopra 				   vport_params[i].first_tx_pq_id,
513792fae6fbSMichal Kalderon 				   vport_params[i].wfq);
5138bcd197c8SManish Chopra 	}
5139bcd197c8SManish Chopra }
5140bcd197c8SManish Chopra 
5141bcd197c8SManish Chopra static void qed_init_wfq_default_param(struct qed_hwfn *p_hwfn,
5142bcd197c8SManish Chopra 				       u32 min_pf_rate)
5143bcd197c8SManish Chopra 
5144bcd197c8SManish Chopra {
5145bcd197c8SManish Chopra 	int i;
5146bcd197c8SManish Chopra 
5147bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++)
514892fae6fbSMichal Kalderon 		p_hwfn->qm_info.qm_vport_params[i].wfq = 1;
5149bcd197c8SManish Chopra }
5150bcd197c8SManish Chopra 
5151bcd197c8SManish Chopra static void qed_disable_wfq_for_all_vports(struct qed_hwfn *p_hwfn,
5152bcd197c8SManish Chopra 					   struct qed_ptt *p_ptt,
5153bcd197c8SManish Chopra 					   u32 min_pf_rate)
5154bcd197c8SManish Chopra {
5155bcd197c8SManish Chopra 	struct init_qm_vport_params *vport_params;
5156bcd197c8SManish Chopra 	int i;
5157bcd197c8SManish Chopra 
5158bcd197c8SManish Chopra 	vport_params = p_hwfn->qm_info.qm_vport_params;
5159bcd197c8SManish Chopra 
5160bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++) {
5161bcd197c8SManish Chopra 		qed_init_wfq_default_param(p_hwfn, min_pf_rate);
5162bcd197c8SManish Chopra 		qed_init_vport_wfq(p_hwfn, p_ptt,
5163bcd197c8SManish Chopra 				   vport_params[i].first_tx_pq_id,
516492fae6fbSMichal Kalderon 				   vport_params[i].wfq);
5165bcd197c8SManish Chopra 	}
5166bcd197c8SManish Chopra }
5167bcd197c8SManish Chopra 
5168bcd197c8SManish Chopra /* This function performs several validations for WFQ
5169bcd197c8SManish Chopra  * configuration and required min rate for a given vport
5170bcd197c8SManish Chopra  * 1. req_rate must be greater than one percent of min_pf_rate.
5171bcd197c8SManish Chopra  * 2. req_rate should not cause other vports [not configured for WFQ explicitly]
5172bcd197c8SManish Chopra  *    rates to get less than one percent of min_pf_rate.
5173bcd197c8SManish Chopra  * 3. total_req_min_rate [all vports min rate sum] shouldn't exceed min_pf_rate.
5174bcd197c8SManish Chopra  */
5175bcd197c8SManish Chopra static int qed_init_wfq_param(struct qed_hwfn *p_hwfn,
51761a635e48SYuval Mintz 			      u16 vport_id, u32 req_rate, u32 min_pf_rate)
5177bcd197c8SManish Chopra {
5178bcd197c8SManish Chopra 	u32 total_req_min_rate = 0, total_left_rate = 0, left_rate_per_vp = 0;
5179bcd197c8SManish Chopra 	int non_requested_count = 0, req_count = 0, i, num_vports;
5180bcd197c8SManish Chopra 
5181bcd197c8SManish Chopra 	num_vports = p_hwfn->qm_info.num_vports;
5182bcd197c8SManish Chopra 
5183bcd197c8SManish Chopra 	/* Accounting for the vports which are configured for WFQ explicitly */
5184bcd197c8SManish Chopra 	for (i = 0; i < num_vports; i++) {
5185bcd197c8SManish Chopra 		u32 tmp_speed;
5186bcd197c8SManish Chopra 
5187bcd197c8SManish Chopra 		if ((i != vport_id) &&
5188bcd197c8SManish Chopra 		    p_hwfn->qm_info.wfq_data[i].configured) {
5189bcd197c8SManish Chopra 			req_count++;
5190bcd197c8SManish Chopra 			tmp_speed = p_hwfn->qm_info.wfq_data[i].min_speed;
5191bcd197c8SManish Chopra 			total_req_min_rate += tmp_speed;
5192bcd197c8SManish Chopra 		}
5193bcd197c8SManish Chopra 	}
5194bcd197c8SManish Chopra 
5195bcd197c8SManish Chopra 	/* Include current vport data as well */
5196bcd197c8SManish Chopra 	req_count++;
5197bcd197c8SManish Chopra 	total_req_min_rate += req_rate;
5198bcd197c8SManish Chopra 	non_requested_count = num_vports - req_count;
5199bcd197c8SManish Chopra 
5200bcd197c8SManish Chopra 	if (req_rate < min_pf_rate / QED_WFQ_UNIT) {
5201bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5202bcd197c8SManish Chopra 			   "Vport [%d] - Requested rate[%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n",
5203bcd197c8SManish Chopra 			   vport_id, req_rate, min_pf_rate);
5204bcd197c8SManish Chopra 		return -EINVAL;
5205bcd197c8SManish Chopra 	}
5206bcd197c8SManish Chopra 
5207bcd197c8SManish Chopra 	if (num_vports > QED_WFQ_UNIT) {
5208bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5209bcd197c8SManish Chopra 			   "Number of vports is greater than %d\n",
5210bcd197c8SManish Chopra 			   QED_WFQ_UNIT);
5211bcd197c8SManish Chopra 		return -EINVAL;
5212bcd197c8SManish Chopra 	}
5213bcd197c8SManish Chopra 
5214bcd197c8SManish Chopra 	if (total_req_min_rate > min_pf_rate) {
5215bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5216bcd197c8SManish Chopra 			   "Total requested min rate for all vports[%d Mbps] is greater than configured PF min rate[%d Mbps]\n",
5217bcd197c8SManish Chopra 			   total_req_min_rate, min_pf_rate);
5218bcd197c8SManish Chopra 		return -EINVAL;
5219bcd197c8SManish Chopra 	}
5220bcd197c8SManish Chopra 
5221bcd197c8SManish Chopra 	total_left_rate	= min_pf_rate - total_req_min_rate;
5222bcd197c8SManish Chopra 
5223bcd197c8SManish Chopra 	left_rate_per_vp = total_left_rate / non_requested_count;
5224bcd197c8SManish Chopra 	if (left_rate_per_vp <  min_pf_rate / QED_WFQ_UNIT) {
5225bcd197c8SManish Chopra 		DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5226bcd197c8SManish Chopra 			   "Non WFQ configured vports rate [%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n",
5227bcd197c8SManish Chopra 			   left_rate_per_vp, min_pf_rate);
5228bcd197c8SManish Chopra 		return -EINVAL;
5229bcd197c8SManish Chopra 	}
5230bcd197c8SManish Chopra 
5231bcd197c8SManish Chopra 	p_hwfn->qm_info.wfq_data[vport_id].min_speed = req_rate;
5232bcd197c8SManish Chopra 	p_hwfn->qm_info.wfq_data[vport_id].configured = true;
5233bcd197c8SManish Chopra 
5234bcd197c8SManish Chopra 	for (i = 0; i < num_vports; i++) {
5235bcd197c8SManish Chopra 		if (p_hwfn->qm_info.wfq_data[i].configured)
5236bcd197c8SManish Chopra 			continue;
5237bcd197c8SManish Chopra 
5238bcd197c8SManish Chopra 		p_hwfn->qm_info.wfq_data[i].min_speed = left_rate_per_vp;
5239bcd197c8SManish Chopra 	}
5240bcd197c8SManish Chopra 
5241bcd197c8SManish Chopra 	return 0;
5242bcd197c8SManish Chopra }
5243bcd197c8SManish Chopra 
5244733def6aSYuval Mintz static int __qed_configure_vport_wfq(struct qed_hwfn *p_hwfn,
5245733def6aSYuval Mintz 				     struct qed_ptt *p_ptt, u16 vp_id, u32 rate)
5246733def6aSYuval Mintz {
5247733def6aSYuval Mintz 	struct qed_mcp_link_state *p_link;
5248733def6aSYuval Mintz 	int rc = 0;
5249733def6aSYuval Mintz 
5250733def6aSYuval Mintz 	p_link = &p_hwfn->cdev->hwfns[0].mcp_info->link_output;
5251733def6aSYuval Mintz 
5252733def6aSYuval Mintz 	if (!p_link->min_pf_rate) {
5253733def6aSYuval Mintz 		p_hwfn->qm_info.wfq_data[vp_id].min_speed = rate;
5254733def6aSYuval Mintz 		p_hwfn->qm_info.wfq_data[vp_id].configured = true;
5255733def6aSYuval Mintz 		return rc;
5256733def6aSYuval Mintz 	}
5257733def6aSYuval Mintz 
5258733def6aSYuval Mintz 	rc = qed_init_wfq_param(p_hwfn, vp_id, rate, p_link->min_pf_rate);
5259733def6aSYuval Mintz 
52601a635e48SYuval Mintz 	if (!rc)
5261733def6aSYuval Mintz 		qed_configure_wfq_for_all_vports(p_hwfn, p_ptt,
5262733def6aSYuval Mintz 						 p_link->min_pf_rate);
5263733def6aSYuval Mintz 	else
5264733def6aSYuval Mintz 		DP_NOTICE(p_hwfn,
5265733def6aSYuval Mintz 			  "Validation failed while configuring min rate\n");
5266733def6aSYuval Mintz 
5267733def6aSYuval Mintz 	return rc;
5268733def6aSYuval Mintz }
5269733def6aSYuval Mintz 
5270bcd197c8SManish Chopra static int __qed_configure_vp_wfq_on_link_change(struct qed_hwfn *p_hwfn,
5271bcd197c8SManish Chopra 						 struct qed_ptt *p_ptt,
5272bcd197c8SManish Chopra 						 u32 min_pf_rate)
5273bcd197c8SManish Chopra {
5274bcd197c8SManish Chopra 	bool use_wfq = false;
5275bcd197c8SManish Chopra 	int rc = 0;
5276bcd197c8SManish Chopra 	u16 i;
5277bcd197c8SManish Chopra 
5278bcd197c8SManish Chopra 	/* Validate all pre configured vports for wfq */
5279bcd197c8SManish Chopra 	for (i = 0; i < p_hwfn->qm_info.num_vports; i++) {
5280bcd197c8SManish Chopra 		u32 rate;
5281bcd197c8SManish Chopra 
5282bcd197c8SManish Chopra 		if (!p_hwfn->qm_info.wfq_data[i].configured)
5283bcd197c8SManish Chopra 			continue;
5284bcd197c8SManish Chopra 
5285bcd197c8SManish Chopra 		rate = p_hwfn->qm_info.wfq_data[i].min_speed;
5286bcd197c8SManish Chopra 		use_wfq = true;
5287bcd197c8SManish Chopra 
5288bcd197c8SManish Chopra 		rc = qed_init_wfq_param(p_hwfn, i, rate, min_pf_rate);
5289bcd197c8SManish Chopra 		if (rc) {
5290bcd197c8SManish Chopra 			DP_NOTICE(p_hwfn,
5291bcd197c8SManish Chopra 				  "WFQ validation failed while configuring min rate\n");
5292bcd197c8SManish Chopra 			break;
5293bcd197c8SManish Chopra 		}
5294bcd197c8SManish Chopra 	}
5295bcd197c8SManish Chopra 
5296bcd197c8SManish Chopra 	if (!rc && use_wfq)
5297bcd197c8SManish Chopra 		qed_configure_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate);
5298bcd197c8SManish Chopra 	else
5299bcd197c8SManish Chopra 		qed_disable_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate);
5300bcd197c8SManish Chopra 
5301bcd197c8SManish Chopra 	return rc;
5302bcd197c8SManish Chopra }
5303bcd197c8SManish Chopra 
5304733def6aSYuval Mintz /* Main API for qed clients to configure vport min rate.
5305733def6aSYuval Mintz  * vp_id - vport id in PF Range[0 - (total_num_vports_per_pf - 1)]
5306733def6aSYuval Mintz  * rate - Speed in Mbps needs to be assigned to a given vport.
5307733def6aSYuval Mintz  */
5308733def6aSYuval Mintz int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate)
5309733def6aSYuval Mintz {
5310733def6aSYuval Mintz 	int i, rc = -EINVAL;
5311733def6aSYuval Mintz 
5312733def6aSYuval Mintz 	/* Currently not supported; Might change in future */
5313733def6aSYuval Mintz 	if (cdev->num_hwfns > 1) {
5314733def6aSYuval Mintz 		DP_NOTICE(cdev,
5315733def6aSYuval Mintz 			  "WFQ configuration is not supported for this device\n");
5316733def6aSYuval Mintz 		return rc;
5317733def6aSYuval Mintz 	}
5318733def6aSYuval Mintz 
5319733def6aSYuval Mintz 	for_each_hwfn(cdev, i) {
5320733def6aSYuval Mintz 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
5321733def6aSYuval Mintz 		struct qed_ptt *p_ptt;
5322733def6aSYuval Mintz 
5323733def6aSYuval Mintz 		p_ptt = qed_ptt_acquire(p_hwfn);
5324733def6aSYuval Mintz 		if (!p_ptt)
5325733def6aSYuval Mintz 			return -EBUSY;
5326733def6aSYuval Mintz 
5327733def6aSYuval Mintz 		rc = __qed_configure_vport_wfq(p_hwfn, p_ptt, vp_id, rate);
5328733def6aSYuval Mintz 
5329d572c430SYuval Mintz 		if (rc) {
5330733def6aSYuval Mintz 			qed_ptt_release(p_hwfn, p_ptt);
5331733def6aSYuval Mintz 			return rc;
5332733def6aSYuval Mintz 		}
5333733def6aSYuval Mintz 
5334733def6aSYuval Mintz 		qed_ptt_release(p_hwfn, p_ptt);
5335733def6aSYuval Mintz 	}
5336733def6aSYuval Mintz 
5337733def6aSYuval Mintz 	return rc;
5338733def6aSYuval Mintz }
5339733def6aSYuval Mintz 
5340bcd197c8SManish Chopra /* API to configure WFQ from mcp link change */
53416f437d43SMintz, Yuval void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev,
53426f437d43SMintz, Yuval 					 struct qed_ptt *p_ptt, u32 min_pf_rate)
5343bcd197c8SManish Chopra {
5344bcd197c8SManish Chopra 	int i;
5345bcd197c8SManish Chopra 
53463e7cfce2SYuval Mintz 	if (cdev->num_hwfns > 1) {
53473e7cfce2SYuval Mintz 		DP_VERBOSE(cdev,
53483e7cfce2SYuval Mintz 			   NETIF_MSG_LINK,
53493e7cfce2SYuval Mintz 			   "WFQ configuration is not supported for this device\n");
53503e7cfce2SYuval Mintz 		return;
53513e7cfce2SYuval Mintz 	}
53523e7cfce2SYuval Mintz 
5353bcd197c8SManish Chopra 	for_each_hwfn(cdev, i) {
5354bcd197c8SManish Chopra 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
5355bcd197c8SManish Chopra 
53566f437d43SMintz, Yuval 		__qed_configure_vp_wfq_on_link_change(p_hwfn, p_ptt,
5357bcd197c8SManish Chopra 						      min_pf_rate);
5358bcd197c8SManish Chopra 	}
5359bcd197c8SManish Chopra }
53604b01e519SManish Chopra 
53614b01e519SManish Chopra int __qed_configure_pf_max_bandwidth(struct qed_hwfn *p_hwfn,
53624b01e519SManish Chopra 				     struct qed_ptt *p_ptt,
53634b01e519SManish Chopra 				     struct qed_mcp_link_state *p_link,
53644b01e519SManish Chopra 				     u8 max_bw)
53654b01e519SManish Chopra {
53664b01e519SManish Chopra 	int rc = 0;
53674b01e519SManish Chopra 
53684b01e519SManish Chopra 	p_hwfn->mcp_info->func_info.bandwidth_max = max_bw;
53694b01e519SManish Chopra 
53704b01e519SManish Chopra 	if (!p_link->line_speed && (max_bw != 100))
53714b01e519SManish Chopra 		return rc;
53724b01e519SManish Chopra 
53734b01e519SManish Chopra 	p_link->speed = (p_link->line_speed * max_bw) / 100;
53744b01e519SManish Chopra 	p_hwfn->qm_info.pf_rl = p_link->speed;
53754b01e519SManish Chopra 
53764b01e519SManish Chopra 	/* Since the limiter also affects Tx-switched traffic, we don't want it
53774b01e519SManish Chopra 	 * to limit such traffic in case there's no actual limit.
53784b01e519SManish Chopra 	 * In that case, set limit to imaginary high boundary.
53794b01e519SManish Chopra 	 */
53804b01e519SManish Chopra 	if (max_bw == 100)
53814b01e519SManish Chopra 		p_hwfn->qm_info.pf_rl = 100000;
53824b01e519SManish Chopra 
53834b01e519SManish Chopra 	rc = qed_init_pf_rl(p_hwfn, p_ptt, p_hwfn->rel_pf_id,
53844b01e519SManish Chopra 			    p_hwfn->qm_info.pf_rl);
53854b01e519SManish Chopra 
53864b01e519SManish Chopra 	DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
53874b01e519SManish Chopra 		   "Configured MAX bandwidth to be %08x Mb/sec\n",
53884b01e519SManish Chopra 		   p_link->speed);
53894b01e519SManish Chopra 
53904b01e519SManish Chopra 	return rc;
53914b01e519SManish Chopra }
53924b01e519SManish Chopra 
53934b01e519SManish Chopra /* Main API to configure PF max bandwidth where bw range is [1 - 100] */
53944b01e519SManish Chopra int qed_configure_pf_max_bandwidth(struct qed_dev *cdev, u8 max_bw)
53954b01e519SManish Chopra {
53964b01e519SManish Chopra 	int i, rc = -EINVAL;
53974b01e519SManish Chopra 
53984b01e519SManish Chopra 	if (max_bw < 1 || max_bw > 100) {
53994b01e519SManish Chopra 		DP_NOTICE(cdev, "PF max bw valid range is [1-100]\n");
54004b01e519SManish Chopra 		return rc;
54014b01e519SManish Chopra 	}
54024b01e519SManish Chopra 
54034b01e519SManish Chopra 	for_each_hwfn(cdev, i) {
54044b01e519SManish Chopra 		struct qed_hwfn	*p_hwfn = &cdev->hwfns[i];
54054b01e519SManish Chopra 		struct qed_hwfn *p_lead = QED_LEADING_HWFN(cdev);
54064b01e519SManish Chopra 		struct qed_mcp_link_state *p_link;
54074b01e519SManish Chopra 		struct qed_ptt *p_ptt;
54084b01e519SManish Chopra 
54094b01e519SManish Chopra 		p_link = &p_lead->mcp_info->link_output;
54104b01e519SManish Chopra 
54114b01e519SManish Chopra 		p_ptt = qed_ptt_acquire(p_hwfn);
54124b01e519SManish Chopra 		if (!p_ptt)
54134b01e519SManish Chopra 			return -EBUSY;
54144b01e519SManish Chopra 
54154b01e519SManish Chopra 		rc = __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt,
54164b01e519SManish Chopra 						      p_link, max_bw);
54174b01e519SManish Chopra 
54184b01e519SManish Chopra 		qed_ptt_release(p_hwfn, p_ptt);
54194b01e519SManish Chopra 
54204b01e519SManish Chopra 		if (rc)
54214b01e519SManish Chopra 			break;
54224b01e519SManish Chopra 	}
54234b01e519SManish Chopra 
54244b01e519SManish Chopra 	return rc;
54254b01e519SManish Chopra }
5426a64b02d5SManish Chopra 
5427a64b02d5SManish Chopra int __qed_configure_pf_min_bandwidth(struct qed_hwfn *p_hwfn,
5428a64b02d5SManish Chopra 				     struct qed_ptt *p_ptt,
5429a64b02d5SManish Chopra 				     struct qed_mcp_link_state *p_link,
5430a64b02d5SManish Chopra 				     u8 min_bw)
5431a64b02d5SManish Chopra {
5432a64b02d5SManish Chopra 	int rc = 0;
5433a64b02d5SManish Chopra 
5434a64b02d5SManish Chopra 	p_hwfn->mcp_info->func_info.bandwidth_min = min_bw;
5435a64b02d5SManish Chopra 	p_hwfn->qm_info.pf_wfq = min_bw;
5436a64b02d5SManish Chopra 
5437a64b02d5SManish Chopra 	if (!p_link->line_speed)
5438a64b02d5SManish Chopra 		return rc;
5439a64b02d5SManish Chopra 
5440a64b02d5SManish Chopra 	p_link->min_pf_rate = (p_link->line_speed * min_bw) / 100;
5441a64b02d5SManish Chopra 
5442a64b02d5SManish Chopra 	rc = qed_init_pf_wfq(p_hwfn, p_ptt, p_hwfn->rel_pf_id, min_bw);
5443a64b02d5SManish Chopra 
5444a64b02d5SManish Chopra 	DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
5445a64b02d5SManish Chopra 		   "Configured MIN bandwidth to be %d Mb/sec\n",
5446a64b02d5SManish Chopra 		   p_link->min_pf_rate);
5447a64b02d5SManish Chopra 
5448a64b02d5SManish Chopra 	return rc;
5449a64b02d5SManish Chopra }
5450a64b02d5SManish Chopra 
5451a64b02d5SManish Chopra /* Main API to configure PF min bandwidth where bw range is [1-100] */
5452a64b02d5SManish Chopra int qed_configure_pf_min_bandwidth(struct qed_dev *cdev, u8 min_bw)
5453a64b02d5SManish Chopra {
5454a64b02d5SManish Chopra 	int i, rc = -EINVAL;
5455a64b02d5SManish Chopra 
5456a64b02d5SManish Chopra 	if (min_bw < 1 || min_bw > 100) {
5457a64b02d5SManish Chopra 		DP_NOTICE(cdev, "PF min bw valid range is [1-100]\n");
5458a64b02d5SManish Chopra 		return rc;
5459a64b02d5SManish Chopra 	}
5460a64b02d5SManish Chopra 
5461a64b02d5SManish Chopra 	for_each_hwfn(cdev, i) {
5462a64b02d5SManish Chopra 		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
5463a64b02d5SManish Chopra 		struct qed_hwfn *p_lead = QED_LEADING_HWFN(cdev);
5464a64b02d5SManish Chopra 		struct qed_mcp_link_state *p_link;
5465a64b02d5SManish Chopra 		struct qed_ptt *p_ptt;
5466a64b02d5SManish Chopra 
5467a64b02d5SManish Chopra 		p_link = &p_lead->mcp_info->link_output;
5468a64b02d5SManish Chopra 
5469a64b02d5SManish Chopra 		p_ptt = qed_ptt_acquire(p_hwfn);
5470a64b02d5SManish Chopra 		if (!p_ptt)
5471a64b02d5SManish Chopra 			return -EBUSY;
5472a64b02d5SManish Chopra 
5473a64b02d5SManish Chopra 		rc = __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt,
5474a64b02d5SManish Chopra 						      p_link, min_bw);
5475a64b02d5SManish Chopra 		if (rc) {
5476a64b02d5SManish Chopra 			qed_ptt_release(p_hwfn, p_ptt);
5477a64b02d5SManish Chopra 			return rc;
5478a64b02d5SManish Chopra 		}
5479a64b02d5SManish Chopra 
5480a64b02d5SManish Chopra 		if (p_link->min_pf_rate) {
5481a64b02d5SManish Chopra 			u32 min_rate = p_link->min_pf_rate;
5482a64b02d5SManish Chopra 
5483a64b02d5SManish Chopra 			rc = __qed_configure_vp_wfq_on_link_change(p_hwfn,
5484a64b02d5SManish Chopra 								   p_ptt,
5485a64b02d5SManish Chopra 								   min_rate);
5486a64b02d5SManish Chopra 		}
5487a64b02d5SManish Chopra 
5488a64b02d5SManish Chopra 		qed_ptt_release(p_hwfn, p_ptt);
5489a64b02d5SManish Chopra 	}
5490a64b02d5SManish Chopra 
5491a64b02d5SManish Chopra 	return rc;
5492a64b02d5SManish Chopra }
5493733def6aSYuval Mintz 
5494733def6aSYuval Mintz void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
5495733def6aSYuval Mintz {
5496733def6aSYuval Mintz 	struct qed_mcp_link_state *p_link;
5497733def6aSYuval Mintz 
5498733def6aSYuval Mintz 	p_link = &p_hwfn->mcp_info->link_output;
5499733def6aSYuval Mintz 
5500733def6aSYuval Mintz 	if (p_link->min_pf_rate)
5501733def6aSYuval Mintz 		qed_disable_wfq_for_all_vports(p_hwfn, p_ptt,
5502733def6aSYuval Mintz 					       p_link->min_pf_rate);
5503733def6aSYuval Mintz 
5504733def6aSYuval Mintz 	memset(p_hwfn->qm_info.wfq_data, 0,
5505733def6aSYuval Mintz 	       sizeof(*p_hwfn->qm_info.wfq_data) * p_hwfn->qm_info.num_vports);
5506733def6aSYuval Mintz }
55079c79ddaaSMintz, Yuval 
55080ebcebbeSSudarsana Reddy Kalluru int qed_device_num_ports(struct qed_dev *cdev)
55099c79ddaaSMintz, Yuval {
55100ebcebbeSSudarsana Reddy Kalluru 	return cdev->num_ports;
5511db82f70eSsudarsana.kalluru@cavium.com }
5512456a5849SKalderon, Michal 
5513456a5849SKalderon, Michal void qed_set_fw_mac_addr(__le16 *fw_msb,
5514456a5849SKalderon, Michal 			 __le16 *fw_mid, __le16 *fw_lsb, u8 *mac)
5515456a5849SKalderon, Michal {
5516456a5849SKalderon, Michal 	((u8 *)fw_msb)[0] = mac[1];
5517456a5849SKalderon, Michal 	((u8 *)fw_msb)[1] = mac[0];
5518456a5849SKalderon, Michal 	((u8 *)fw_mid)[0] = mac[3];
5519456a5849SKalderon, Michal 	((u8 *)fw_mid)[1] = mac[2];
5520456a5849SKalderon, Michal 	((u8 *)fw_lsb)[0] = mac[5];
5521456a5849SKalderon, Michal 	((u8 *)fw_lsb)[1] = mac[4];
5522456a5849SKalderon, Michal }
5523