162306a36Sopenharmony_ci/* bnx2x_sp.c: Qlogic Everest network driver.
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Copyright 2011-2013 Broadcom Corporation
462306a36Sopenharmony_ci * Copyright (c) 2014 QLogic Corporation
562306a36Sopenharmony_ci * All rights reserved
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Unless you and Qlogic execute a separate written software license
862306a36Sopenharmony_ci * agreement governing use of this software, this software is licensed to you
962306a36Sopenharmony_ci * under the terms of the GNU General Public License version 2, available
1062306a36Sopenharmony_ci * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL").
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Notwithstanding the above, under no circumstances may you combine this
1362306a36Sopenharmony_ci * software in any way with any other Qlogic software provided under a
1462306a36Sopenharmony_ci * license other than the GPL, without Qlogic's express prior written
1562306a36Sopenharmony_ci * consent.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com>
1862306a36Sopenharmony_ci * Written by: Vladislav Zolotarov
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/module.h>
2562306a36Sopenharmony_ci#include <linux/crc32.h>
2662306a36Sopenharmony_ci#include <linux/netdevice.h>
2762306a36Sopenharmony_ci#include <linux/etherdevice.h>
2862306a36Sopenharmony_ci#include <linux/crc32c.h>
2962306a36Sopenharmony_ci#include "bnx2x.h"
3062306a36Sopenharmony_ci#include "bnx2x_cmn.h"
3162306a36Sopenharmony_ci#include "bnx2x_sp.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define BNX2X_MAX_EMUL_MULTI		16
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/**** Exe Queue interfaces ****/
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/**
3862306a36Sopenharmony_ci * bnx2x_exe_queue_init - init the Exe Queue object
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * @bp:		driver handle
4162306a36Sopenharmony_ci * @o:		pointer to the object
4262306a36Sopenharmony_ci * @exe_len:	length
4362306a36Sopenharmony_ci * @owner:	pointer to the owner
4462306a36Sopenharmony_ci * @validate:	validate function pointer
4562306a36Sopenharmony_ci * @remove:	remove function pointer
4662306a36Sopenharmony_ci * @optimize:	optimize function pointer
4762306a36Sopenharmony_ci * @exec:	execute function pointer
4862306a36Sopenharmony_ci * @get:	get function pointer
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_cistatic inline void bnx2x_exe_queue_init(struct bnx2x *bp,
5162306a36Sopenharmony_ci					struct bnx2x_exe_queue_obj *o,
5262306a36Sopenharmony_ci					int exe_len,
5362306a36Sopenharmony_ci					union bnx2x_qable_obj *owner,
5462306a36Sopenharmony_ci					exe_q_validate validate,
5562306a36Sopenharmony_ci					exe_q_remove remove,
5662306a36Sopenharmony_ci					exe_q_optimize optimize,
5762306a36Sopenharmony_ci					exe_q_execute exec,
5862306a36Sopenharmony_ci					exe_q_get get)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	memset(o, 0, sizeof(*o));
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	INIT_LIST_HEAD(&o->exe_queue);
6362306a36Sopenharmony_ci	INIT_LIST_HEAD(&o->pending_comp);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	spin_lock_init(&o->lock);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	o->exe_chunk_len = exe_len;
6862306a36Sopenharmony_ci	o->owner         = owner;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Owner specific callbacks */
7162306a36Sopenharmony_ci	o->validate      = validate;
7262306a36Sopenharmony_ci	o->remove        = remove;
7362306a36Sopenharmony_ci	o->optimize      = optimize;
7462306a36Sopenharmony_ci	o->execute       = exec;
7562306a36Sopenharmony_ci	o->get           = get;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Setup the execution queue with the chunk length of %d\n",
7862306a36Sopenharmony_ci	   exe_len);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic inline void bnx2x_exe_queue_free_elem(struct bnx2x *bp,
8262306a36Sopenharmony_ci					     struct bnx2x_exeq_elem *elem)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Deleting an exe_queue element\n");
8562306a36Sopenharmony_ci	kfree(elem);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline int bnx2x_exe_queue_length(struct bnx2x_exe_queue_obj *o)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem;
9162306a36Sopenharmony_ci	int cnt = 0;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	spin_lock_bh(&o->lock);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	list_for_each_entry(elem, &o->exe_queue, link)
9662306a36Sopenharmony_ci		cnt++;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	spin_unlock_bh(&o->lock);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return cnt;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci * bnx2x_exe_queue_add - add a new element to the execution queue
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci * @bp:		driver handle
10762306a36Sopenharmony_ci * @o:		queue
10862306a36Sopenharmony_ci * @elem:	new command to add
10962306a36Sopenharmony_ci * @restore:	true - do not optimize the command
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * If the element is optimized or is illegal, frees it.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic inline int bnx2x_exe_queue_add(struct bnx2x *bp,
11462306a36Sopenharmony_ci				      struct bnx2x_exe_queue_obj *o,
11562306a36Sopenharmony_ci				      struct bnx2x_exeq_elem *elem,
11662306a36Sopenharmony_ci				      bool restore)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	int rc;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	spin_lock_bh(&o->lock);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (!restore) {
12362306a36Sopenharmony_ci		/* Try to cancel this element queue */
12462306a36Sopenharmony_ci		rc = o->optimize(bp, o->owner, elem);
12562306a36Sopenharmony_ci		if (rc)
12662306a36Sopenharmony_ci			goto free_and_exit;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		/* Check if this request is ok */
12962306a36Sopenharmony_ci		rc = o->validate(bp, o->owner, elem);
13062306a36Sopenharmony_ci		if (rc) {
13162306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "Preamble failed: %d\n", rc);
13262306a36Sopenharmony_ci			goto free_and_exit;
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* If so, add it to the execution queue */
13762306a36Sopenharmony_ci	list_add_tail(&elem->link, &o->exe_queue);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	spin_unlock_bh(&o->lock);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return 0;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cifree_and_exit:
14462306a36Sopenharmony_ci	bnx2x_exe_queue_free_elem(bp, elem);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	spin_unlock_bh(&o->lock);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return rc;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic inline void __bnx2x_exe_queue_reset_pending(
15262306a36Sopenharmony_ci	struct bnx2x *bp,
15362306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *o)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	while (!list_empty(&o->pending_comp)) {
15862306a36Sopenharmony_ci		elem = list_first_entry(&o->pending_comp,
15962306a36Sopenharmony_ci					struct bnx2x_exeq_elem, link);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		list_del(&elem->link);
16262306a36Sopenharmony_ci		bnx2x_exe_queue_free_elem(bp, elem);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * bnx2x_exe_queue_step - execute one execution chunk atomically
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * @bp:			driver handle
17062306a36Sopenharmony_ci * @o:			queue
17162306a36Sopenharmony_ci * @ramrod_flags:	flags
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * (Should be called while holding the exe_queue->lock).
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_cistatic inline int bnx2x_exe_queue_step(struct bnx2x *bp,
17662306a36Sopenharmony_ci				       struct bnx2x_exe_queue_obj *o,
17762306a36Sopenharmony_ci				       unsigned long *ramrod_flags)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem, spacer;
18062306a36Sopenharmony_ci	int cur_len = 0, rc;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	memset(&spacer, 0, sizeof(spacer));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Next step should not be performed until the current is finished,
18562306a36Sopenharmony_ci	 * unless a DRV_CLEAR_ONLY bit is set. In this case we just want to
18662306a36Sopenharmony_ci	 * properly clear object internals without sending any command to the FW
18762306a36Sopenharmony_ci	 * which also implies there won't be any completion to clear the
18862306a36Sopenharmony_ci	 * 'pending' list.
18962306a36Sopenharmony_ci	 */
19062306a36Sopenharmony_ci	if (!list_empty(&o->pending_comp)) {
19162306a36Sopenharmony_ci		if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags)) {
19262306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: resetting a pending_comp list\n");
19362306a36Sopenharmony_ci			__bnx2x_exe_queue_reset_pending(bp, o);
19462306a36Sopenharmony_ci		} else {
19562306a36Sopenharmony_ci			return 1;
19662306a36Sopenharmony_ci		}
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Run through the pending commands list and create a next
20062306a36Sopenharmony_ci	 * execution chunk.
20162306a36Sopenharmony_ci	 */
20262306a36Sopenharmony_ci	while (!list_empty(&o->exe_queue)) {
20362306a36Sopenharmony_ci		elem = list_first_entry(&o->exe_queue, struct bnx2x_exeq_elem,
20462306a36Sopenharmony_ci					link);
20562306a36Sopenharmony_ci		WARN_ON(!elem->cmd_len);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		if (cur_len + elem->cmd_len <= o->exe_chunk_len) {
20862306a36Sopenharmony_ci			cur_len += elem->cmd_len;
20962306a36Sopenharmony_ci			/* Prevent from both lists being empty when moving an
21062306a36Sopenharmony_ci			 * element. This will allow the call of
21162306a36Sopenharmony_ci			 * bnx2x_exe_queue_empty() without locking.
21262306a36Sopenharmony_ci			 */
21362306a36Sopenharmony_ci			list_add_tail(&spacer.link, &o->pending_comp);
21462306a36Sopenharmony_ci			mb();
21562306a36Sopenharmony_ci			list_move_tail(&elem->link, &o->pending_comp);
21662306a36Sopenharmony_ci			list_del(&spacer.link);
21762306a36Sopenharmony_ci		} else
21862306a36Sopenharmony_ci			break;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Sanity check */
22262306a36Sopenharmony_ci	if (!cur_len)
22362306a36Sopenharmony_ci		return 0;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags);
22662306a36Sopenharmony_ci	if (rc < 0)
22762306a36Sopenharmony_ci		/* In case of an error return the commands back to the queue
22862306a36Sopenharmony_ci		 * and reset the pending_comp.
22962306a36Sopenharmony_ci		 */
23062306a36Sopenharmony_ci		list_splice_init(&o->pending_comp, &o->exe_queue);
23162306a36Sopenharmony_ci	else if (!rc)
23262306a36Sopenharmony_ci		/* If zero is returned, means there are no outstanding pending
23362306a36Sopenharmony_ci		 * completions and we may dismiss the pending list.
23462306a36Sopenharmony_ci		 */
23562306a36Sopenharmony_ci		__bnx2x_exe_queue_reset_pending(bp, o);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return rc;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic inline bool bnx2x_exe_queue_empty(struct bnx2x_exe_queue_obj *o)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	bool empty = list_empty(&o->exe_queue);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/* Don't reorder!!! */
24562306a36Sopenharmony_ci	mb();
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return empty && list_empty(&o->pending_comp);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic inline struct bnx2x_exeq_elem *bnx2x_exe_queue_alloc_elem(
25162306a36Sopenharmony_ci	struct bnx2x *bp)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Allocating a new exe_queue element\n");
25462306a36Sopenharmony_ci	return kzalloc(sizeof(struct bnx2x_exeq_elem), GFP_ATOMIC);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/************************ raw_obj functions ***********************************/
25862306a36Sopenharmony_cistatic bool bnx2x_raw_check_pending(struct bnx2x_raw_obj *o)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	return !!test_bit(o->state, o->pstate);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic void bnx2x_raw_clear_pending(struct bnx2x_raw_obj *o)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	smp_mb__before_atomic();
26662306a36Sopenharmony_ci	clear_bit(o->state, o->pstate);
26762306a36Sopenharmony_ci	smp_mb__after_atomic();
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void bnx2x_raw_set_pending(struct bnx2x_raw_obj *o)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	smp_mb__before_atomic();
27362306a36Sopenharmony_ci	set_bit(o->state, o->pstate);
27462306a36Sopenharmony_ci	smp_mb__after_atomic();
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/**
27862306a36Sopenharmony_ci * bnx2x_state_wait - wait until the given bit(state) is cleared
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * @bp:		device handle
28162306a36Sopenharmony_ci * @state:	state which is to be cleared
28262306a36Sopenharmony_ci * @pstate:	state buffer
28362306a36Sopenharmony_ci *
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_cistatic inline int bnx2x_state_wait(struct bnx2x *bp, int state,
28662306a36Sopenharmony_ci				   unsigned long *pstate)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	/* can take a while if any port is running */
28962306a36Sopenharmony_ci	int cnt = 5000;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (CHIP_REV_IS_EMUL(bp))
29262306a36Sopenharmony_ci		cnt *= 20;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "waiting for state to become %d\n", state);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	might_sleep();
29762306a36Sopenharmony_ci	while (cnt--) {
29862306a36Sopenharmony_ci		if (!test_bit(state, pstate)) {
29962306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
30062306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "exit  (cnt %d)\n", 5000 - cnt);
30162306a36Sopenharmony_ci#endif
30262306a36Sopenharmony_ci			return 0;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		usleep_range(1000, 2000);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		if (bp->panic)
30862306a36Sopenharmony_ci			return -EIO;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* timeout! */
31262306a36Sopenharmony_ci	BNX2X_ERR("timeout waiting for state %d\n", state);
31362306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
31462306a36Sopenharmony_ci	bnx2x_panic();
31562306a36Sopenharmony_ci#endif
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return -EBUSY;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int bnx2x_raw_wait(struct bnx2x *bp, struct bnx2x_raw_obj *raw)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	return bnx2x_state_wait(bp, raw->state, raw->pstate);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/***************** Classification verbs: Set/Del MAC/VLAN/VLAN-MAC ************/
32662306a36Sopenharmony_ci/* credit handling callbacks */
32762306a36Sopenharmony_cistatic bool bnx2x_get_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int *offset)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	WARN_ON(!mp);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return mp->get_entry(mp, offset);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic bool bnx2x_get_credit_mac(struct bnx2x_vlan_mac_obj *o)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	WARN_ON(!mp);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return mp->get(mp, 1);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic bool bnx2x_get_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int *offset)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	WARN_ON(!vp);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return vp->get_entry(vp, offset);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	WARN_ON(!vp);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return vp->get(vp, 1);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
36662306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (!mp->get(mp, 1))
36962306a36Sopenharmony_ci		return false;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!vp->get(vp, 1)) {
37262306a36Sopenharmony_ci		mp->put(mp, 1);
37362306a36Sopenharmony_ci		return false;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return true;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return mp->put_entry(mp, offset);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic bool bnx2x_put_credit_mac(struct bnx2x_vlan_mac_obj *o)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return mp->put(mp, 1);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic bool bnx2x_put_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int offset)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return vp->put_entry(vp, offset);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return vp->put(vp, 1);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
41062306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (!mp->put(mp, 1))
41362306a36Sopenharmony_ci		return false;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (!vp->put(vp, 1)) {
41662306a36Sopenharmony_ci		mp->get(mp, 1);
41762306a36Sopenharmony_ci		return false;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return true;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/**
42462306a36Sopenharmony_ci * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * @bp:		device handle
42762306a36Sopenharmony_ci * @o:		vlan_mac object
42862306a36Sopenharmony_ci *
42962306a36Sopenharmony_ci * Context: Non-blocking implementation; should be called under execution
43062306a36Sopenharmony_ci *          queue lock.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_cistatic int __bnx2x_vlan_mac_h_write_trylock(struct bnx2x *bp,
43362306a36Sopenharmony_ci					    struct bnx2x_vlan_mac_obj *o)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	if (o->head_reader) {
43662306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "vlan_mac_lock writer - There are readers; Busy\n");
43762306a36Sopenharmony_ci		return -EBUSY;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "vlan_mac_lock writer - Taken\n");
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/**
44562306a36Sopenharmony_ci * __bnx2x_vlan_mac_h_exec_pending - execute step instead of a previous step
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * @bp:		device handle
44862306a36Sopenharmony_ci * @o:		vlan_mac object
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * details Should be called under execution queue lock; notice it might release
45162306a36Sopenharmony_ci *          and reclaim it during its run.
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_cistatic void __bnx2x_vlan_mac_h_exec_pending(struct bnx2x *bp,
45462306a36Sopenharmony_ci					    struct bnx2x_vlan_mac_obj *o)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	int rc;
45762306a36Sopenharmony_ci	unsigned long ramrod_flags = o->saved_ramrod_flags;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "vlan_mac_lock execute pending command with ramrod flags %lu\n",
46062306a36Sopenharmony_ci	   ramrod_flags);
46162306a36Sopenharmony_ci	o->head_exe_request = false;
46262306a36Sopenharmony_ci	o->saved_ramrod_flags = 0;
46362306a36Sopenharmony_ci	rc = bnx2x_exe_queue_step(bp, &o->exe_queue, &ramrod_flags);
46462306a36Sopenharmony_ci	if ((rc != 0) && (rc != 1)) {
46562306a36Sopenharmony_ci		BNX2X_ERR("execution of pending commands failed with rc %d\n",
46662306a36Sopenharmony_ci			  rc);
46762306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
46862306a36Sopenharmony_ci		bnx2x_panic();
46962306a36Sopenharmony_ci#endif
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci/**
47462306a36Sopenharmony_ci * __bnx2x_vlan_mac_h_pend - Pend an execution step which couldn't run
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * @bp:			device handle
47762306a36Sopenharmony_ci * @o:			vlan_mac object
47862306a36Sopenharmony_ci * @ramrod_flags:	ramrod flags of missed execution
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci * Context: Should be called under execution queue lock.
48162306a36Sopenharmony_ci */
48262306a36Sopenharmony_cistatic void __bnx2x_vlan_mac_h_pend(struct bnx2x *bp,
48362306a36Sopenharmony_ci				    struct bnx2x_vlan_mac_obj *o,
48462306a36Sopenharmony_ci				    unsigned long ramrod_flags)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	o->head_exe_request = true;
48762306a36Sopenharmony_ci	o->saved_ramrod_flags = ramrod_flags;
48862306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Placing pending execution with ramrod flags %lu\n",
48962306a36Sopenharmony_ci	   ramrod_flags);
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/**
49362306a36Sopenharmony_ci * __bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock
49462306a36Sopenharmony_ci *
49562306a36Sopenharmony_ci * @bp:			device handle
49662306a36Sopenharmony_ci * @o:			vlan_mac object
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * Context: Should be called under execution queue lock. Notice if a pending
49962306a36Sopenharmony_ci *          execution exists, it would perform it - possibly releasing and
50062306a36Sopenharmony_ci *          reclaiming the execution queue lock.
50162306a36Sopenharmony_ci */
50262306a36Sopenharmony_cistatic void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
50362306a36Sopenharmony_ci					    struct bnx2x_vlan_mac_obj *o)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	/* It's possible a new pending execution was added since this writer
50662306a36Sopenharmony_ci	 * executed. If so, execute again. [Ad infinitum]
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	while (o->head_exe_request) {
50962306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "vlan_mac_lock - writer release encountered a pending request\n");
51062306a36Sopenharmony_ci		__bnx2x_vlan_mac_h_exec_pending(bp, o);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/**
51662306a36Sopenharmony_ci * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * @bp:			device handle
51962306a36Sopenharmony_ci * @o:			vlan_mac object
52062306a36Sopenharmony_ci *
52162306a36Sopenharmony_ci * Context: Should be called under the execution queue lock. May sleep. May
52262306a36Sopenharmony_ci *          release and reclaim execution queue lock during its run.
52362306a36Sopenharmony_ci */
52462306a36Sopenharmony_cistatic int __bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
52562306a36Sopenharmony_ci					struct bnx2x_vlan_mac_obj *o)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	/* If we got here, we're holding lock --> no WRITER exists */
52862306a36Sopenharmony_ci	o->head_reader++;
52962306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "vlan_mac_lock - locked reader - number %d\n",
53062306a36Sopenharmony_ci	   o->head_reader);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	return 0;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci/**
53662306a36Sopenharmony_ci * bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
53762306a36Sopenharmony_ci *
53862306a36Sopenharmony_ci * @bp:			device handle
53962306a36Sopenharmony_ci * @o:			vlan_mac object
54062306a36Sopenharmony_ci *
54162306a36Sopenharmony_ci * Context: May sleep. Claims and releases execution queue lock during its run.
54262306a36Sopenharmony_ci */
54362306a36Sopenharmony_ciint bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
54462306a36Sopenharmony_ci			       struct bnx2x_vlan_mac_obj *o)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	int rc;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	spin_lock_bh(&o->exe_queue.lock);
54962306a36Sopenharmony_ci	rc = __bnx2x_vlan_mac_h_read_lock(bp, o);
55062306a36Sopenharmony_ci	spin_unlock_bh(&o->exe_queue.lock);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return rc;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci/**
55662306a36Sopenharmony_ci * __bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci * @bp:			device handle
55962306a36Sopenharmony_ci * @o:			vlan_mac object
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci * Context: Should be called under execution queue lock. Notice if a pending
56262306a36Sopenharmony_ci *          execution exists, it would be performed if this was the last
56362306a36Sopenharmony_ci *          reader. possibly releasing and reclaiming the execution queue lock.
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_cistatic void __bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
56662306a36Sopenharmony_ci					  struct bnx2x_vlan_mac_obj *o)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	if (!o->head_reader) {
56962306a36Sopenharmony_ci		BNX2X_ERR("Need to release vlan mac reader lock, but lock isn't taken\n");
57062306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
57162306a36Sopenharmony_ci		bnx2x_panic();
57262306a36Sopenharmony_ci#endif
57362306a36Sopenharmony_ci	} else {
57462306a36Sopenharmony_ci		o->head_reader--;
57562306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "vlan_mac_lock - decreased readers to %d\n",
57662306a36Sopenharmony_ci		   o->head_reader);
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* It's possible a new pending execution was added, and that this reader
58062306a36Sopenharmony_ci	 * was last - if so we need to execute the command.
58162306a36Sopenharmony_ci	 */
58262306a36Sopenharmony_ci	if (!o->head_reader && o->head_exe_request) {
58362306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "vlan_mac_lock - reader release encountered a pending request\n");
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		/* Writer release will do the trick */
58662306a36Sopenharmony_ci		__bnx2x_vlan_mac_h_write_unlock(bp, o);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/**
59162306a36Sopenharmony_ci * bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock
59262306a36Sopenharmony_ci *
59362306a36Sopenharmony_ci * @bp:			device handle
59462306a36Sopenharmony_ci * @o:			vlan_mac object
59562306a36Sopenharmony_ci *
59662306a36Sopenharmony_ci * Context: Notice if a pending execution exists, it would be performed if this
59762306a36Sopenharmony_ci *          was the last reader. Claims and releases the execution queue lock
59862306a36Sopenharmony_ci *          during its run.
59962306a36Sopenharmony_ci */
60062306a36Sopenharmony_civoid bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
60162306a36Sopenharmony_ci				  struct bnx2x_vlan_mac_obj *o)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	spin_lock_bh(&o->exe_queue.lock);
60462306a36Sopenharmony_ci	__bnx2x_vlan_mac_h_read_unlock(bp, o);
60562306a36Sopenharmony_ci	spin_unlock_bh(&o->exe_queue.lock);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
60962306a36Sopenharmony_ci				int n, u8 *base, u8 stride, u8 size)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
61262306a36Sopenharmony_ci	u8 *next = base;
61362306a36Sopenharmony_ci	int counter = 0;
61462306a36Sopenharmony_ci	int read_lock;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "get_n_elements - taking vlan_mac_lock (reader)\n");
61762306a36Sopenharmony_ci	read_lock = bnx2x_vlan_mac_h_read_lock(bp, o);
61862306a36Sopenharmony_ci	if (read_lock != 0)
61962306a36Sopenharmony_ci		BNX2X_ERR("get_n_elements failed to get vlan mac reader lock; Access without lock\n");
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* traverse list */
62262306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link) {
62362306a36Sopenharmony_ci		if (counter < n) {
62462306a36Sopenharmony_ci			memcpy(next, &pos->u, size);
62562306a36Sopenharmony_ci			counter++;
62662306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "copied element number %d to address %p element was:\n",
62762306a36Sopenharmony_ci			   counter, next);
62862306a36Sopenharmony_ci			next += stride + size;
62962306a36Sopenharmony_ci		}
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (read_lock == 0) {
63362306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "get_n_elements - releasing vlan_mac_lock (reader)\n");
63462306a36Sopenharmony_ci		bnx2x_vlan_mac_h_read_unlock(bp, o);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return counter * ETH_ALEN;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/* check_add() callbacks */
64162306a36Sopenharmony_cistatic int bnx2x_check_mac_add(struct bnx2x *bp,
64262306a36Sopenharmony_ci			       struct bnx2x_vlan_mac_obj *o,
64362306a36Sopenharmony_ci			       union bnx2x_classification_ramrod_data *data)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Checking MAC %pM for ADD command\n", data->mac.mac);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (!is_valid_ether_addr(data->mac.mac))
65062306a36Sopenharmony_ci		return -EINVAL;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Check if a requested MAC already exists */
65362306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link)
65462306a36Sopenharmony_ci		if (ether_addr_equal(data->mac.mac, pos->u.mac.mac) &&
65562306a36Sopenharmony_ci		    (data->mac.is_inner_mac == pos->u.mac.is_inner_mac))
65662306a36Sopenharmony_ci			return -EEXIST;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return 0;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int bnx2x_check_vlan_add(struct bnx2x *bp,
66262306a36Sopenharmony_ci				struct bnx2x_vlan_mac_obj *o,
66362306a36Sopenharmony_ci				union bnx2x_classification_ramrod_data *data)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Checking VLAN %d for ADD command\n", data->vlan.vlan);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link)
67062306a36Sopenharmony_ci		if (data->vlan.vlan == pos->u.vlan.vlan)
67162306a36Sopenharmony_ci			return -EEXIST;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	return 0;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic int bnx2x_check_vlan_mac_add(struct bnx2x *bp,
67762306a36Sopenharmony_ci				    struct bnx2x_vlan_mac_obj *o,
67862306a36Sopenharmony_ci				   union bnx2x_classification_ramrod_data *data)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for ADD command\n",
68362306a36Sopenharmony_ci	   data->vlan_mac.mac, data->vlan_mac.vlan);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link)
68662306a36Sopenharmony_ci		if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
68762306a36Sopenharmony_ci		    (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac,
68862306a36Sopenharmony_ci				  ETH_ALEN)) &&
68962306a36Sopenharmony_ci		    (data->vlan_mac.is_inner_mac ==
69062306a36Sopenharmony_ci		     pos->u.vlan_mac.is_inner_mac))
69162306a36Sopenharmony_ci			return -EEXIST;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/* check_del() callbacks */
69762306a36Sopenharmony_cistatic struct bnx2x_vlan_mac_registry_elem *
69862306a36Sopenharmony_ci	bnx2x_check_mac_del(struct bnx2x *bp,
69962306a36Sopenharmony_ci			    struct bnx2x_vlan_mac_obj *o,
70062306a36Sopenharmony_ci			    union bnx2x_classification_ramrod_data *data)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Checking MAC %pM for DEL command\n", data->mac.mac);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link)
70762306a36Sopenharmony_ci		if (ether_addr_equal(data->mac.mac, pos->u.mac.mac) &&
70862306a36Sopenharmony_ci		    (data->mac.is_inner_mac == pos->u.mac.is_inner_mac))
70962306a36Sopenharmony_ci			return pos;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	return NULL;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic struct bnx2x_vlan_mac_registry_elem *
71562306a36Sopenharmony_ci	bnx2x_check_vlan_del(struct bnx2x *bp,
71662306a36Sopenharmony_ci			     struct bnx2x_vlan_mac_obj *o,
71762306a36Sopenharmony_ci			     union bnx2x_classification_ramrod_data *data)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Checking VLAN %d for DEL command\n", data->vlan.vlan);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link)
72462306a36Sopenharmony_ci		if (data->vlan.vlan == pos->u.vlan.vlan)
72562306a36Sopenharmony_ci			return pos;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return NULL;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic struct bnx2x_vlan_mac_registry_elem *
73162306a36Sopenharmony_ci	bnx2x_check_vlan_mac_del(struct bnx2x *bp,
73262306a36Sopenharmony_ci				 struct bnx2x_vlan_mac_obj *o,
73362306a36Sopenharmony_ci				 union bnx2x_classification_ramrod_data *data)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for DEL command\n",
73862306a36Sopenharmony_ci	   data->vlan_mac.mac, data->vlan_mac.vlan);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link)
74162306a36Sopenharmony_ci		if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
74262306a36Sopenharmony_ci		    (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac,
74362306a36Sopenharmony_ci			     ETH_ALEN)) &&
74462306a36Sopenharmony_ci		    (data->vlan_mac.is_inner_mac ==
74562306a36Sopenharmony_ci		     pos->u.vlan_mac.is_inner_mac))
74662306a36Sopenharmony_ci			return pos;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	return NULL;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci/* check_move() callback */
75262306a36Sopenharmony_cistatic bool bnx2x_check_move(struct bnx2x *bp,
75362306a36Sopenharmony_ci			     struct bnx2x_vlan_mac_obj *src_o,
75462306a36Sopenharmony_ci			     struct bnx2x_vlan_mac_obj *dst_o,
75562306a36Sopenharmony_ci			     union bnx2x_classification_ramrod_data *data)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
75862306a36Sopenharmony_ci	int rc;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	/* Check if we can delete the requested configuration from the first
76162306a36Sopenharmony_ci	 * object.
76262306a36Sopenharmony_ci	 */
76362306a36Sopenharmony_ci	pos = src_o->check_del(bp, src_o, data);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/*  check if configuration can be added */
76662306a36Sopenharmony_ci	rc = dst_o->check_add(bp, dst_o, data);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* If this classification can not be added (is already set)
76962306a36Sopenharmony_ci	 * or can't be deleted - return an error.
77062306a36Sopenharmony_ci	 */
77162306a36Sopenharmony_ci	if (rc || !pos)
77262306a36Sopenharmony_ci		return false;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	return true;
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic bool bnx2x_check_move_always_err(
77862306a36Sopenharmony_ci	struct bnx2x *bp,
77962306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *src_o,
78062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *dst_o,
78162306a36Sopenharmony_ci	union bnx2x_classification_ramrod_data *data)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	return false;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
78962306a36Sopenharmony_ci	u8 rx_tx_flag = 0;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if ((raw->obj_type == BNX2X_OBJ_TYPE_TX) ||
79262306a36Sopenharmony_ci	    (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX))
79362306a36Sopenharmony_ci		rx_tx_flag |= ETH_CLASSIFY_CMD_HEADER_TX_CMD;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if ((raw->obj_type == BNX2X_OBJ_TYPE_RX) ||
79662306a36Sopenharmony_ci	    (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX))
79762306a36Sopenharmony_ci		rx_tx_flag |= ETH_CLASSIFY_CMD_HEADER_RX_CMD;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	return rx_tx_flag;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic void bnx2x_set_mac_in_nig(struct bnx2x *bp,
80362306a36Sopenharmony_ci				 bool add, unsigned char *dev_addr, int index)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	u32 wb_data[2];
80662306a36Sopenharmony_ci	u32 reg_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM :
80762306a36Sopenharmony_ci			 NIG_REG_LLH0_FUNC_MEM;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (!IS_MF_SI(bp) && !IS_MF_AFEX(bp))
81062306a36Sopenharmony_ci		return;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if (index > BNX2X_LLH_CAM_MAX_PF_LINE)
81362306a36Sopenharmony_ci		return;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Going to %s LLH configuration at entry %d\n",
81662306a36Sopenharmony_ci			 (add ? "ADD" : "DELETE"), index);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	if (add) {
81962306a36Sopenharmony_ci		/* LLH_FUNC_MEM is a u64 WB register */
82062306a36Sopenharmony_ci		reg_offset += 8*index;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		wb_data[0] = ((dev_addr[2] << 24) | (dev_addr[3] << 16) |
82362306a36Sopenharmony_ci			      (dev_addr[4] <<  8) |  dev_addr[5]);
82462306a36Sopenharmony_ci		wb_data[1] = ((dev_addr[0] <<  8) |  dev_addr[1]);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		REG_WR_DMAE(bp, reg_offset, wb_data, 2);
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	REG_WR(bp, (BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM_ENABLE :
83062306a36Sopenharmony_ci				  NIG_REG_LLH0_FUNC_MEM_ENABLE) + 4*index, add);
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci/**
83462306a36Sopenharmony_ci * bnx2x_vlan_mac_set_cmd_hdr_e2 - set a header in a single classify ramrod
83562306a36Sopenharmony_ci *
83662306a36Sopenharmony_ci * @bp:		device handle
83762306a36Sopenharmony_ci * @o:		queue for which we want to configure this rule
83862306a36Sopenharmony_ci * @add:	if true the command is an ADD command, DEL otherwise
83962306a36Sopenharmony_ci * @opcode:	CLASSIFY_RULE_OPCODE_XXX
84062306a36Sopenharmony_ci * @hdr:	pointer to a header to setup
84162306a36Sopenharmony_ci *
84262306a36Sopenharmony_ci */
84362306a36Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_cmd_hdr_e2(struct bnx2x *bp,
84462306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o, bool add, int opcode,
84562306a36Sopenharmony_ci	struct eth_classify_cmd_header *hdr)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	hdr->client_id = raw->cl_id;
85062306a36Sopenharmony_ci	hdr->func_id = raw->func_id;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	/* Rx or/and Tx (internal switching) configuration ? */
85362306a36Sopenharmony_ci	hdr->cmd_general_data |=
85462306a36Sopenharmony_ci		bnx2x_vlan_mac_get_rx_tx_flag(o);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (add)
85762306a36Sopenharmony_ci		hdr->cmd_general_data |= ETH_CLASSIFY_CMD_HEADER_IS_ADD;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	hdr->cmd_general_data |=
86062306a36Sopenharmony_ci		(opcode << ETH_CLASSIFY_CMD_HEADER_OPCODE_SHIFT);
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci/**
86462306a36Sopenharmony_ci * bnx2x_vlan_mac_set_rdata_hdr_e2 - set the classify ramrod data header
86562306a36Sopenharmony_ci *
86662306a36Sopenharmony_ci * @cid:	connection id
86762306a36Sopenharmony_ci * @type:	BNX2X_FILTER_XXX_PENDING
86862306a36Sopenharmony_ci * @hdr:	pointer to header to setup
86962306a36Sopenharmony_ci * @rule_cnt:
87062306a36Sopenharmony_ci *
87162306a36Sopenharmony_ci * currently we always configure one rule and echo field to contain a CID and an
87262306a36Sopenharmony_ci * opcode type.
87362306a36Sopenharmony_ci */
87462306a36Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type,
87562306a36Sopenharmony_ci				struct eth_classify_header *hdr, int rule_cnt)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	hdr->echo = cpu_to_le32((cid & BNX2X_SWCID_MASK) |
87862306a36Sopenharmony_ci				(type << BNX2X_SWCID_SHIFT));
87962306a36Sopenharmony_ci	hdr->rule_cnt = (u8)rule_cnt;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci/* hw_config() callbacks */
88362306a36Sopenharmony_cistatic void bnx2x_set_one_mac_e2(struct bnx2x *bp,
88462306a36Sopenharmony_ci				 struct bnx2x_vlan_mac_obj *o,
88562306a36Sopenharmony_ci				 struct bnx2x_exeq_elem *elem, int rule_idx,
88662306a36Sopenharmony_ci				 int cam_offset)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
88962306a36Sopenharmony_ci	struct eth_classify_rules_ramrod_data *data =
89062306a36Sopenharmony_ci		(struct eth_classify_rules_ramrod_data *)(raw->rdata);
89162306a36Sopenharmony_ci	int rule_cnt = rule_idx + 1, cmd = elem->cmd_data.vlan_mac.cmd;
89262306a36Sopenharmony_ci	union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
89362306a36Sopenharmony_ci	bool add = cmd == BNX2X_VLAN_MAC_ADD;
89462306a36Sopenharmony_ci	unsigned long *vlan_mac_flags = &elem->cmd_data.vlan_mac.vlan_mac_flags;
89562306a36Sopenharmony_ci	u8 *mac = elem->cmd_data.vlan_mac.u.mac.mac;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* Set LLH CAM entry: currently only iSCSI and ETH macs are
89862306a36Sopenharmony_ci	 * relevant. In addition, current implementation is tuned for a
89962306a36Sopenharmony_ci	 * single ETH MAC.
90062306a36Sopenharmony_ci	 *
90162306a36Sopenharmony_ci	 * When multiple unicast ETH MACs PF configuration in switch
90262306a36Sopenharmony_ci	 * independent mode is required (NetQ, multiple netdev MACs,
90362306a36Sopenharmony_ci	 * etc.), consider better utilisation of 8 per function MAC
90462306a36Sopenharmony_ci	 * entries in the LLH register. There is also
90562306a36Sopenharmony_ci	 * NIG_REG_P[01]_LLH_FUNC_MEM2 registers that complete the
90662306a36Sopenharmony_ci	 * total number of CAM entries to 16.
90762306a36Sopenharmony_ci	 *
90862306a36Sopenharmony_ci	 * Currently we won't configure NIG for MACs other than a primary ETH
90962306a36Sopenharmony_ci	 * MAC and iSCSI L2 MAC.
91062306a36Sopenharmony_ci	 *
91162306a36Sopenharmony_ci	 * If this MAC is moving from one Queue to another, no need to change
91262306a36Sopenharmony_ci	 * NIG configuration.
91362306a36Sopenharmony_ci	 */
91462306a36Sopenharmony_ci	if (cmd != BNX2X_VLAN_MAC_MOVE) {
91562306a36Sopenharmony_ci		if (test_bit(BNX2X_ISCSI_ETH_MAC, vlan_mac_flags))
91662306a36Sopenharmony_ci			bnx2x_set_mac_in_nig(bp, add, mac,
91762306a36Sopenharmony_ci					     BNX2X_LLH_CAM_ISCSI_ETH_LINE);
91862306a36Sopenharmony_ci		else if (test_bit(BNX2X_ETH_MAC, vlan_mac_flags))
91962306a36Sopenharmony_ci			bnx2x_set_mac_in_nig(bp, add, mac,
92062306a36Sopenharmony_ci					     BNX2X_LLH_CAM_ETH_LINE);
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	/* Reset the ramrod data buffer for the first rule */
92462306a36Sopenharmony_ci	if (rule_idx == 0)
92562306a36Sopenharmony_ci		memset(data, 0, sizeof(*data));
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	/* Setup a command header */
92862306a36Sopenharmony_ci	bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_MAC,
92962306a36Sopenharmony_ci				      &rule_entry->mac.header);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "About to %s MAC %pM for Queue %d\n",
93262306a36Sopenharmony_ci	   (add ? "add" : "delete"), mac, raw->cl_id);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* Set a MAC itself */
93562306a36Sopenharmony_ci	bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb,
93662306a36Sopenharmony_ci			      &rule_entry->mac.mac_mid,
93762306a36Sopenharmony_ci			      &rule_entry->mac.mac_lsb, mac);
93862306a36Sopenharmony_ci	rule_entry->mac.inner_mac =
93962306a36Sopenharmony_ci		cpu_to_le16(elem->cmd_data.vlan_mac.u.mac.is_inner_mac);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/* MOVE: Add a rule that will add this MAC to the target Queue */
94262306a36Sopenharmony_ci	if (cmd == BNX2X_VLAN_MAC_MOVE) {
94362306a36Sopenharmony_ci		rule_entry++;
94462306a36Sopenharmony_ci		rule_cnt++;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		/* Setup ramrod data */
94762306a36Sopenharmony_ci		bnx2x_vlan_mac_set_cmd_hdr_e2(bp,
94862306a36Sopenharmony_ci					elem->cmd_data.vlan_mac.target_obj,
94962306a36Sopenharmony_ci					      true, CLASSIFY_RULE_OPCODE_MAC,
95062306a36Sopenharmony_ci					      &rule_entry->mac.header);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		/* Set a MAC itself */
95362306a36Sopenharmony_ci		bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb,
95462306a36Sopenharmony_ci				      &rule_entry->mac.mac_mid,
95562306a36Sopenharmony_ci				      &rule_entry->mac.mac_lsb, mac);
95662306a36Sopenharmony_ci		rule_entry->mac.inner_mac =
95762306a36Sopenharmony_ci			cpu_to_le16(elem->cmd_data.vlan_mac.
95862306a36Sopenharmony_ci						u.mac.is_inner_mac);
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* Set the ramrod data header */
96262306a36Sopenharmony_ci	/* TODO: take this to the higher level in order to prevent multiple
96362306a36Sopenharmony_ci		 writing */
96462306a36Sopenharmony_ci	bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header,
96562306a36Sopenharmony_ci					rule_cnt);
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci/**
96962306a36Sopenharmony_ci * bnx2x_vlan_mac_set_rdata_hdr_e1x - set a header in a single classify ramrod
97062306a36Sopenharmony_ci *
97162306a36Sopenharmony_ci * @bp:		device handle
97262306a36Sopenharmony_ci * @o:		queue
97362306a36Sopenharmony_ci * @type:	the type of echo
97462306a36Sopenharmony_ci * @cam_offset:	offset in cam memory
97562306a36Sopenharmony_ci * @hdr:	pointer to a header to setup
97662306a36Sopenharmony_ci *
97762306a36Sopenharmony_ci * E1/E1H
97862306a36Sopenharmony_ci */
97962306a36Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_rdata_hdr_e1x(struct bnx2x *bp,
98062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o, int type, int cam_offset,
98162306a36Sopenharmony_ci	struct mac_configuration_hdr *hdr)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	hdr->length = 1;
98662306a36Sopenharmony_ci	hdr->offset = (u8)cam_offset;
98762306a36Sopenharmony_ci	hdr->client_id = cpu_to_le16(0xff);
98862306a36Sopenharmony_ci	hdr->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
98962306a36Sopenharmony_ci				(type << BNX2X_SWCID_SHIFT));
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_cfg_entry_e1x(struct bnx2x *bp,
99362306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o, bool add, int opcode, u8 *mac,
99462306a36Sopenharmony_ci	u16 vlan_id, struct mac_configuration_entry *cfg_entry)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
99762306a36Sopenharmony_ci	u32 cl_bit_vec = (1 << r->cl_id);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	cfg_entry->clients_bit_vector = cpu_to_le32(cl_bit_vec);
100062306a36Sopenharmony_ci	cfg_entry->pf_id = r->func_id;
100162306a36Sopenharmony_ci	cfg_entry->vlan_id = cpu_to_le16(vlan_id);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (add) {
100462306a36Sopenharmony_ci		SET_FLAG(cfg_entry->flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
100562306a36Sopenharmony_ci			 T_ETH_MAC_COMMAND_SET);
100662306a36Sopenharmony_ci		SET_FLAG(cfg_entry->flags,
100762306a36Sopenharmony_ci			 MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE, opcode);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci		/* Set a MAC in a ramrod data */
101062306a36Sopenharmony_ci		bnx2x_set_fw_mac_addr(&cfg_entry->msb_mac_addr,
101162306a36Sopenharmony_ci				      &cfg_entry->middle_mac_addr,
101262306a36Sopenharmony_ci				      &cfg_entry->lsb_mac_addr, mac);
101362306a36Sopenharmony_ci	} else
101462306a36Sopenharmony_ci		SET_FLAG(cfg_entry->flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
101562306a36Sopenharmony_ci			 T_ETH_MAC_COMMAND_INVALIDATE);
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_rdata_e1x(struct bnx2x *bp,
101962306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o, int type, int cam_offset, bool add,
102062306a36Sopenharmony_ci	u8 *mac, u16 vlan_id, int opcode, struct mac_configuration_cmd *config)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct mac_configuration_entry *cfg_entry = &config->config_table[0];
102362306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	bnx2x_vlan_mac_set_rdata_hdr_e1x(bp, o, type, cam_offset,
102662306a36Sopenharmony_ci					 &config->hdr);
102762306a36Sopenharmony_ci	bnx2x_vlan_mac_set_cfg_entry_e1x(bp, o, add, opcode, mac, vlan_id,
102862306a36Sopenharmony_ci					 cfg_entry);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "%s MAC %pM CLID %d CAM offset %d\n",
103162306a36Sopenharmony_ci			 (add ? "setting" : "clearing"),
103262306a36Sopenharmony_ci			 mac, raw->cl_id, cam_offset);
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci/**
103662306a36Sopenharmony_ci * bnx2x_set_one_mac_e1x - fill a single MAC rule ramrod data
103762306a36Sopenharmony_ci *
103862306a36Sopenharmony_ci * @bp:		device handle
103962306a36Sopenharmony_ci * @o:		bnx2x_vlan_mac_obj
104062306a36Sopenharmony_ci * @elem:	bnx2x_exeq_elem
104162306a36Sopenharmony_ci * @rule_idx:	rule_idx
104262306a36Sopenharmony_ci * @cam_offset: cam_offset
104362306a36Sopenharmony_ci */
104462306a36Sopenharmony_cistatic void bnx2x_set_one_mac_e1x(struct bnx2x *bp,
104562306a36Sopenharmony_ci				  struct bnx2x_vlan_mac_obj *o,
104662306a36Sopenharmony_ci				  struct bnx2x_exeq_elem *elem, int rule_idx,
104762306a36Sopenharmony_ci				  int cam_offset)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
105062306a36Sopenharmony_ci	struct mac_configuration_cmd *config =
105162306a36Sopenharmony_ci		(struct mac_configuration_cmd *)(raw->rdata);
105262306a36Sopenharmony_ci	/* 57710 and 57711 do not support MOVE command,
105362306a36Sopenharmony_ci	 * so it's either ADD or DEL
105462306a36Sopenharmony_ci	 */
105562306a36Sopenharmony_ci	bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
105662306a36Sopenharmony_ci		true : false;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* Reset the ramrod data buffer */
105962306a36Sopenharmony_ci	memset(config, 0, sizeof(*config));
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	bnx2x_vlan_mac_set_rdata_e1x(bp, o, raw->state,
106262306a36Sopenharmony_ci				     cam_offset, add,
106362306a36Sopenharmony_ci				     elem->cmd_data.vlan_mac.u.mac.mac, 0,
106462306a36Sopenharmony_ci				     ETH_VLAN_FILTER_ANY_VLAN, config);
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic void bnx2x_set_one_vlan_e2(struct bnx2x *bp,
106862306a36Sopenharmony_ci				  struct bnx2x_vlan_mac_obj *o,
106962306a36Sopenharmony_ci				  struct bnx2x_exeq_elem *elem, int rule_idx,
107062306a36Sopenharmony_ci				  int cam_offset)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
107362306a36Sopenharmony_ci	struct eth_classify_rules_ramrod_data *data =
107462306a36Sopenharmony_ci		(struct eth_classify_rules_ramrod_data *)(raw->rdata);
107562306a36Sopenharmony_ci	int rule_cnt = rule_idx + 1;
107662306a36Sopenharmony_ci	union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
107762306a36Sopenharmony_ci	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
107862306a36Sopenharmony_ci	bool add = cmd == BNX2X_VLAN_MAC_ADD;
107962306a36Sopenharmony_ci	u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	/* Reset the ramrod data buffer for the first rule */
108262306a36Sopenharmony_ci	if (rule_idx == 0)
108362306a36Sopenharmony_ci		memset(data, 0, sizeof(*data));
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* Set a rule header */
108662306a36Sopenharmony_ci	bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_VLAN,
108762306a36Sopenharmony_ci				      &rule_entry->vlan.header);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "About to %s VLAN %d\n", (add ? "add" : "delete"),
109062306a36Sopenharmony_ci			 vlan);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/* Set a VLAN itself */
109362306a36Sopenharmony_ci	rule_entry->vlan.vlan = cpu_to_le16(vlan);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	/* MOVE: Add a rule that will add this MAC to the target Queue */
109662306a36Sopenharmony_ci	if (cmd == BNX2X_VLAN_MAC_MOVE) {
109762306a36Sopenharmony_ci		rule_entry++;
109862306a36Sopenharmony_ci		rule_cnt++;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci		/* Setup ramrod data */
110162306a36Sopenharmony_ci		bnx2x_vlan_mac_set_cmd_hdr_e2(bp,
110262306a36Sopenharmony_ci					elem->cmd_data.vlan_mac.target_obj,
110362306a36Sopenharmony_ci					      true, CLASSIFY_RULE_OPCODE_VLAN,
110462306a36Sopenharmony_ci					      &rule_entry->vlan.header);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		/* Set a VLAN itself */
110762306a36Sopenharmony_ci		rule_entry->vlan.vlan = cpu_to_le16(vlan);
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/* Set the ramrod data header */
111162306a36Sopenharmony_ci	/* TODO: take this to the higher level in order to prevent multiple
111262306a36Sopenharmony_ci		 writing */
111362306a36Sopenharmony_ci	bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header,
111462306a36Sopenharmony_ci					rule_cnt);
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
111862306a36Sopenharmony_ci				      struct bnx2x_vlan_mac_obj *o,
111962306a36Sopenharmony_ci				      struct bnx2x_exeq_elem *elem,
112062306a36Sopenharmony_ci				      int rule_idx, int cam_offset)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
112362306a36Sopenharmony_ci	struct eth_classify_rules_ramrod_data *data =
112462306a36Sopenharmony_ci		(struct eth_classify_rules_ramrod_data *)(raw->rdata);
112562306a36Sopenharmony_ci	int rule_cnt = rule_idx + 1;
112662306a36Sopenharmony_ci	union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
112762306a36Sopenharmony_ci	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
112862306a36Sopenharmony_ci	bool add = cmd == BNX2X_VLAN_MAC_ADD;
112962306a36Sopenharmony_ci	u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
113062306a36Sopenharmony_ci	u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
113162306a36Sopenharmony_ci	u16 inner_mac;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* Reset the ramrod data buffer for the first rule */
113462306a36Sopenharmony_ci	if (rule_idx == 0)
113562306a36Sopenharmony_ci		memset(data, 0, sizeof(*data));
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	/* Set a rule header */
113862306a36Sopenharmony_ci	bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR,
113962306a36Sopenharmony_ci				      &rule_entry->pair.header);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* Set VLAN and MAC themselves */
114262306a36Sopenharmony_ci	rule_entry->pair.vlan = cpu_to_le16(vlan);
114362306a36Sopenharmony_ci	bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
114462306a36Sopenharmony_ci			      &rule_entry->pair.mac_mid,
114562306a36Sopenharmony_ci			      &rule_entry->pair.mac_lsb, mac);
114662306a36Sopenharmony_ci	inner_mac = elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac;
114762306a36Sopenharmony_ci	rule_entry->pair.inner_mac = cpu_to_le16(inner_mac);
114862306a36Sopenharmony_ci	/* MOVE: Add a rule that will add this MAC/VLAN to the target Queue */
114962306a36Sopenharmony_ci	if (cmd == BNX2X_VLAN_MAC_MOVE) {
115062306a36Sopenharmony_ci		struct bnx2x_vlan_mac_obj *target_obj;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci		rule_entry++;
115362306a36Sopenharmony_ci		rule_cnt++;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci		/* Setup ramrod data */
115662306a36Sopenharmony_ci		target_obj = elem->cmd_data.vlan_mac.target_obj;
115762306a36Sopenharmony_ci		bnx2x_vlan_mac_set_cmd_hdr_e2(bp, target_obj,
115862306a36Sopenharmony_ci					      true, CLASSIFY_RULE_OPCODE_PAIR,
115962306a36Sopenharmony_ci					      &rule_entry->pair.header);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		/* Set a VLAN itself */
116262306a36Sopenharmony_ci		rule_entry->pair.vlan = cpu_to_le16(vlan);
116362306a36Sopenharmony_ci		bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
116462306a36Sopenharmony_ci				      &rule_entry->pair.mac_mid,
116562306a36Sopenharmony_ci				      &rule_entry->pair.mac_lsb, mac);
116662306a36Sopenharmony_ci		rule_entry->pair.inner_mac = cpu_to_le16(inner_mac);
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	/* Set the ramrod data header */
117062306a36Sopenharmony_ci	bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header,
117162306a36Sopenharmony_ci					rule_cnt);
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci/**
117562306a36Sopenharmony_ci * bnx2x_set_one_vlan_mac_e1h -
117662306a36Sopenharmony_ci *
117762306a36Sopenharmony_ci * @bp:		device handle
117862306a36Sopenharmony_ci * @o:		bnx2x_vlan_mac_obj
117962306a36Sopenharmony_ci * @elem:	bnx2x_exeq_elem
118062306a36Sopenharmony_ci * @rule_idx:	rule_idx
118162306a36Sopenharmony_ci * @cam_offset:	cam_offset
118262306a36Sopenharmony_ci */
118362306a36Sopenharmony_cistatic void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp,
118462306a36Sopenharmony_ci				       struct bnx2x_vlan_mac_obj *o,
118562306a36Sopenharmony_ci				       struct bnx2x_exeq_elem *elem,
118662306a36Sopenharmony_ci				       int rule_idx, int cam_offset)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
118962306a36Sopenharmony_ci	struct mac_configuration_cmd *config =
119062306a36Sopenharmony_ci		(struct mac_configuration_cmd *)(raw->rdata);
119162306a36Sopenharmony_ci	/* 57710 and 57711 do not support MOVE command,
119262306a36Sopenharmony_ci	 * so it's either ADD or DEL
119362306a36Sopenharmony_ci	 */
119462306a36Sopenharmony_ci	bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
119562306a36Sopenharmony_ci		true : false;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* Reset the ramrod data buffer */
119862306a36Sopenharmony_ci	memset(config, 0, sizeof(*config));
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING,
120162306a36Sopenharmony_ci				     cam_offset, add,
120262306a36Sopenharmony_ci				     elem->cmd_data.vlan_mac.u.vlan_mac.mac,
120362306a36Sopenharmony_ci				     elem->cmd_data.vlan_mac.u.vlan_mac.vlan,
120462306a36Sopenharmony_ci				     ETH_VLAN_FILTER_CLASSIFY, config);
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci/**
120862306a36Sopenharmony_ci * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element
120962306a36Sopenharmony_ci *
121062306a36Sopenharmony_ci * @bp:		device handle
121162306a36Sopenharmony_ci * @p:		command parameters
121262306a36Sopenharmony_ci * @ppos:	pointer to the cookie
121362306a36Sopenharmony_ci *
121462306a36Sopenharmony_ci * reconfigure next MAC/VLAN/VLAN-MAC element from the
121562306a36Sopenharmony_ci * previously configured elements list.
121662306a36Sopenharmony_ci *
121762306a36Sopenharmony_ci * from command parameters only RAMROD_COMP_WAIT bit in ramrod_flags is	taken
121862306a36Sopenharmony_ci * into an account
121962306a36Sopenharmony_ci *
122062306a36Sopenharmony_ci * pointer to the cookie  - that should be given back in the next call to make
122162306a36Sopenharmony_ci * function handle the next element. If *ppos is set to NULL it will restart the
122262306a36Sopenharmony_ci * iterator. If returned *ppos == NULL this means that the last element has been
122362306a36Sopenharmony_ci * handled.
122462306a36Sopenharmony_ci *
122562306a36Sopenharmony_ci */
122662306a36Sopenharmony_cistatic int bnx2x_vlan_mac_restore(struct bnx2x *bp,
122762306a36Sopenharmony_ci			   struct bnx2x_vlan_mac_ramrod_params *p,
122862306a36Sopenharmony_ci			   struct bnx2x_vlan_mac_registry_elem **ppos)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
123162306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/* If list is empty - there is nothing to do here */
123462306a36Sopenharmony_ci	if (list_empty(&o->head)) {
123562306a36Sopenharmony_ci		*ppos = NULL;
123662306a36Sopenharmony_ci		return 0;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* make a step... */
124062306a36Sopenharmony_ci	if (*ppos == NULL)
124162306a36Sopenharmony_ci		*ppos = list_first_entry(&o->head,
124262306a36Sopenharmony_ci					 struct bnx2x_vlan_mac_registry_elem,
124362306a36Sopenharmony_ci					 link);
124462306a36Sopenharmony_ci	else
124562306a36Sopenharmony_ci		*ppos = list_next_entry(*ppos, link);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	pos = *ppos;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* If it's the last step - return NULL */
125062306a36Sopenharmony_ci	if (list_is_last(&pos->link, &o->head))
125162306a36Sopenharmony_ci		*ppos = NULL;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	/* Prepare a 'user_req' */
125462306a36Sopenharmony_ci	memcpy(&p->user_req.u, &pos->u, sizeof(pos->u));
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	/* Set the command */
125762306a36Sopenharmony_ci	p->user_req.cmd = BNX2X_VLAN_MAC_ADD;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* Set vlan_mac_flags */
126062306a36Sopenharmony_ci	p->user_req.vlan_mac_flags = pos->vlan_mac_flags;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* Set a restore bit */
126362306a36Sopenharmony_ci	__set_bit(RAMROD_RESTORE, &p->ramrod_flags);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	return bnx2x_config_vlan_mac(bp, p);
126662306a36Sopenharmony_ci}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci/* bnx2x_exeq_get_mac/bnx2x_exeq_get_vlan/bnx2x_exeq_get_vlan_mac return a
126962306a36Sopenharmony_ci * pointer to an element with a specific criteria and NULL if such an element
127062306a36Sopenharmony_ci * hasn't been found.
127162306a36Sopenharmony_ci */
127262306a36Sopenharmony_cistatic struct bnx2x_exeq_elem *bnx2x_exeq_get_mac(
127362306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *o,
127462306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct bnx2x_exeq_elem *pos;
127762306a36Sopenharmony_ci	struct bnx2x_mac_ramrod_data *data = &elem->cmd_data.vlan_mac.u.mac;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	/* Check pending for execution commands */
128062306a36Sopenharmony_ci	list_for_each_entry(pos, &o->exe_queue, link)
128162306a36Sopenharmony_ci		if (!memcmp(&pos->cmd_data.vlan_mac.u.mac, data,
128262306a36Sopenharmony_ci			      sizeof(*data)) &&
128362306a36Sopenharmony_ci		    (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd))
128462306a36Sopenharmony_ci			return pos;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	return NULL;
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_cistatic struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan(
129062306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *o,
129162306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	struct bnx2x_exeq_elem *pos;
129462306a36Sopenharmony_ci	struct bnx2x_vlan_ramrod_data *data = &elem->cmd_data.vlan_mac.u.vlan;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	/* Check pending for execution commands */
129762306a36Sopenharmony_ci	list_for_each_entry(pos, &o->exe_queue, link)
129862306a36Sopenharmony_ci		if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan, data,
129962306a36Sopenharmony_ci			      sizeof(*data)) &&
130062306a36Sopenharmony_ci		    (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd))
130162306a36Sopenharmony_ci			return pos;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	return NULL;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistatic struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac(
130762306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *o,
130862306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct bnx2x_exeq_elem *pos;
131162306a36Sopenharmony_ci	struct bnx2x_vlan_mac_ramrod_data *data =
131262306a36Sopenharmony_ci		&elem->cmd_data.vlan_mac.u.vlan_mac;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	/* Check pending for execution commands */
131562306a36Sopenharmony_ci	list_for_each_entry(pos, &o->exe_queue, link)
131662306a36Sopenharmony_ci		if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data,
131762306a36Sopenharmony_ci			    sizeof(*data)) &&
131862306a36Sopenharmony_ci		    (pos->cmd_data.vlan_mac.cmd ==
131962306a36Sopenharmony_ci		     elem->cmd_data.vlan_mac.cmd))
132062306a36Sopenharmony_ci			return pos;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	return NULL;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/**
132662306a36Sopenharmony_ci * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed
132762306a36Sopenharmony_ci *
132862306a36Sopenharmony_ci * @bp:		device handle
132962306a36Sopenharmony_ci * @qo:		bnx2x_qable_obj
133062306a36Sopenharmony_ci * @elem:	bnx2x_exeq_elem
133162306a36Sopenharmony_ci *
133262306a36Sopenharmony_ci * Checks that the requested configuration can be added. If yes and if
133362306a36Sopenharmony_ci * requested, consume CAM credit.
133462306a36Sopenharmony_ci *
133562306a36Sopenharmony_ci * The 'validate' is run after the 'optimize'.
133662306a36Sopenharmony_ci *
133762306a36Sopenharmony_ci */
133862306a36Sopenharmony_cistatic inline int bnx2x_validate_vlan_mac_add(struct bnx2x *bp,
133962306a36Sopenharmony_ci					      union bnx2x_qable_obj *qo,
134062306a36Sopenharmony_ci					      struct bnx2x_exeq_elem *elem)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac;
134362306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
134462306a36Sopenharmony_ci	int rc;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* Check the registry */
134762306a36Sopenharmony_ci	rc = o->check_add(bp, o, &elem->cmd_data.vlan_mac.u);
134862306a36Sopenharmony_ci	if (rc) {
134962306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "ADD command is not allowed considering current registry state.\n");
135062306a36Sopenharmony_ci		return rc;
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	/* Check if there is a pending ADD command for this
135462306a36Sopenharmony_ci	 * MAC/VLAN/VLAN-MAC. Return an error if there is.
135562306a36Sopenharmony_ci	 */
135662306a36Sopenharmony_ci	if (exeq->get(exeq, elem)) {
135762306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "There is a pending ADD command already\n");
135862306a36Sopenharmony_ci		return -EEXIST;
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	/* TODO: Check the pending MOVE from other objects where this
136262306a36Sopenharmony_ci	 * object is a destination object.
136362306a36Sopenharmony_ci	 */
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	/* Consume the credit if not requested not to */
136662306a36Sopenharmony_ci	if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
136762306a36Sopenharmony_ci		       &elem->cmd_data.vlan_mac.vlan_mac_flags) ||
136862306a36Sopenharmony_ci	    o->get_credit(o)))
136962306a36Sopenharmony_ci		return -EINVAL;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	return 0;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci/**
137562306a36Sopenharmony_ci * bnx2x_validate_vlan_mac_del - check if the DEL command can be executed
137662306a36Sopenharmony_ci *
137762306a36Sopenharmony_ci * @bp:		device handle
137862306a36Sopenharmony_ci * @qo:		quable object to check
137962306a36Sopenharmony_ci * @elem:	element that needs to be deleted
138062306a36Sopenharmony_ci *
138162306a36Sopenharmony_ci * Checks that the requested configuration can be deleted. If yes and if
138262306a36Sopenharmony_ci * requested, returns a CAM credit.
138362306a36Sopenharmony_ci *
138462306a36Sopenharmony_ci * The 'validate' is run after the 'optimize'.
138562306a36Sopenharmony_ci */
138662306a36Sopenharmony_cistatic inline int bnx2x_validate_vlan_mac_del(struct bnx2x *bp,
138762306a36Sopenharmony_ci					      union bnx2x_qable_obj *qo,
138862306a36Sopenharmony_ci					      struct bnx2x_exeq_elem *elem)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac;
139162306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos;
139262306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
139362306a36Sopenharmony_ci	struct bnx2x_exeq_elem query_elem;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* If this classification can not be deleted (doesn't exist)
139662306a36Sopenharmony_ci	 * - return a BNX2X_EXIST.
139762306a36Sopenharmony_ci	 */
139862306a36Sopenharmony_ci	pos = o->check_del(bp, o, &elem->cmd_data.vlan_mac.u);
139962306a36Sopenharmony_ci	if (!pos) {
140062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "DEL command is not allowed considering current registry state\n");
140162306a36Sopenharmony_ci		return -EEXIST;
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/* Check if there are pending DEL or MOVE commands for this
140562306a36Sopenharmony_ci	 * MAC/VLAN/VLAN-MAC. Return an error if so.
140662306a36Sopenharmony_ci	 */
140762306a36Sopenharmony_ci	memcpy(&query_elem, elem, sizeof(query_elem));
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* Check for MOVE commands */
141062306a36Sopenharmony_ci	query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_MOVE;
141162306a36Sopenharmony_ci	if (exeq->get(exeq, &query_elem)) {
141262306a36Sopenharmony_ci		BNX2X_ERR("There is a pending MOVE command already\n");
141362306a36Sopenharmony_ci		return -EINVAL;
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	/* Check for DEL commands */
141762306a36Sopenharmony_ci	if (exeq->get(exeq, elem)) {
141862306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "There is a pending DEL command already\n");
141962306a36Sopenharmony_ci		return -EEXIST;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	/* Return the credit to the credit pool if not requested not to */
142362306a36Sopenharmony_ci	if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
142462306a36Sopenharmony_ci		       &elem->cmd_data.vlan_mac.vlan_mac_flags) ||
142562306a36Sopenharmony_ci	    o->put_credit(o))) {
142662306a36Sopenharmony_ci		BNX2X_ERR("Failed to return a credit\n");
142762306a36Sopenharmony_ci		return -EINVAL;
142862306a36Sopenharmony_ci	}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	return 0;
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci/**
143462306a36Sopenharmony_ci * bnx2x_validate_vlan_mac_move - check if the MOVE command can be executed
143562306a36Sopenharmony_ci *
143662306a36Sopenharmony_ci * @bp:		device handle
143762306a36Sopenharmony_ci * @qo:		quable object to check (source)
143862306a36Sopenharmony_ci * @elem:	element that needs to be moved
143962306a36Sopenharmony_ci *
144062306a36Sopenharmony_ci * Checks that the requested configuration can be moved. If yes and if
144162306a36Sopenharmony_ci * requested, returns a CAM credit.
144262306a36Sopenharmony_ci *
144362306a36Sopenharmony_ci * The 'validate' is run after the 'optimize'.
144462306a36Sopenharmony_ci */
144562306a36Sopenharmony_cistatic inline int bnx2x_validate_vlan_mac_move(struct bnx2x *bp,
144662306a36Sopenharmony_ci					       union bnx2x_qable_obj *qo,
144762306a36Sopenharmony_ci					       struct bnx2x_exeq_elem *elem)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *src_o = &qo->vlan_mac;
145062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *dest_o = elem->cmd_data.vlan_mac.target_obj;
145162306a36Sopenharmony_ci	struct bnx2x_exeq_elem query_elem;
145262306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *src_exeq = &src_o->exe_queue;
145362306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *dest_exeq = &dest_o->exe_queue;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	/* Check if we can perform this operation based on the current registry
145662306a36Sopenharmony_ci	 * state.
145762306a36Sopenharmony_ci	 */
145862306a36Sopenharmony_ci	if (!src_o->check_move(bp, src_o, dest_o,
145962306a36Sopenharmony_ci			       &elem->cmd_data.vlan_mac.u)) {
146062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "MOVE command is not allowed considering current registry state\n");
146162306a36Sopenharmony_ci		return -EINVAL;
146262306a36Sopenharmony_ci	}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	/* Check if there is an already pending DEL or MOVE command for the
146562306a36Sopenharmony_ci	 * source object or ADD command for a destination object. Return an
146662306a36Sopenharmony_ci	 * error if so.
146762306a36Sopenharmony_ci	 */
146862306a36Sopenharmony_ci	memcpy(&query_elem, elem, sizeof(query_elem));
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	/* Check DEL on source */
147162306a36Sopenharmony_ci	query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_DEL;
147262306a36Sopenharmony_ci	if (src_exeq->get(src_exeq, &query_elem)) {
147362306a36Sopenharmony_ci		BNX2X_ERR("There is a pending DEL command on the source queue already\n");
147462306a36Sopenharmony_ci		return -EINVAL;
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	/* Check MOVE on source */
147862306a36Sopenharmony_ci	if (src_exeq->get(src_exeq, elem)) {
147962306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "There is a pending MOVE command already\n");
148062306a36Sopenharmony_ci		return -EEXIST;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	/* Check ADD on destination */
148462306a36Sopenharmony_ci	query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_ADD;
148562306a36Sopenharmony_ci	if (dest_exeq->get(dest_exeq, &query_elem)) {
148662306a36Sopenharmony_ci		BNX2X_ERR("There is a pending ADD command on the destination queue already\n");
148762306a36Sopenharmony_ci		return -EINVAL;
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/* Consume the credit if not requested not to */
149162306a36Sopenharmony_ci	if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT_DEST,
149262306a36Sopenharmony_ci		       &elem->cmd_data.vlan_mac.vlan_mac_flags) ||
149362306a36Sopenharmony_ci	    dest_o->get_credit(dest_o)))
149462306a36Sopenharmony_ci		return -EINVAL;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
149762306a36Sopenharmony_ci		       &elem->cmd_data.vlan_mac.vlan_mac_flags) ||
149862306a36Sopenharmony_ci	    src_o->put_credit(src_o))) {
149962306a36Sopenharmony_ci		/* return the credit taken from dest... */
150062306a36Sopenharmony_ci		dest_o->put_credit(dest_o);
150162306a36Sopenharmony_ci		return -EINVAL;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	return 0;
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_cistatic int bnx2x_validate_vlan_mac(struct bnx2x *bp,
150862306a36Sopenharmony_ci				   union bnx2x_qable_obj *qo,
150962306a36Sopenharmony_ci				   struct bnx2x_exeq_elem *elem)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	switch (elem->cmd_data.vlan_mac.cmd) {
151262306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_ADD:
151362306a36Sopenharmony_ci		return bnx2x_validate_vlan_mac_add(bp, qo, elem);
151462306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_DEL:
151562306a36Sopenharmony_ci		return bnx2x_validate_vlan_mac_del(bp, qo, elem);
151662306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_MOVE:
151762306a36Sopenharmony_ci		return bnx2x_validate_vlan_mac_move(bp, qo, elem);
151862306a36Sopenharmony_ci	default:
151962306a36Sopenharmony_ci		return -EINVAL;
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic int bnx2x_remove_vlan_mac(struct bnx2x *bp,
152462306a36Sopenharmony_ci				  union bnx2x_qable_obj *qo,
152562306a36Sopenharmony_ci				  struct bnx2x_exeq_elem *elem)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	int rc = 0;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	/* If consumption wasn't required, nothing to do */
153062306a36Sopenharmony_ci	if (test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
153162306a36Sopenharmony_ci		     &elem->cmd_data.vlan_mac.vlan_mac_flags))
153262306a36Sopenharmony_ci		return 0;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	switch (elem->cmd_data.vlan_mac.cmd) {
153562306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_ADD:
153662306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_MOVE:
153762306a36Sopenharmony_ci		rc = qo->vlan_mac.put_credit(&qo->vlan_mac);
153862306a36Sopenharmony_ci		break;
153962306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_DEL:
154062306a36Sopenharmony_ci		rc = qo->vlan_mac.get_credit(&qo->vlan_mac);
154162306a36Sopenharmony_ci		break;
154262306a36Sopenharmony_ci	default:
154362306a36Sopenharmony_ci		return -EINVAL;
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	if (rc != true)
154762306a36Sopenharmony_ci		return -EINVAL;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	return 0;
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci/**
155362306a36Sopenharmony_ci * bnx2x_wait_vlan_mac - passively wait for 5 seconds until all work completes.
155462306a36Sopenharmony_ci *
155562306a36Sopenharmony_ci * @bp:		device handle
155662306a36Sopenharmony_ci * @o:		bnx2x_vlan_mac_obj
155762306a36Sopenharmony_ci *
155862306a36Sopenharmony_ci */
155962306a36Sopenharmony_cistatic int bnx2x_wait_vlan_mac(struct bnx2x *bp,
156062306a36Sopenharmony_ci			       struct bnx2x_vlan_mac_obj *o)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	int cnt = 5000, rc;
156362306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
156462306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	while (cnt--) {
156762306a36Sopenharmony_ci		/* Wait for the current command to complete */
156862306a36Sopenharmony_ci		rc = raw->wait_comp(bp, raw);
156962306a36Sopenharmony_ci		if (rc)
157062306a36Sopenharmony_ci			return rc;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		/* Wait until there are no pending commands */
157362306a36Sopenharmony_ci		if (!bnx2x_exe_queue_empty(exeq))
157462306a36Sopenharmony_ci			usleep_range(1000, 2000);
157562306a36Sopenharmony_ci		else
157662306a36Sopenharmony_ci			return 0;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return -EBUSY;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic int __bnx2x_vlan_mac_execute_step(struct bnx2x *bp,
158362306a36Sopenharmony_ci					 struct bnx2x_vlan_mac_obj *o,
158462306a36Sopenharmony_ci					 unsigned long *ramrod_flags)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	int rc = 0;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	spin_lock_bh(&o->exe_queue.lock);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "vlan_mac_execute_step - trying to take writer lock\n");
159162306a36Sopenharmony_ci	rc = __bnx2x_vlan_mac_h_write_trylock(bp, o);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (rc != 0) {
159462306a36Sopenharmony_ci		__bnx2x_vlan_mac_h_pend(bp, o, *ramrod_flags);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		/* Calling function should not differentiate between this case
159762306a36Sopenharmony_ci		 * and the case in which there is already a pending ramrod
159862306a36Sopenharmony_ci		 */
159962306a36Sopenharmony_ci		rc = 1;
160062306a36Sopenharmony_ci	} else {
160162306a36Sopenharmony_ci		rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci	spin_unlock_bh(&o->exe_queue.lock);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	return rc;
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci/**
160962306a36Sopenharmony_ci * bnx2x_complete_vlan_mac - complete one VLAN-MAC ramrod
161062306a36Sopenharmony_ci *
161162306a36Sopenharmony_ci * @bp:		device handle
161262306a36Sopenharmony_ci * @o:		bnx2x_vlan_mac_obj
161362306a36Sopenharmony_ci * @cqe:	completion element
161462306a36Sopenharmony_ci * @ramrod_flags: if set schedule next execution chunk
161562306a36Sopenharmony_ci *
161662306a36Sopenharmony_ci */
161762306a36Sopenharmony_cistatic int bnx2x_complete_vlan_mac(struct bnx2x *bp,
161862306a36Sopenharmony_ci				   struct bnx2x_vlan_mac_obj *o,
161962306a36Sopenharmony_ci				   union event_ring_elem *cqe,
162062306a36Sopenharmony_ci				   unsigned long *ramrod_flags)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
162362306a36Sopenharmony_ci	int rc;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/* Clearing the pending list & raw state should be made
162662306a36Sopenharmony_ci	 * atomically (as execution flow assumes they represent the same).
162762306a36Sopenharmony_ci	 */
162862306a36Sopenharmony_ci	spin_lock_bh(&o->exe_queue.lock);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	/* Reset pending list */
163162306a36Sopenharmony_ci	__bnx2x_exe_queue_reset_pending(bp, &o->exe_queue);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	/* Clear pending */
163462306a36Sopenharmony_ci	r->clear_pending(r);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	spin_unlock_bh(&o->exe_queue.lock);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	/* If ramrod failed this is most likely a SW bug */
163962306a36Sopenharmony_ci	if (cqe->message.error)
164062306a36Sopenharmony_ci		return -EINVAL;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	/* Run the next bulk of pending commands if requested */
164362306a36Sopenharmony_ci	if (test_bit(RAMROD_CONT, ramrod_flags)) {
164462306a36Sopenharmony_ci		rc = __bnx2x_vlan_mac_execute_step(bp, o, ramrod_flags);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci		if (rc < 0)
164762306a36Sopenharmony_ci			return rc;
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/* If there is more work to do return PENDING */
165162306a36Sopenharmony_ci	if (!bnx2x_exe_queue_empty(&o->exe_queue))
165262306a36Sopenharmony_ci		return 1;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	return 0;
165562306a36Sopenharmony_ci}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci/**
165862306a36Sopenharmony_ci * bnx2x_optimize_vlan_mac - optimize ADD and DEL commands.
165962306a36Sopenharmony_ci *
166062306a36Sopenharmony_ci * @bp:		device handle
166162306a36Sopenharmony_ci * @qo:		bnx2x_qable_obj
166262306a36Sopenharmony_ci * @elem:	bnx2x_exeq_elem
166362306a36Sopenharmony_ci */
166462306a36Sopenharmony_cistatic int bnx2x_optimize_vlan_mac(struct bnx2x *bp,
166562306a36Sopenharmony_ci				   union bnx2x_qable_obj *qo,
166662306a36Sopenharmony_ci				   struct bnx2x_exeq_elem *elem)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	struct bnx2x_exeq_elem query, *pos;
166962306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac;
167062306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	memcpy(&query, elem, sizeof(query));
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	switch (elem->cmd_data.vlan_mac.cmd) {
167562306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_ADD:
167662306a36Sopenharmony_ci		query.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_DEL;
167762306a36Sopenharmony_ci		break;
167862306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_DEL:
167962306a36Sopenharmony_ci		query.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_ADD;
168062306a36Sopenharmony_ci		break;
168162306a36Sopenharmony_ci	default:
168262306a36Sopenharmony_ci		/* Don't handle anything other than ADD or DEL */
168362306a36Sopenharmony_ci		return 0;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	/* If we found the appropriate element - delete it */
168762306a36Sopenharmony_ci	pos = exeq->get(exeq, &query);
168862306a36Sopenharmony_ci	if (pos) {
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci		/* Return the credit of the optimized command */
169162306a36Sopenharmony_ci		if (!test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
169262306a36Sopenharmony_ci			      &pos->cmd_data.vlan_mac.vlan_mac_flags)) {
169362306a36Sopenharmony_ci			if ((query.cmd_data.vlan_mac.cmd ==
169462306a36Sopenharmony_ci			     BNX2X_VLAN_MAC_ADD) && !o->put_credit(o)) {
169562306a36Sopenharmony_ci				BNX2X_ERR("Failed to return the credit for the optimized ADD command\n");
169662306a36Sopenharmony_ci				return -EINVAL;
169762306a36Sopenharmony_ci			} else if (!o->get_credit(o)) { /* VLAN_MAC_DEL */
169862306a36Sopenharmony_ci				BNX2X_ERR("Failed to recover the credit from the optimized DEL command\n");
169962306a36Sopenharmony_ci				return -EINVAL;
170062306a36Sopenharmony_ci			}
170162306a36Sopenharmony_ci		}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Optimizing %s command\n",
170462306a36Sopenharmony_ci			   (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
170562306a36Sopenharmony_ci			   "ADD" : "DEL");
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci		list_del(&pos->link);
170862306a36Sopenharmony_ci		bnx2x_exe_queue_free_elem(bp, pos);
170962306a36Sopenharmony_ci		return 1;
171062306a36Sopenharmony_ci	}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	return 0;
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci/**
171662306a36Sopenharmony_ci * bnx2x_vlan_mac_get_registry_elem - prepare a registry element
171762306a36Sopenharmony_ci *
171862306a36Sopenharmony_ci * @bp:	  device handle
171962306a36Sopenharmony_ci * @o:	vlan object
172062306a36Sopenharmony_ci * @elem: element
172162306a36Sopenharmony_ci * @restore: to restore or not
172262306a36Sopenharmony_ci * @re: registry
172362306a36Sopenharmony_ci *
172462306a36Sopenharmony_ci * prepare a registry element according to the current command request.
172562306a36Sopenharmony_ci */
172662306a36Sopenharmony_cistatic inline int bnx2x_vlan_mac_get_registry_elem(
172762306a36Sopenharmony_ci	struct bnx2x *bp,
172862306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o,
172962306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem,
173062306a36Sopenharmony_ci	bool restore,
173162306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem **re)
173262306a36Sopenharmony_ci{
173362306a36Sopenharmony_ci	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
173462306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *reg_elem;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	/* Allocate a new registry element if needed. */
173762306a36Sopenharmony_ci	if (!restore &&
173862306a36Sopenharmony_ci	    ((cmd == BNX2X_VLAN_MAC_ADD) || (cmd == BNX2X_VLAN_MAC_MOVE))) {
173962306a36Sopenharmony_ci		reg_elem = kzalloc(sizeof(*reg_elem), GFP_ATOMIC);
174062306a36Sopenharmony_ci		if (!reg_elem)
174162306a36Sopenharmony_ci			return -ENOMEM;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci		/* Get a new CAM offset */
174462306a36Sopenharmony_ci		if (!o->get_cam_offset(o, &reg_elem->cam_offset)) {
174562306a36Sopenharmony_ci			/* This shall never happen, because we have checked the
174662306a36Sopenharmony_ci			 * CAM availability in the 'validate'.
174762306a36Sopenharmony_ci			 */
174862306a36Sopenharmony_ci			WARN_ON(1);
174962306a36Sopenharmony_ci			kfree(reg_elem);
175062306a36Sopenharmony_ci			return -EINVAL;
175162306a36Sopenharmony_ci		}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Got cam offset %d\n", reg_elem->cam_offset);
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		/* Set a VLAN-MAC data */
175662306a36Sopenharmony_ci		memcpy(&reg_elem->u, &elem->cmd_data.vlan_mac.u,
175762306a36Sopenharmony_ci			  sizeof(reg_elem->u));
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci		/* Copy the flags (needed for DEL and RESTORE flows) */
176062306a36Sopenharmony_ci		reg_elem->vlan_mac_flags =
176162306a36Sopenharmony_ci			elem->cmd_data.vlan_mac.vlan_mac_flags;
176262306a36Sopenharmony_ci	} else /* DEL, RESTORE */
176362306a36Sopenharmony_ci		reg_elem = o->check_del(bp, o, &elem->cmd_data.vlan_mac.u);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	*re = reg_elem;
176662306a36Sopenharmony_ci	return 0;
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci/**
177062306a36Sopenharmony_ci * bnx2x_execute_vlan_mac - execute vlan mac command
177162306a36Sopenharmony_ci *
177262306a36Sopenharmony_ci * @bp:			device handle
177362306a36Sopenharmony_ci * @qo:			bnx2x_qable_obj pointer
177462306a36Sopenharmony_ci * @exe_chunk:		chunk
177562306a36Sopenharmony_ci * @ramrod_flags:	flags
177662306a36Sopenharmony_ci *
177762306a36Sopenharmony_ci * go and send a ramrod!
177862306a36Sopenharmony_ci */
177962306a36Sopenharmony_cistatic int bnx2x_execute_vlan_mac(struct bnx2x *bp,
178062306a36Sopenharmony_ci				  union bnx2x_qable_obj *qo,
178162306a36Sopenharmony_ci				  struct list_head *exe_chunk,
178262306a36Sopenharmony_ci				  unsigned long *ramrod_flags)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem;
178562306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac, *cam_obj;
178662306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
178762306a36Sopenharmony_ci	int rc, idx = 0;
178862306a36Sopenharmony_ci	bool restore = test_bit(RAMROD_RESTORE, ramrod_flags);
178962306a36Sopenharmony_ci	bool drv_only = test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags);
179062306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *reg_elem;
179162306a36Sopenharmony_ci	enum bnx2x_vlan_mac_cmd cmd;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	/* If DRIVER_ONLY execution is requested, cleanup a registry
179462306a36Sopenharmony_ci	 * and exit. Otherwise send a ramrod to FW.
179562306a36Sopenharmony_ci	 */
179662306a36Sopenharmony_ci	if (!drv_only) {
179762306a36Sopenharmony_ci		WARN_ON(r->check_pending(r));
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci		/* Set pending */
180062306a36Sopenharmony_ci		r->set_pending(r);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci		/* Fill the ramrod data */
180362306a36Sopenharmony_ci		list_for_each_entry(elem, exe_chunk, link) {
180462306a36Sopenharmony_ci			cmd = elem->cmd_data.vlan_mac.cmd;
180562306a36Sopenharmony_ci			/* We will add to the target object in MOVE command, so
180662306a36Sopenharmony_ci			 * change the object for a CAM search.
180762306a36Sopenharmony_ci			 */
180862306a36Sopenharmony_ci			if (cmd == BNX2X_VLAN_MAC_MOVE)
180962306a36Sopenharmony_ci				cam_obj = elem->cmd_data.vlan_mac.target_obj;
181062306a36Sopenharmony_ci			else
181162306a36Sopenharmony_ci				cam_obj = o;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci			rc = bnx2x_vlan_mac_get_registry_elem(bp, cam_obj,
181462306a36Sopenharmony_ci							      elem, restore,
181562306a36Sopenharmony_ci							      &reg_elem);
181662306a36Sopenharmony_ci			if (rc)
181762306a36Sopenharmony_ci				goto error_exit;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci			WARN_ON(!reg_elem);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci			/* Push a new entry into the registry */
182262306a36Sopenharmony_ci			if (!restore &&
182362306a36Sopenharmony_ci			    ((cmd == BNX2X_VLAN_MAC_ADD) ||
182462306a36Sopenharmony_ci			    (cmd == BNX2X_VLAN_MAC_MOVE)))
182562306a36Sopenharmony_ci				list_add(&reg_elem->link, &cam_obj->head);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci			/* Configure a single command in a ramrod data buffer */
182862306a36Sopenharmony_ci			o->set_one_rule(bp, o, elem, idx,
182962306a36Sopenharmony_ci					reg_elem->cam_offset);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci			/* MOVE command consumes 2 entries in the ramrod data */
183262306a36Sopenharmony_ci			if (cmd == BNX2X_VLAN_MAC_MOVE)
183362306a36Sopenharmony_ci				idx += 2;
183462306a36Sopenharmony_ci			else
183562306a36Sopenharmony_ci				idx++;
183662306a36Sopenharmony_ci		}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci		/* No need for an explicit memory barrier here as long we would
183962306a36Sopenharmony_ci		 * need to ensure the ordering of writing to the SPQ element
184062306a36Sopenharmony_ci		 * and updating of the SPQ producer which involves a memory
184162306a36Sopenharmony_ci		 * read and we will have to put a full memory barrier there
184262306a36Sopenharmony_ci		 * (inside bnx2x_sp_post()).
184362306a36Sopenharmony_ci		 */
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci		rc = bnx2x_sp_post(bp, o->ramrod_cmd, r->cid,
184662306a36Sopenharmony_ci				   U64_HI(r->rdata_mapping),
184762306a36Sopenharmony_ci				   U64_LO(r->rdata_mapping),
184862306a36Sopenharmony_ci				   ETH_CONNECTION_TYPE);
184962306a36Sopenharmony_ci		if (rc)
185062306a36Sopenharmony_ci			goto error_exit;
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/* Now, when we are done with the ramrod - clean up the registry */
185462306a36Sopenharmony_ci	list_for_each_entry(elem, exe_chunk, link) {
185562306a36Sopenharmony_ci		cmd = elem->cmd_data.vlan_mac.cmd;
185662306a36Sopenharmony_ci		if ((cmd == BNX2X_VLAN_MAC_DEL) ||
185762306a36Sopenharmony_ci		    (cmd == BNX2X_VLAN_MAC_MOVE)) {
185862306a36Sopenharmony_ci			reg_elem = o->check_del(bp, o,
185962306a36Sopenharmony_ci						&elem->cmd_data.vlan_mac.u);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci			WARN_ON(!reg_elem);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci			o->put_cam_offset(o, reg_elem->cam_offset);
186462306a36Sopenharmony_ci			list_del(&reg_elem->link);
186562306a36Sopenharmony_ci			kfree(reg_elem);
186662306a36Sopenharmony_ci		}
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	if (!drv_only)
187062306a36Sopenharmony_ci		return 1;
187162306a36Sopenharmony_ci	else
187262306a36Sopenharmony_ci		return 0;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cierror_exit:
187562306a36Sopenharmony_ci	r->clear_pending(r);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	/* Cleanup a registry in case of a failure */
187862306a36Sopenharmony_ci	list_for_each_entry(elem, exe_chunk, link) {
187962306a36Sopenharmony_ci		cmd = elem->cmd_data.vlan_mac.cmd;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci		if (cmd == BNX2X_VLAN_MAC_MOVE)
188262306a36Sopenharmony_ci			cam_obj = elem->cmd_data.vlan_mac.target_obj;
188362306a36Sopenharmony_ci		else
188462306a36Sopenharmony_ci			cam_obj = o;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci		/* Delete all newly added above entries */
188762306a36Sopenharmony_ci		if (!restore &&
188862306a36Sopenharmony_ci		    ((cmd == BNX2X_VLAN_MAC_ADD) ||
188962306a36Sopenharmony_ci		    (cmd == BNX2X_VLAN_MAC_MOVE))) {
189062306a36Sopenharmony_ci			reg_elem = o->check_del(bp, cam_obj,
189162306a36Sopenharmony_ci						&elem->cmd_data.vlan_mac.u);
189262306a36Sopenharmony_ci			if (reg_elem) {
189362306a36Sopenharmony_ci				list_del(&reg_elem->link);
189462306a36Sopenharmony_ci				kfree(reg_elem);
189562306a36Sopenharmony_ci			}
189662306a36Sopenharmony_ci		}
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	return rc;
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_cistatic inline int bnx2x_vlan_mac_push_new_cmd(
190362306a36Sopenharmony_ci	struct bnx2x *bp,
190462306a36Sopenharmony_ci	struct bnx2x_vlan_mac_ramrod_params *p)
190562306a36Sopenharmony_ci{
190662306a36Sopenharmony_ci	struct bnx2x_exeq_elem *elem;
190762306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj;
190862306a36Sopenharmony_ci	bool restore = test_bit(RAMROD_RESTORE, &p->ramrod_flags);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	/* Allocate the execution queue element */
191162306a36Sopenharmony_ci	elem = bnx2x_exe_queue_alloc_elem(bp);
191262306a36Sopenharmony_ci	if (!elem)
191362306a36Sopenharmony_ci		return -ENOMEM;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	/* Set the command 'length' */
191662306a36Sopenharmony_ci	switch (p->user_req.cmd) {
191762306a36Sopenharmony_ci	case BNX2X_VLAN_MAC_MOVE:
191862306a36Sopenharmony_ci		elem->cmd_len = 2;
191962306a36Sopenharmony_ci		break;
192062306a36Sopenharmony_ci	default:
192162306a36Sopenharmony_ci		elem->cmd_len = 1;
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	/* Fill the object specific info */
192562306a36Sopenharmony_ci	memcpy(&elem->cmd_data.vlan_mac, &p->user_req, sizeof(p->user_req));
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	/* Try to add a new command to the pending list */
192862306a36Sopenharmony_ci	return bnx2x_exe_queue_add(bp, &o->exe_queue, elem, restore);
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci/**
193262306a36Sopenharmony_ci * bnx2x_config_vlan_mac - configure VLAN/MAC/VLAN_MAC filtering rules.
193362306a36Sopenharmony_ci *
193462306a36Sopenharmony_ci * @bp:	  device handle
193562306a36Sopenharmony_ci * @p:
193662306a36Sopenharmony_ci *
193762306a36Sopenharmony_ci */
193862306a36Sopenharmony_ciint bnx2x_config_vlan_mac(struct bnx2x *bp,
193962306a36Sopenharmony_ci			   struct bnx2x_vlan_mac_ramrod_params *p)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	int rc = 0;
194262306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj;
194362306a36Sopenharmony_ci	unsigned long *ramrod_flags = &p->ramrod_flags;
194462306a36Sopenharmony_ci	bool cont = test_bit(RAMROD_CONT, ramrod_flags);
194562306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	/*
194862306a36Sopenharmony_ci	 * Add new elements to the execution list for commands that require it.
194962306a36Sopenharmony_ci	 */
195062306a36Sopenharmony_ci	if (!cont) {
195162306a36Sopenharmony_ci		rc = bnx2x_vlan_mac_push_new_cmd(bp, p);
195262306a36Sopenharmony_ci		if (rc)
195362306a36Sopenharmony_ci			return rc;
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	/* If nothing will be executed further in this iteration we want to
195762306a36Sopenharmony_ci	 * return PENDING if there are pending commands
195862306a36Sopenharmony_ci	 */
195962306a36Sopenharmony_ci	if (!bnx2x_exe_queue_empty(&o->exe_queue))
196062306a36Sopenharmony_ci		rc = 1;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags))  {
196362306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: clearing a pending bit.\n");
196462306a36Sopenharmony_ci		raw->clear_pending(raw);
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	/* Execute commands if required */
196862306a36Sopenharmony_ci	if (cont || test_bit(RAMROD_EXEC, ramrod_flags) ||
196962306a36Sopenharmony_ci	    test_bit(RAMROD_COMP_WAIT, ramrod_flags)) {
197062306a36Sopenharmony_ci		rc = __bnx2x_vlan_mac_execute_step(bp, p->vlan_mac_obj,
197162306a36Sopenharmony_ci						   &p->ramrod_flags);
197262306a36Sopenharmony_ci		if (rc < 0)
197362306a36Sopenharmony_ci			return rc;
197462306a36Sopenharmony_ci	}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	/* RAMROD_COMP_WAIT is a superset of RAMROD_EXEC. If it was set
197762306a36Sopenharmony_ci	 * then user want to wait until the last command is done.
197862306a36Sopenharmony_ci	 */
197962306a36Sopenharmony_ci	if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) {
198062306a36Sopenharmony_ci		/* Wait maximum for the current exe_queue length iterations plus
198162306a36Sopenharmony_ci		 * one (for the current pending command).
198262306a36Sopenharmony_ci		 */
198362306a36Sopenharmony_ci		int max_iterations = bnx2x_exe_queue_length(&o->exe_queue) + 1;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		while (!bnx2x_exe_queue_empty(&o->exe_queue) &&
198662306a36Sopenharmony_ci		       max_iterations--) {
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci			/* Wait for the current command to complete */
198962306a36Sopenharmony_ci			rc = raw->wait_comp(bp, raw);
199062306a36Sopenharmony_ci			if (rc)
199162306a36Sopenharmony_ci				return rc;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci			/* Make a next step */
199462306a36Sopenharmony_ci			rc = __bnx2x_vlan_mac_execute_step(bp,
199562306a36Sopenharmony_ci							   p->vlan_mac_obj,
199662306a36Sopenharmony_ci							   &p->ramrod_flags);
199762306a36Sopenharmony_ci			if (rc < 0)
199862306a36Sopenharmony_ci				return rc;
199962306a36Sopenharmony_ci		}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci		return 0;
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	return rc;
200562306a36Sopenharmony_ci}
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci/**
200862306a36Sopenharmony_ci * bnx2x_vlan_mac_del_all - delete elements with given vlan_mac_flags spec
200962306a36Sopenharmony_ci *
201062306a36Sopenharmony_ci * @bp:			device handle
201162306a36Sopenharmony_ci * @o:			vlan object info
201262306a36Sopenharmony_ci * @vlan_mac_flags:	vlan flags
201362306a36Sopenharmony_ci * @ramrod_flags:	execution flags to be used for this deletion
201462306a36Sopenharmony_ci *
201562306a36Sopenharmony_ci * if the last operation has completed successfully and there are no
201662306a36Sopenharmony_ci * more elements left, positive value if the last operation has completed
201762306a36Sopenharmony_ci * successfully and there are more previously configured elements, negative
201862306a36Sopenharmony_ci * value is current operation has failed.
201962306a36Sopenharmony_ci */
202062306a36Sopenharmony_cistatic int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
202162306a36Sopenharmony_ci				  struct bnx2x_vlan_mac_obj *o,
202262306a36Sopenharmony_ci				  unsigned long *vlan_mac_flags,
202362306a36Sopenharmony_ci				  unsigned long *ramrod_flags)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct bnx2x_vlan_mac_registry_elem *pos = NULL;
202662306a36Sopenharmony_ci	struct bnx2x_vlan_mac_ramrod_params p;
202762306a36Sopenharmony_ci	struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
202862306a36Sopenharmony_ci	struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n;
202962306a36Sopenharmony_ci	unsigned long flags;
203062306a36Sopenharmony_ci	int read_lock;
203162306a36Sopenharmony_ci	int rc = 0;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	/* Clear pending commands first */
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	spin_lock_bh(&exeq->lock);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	list_for_each_entry_safe(exeq_pos, exeq_pos_n, &exeq->exe_queue, link) {
203862306a36Sopenharmony_ci		flags = exeq_pos->cmd_data.vlan_mac.vlan_mac_flags;
203962306a36Sopenharmony_ci		if (BNX2X_VLAN_MAC_CMP_FLAGS(flags) ==
204062306a36Sopenharmony_ci		    BNX2X_VLAN_MAC_CMP_FLAGS(*vlan_mac_flags)) {
204162306a36Sopenharmony_ci			rc = exeq->remove(bp, exeq->owner, exeq_pos);
204262306a36Sopenharmony_ci			if (rc) {
204362306a36Sopenharmony_ci				BNX2X_ERR("Failed to remove command\n");
204462306a36Sopenharmony_ci				spin_unlock_bh(&exeq->lock);
204562306a36Sopenharmony_ci				return rc;
204662306a36Sopenharmony_ci			}
204762306a36Sopenharmony_ci			list_del(&exeq_pos->link);
204862306a36Sopenharmony_ci			bnx2x_exe_queue_free_elem(bp, exeq_pos);
204962306a36Sopenharmony_ci		}
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	spin_unlock_bh(&exeq->lock);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	/* Prepare a command request */
205562306a36Sopenharmony_ci	memset(&p, 0, sizeof(p));
205662306a36Sopenharmony_ci	p.vlan_mac_obj = o;
205762306a36Sopenharmony_ci	p.ramrod_flags = *ramrod_flags;
205862306a36Sopenharmony_ci	p.user_req.cmd = BNX2X_VLAN_MAC_DEL;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	/* Add all but the last VLAN-MAC to the execution queue without actually
206162306a36Sopenharmony_ci	 * execution anything.
206262306a36Sopenharmony_ci	 */
206362306a36Sopenharmony_ci	__clear_bit(RAMROD_COMP_WAIT, &p.ramrod_flags);
206462306a36Sopenharmony_ci	__clear_bit(RAMROD_EXEC, &p.ramrod_flags);
206562306a36Sopenharmony_ci	__clear_bit(RAMROD_CONT, &p.ramrod_flags);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "vlan_mac_del_all -- taking vlan_mac_lock (reader)\n");
206862306a36Sopenharmony_ci	read_lock = bnx2x_vlan_mac_h_read_lock(bp, o);
206962306a36Sopenharmony_ci	if (read_lock != 0)
207062306a36Sopenharmony_ci		return read_lock;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	list_for_each_entry(pos, &o->head, link) {
207362306a36Sopenharmony_ci		flags = pos->vlan_mac_flags;
207462306a36Sopenharmony_ci		if (BNX2X_VLAN_MAC_CMP_FLAGS(flags) ==
207562306a36Sopenharmony_ci		    BNX2X_VLAN_MAC_CMP_FLAGS(*vlan_mac_flags)) {
207662306a36Sopenharmony_ci			p.user_req.vlan_mac_flags = pos->vlan_mac_flags;
207762306a36Sopenharmony_ci			memcpy(&p.user_req.u, &pos->u, sizeof(pos->u));
207862306a36Sopenharmony_ci			rc = bnx2x_config_vlan_mac(bp, &p);
207962306a36Sopenharmony_ci			if (rc < 0) {
208062306a36Sopenharmony_ci				BNX2X_ERR("Failed to add a new DEL command\n");
208162306a36Sopenharmony_ci				bnx2x_vlan_mac_h_read_unlock(bp, o);
208262306a36Sopenharmony_ci				return rc;
208362306a36Sopenharmony_ci			}
208462306a36Sopenharmony_ci		}
208562306a36Sopenharmony_ci	}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "vlan_mac_del_all -- releasing vlan_mac_lock (reader)\n");
208862306a36Sopenharmony_ci	bnx2x_vlan_mac_h_read_unlock(bp, o);
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	p.ramrod_flags = *ramrod_flags;
209162306a36Sopenharmony_ci	__set_bit(RAMROD_CONT, &p.ramrod_flags);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	return bnx2x_config_vlan_mac(bp, &p);
209462306a36Sopenharmony_ci}
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_cistatic inline void bnx2x_init_raw_obj(struct bnx2x_raw_obj *raw, u8 cl_id,
209762306a36Sopenharmony_ci	u32 cid, u8 func_id, void *rdata, dma_addr_t rdata_mapping, int state,
209862306a36Sopenharmony_ci	unsigned long *pstate, bnx2x_obj_type type)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	raw->func_id = func_id;
210162306a36Sopenharmony_ci	raw->cid = cid;
210262306a36Sopenharmony_ci	raw->cl_id = cl_id;
210362306a36Sopenharmony_ci	raw->rdata = rdata;
210462306a36Sopenharmony_ci	raw->rdata_mapping = rdata_mapping;
210562306a36Sopenharmony_ci	raw->state = state;
210662306a36Sopenharmony_ci	raw->pstate = pstate;
210762306a36Sopenharmony_ci	raw->obj_type = type;
210862306a36Sopenharmony_ci	raw->check_pending = bnx2x_raw_check_pending;
210962306a36Sopenharmony_ci	raw->clear_pending = bnx2x_raw_clear_pending;
211062306a36Sopenharmony_ci	raw->set_pending = bnx2x_raw_set_pending;
211162306a36Sopenharmony_ci	raw->wait_comp = bnx2x_raw_wait;
211262306a36Sopenharmony_ci}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_cistatic inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o,
211562306a36Sopenharmony_ci	u8 cl_id, u32 cid, u8 func_id, void *rdata, dma_addr_t rdata_mapping,
211662306a36Sopenharmony_ci	int state, unsigned long *pstate, bnx2x_obj_type type,
211762306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *macs_pool,
211862306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *vlans_pool)
211962306a36Sopenharmony_ci{
212062306a36Sopenharmony_ci	INIT_LIST_HEAD(&o->head);
212162306a36Sopenharmony_ci	o->head_reader = 0;
212262306a36Sopenharmony_ci	o->head_exe_request = false;
212362306a36Sopenharmony_ci	o->saved_ramrod_flags = 0;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	o->macs_pool = macs_pool;
212662306a36Sopenharmony_ci	o->vlans_pool = vlans_pool;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	o->delete_all = bnx2x_vlan_mac_del_all;
212962306a36Sopenharmony_ci	o->restore = bnx2x_vlan_mac_restore;
213062306a36Sopenharmony_ci	o->complete = bnx2x_complete_vlan_mac;
213162306a36Sopenharmony_ci	o->wait = bnx2x_wait_vlan_mac;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	bnx2x_init_raw_obj(&o->raw, cl_id, cid, func_id, rdata, rdata_mapping,
213462306a36Sopenharmony_ci			   state, pstate, type);
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_civoid bnx2x_init_mac_obj(struct bnx2x *bp,
213862306a36Sopenharmony_ci			struct bnx2x_vlan_mac_obj *mac_obj,
213962306a36Sopenharmony_ci			u8 cl_id, u32 cid, u8 func_id, void *rdata,
214062306a36Sopenharmony_ci			dma_addr_t rdata_mapping, int state,
214162306a36Sopenharmony_ci			unsigned long *pstate, bnx2x_obj_type type,
214262306a36Sopenharmony_ci			struct bnx2x_credit_pool_obj *macs_pool)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	union bnx2x_qable_obj *qable_obj = (union bnx2x_qable_obj *)mac_obj;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	bnx2x_init_vlan_mac_common(mac_obj, cl_id, cid, func_id, rdata,
214762306a36Sopenharmony_ci				   rdata_mapping, state, pstate, type,
214862306a36Sopenharmony_ci				   macs_pool, NULL);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	/* CAM credit pool handling */
215162306a36Sopenharmony_ci	mac_obj->get_credit = bnx2x_get_credit_mac;
215262306a36Sopenharmony_ci	mac_obj->put_credit = bnx2x_put_credit_mac;
215362306a36Sopenharmony_ci	mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac;
215462306a36Sopenharmony_ci	mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	if (CHIP_IS_E1x(bp)) {
215762306a36Sopenharmony_ci		mac_obj->set_one_rule      = bnx2x_set_one_mac_e1x;
215862306a36Sopenharmony_ci		mac_obj->check_del         = bnx2x_check_mac_del;
215962306a36Sopenharmony_ci		mac_obj->check_add         = bnx2x_check_mac_add;
216062306a36Sopenharmony_ci		mac_obj->check_move        = bnx2x_check_move_always_err;
216162306a36Sopenharmony_ci		mac_obj->ramrod_cmd        = RAMROD_CMD_ID_ETH_SET_MAC;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci		/* Exe Queue */
216462306a36Sopenharmony_ci		bnx2x_exe_queue_init(bp,
216562306a36Sopenharmony_ci				     &mac_obj->exe_queue, 1, qable_obj,
216662306a36Sopenharmony_ci				     bnx2x_validate_vlan_mac,
216762306a36Sopenharmony_ci				     bnx2x_remove_vlan_mac,
216862306a36Sopenharmony_ci				     bnx2x_optimize_vlan_mac,
216962306a36Sopenharmony_ci				     bnx2x_execute_vlan_mac,
217062306a36Sopenharmony_ci				     bnx2x_exeq_get_mac);
217162306a36Sopenharmony_ci	} else {
217262306a36Sopenharmony_ci		mac_obj->set_one_rule      = bnx2x_set_one_mac_e2;
217362306a36Sopenharmony_ci		mac_obj->check_del         = bnx2x_check_mac_del;
217462306a36Sopenharmony_ci		mac_obj->check_add         = bnx2x_check_mac_add;
217562306a36Sopenharmony_ci		mac_obj->check_move        = bnx2x_check_move;
217662306a36Sopenharmony_ci		mac_obj->ramrod_cmd        =
217762306a36Sopenharmony_ci			RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES;
217862306a36Sopenharmony_ci		mac_obj->get_n_elements    = bnx2x_get_n_elements;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci		/* Exe Queue */
218162306a36Sopenharmony_ci		bnx2x_exe_queue_init(bp,
218262306a36Sopenharmony_ci				     &mac_obj->exe_queue, CLASSIFY_RULES_COUNT,
218362306a36Sopenharmony_ci				     qable_obj, bnx2x_validate_vlan_mac,
218462306a36Sopenharmony_ci				     bnx2x_remove_vlan_mac,
218562306a36Sopenharmony_ci				     bnx2x_optimize_vlan_mac,
218662306a36Sopenharmony_ci				     bnx2x_execute_vlan_mac,
218762306a36Sopenharmony_ci				     bnx2x_exeq_get_mac);
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_civoid bnx2x_init_vlan_obj(struct bnx2x *bp,
219262306a36Sopenharmony_ci			 struct bnx2x_vlan_mac_obj *vlan_obj,
219362306a36Sopenharmony_ci			 u8 cl_id, u32 cid, u8 func_id, void *rdata,
219462306a36Sopenharmony_ci			 dma_addr_t rdata_mapping, int state,
219562306a36Sopenharmony_ci			 unsigned long *pstate, bnx2x_obj_type type,
219662306a36Sopenharmony_ci			 struct bnx2x_credit_pool_obj *vlans_pool)
219762306a36Sopenharmony_ci{
219862306a36Sopenharmony_ci	union bnx2x_qable_obj *qable_obj = (union bnx2x_qable_obj *)vlan_obj;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	bnx2x_init_vlan_mac_common(vlan_obj, cl_id, cid, func_id, rdata,
220162306a36Sopenharmony_ci				   rdata_mapping, state, pstate, type, NULL,
220262306a36Sopenharmony_ci				   vlans_pool);
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	vlan_obj->get_credit = bnx2x_get_credit_vlan;
220562306a36Sopenharmony_ci	vlan_obj->put_credit = bnx2x_put_credit_vlan;
220662306a36Sopenharmony_ci	vlan_obj->get_cam_offset = bnx2x_get_cam_offset_vlan;
220762306a36Sopenharmony_ci	vlan_obj->put_cam_offset = bnx2x_put_cam_offset_vlan;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	if (CHIP_IS_E1x(bp)) {
221062306a36Sopenharmony_ci		BNX2X_ERR("Do not support chips others than E2 and newer\n");
221162306a36Sopenharmony_ci		BUG();
221262306a36Sopenharmony_ci	} else {
221362306a36Sopenharmony_ci		vlan_obj->set_one_rule      = bnx2x_set_one_vlan_e2;
221462306a36Sopenharmony_ci		vlan_obj->check_del         = bnx2x_check_vlan_del;
221562306a36Sopenharmony_ci		vlan_obj->check_add         = bnx2x_check_vlan_add;
221662306a36Sopenharmony_ci		vlan_obj->check_move        = bnx2x_check_move;
221762306a36Sopenharmony_ci		vlan_obj->ramrod_cmd        =
221862306a36Sopenharmony_ci			RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES;
221962306a36Sopenharmony_ci		vlan_obj->get_n_elements    = bnx2x_get_n_elements;
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci		/* Exe Queue */
222262306a36Sopenharmony_ci		bnx2x_exe_queue_init(bp,
222362306a36Sopenharmony_ci				     &vlan_obj->exe_queue, CLASSIFY_RULES_COUNT,
222462306a36Sopenharmony_ci				     qable_obj, bnx2x_validate_vlan_mac,
222562306a36Sopenharmony_ci				     bnx2x_remove_vlan_mac,
222662306a36Sopenharmony_ci				     bnx2x_optimize_vlan_mac,
222762306a36Sopenharmony_ci				     bnx2x_execute_vlan_mac,
222862306a36Sopenharmony_ci				     bnx2x_exeq_get_vlan);
222962306a36Sopenharmony_ci	}
223062306a36Sopenharmony_ci}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_civoid bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
223362306a36Sopenharmony_ci			     struct bnx2x_vlan_mac_obj *vlan_mac_obj,
223462306a36Sopenharmony_ci			     u8 cl_id, u32 cid, u8 func_id, void *rdata,
223562306a36Sopenharmony_ci			     dma_addr_t rdata_mapping, int state,
223662306a36Sopenharmony_ci			     unsigned long *pstate, bnx2x_obj_type type,
223762306a36Sopenharmony_ci			     struct bnx2x_credit_pool_obj *macs_pool,
223862306a36Sopenharmony_ci			     struct bnx2x_credit_pool_obj *vlans_pool)
223962306a36Sopenharmony_ci{
224062306a36Sopenharmony_ci	union bnx2x_qable_obj *qable_obj =
224162306a36Sopenharmony_ci		(union bnx2x_qable_obj *)vlan_mac_obj;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata,
224462306a36Sopenharmony_ci				   rdata_mapping, state, pstate, type,
224562306a36Sopenharmony_ci				   macs_pool, vlans_pool);
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	/* CAM pool handling */
224862306a36Sopenharmony_ci	vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac;
224962306a36Sopenharmony_ci	vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac;
225062306a36Sopenharmony_ci	/* CAM offset is relevant for 57710 and 57711 chips only which have a
225162306a36Sopenharmony_ci	 * single CAM for both MACs and VLAN-MAC pairs. So the offset
225262306a36Sopenharmony_ci	 * will be taken from MACs' pool object only.
225362306a36Sopenharmony_ci	 */
225462306a36Sopenharmony_ci	vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac;
225562306a36Sopenharmony_ci	vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	if (CHIP_IS_E1(bp)) {
225862306a36Sopenharmony_ci		BNX2X_ERR("Do not support chips others than E2\n");
225962306a36Sopenharmony_ci		BUG();
226062306a36Sopenharmony_ci	} else if (CHIP_IS_E1H(bp)) {
226162306a36Sopenharmony_ci		vlan_mac_obj->set_one_rule      = bnx2x_set_one_vlan_mac_e1h;
226262306a36Sopenharmony_ci		vlan_mac_obj->check_del         = bnx2x_check_vlan_mac_del;
226362306a36Sopenharmony_ci		vlan_mac_obj->check_add         = bnx2x_check_vlan_mac_add;
226462306a36Sopenharmony_ci		vlan_mac_obj->check_move        = bnx2x_check_move_always_err;
226562306a36Sopenharmony_ci		vlan_mac_obj->ramrod_cmd        = RAMROD_CMD_ID_ETH_SET_MAC;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci		/* Exe Queue */
226862306a36Sopenharmony_ci		bnx2x_exe_queue_init(bp,
226962306a36Sopenharmony_ci				     &vlan_mac_obj->exe_queue, 1, qable_obj,
227062306a36Sopenharmony_ci				     bnx2x_validate_vlan_mac,
227162306a36Sopenharmony_ci				     bnx2x_remove_vlan_mac,
227262306a36Sopenharmony_ci				     bnx2x_optimize_vlan_mac,
227362306a36Sopenharmony_ci				     bnx2x_execute_vlan_mac,
227462306a36Sopenharmony_ci				     bnx2x_exeq_get_vlan_mac);
227562306a36Sopenharmony_ci	} else {
227662306a36Sopenharmony_ci		vlan_mac_obj->set_one_rule      = bnx2x_set_one_vlan_mac_e2;
227762306a36Sopenharmony_ci		vlan_mac_obj->check_del         = bnx2x_check_vlan_mac_del;
227862306a36Sopenharmony_ci		vlan_mac_obj->check_add         = bnx2x_check_vlan_mac_add;
227962306a36Sopenharmony_ci		vlan_mac_obj->check_move        = bnx2x_check_move;
228062306a36Sopenharmony_ci		vlan_mac_obj->ramrod_cmd        =
228162306a36Sopenharmony_ci			RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci		/* Exe Queue */
228462306a36Sopenharmony_ci		bnx2x_exe_queue_init(bp,
228562306a36Sopenharmony_ci				     &vlan_mac_obj->exe_queue,
228662306a36Sopenharmony_ci				     CLASSIFY_RULES_COUNT,
228762306a36Sopenharmony_ci				     qable_obj, bnx2x_validate_vlan_mac,
228862306a36Sopenharmony_ci				     bnx2x_remove_vlan_mac,
228962306a36Sopenharmony_ci				     bnx2x_optimize_vlan_mac,
229062306a36Sopenharmony_ci				     bnx2x_execute_vlan_mac,
229162306a36Sopenharmony_ci				     bnx2x_exeq_get_vlan_mac);
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci}
229462306a36Sopenharmony_ci/* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */
229562306a36Sopenharmony_cistatic inline void __storm_memset_mac_filters(struct bnx2x *bp,
229662306a36Sopenharmony_ci			struct tstorm_eth_mac_filter_config *mac_filters,
229762306a36Sopenharmony_ci			u16 pf_id)
229862306a36Sopenharmony_ci{
229962306a36Sopenharmony_ci	size_t size = sizeof(struct tstorm_eth_mac_filter_config);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	u32 addr = BAR_TSTRORM_INTMEM +
230262306a36Sopenharmony_ci			TSTORM_MAC_FILTER_CONFIG_OFFSET(pf_id);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	__storm_memset_struct(bp, addr, size, (u32 *)mac_filters);
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_cistatic int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
230862306a36Sopenharmony_ci				 struct bnx2x_rx_mode_ramrod_params *p)
230962306a36Sopenharmony_ci{
231062306a36Sopenharmony_ci	/* update the bp MAC filter structure */
231162306a36Sopenharmony_ci	u32 mask = (1 << p->cl_id);
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	struct tstorm_eth_mac_filter_config *mac_filters =
231462306a36Sopenharmony_ci		(struct tstorm_eth_mac_filter_config *)p->rdata;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/* initial setting is drop-all */
231762306a36Sopenharmony_ci	u8 drop_all_ucast = 1, drop_all_mcast = 1;
231862306a36Sopenharmony_ci	u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0;
231962306a36Sopenharmony_ci	u8 unmatched_unicast = 0;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci    /* In e1x there we only take into account rx accept flag since tx switching
232262306a36Sopenharmony_ci     * isn't enabled. */
232362306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_UNICAST, &p->rx_accept_flags))
232462306a36Sopenharmony_ci		/* accept matched ucast */
232562306a36Sopenharmony_ci		drop_all_ucast = 0;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_MULTICAST, &p->rx_accept_flags))
232862306a36Sopenharmony_ci		/* accept matched mcast */
232962306a36Sopenharmony_ci		drop_all_mcast = 0;
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &p->rx_accept_flags)) {
233262306a36Sopenharmony_ci		/* accept all mcast */
233362306a36Sopenharmony_ci		drop_all_ucast = 0;
233462306a36Sopenharmony_ci		accp_all_ucast = 1;
233562306a36Sopenharmony_ci	}
233662306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &p->rx_accept_flags)) {
233762306a36Sopenharmony_ci		/* accept all mcast */
233862306a36Sopenharmony_ci		drop_all_mcast = 0;
233962306a36Sopenharmony_ci		accp_all_mcast = 1;
234062306a36Sopenharmony_ci	}
234162306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_BROADCAST, &p->rx_accept_flags))
234262306a36Sopenharmony_ci		/* accept (all) bcast */
234362306a36Sopenharmony_ci		accp_all_bcast = 1;
234462306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_UNMATCHED, &p->rx_accept_flags))
234562306a36Sopenharmony_ci		/* accept unmatched unicasts */
234662306a36Sopenharmony_ci		unmatched_unicast = 1;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	mac_filters->ucast_drop_all = drop_all_ucast ?
234962306a36Sopenharmony_ci		mac_filters->ucast_drop_all | mask :
235062306a36Sopenharmony_ci		mac_filters->ucast_drop_all & ~mask;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	mac_filters->mcast_drop_all = drop_all_mcast ?
235362306a36Sopenharmony_ci		mac_filters->mcast_drop_all | mask :
235462306a36Sopenharmony_ci		mac_filters->mcast_drop_all & ~mask;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	mac_filters->ucast_accept_all = accp_all_ucast ?
235762306a36Sopenharmony_ci		mac_filters->ucast_accept_all | mask :
235862306a36Sopenharmony_ci		mac_filters->ucast_accept_all & ~mask;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	mac_filters->mcast_accept_all = accp_all_mcast ?
236162306a36Sopenharmony_ci		mac_filters->mcast_accept_all | mask :
236262306a36Sopenharmony_ci		mac_filters->mcast_accept_all & ~mask;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	mac_filters->bcast_accept_all = accp_all_bcast ?
236562306a36Sopenharmony_ci		mac_filters->bcast_accept_all | mask :
236662306a36Sopenharmony_ci		mac_filters->bcast_accept_all & ~mask;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	mac_filters->unmatched_unicast = unmatched_unicast ?
236962306a36Sopenharmony_ci		mac_filters->unmatched_unicast | mask :
237062306a36Sopenharmony_ci		mac_filters->unmatched_unicast & ~mask;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "drop_ucast 0x%x\ndrop_mcast 0x%x\n accp_ucast 0x%x\n"
237362306a36Sopenharmony_ci			 "accp_mcast 0x%x\naccp_bcast 0x%x\n",
237462306a36Sopenharmony_ci	   mac_filters->ucast_drop_all, mac_filters->mcast_drop_all,
237562306a36Sopenharmony_ci	   mac_filters->ucast_accept_all, mac_filters->mcast_accept_all,
237662306a36Sopenharmony_ci	   mac_filters->bcast_accept_all);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	/* write the MAC filter structure*/
237962306a36Sopenharmony_ci	__storm_memset_mac_filters(bp, mac_filters, p->func_id);
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	/* The operation is completed */
238262306a36Sopenharmony_ci	clear_bit(p->state, p->pstate);
238362306a36Sopenharmony_ci	smp_mb__after_atomic();
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	return 0;
238662306a36Sopenharmony_ci}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci/* Setup ramrod data */
238962306a36Sopenharmony_cistatic inline void bnx2x_rx_mode_set_rdata_hdr_e2(u32 cid,
239062306a36Sopenharmony_ci				struct eth_classify_header *hdr,
239162306a36Sopenharmony_ci				u8 rule_cnt)
239262306a36Sopenharmony_ci{
239362306a36Sopenharmony_ci	hdr->echo = cpu_to_le32(cid);
239462306a36Sopenharmony_ci	hdr->rule_cnt = rule_cnt;
239562306a36Sopenharmony_ci}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_cistatic inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
239862306a36Sopenharmony_ci				unsigned long *accept_flags,
239962306a36Sopenharmony_ci				struct eth_filter_rules_cmd *cmd,
240062306a36Sopenharmony_ci				bool clear_accept_all)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	u16 state;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/* start with 'drop-all' */
240562306a36Sopenharmony_ci	state = ETH_FILTER_RULES_CMD_UCAST_DROP_ALL |
240662306a36Sopenharmony_ci		ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_UNICAST, accept_flags))
240962306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_MULTICAST, accept_flags))
241262306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, accept_flags)) {
241562306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
241662306a36Sopenharmony_ci		state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
241762306a36Sopenharmony_ci	}
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, accept_flags)) {
242062306a36Sopenharmony_ci		state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
242162306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
242262306a36Sopenharmony_ci	}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_BROADCAST, accept_flags))
242562306a36Sopenharmony_ci		state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_UNMATCHED, accept_flags)) {
242862306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
242962306a36Sopenharmony_ci		state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
243062306a36Sopenharmony_ci	}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	if (test_bit(BNX2X_ACCEPT_ANY_VLAN, accept_flags))
243362306a36Sopenharmony_ci		state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	/* Clear ACCEPT_ALL_XXX flags for FCoE L2 Queue */
243662306a36Sopenharmony_ci	if (clear_accept_all) {
243762306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
243862306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
243962306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
244062306a36Sopenharmony_ci		state &= ~ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
244162306a36Sopenharmony_ci	}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	cmd->state = cpu_to_le16(state);
244462306a36Sopenharmony_ci}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_cistatic int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
244762306a36Sopenharmony_ci				struct bnx2x_rx_mode_ramrod_params *p)
244862306a36Sopenharmony_ci{
244962306a36Sopenharmony_ci	struct eth_filter_rules_ramrod_data *data = p->rdata;
245062306a36Sopenharmony_ci	int rc;
245162306a36Sopenharmony_ci	u8 rule_idx = 0;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	/* Reset the ramrod data buffer */
245462306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	/* Setup ramrod data */
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	/* Tx (internal switching) */
245962306a36Sopenharmony_ci	if (test_bit(RAMROD_TX, &p->ramrod_flags)) {
246062306a36Sopenharmony_ci		data->rules[rule_idx].client_id = p->cl_id;
246162306a36Sopenharmony_ci		data->rules[rule_idx].func_id = p->func_id;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci		data->rules[rule_idx].cmd_general_data =
246462306a36Sopenharmony_ci			ETH_FILTER_RULES_CMD_TX_CMD;
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci		bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
246762306a36Sopenharmony_ci					       &(data->rules[rule_idx++]),
246862306a36Sopenharmony_ci					       false);
246962306a36Sopenharmony_ci	}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	/* Rx */
247262306a36Sopenharmony_ci	if (test_bit(RAMROD_RX, &p->ramrod_flags)) {
247362306a36Sopenharmony_ci		data->rules[rule_idx].client_id = p->cl_id;
247462306a36Sopenharmony_ci		data->rules[rule_idx].func_id = p->func_id;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci		data->rules[rule_idx].cmd_general_data =
247762306a36Sopenharmony_ci			ETH_FILTER_RULES_CMD_RX_CMD;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci		bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
248062306a36Sopenharmony_ci					       &(data->rules[rule_idx++]),
248162306a36Sopenharmony_ci					       false);
248262306a36Sopenharmony_ci	}
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	/* If FCoE Queue configuration has been requested configure the Rx and
248562306a36Sopenharmony_ci	 * internal switching modes for this queue in separate rules.
248662306a36Sopenharmony_ci	 *
248762306a36Sopenharmony_ci	 * FCoE queue shell never be set to ACCEPT_ALL packets of any sort:
248862306a36Sopenharmony_ci	 * MCAST_ALL, UCAST_ALL, BCAST_ALL and UNMATCHED.
248962306a36Sopenharmony_ci	 */
249062306a36Sopenharmony_ci	if (test_bit(BNX2X_RX_MODE_FCOE_ETH, &p->rx_mode_flags)) {
249162306a36Sopenharmony_ci		/*  Tx (internal switching) */
249262306a36Sopenharmony_ci		if (test_bit(RAMROD_TX, &p->ramrod_flags)) {
249362306a36Sopenharmony_ci			data->rules[rule_idx].client_id = bnx2x_fcoe(bp, cl_id);
249462306a36Sopenharmony_ci			data->rules[rule_idx].func_id = p->func_id;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci			data->rules[rule_idx].cmd_general_data =
249762306a36Sopenharmony_ci						ETH_FILTER_RULES_CMD_TX_CMD;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci			bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
250062306a36Sopenharmony_ci						       &(data->rules[rule_idx]),
250162306a36Sopenharmony_ci						       true);
250262306a36Sopenharmony_ci			rule_idx++;
250362306a36Sopenharmony_ci		}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci		/* Rx */
250662306a36Sopenharmony_ci		if (test_bit(RAMROD_RX, &p->ramrod_flags)) {
250762306a36Sopenharmony_ci			data->rules[rule_idx].client_id = bnx2x_fcoe(bp, cl_id);
250862306a36Sopenharmony_ci			data->rules[rule_idx].func_id = p->func_id;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci			data->rules[rule_idx].cmd_general_data =
251162306a36Sopenharmony_ci						ETH_FILTER_RULES_CMD_RX_CMD;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci			bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
251462306a36Sopenharmony_ci						       &(data->rules[rule_idx]),
251562306a36Sopenharmony_ci						       true);
251662306a36Sopenharmony_ci			rule_idx++;
251762306a36Sopenharmony_ci		}
251862306a36Sopenharmony_ci	}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	/* Set the ramrod header (most importantly - number of rules to
252162306a36Sopenharmony_ci	 * configure).
252262306a36Sopenharmony_ci	 */
252362306a36Sopenharmony_ci	bnx2x_rx_mode_set_rdata_hdr_e2(p->cid, &data->header, rule_idx);
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "About to configure %d rules, rx_accept_flags 0x%lx, tx_accept_flags 0x%lx\n",
252662306a36Sopenharmony_ci			 data->header.rule_cnt, p->rx_accept_flags,
252762306a36Sopenharmony_ci			 p->tx_accept_flags);
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
253062306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
253162306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
253262306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
253362306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
253462306a36Sopenharmony_ci	 */
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	/* Send a ramrod */
253762306a36Sopenharmony_ci	rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_FILTER_RULES, p->cid,
253862306a36Sopenharmony_ci			   U64_HI(p->rdata_mapping),
253962306a36Sopenharmony_ci			   U64_LO(p->rdata_mapping),
254062306a36Sopenharmony_ci			   ETH_CONNECTION_TYPE);
254162306a36Sopenharmony_ci	if (rc)
254262306a36Sopenharmony_ci		return rc;
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	/* Ramrod completion is pending */
254562306a36Sopenharmony_ci	return 1;
254662306a36Sopenharmony_ci}
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_cistatic int bnx2x_wait_rx_mode_comp_e2(struct bnx2x *bp,
254962306a36Sopenharmony_ci				      struct bnx2x_rx_mode_ramrod_params *p)
255062306a36Sopenharmony_ci{
255162306a36Sopenharmony_ci	return bnx2x_state_wait(bp, p->state, p->pstate);
255262306a36Sopenharmony_ci}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_cistatic int bnx2x_empty_rx_mode_wait(struct bnx2x *bp,
255562306a36Sopenharmony_ci				    struct bnx2x_rx_mode_ramrod_params *p)
255662306a36Sopenharmony_ci{
255762306a36Sopenharmony_ci	/* Do nothing */
255862306a36Sopenharmony_ci	return 0;
255962306a36Sopenharmony_ci}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ciint bnx2x_config_rx_mode(struct bnx2x *bp,
256262306a36Sopenharmony_ci			 struct bnx2x_rx_mode_ramrod_params *p)
256362306a36Sopenharmony_ci{
256462306a36Sopenharmony_ci	int rc;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	/* Configure the new classification in the chip */
256762306a36Sopenharmony_ci	rc = p->rx_mode_obj->config_rx_mode(bp, p);
256862306a36Sopenharmony_ci	if (rc < 0)
256962306a36Sopenharmony_ci		return rc;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	/* Wait for a ramrod completion if was requested */
257262306a36Sopenharmony_ci	if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) {
257362306a36Sopenharmony_ci		rc = p->rx_mode_obj->wait_comp(bp, p);
257462306a36Sopenharmony_ci		if (rc)
257562306a36Sopenharmony_ci			return rc;
257662306a36Sopenharmony_ci	}
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	return rc;
257962306a36Sopenharmony_ci}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_civoid bnx2x_init_rx_mode_obj(struct bnx2x *bp,
258262306a36Sopenharmony_ci			    struct bnx2x_rx_mode_obj *o)
258362306a36Sopenharmony_ci{
258462306a36Sopenharmony_ci	if (CHIP_IS_E1x(bp)) {
258562306a36Sopenharmony_ci		o->wait_comp      = bnx2x_empty_rx_mode_wait;
258662306a36Sopenharmony_ci		o->config_rx_mode = bnx2x_set_rx_mode_e1x;
258762306a36Sopenharmony_ci	} else {
258862306a36Sopenharmony_ci		o->wait_comp      = bnx2x_wait_rx_mode_comp_e2;
258962306a36Sopenharmony_ci		o->config_rx_mode = bnx2x_set_rx_mode_e2;
259062306a36Sopenharmony_ci	}
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci/********************* Multicast verbs: SET, CLEAR ****************************/
259462306a36Sopenharmony_cistatic inline u8 bnx2x_mcast_bin_from_mac(u8 *mac)
259562306a36Sopenharmony_ci{
259662306a36Sopenharmony_ci	return (crc32c_le(0, mac, ETH_ALEN) >> 24) & 0xff;
259762306a36Sopenharmony_ci}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_cistruct bnx2x_mcast_mac_elem {
260062306a36Sopenharmony_ci	struct list_head link;
260162306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
260262306a36Sopenharmony_ci	u8 pad[2]; /* For a natural alignment of the following buffer */
260362306a36Sopenharmony_ci};
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_cistruct bnx2x_mcast_bin_elem {
260662306a36Sopenharmony_ci	struct list_head link;
260762306a36Sopenharmony_ci	int bin;
260862306a36Sopenharmony_ci	int type; /* BNX2X_MCAST_CMD_SET_{ADD, DEL} */
260962306a36Sopenharmony_ci};
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ciunion bnx2x_mcast_elem {
261262306a36Sopenharmony_ci	struct bnx2x_mcast_bin_elem bin_elem;
261362306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem mac_elem;
261462306a36Sopenharmony_ci};
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_cistruct bnx2x_mcast_elem_group {
261762306a36Sopenharmony_ci	struct list_head mcast_group_link;
261862306a36Sopenharmony_ci	union bnx2x_mcast_elem mcast_elems[];
261962306a36Sopenharmony_ci};
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci#define MCAST_MAC_ELEMS_PER_PG \
262262306a36Sopenharmony_ci	((PAGE_SIZE - sizeof(struct bnx2x_mcast_elem_group)) / \
262362306a36Sopenharmony_ci	sizeof(union bnx2x_mcast_elem))
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_cistruct bnx2x_pending_mcast_cmd {
262662306a36Sopenharmony_ci	struct list_head link;
262762306a36Sopenharmony_ci	struct list_head group_head;
262862306a36Sopenharmony_ci	int type; /* BNX2X_MCAST_CMD_X */
262962306a36Sopenharmony_ci	union {
263062306a36Sopenharmony_ci		struct list_head macs_head;
263162306a36Sopenharmony_ci		u32 macs_num; /* Needed for DEL command */
263262306a36Sopenharmony_ci		int next_bin; /* Needed for RESTORE flow with aprox match */
263362306a36Sopenharmony_ci	} data;
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	bool set_convert; /* in case type == BNX2X_MCAST_CMD_SET, this is set
263662306a36Sopenharmony_ci			   * when macs_head had been converted to a list of
263762306a36Sopenharmony_ci			   * bnx2x_mcast_bin_elem.
263862306a36Sopenharmony_ci			   */
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	bool done; /* set to true, when the command has been handled,
264162306a36Sopenharmony_ci		    * practically used in 57712 handling only, where one pending
264262306a36Sopenharmony_ci		    * command may be handled in a few operations. As long as for
264362306a36Sopenharmony_ci		    * other chips every operation handling is completed in a
264462306a36Sopenharmony_ci		    * single ramrod, there is no need to utilize this field.
264562306a36Sopenharmony_ci		    */
264662306a36Sopenharmony_ci};
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_cistatic int bnx2x_mcast_wait(struct bnx2x *bp,
264962306a36Sopenharmony_ci			    struct bnx2x_mcast_obj *o)
265062306a36Sopenharmony_ci{
265162306a36Sopenharmony_ci	if (bnx2x_state_wait(bp, o->sched_state, o->raw.pstate) ||
265262306a36Sopenharmony_ci			o->raw.wait_comp(bp, &o->raw))
265362306a36Sopenharmony_ci		return -EBUSY;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	return 0;
265662306a36Sopenharmony_ci}
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_cistatic void bnx2x_free_groups(struct list_head *mcast_group_list)
265962306a36Sopenharmony_ci{
266062306a36Sopenharmony_ci	struct bnx2x_mcast_elem_group *current_mcast_group;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	while (!list_empty(mcast_group_list)) {
266362306a36Sopenharmony_ci		current_mcast_group = list_first_entry(mcast_group_list,
266462306a36Sopenharmony_ci				      struct bnx2x_mcast_elem_group,
266562306a36Sopenharmony_ci				      mcast_group_link);
266662306a36Sopenharmony_ci		list_del(&current_mcast_group->mcast_group_link);
266762306a36Sopenharmony_ci		free_page((unsigned long)current_mcast_group);
266862306a36Sopenharmony_ci	}
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_cistatic int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
267262306a36Sopenharmony_ci				   struct bnx2x_mcast_obj *o,
267362306a36Sopenharmony_ci				   struct bnx2x_mcast_ramrod_params *p,
267462306a36Sopenharmony_ci				   enum bnx2x_mcast_cmd cmd)
267562306a36Sopenharmony_ci{
267662306a36Sopenharmony_ci	struct bnx2x_pending_mcast_cmd *new_cmd;
267762306a36Sopenharmony_ci	struct bnx2x_mcast_list_elem *pos;
267862306a36Sopenharmony_ci	struct bnx2x_mcast_elem_group *elem_group;
267962306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem *mac_elem;
268062306a36Sopenharmony_ci	int total_elems = 0, macs_list_len = 0, offset = 0;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	/* When adding MACs we'll need to store their values */
268362306a36Sopenharmony_ci	if (cmd == BNX2X_MCAST_CMD_ADD || cmd == BNX2X_MCAST_CMD_SET)
268462306a36Sopenharmony_ci		macs_list_len = p->mcast_list_len;
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	/* If the command is empty ("handle pending commands only"), break */
268762306a36Sopenharmony_ci	if (!p->mcast_list_len)
268862306a36Sopenharmony_ci		return 0;
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	/* Add mcast is called under spin_lock, thus calling with GFP_ATOMIC */
269162306a36Sopenharmony_ci	new_cmd = kzalloc(sizeof(*new_cmd), GFP_ATOMIC);
269262306a36Sopenharmony_ci	if (!new_cmd)
269362306a36Sopenharmony_ci		return -ENOMEM;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	INIT_LIST_HEAD(&new_cmd->data.macs_head);
269662306a36Sopenharmony_ci	INIT_LIST_HEAD(&new_cmd->group_head);
269762306a36Sopenharmony_ci	new_cmd->type = cmd;
269862306a36Sopenharmony_ci	new_cmd->done = false;
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "About to enqueue a new %d command. macs_list_len=%d\n",
270162306a36Sopenharmony_ci	   cmd, macs_list_len);
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	switch (cmd) {
270462306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_ADD:
270562306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_SET:
270662306a36Sopenharmony_ci		/* For a set command, we need to allocate sufficient memory for
270762306a36Sopenharmony_ci		 * all the bins, since we can't analyze at this point how much
270862306a36Sopenharmony_ci		 * memory would be required.
270962306a36Sopenharmony_ci		 */
271062306a36Sopenharmony_ci		total_elems = macs_list_len;
271162306a36Sopenharmony_ci		if (cmd == BNX2X_MCAST_CMD_SET) {
271262306a36Sopenharmony_ci			if (total_elems < BNX2X_MCAST_BINS_NUM)
271362306a36Sopenharmony_ci				total_elems = BNX2X_MCAST_BINS_NUM;
271462306a36Sopenharmony_ci		}
271562306a36Sopenharmony_ci		while (total_elems > 0) {
271662306a36Sopenharmony_ci			elem_group = (struct bnx2x_mcast_elem_group *)
271762306a36Sopenharmony_ci				     __get_free_page(GFP_ATOMIC | __GFP_ZERO);
271862306a36Sopenharmony_ci			if (!elem_group) {
271962306a36Sopenharmony_ci				bnx2x_free_groups(&new_cmd->group_head);
272062306a36Sopenharmony_ci				kfree(new_cmd);
272162306a36Sopenharmony_ci				return -ENOMEM;
272262306a36Sopenharmony_ci			}
272362306a36Sopenharmony_ci			total_elems -= MCAST_MAC_ELEMS_PER_PG;
272462306a36Sopenharmony_ci			list_add_tail(&elem_group->mcast_group_link,
272562306a36Sopenharmony_ci				      &new_cmd->group_head);
272662306a36Sopenharmony_ci		}
272762306a36Sopenharmony_ci		elem_group = list_first_entry(&new_cmd->group_head,
272862306a36Sopenharmony_ci					      struct bnx2x_mcast_elem_group,
272962306a36Sopenharmony_ci					      mcast_group_link);
273062306a36Sopenharmony_ci		list_for_each_entry(pos, &p->mcast_list, link) {
273162306a36Sopenharmony_ci			mac_elem = &elem_group->mcast_elems[offset].mac_elem;
273262306a36Sopenharmony_ci			memcpy(mac_elem->mac, pos->mac, ETH_ALEN);
273362306a36Sopenharmony_ci			/* Push the MACs of the current command into the pending
273462306a36Sopenharmony_ci			 * command MACs list: FIFO
273562306a36Sopenharmony_ci			 */
273662306a36Sopenharmony_ci			list_add_tail(&mac_elem->link,
273762306a36Sopenharmony_ci				      &new_cmd->data.macs_head);
273862306a36Sopenharmony_ci			offset++;
273962306a36Sopenharmony_ci			if (offset == MCAST_MAC_ELEMS_PER_PG) {
274062306a36Sopenharmony_ci				offset = 0;
274162306a36Sopenharmony_ci				elem_group = list_next_entry(elem_group,
274262306a36Sopenharmony_ci							     mcast_group_link);
274362306a36Sopenharmony_ci			}
274462306a36Sopenharmony_ci		}
274562306a36Sopenharmony_ci		break;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_DEL:
274862306a36Sopenharmony_ci		new_cmd->data.macs_num = p->mcast_list_len;
274962306a36Sopenharmony_ci		break;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_RESTORE:
275262306a36Sopenharmony_ci		new_cmd->data.next_bin = 0;
275362306a36Sopenharmony_ci		break;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	default:
275662306a36Sopenharmony_ci		kfree(new_cmd);
275762306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", cmd);
275862306a36Sopenharmony_ci		return -EINVAL;
275962306a36Sopenharmony_ci	}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	/* Push the new pending command to the tail of the pending list: FIFO */
276262306a36Sopenharmony_ci	list_add_tail(&new_cmd->link, &o->pending_cmds_head);
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	o->set_sched(o);
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	return 1;
276762306a36Sopenharmony_ci}
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci/**
277062306a36Sopenharmony_ci * bnx2x_mcast_get_next_bin - get the next set bin (index)
277162306a36Sopenharmony_ci *
277262306a36Sopenharmony_ci * @o:		multicast object info
277362306a36Sopenharmony_ci * @last:	index to start looking from (including)
277462306a36Sopenharmony_ci *
277562306a36Sopenharmony_ci * returns the next found (set) bin or a negative value if none is found.
277662306a36Sopenharmony_ci */
277762306a36Sopenharmony_cistatic inline int bnx2x_mcast_get_next_bin(struct bnx2x_mcast_obj *o, int last)
277862306a36Sopenharmony_ci{
277962306a36Sopenharmony_ci	int i, j, inner_start = last % BIT_VEC64_ELEM_SZ;
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	for (i = last / BIT_VEC64_ELEM_SZ; i < BNX2X_MCAST_VEC_SZ; i++) {
278262306a36Sopenharmony_ci		if (o->registry.aprox_match.vec[i])
278362306a36Sopenharmony_ci			for (j = inner_start; j < BIT_VEC64_ELEM_SZ; j++) {
278462306a36Sopenharmony_ci				int cur_bit = j + BIT_VEC64_ELEM_SZ * i;
278562306a36Sopenharmony_ci				if (BIT_VEC64_TEST_BIT(o->registry.aprox_match.
278662306a36Sopenharmony_ci						       vec, cur_bit)) {
278762306a36Sopenharmony_ci					return cur_bit;
278862306a36Sopenharmony_ci				}
278962306a36Sopenharmony_ci			}
279062306a36Sopenharmony_ci		inner_start = 0;
279162306a36Sopenharmony_ci	}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	/* None found */
279462306a36Sopenharmony_ci	return -1;
279562306a36Sopenharmony_ci}
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci/**
279862306a36Sopenharmony_ci * bnx2x_mcast_clear_first_bin - find the first set bin and clear it
279962306a36Sopenharmony_ci *
280062306a36Sopenharmony_ci * @o:
280162306a36Sopenharmony_ci *
280262306a36Sopenharmony_ci * returns the index of the found bin or -1 if none is found
280362306a36Sopenharmony_ci */
280462306a36Sopenharmony_cistatic inline int bnx2x_mcast_clear_first_bin(struct bnx2x_mcast_obj *o)
280562306a36Sopenharmony_ci{
280662306a36Sopenharmony_ci	int cur_bit = bnx2x_mcast_get_next_bin(o, 0);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	if (cur_bit >= 0)
280962306a36Sopenharmony_ci		BIT_VEC64_CLEAR_BIT(o->registry.aprox_match.vec, cur_bit);
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	return cur_bit;
281262306a36Sopenharmony_ci}
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_cistatic inline u8 bnx2x_mcast_get_rx_tx_flag(struct bnx2x_mcast_obj *o)
281562306a36Sopenharmony_ci{
281662306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
281762306a36Sopenharmony_ci	u8 rx_tx_flag = 0;
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	if ((raw->obj_type == BNX2X_OBJ_TYPE_TX) ||
282062306a36Sopenharmony_ci	    (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX))
282162306a36Sopenharmony_ci		rx_tx_flag |= ETH_MULTICAST_RULES_CMD_TX_CMD;
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	if ((raw->obj_type == BNX2X_OBJ_TYPE_RX) ||
282462306a36Sopenharmony_ci	    (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX))
282562306a36Sopenharmony_ci		rx_tx_flag |= ETH_MULTICAST_RULES_CMD_RX_CMD;
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	return rx_tx_flag;
282862306a36Sopenharmony_ci}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_cistatic void bnx2x_mcast_set_one_rule_e2(struct bnx2x *bp,
283162306a36Sopenharmony_ci					struct bnx2x_mcast_obj *o, int idx,
283262306a36Sopenharmony_ci					union bnx2x_mcast_config_data *cfg_data,
283362306a36Sopenharmony_ci					enum bnx2x_mcast_cmd cmd)
283462306a36Sopenharmony_ci{
283562306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
283662306a36Sopenharmony_ci	struct eth_multicast_rules_ramrod_data *data =
283762306a36Sopenharmony_ci		(struct eth_multicast_rules_ramrod_data *)(r->rdata);
283862306a36Sopenharmony_ci	u8 func_id = r->func_id;
283962306a36Sopenharmony_ci	u8 rx_tx_add_flag = bnx2x_mcast_get_rx_tx_flag(o);
284062306a36Sopenharmony_ci	int bin;
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	if ((cmd == BNX2X_MCAST_CMD_ADD) || (cmd == BNX2X_MCAST_CMD_RESTORE) ||
284362306a36Sopenharmony_ci	    (cmd == BNX2X_MCAST_CMD_SET_ADD))
284462306a36Sopenharmony_ci		rx_tx_add_flag |= ETH_MULTICAST_RULES_CMD_IS_ADD;
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	data->rules[idx].cmd_general_data |= rx_tx_add_flag;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	/* Get a bin and update a bins' vector */
284962306a36Sopenharmony_ci	switch (cmd) {
285062306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_ADD:
285162306a36Sopenharmony_ci		bin = bnx2x_mcast_bin_from_mac(cfg_data->mac);
285262306a36Sopenharmony_ci		BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, bin);
285362306a36Sopenharmony_ci		break;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_DEL:
285662306a36Sopenharmony_ci		/* If there were no more bins to clear
285762306a36Sopenharmony_ci		 * (bnx2x_mcast_clear_first_bin() returns -1) then we would
285862306a36Sopenharmony_ci		 * clear any (0xff) bin.
285962306a36Sopenharmony_ci		 * See bnx2x_mcast_validate_e2() for explanation when it may
286062306a36Sopenharmony_ci		 * happen.
286162306a36Sopenharmony_ci		 */
286262306a36Sopenharmony_ci		bin = bnx2x_mcast_clear_first_bin(o);
286362306a36Sopenharmony_ci		break;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_RESTORE:
286662306a36Sopenharmony_ci		bin = cfg_data->bin;
286762306a36Sopenharmony_ci		break;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_SET_ADD:
287062306a36Sopenharmony_ci		bin = cfg_data->bin;
287162306a36Sopenharmony_ci		BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, bin);
287262306a36Sopenharmony_ci		break;
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_SET_DEL:
287562306a36Sopenharmony_ci		bin = cfg_data->bin;
287662306a36Sopenharmony_ci		BIT_VEC64_CLEAR_BIT(o->registry.aprox_match.vec, bin);
287762306a36Sopenharmony_ci		break;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci	default:
288062306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", cmd);
288162306a36Sopenharmony_ci		return;
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "%s bin %d\n",
288562306a36Sopenharmony_ci			 ((rx_tx_add_flag & ETH_MULTICAST_RULES_CMD_IS_ADD) ?
288662306a36Sopenharmony_ci			 "Setting"  : "Clearing"), bin);
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	data->rules[idx].bin_id    = (u8)bin;
288962306a36Sopenharmony_ci	data->rules[idx].func_id   = func_id;
289062306a36Sopenharmony_ci	data->rules[idx].engine_id = o->engine_id;
289162306a36Sopenharmony_ci}
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci/**
289462306a36Sopenharmony_ci * bnx2x_mcast_handle_restore_cmd_e2 - restore configuration from the registry
289562306a36Sopenharmony_ci *
289662306a36Sopenharmony_ci * @bp:		device handle
289762306a36Sopenharmony_ci * @o:		multicast object info
289862306a36Sopenharmony_ci * @start_bin:	index in the registry to start from (including)
289962306a36Sopenharmony_ci * @rdata_idx:	index in the ramrod data to start from
290062306a36Sopenharmony_ci *
290162306a36Sopenharmony_ci * returns last handled bin index or -1 if all bins have been handled
290262306a36Sopenharmony_ci */
290362306a36Sopenharmony_cistatic inline int bnx2x_mcast_handle_restore_cmd_e2(
290462306a36Sopenharmony_ci	struct bnx2x *bp, struct bnx2x_mcast_obj *o , int start_bin,
290562306a36Sopenharmony_ci	int *rdata_idx)
290662306a36Sopenharmony_ci{
290762306a36Sopenharmony_ci	int cur_bin, cnt = *rdata_idx;
290862306a36Sopenharmony_ci	union bnx2x_mcast_config_data cfg_data = {NULL};
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	/* go through the registry and configure the bins from it */
291162306a36Sopenharmony_ci	for (cur_bin = bnx2x_mcast_get_next_bin(o, start_bin); cur_bin >= 0;
291262306a36Sopenharmony_ci	    cur_bin = bnx2x_mcast_get_next_bin(o, cur_bin + 1)) {
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci		cfg_data.bin = (u8)cur_bin;
291562306a36Sopenharmony_ci		o->set_one_rule(bp, o, cnt, &cfg_data,
291662306a36Sopenharmony_ci				BNX2X_MCAST_CMD_RESTORE);
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci		cnt++;
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to configure a bin %d\n", cur_bin);
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci		/* Break if we reached the maximum number
292362306a36Sopenharmony_ci		 * of rules.
292462306a36Sopenharmony_ci		 */
292562306a36Sopenharmony_ci		if (cnt >= o->max_cmd_len)
292662306a36Sopenharmony_ci			break;
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	*rdata_idx = cnt;
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	return cur_bin;
293262306a36Sopenharmony_ci}
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_pending_add_e2(struct bnx2x *bp,
293562306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos,
293662306a36Sopenharmony_ci	int *line_idx)
293762306a36Sopenharmony_ci{
293862306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n;
293962306a36Sopenharmony_ci	int cnt = *line_idx;
294062306a36Sopenharmony_ci	union bnx2x_mcast_config_data cfg_data = {NULL};
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci	list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head,
294362306a36Sopenharmony_ci				 link) {
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci		cfg_data.mac = &pmac_pos->mac[0];
294662306a36Sopenharmony_ci		o->set_one_rule(bp, o, cnt, &cfg_data, cmd_pos->type);
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci		cnt++;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
295162306a36Sopenharmony_ci		   pmac_pos->mac);
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci		list_del(&pmac_pos->link);
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci		/* Break if we reached the maximum number
295662306a36Sopenharmony_ci		 * of rules.
295762306a36Sopenharmony_ci		 */
295862306a36Sopenharmony_ci		if (cnt >= o->max_cmd_len)
295962306a36Sopenharmony_ci			break;
296062306a36Sopenharmony_ci	}
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	*line_idx = cnt;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	/* if no more MACs to configure - we are done */
296562306a36Sopenharmony_ci	if (list_empty(&cmd_pos->data.macs_head))
296662306a36Sopenharmony_ci		cmd_pos->done = true;
296762306a36Sopenharmony_ci}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_pending_del_e2(struct bnx2x *bp,
297062306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos,
297162306a36Sopenharmony_ci	int *line_idx)
297262306a36Sopenharmony_ci{
297362306a36Sopenharmony_ci	int cnt = *line_idx;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	while (cmd_pos->data.macs_num) {
297662306a36Sopenharmony_ci		o->set_one_rule(bp, o, cnt, NULL, cmd_pos->type);
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci		cnt++;
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci		cmd_pos->data.macs_num--;
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Deleting MAC. %d left,cnt is %d\n",
298362306a36Sopenharmony_ci		   cmd_pos->data.macs_num, cnt);
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci		/* Break if we reached the maximum
298662306a36Sopenharmony_ci		 * number of rules.
298762306a36Sopenharmony_ci		 */
298862306a36Sopenharmony_ci		if (cnt >= o->max_cmd_len)
298962306a36Sopenharmony_ci			break;
299062306a36Sopenharmony_ci	}
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	*line_idx = cnt;
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	/* If we cleared all bins - we are done */
299562306a36Sopenharmony_ci	if (!cmd_pos->data.macs_num)
299662306a36Sopenharmony_ci		cmd_pos->done = true;
299762306a36Sopenharmony_ci}
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_pending_restore_e2(struct bnx2x *bp,
300062306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos,
300162306a36Sopenharmony_ci	int *line_idx)
300262306a36Sopenharmony_ci{
300362306a36Sopenharmony_ci	cmd_pos->data.next_bin = o->hdl_restore(bp, o, cmd_pos->data.next_bin,
300462306a36Sopenharmony_ci						line_idx);
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci	if (cmd_pos->data.next_bin < 0)
300762306a36Sopenharmony_ci		/* If o->set_restore returned -1 we are done */
300862306a36Sopenharmony_ci		cmd_pos->done = true;
300962306a36Sopenharmony_ci	else
301062306a36Sopenharmony_ci		/* Start from the next bin next time */
301162306a36Sopenharmony_ci		cmd_pos->data.next_bin++;
301262306a36Sopenharmony_ci}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_cistatic void
301562306a36Sopenharmony_cibnx2x_mcast_hdl_pending_set_e2_convert(struct bnx2x *bp,
301662306a36Sopenharmony_ci				       struct bnx2x_mcast_obj *o,
301762306a36Sopenharmony_ci				       struct bnx2x_pending_mcast_cmd *cmd_pos)
301862306a36Sopenharmony_ci{
301962306a36Sopenharmony_ci	u64 cur[BNX2X_MCAST_VEC_SZ], req[BNX2X_MCAST_VEC_SZ];
302062306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n;
302162306a36Sopenharmony_ci	struct bnx2x_mcast_bin_elem *p_item;
302262306a36Sopenharmony_ci	struct bnx2x_mcast_elem_group *elem_group;
302362306a36Sopenharmony_ci	int cnt = 0, mac_cnt = 0, offset = 0, i;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	memset(req, 0, sizeof(u64) * BNX2X_MCAST_VEC_SZ);
302662306a36Sopenharmony_ci	memcpy(cur, o->registry.aprox_match.vec,
302762306a36Sopenharmony_ci	       sizeof(u64) * BNX2X_MCAST_VEC_SZ);
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	/* Fill `current' with the required set of bins to configure */
303062306a36Sopenharmony_ci	list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head,
303162306a36Sopenharmony_ci				 link) {
303262306a36Sopenharmony_ci		int bin = bnx2x_mcast_bin_from_mac(pmac_pos->mac);
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Set contains %pM mcast MAC\n",
303562306a36Sopenharmony_ci		   pmac_pos->mac);
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci		BIT_VEC64_SET_BIT(req, bin);
303862306a36Sopenharmony_ci		list_del(&pmac_pos->link);
303962306a36Sopenharmony_ci		mac_cnt++;
304062306a36Sopenharmony_ci	}
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	/* We no longer have use for the MACs; Need to re-use memory for
304362306a36Sopenharmony_ci	 * a list that will be used to configure bins.
304462306a36Sopenharmony_ci	 */
304562306a36Sopenharmony_ci	cmd_pos->set_convert = true;
304662306a36Sopenharmony_ci	INIT_LIST_HEAD(&cmd_pos->data.macs_head);
304762306a36Sopenharmony_ci	elem_group = list_first_entry(&cmd_pos->group_head,
304862306a36Sopenharmony_ci				      struct bnx2x_mcast_elem_group,
304962306a36Sopenharmony_ci				      mcast_group_link);
305062306a36Sopenharmony_ci	for (i = 0; i < BNX2X_MCAST_BINS_NUM; i++) {
305162306a36Sopenharmony_ci		bool b_current = !!BIT_VEC64_TEST_BIT(cur, i);
305262306a36Sopenharmony_ci		bool b_required = !!BIT_VEC64_TEST_BIT(req, i);
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci		if (b_current == b_required)
305562306a36Sopenharmony_ci			continue;
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci		p_item = &elem_group->mcast_elems[offset].bin_elem;
305862306a36Sopenharmony_ci		p_item->bin = i;
305962306a36Sopenharmony_ci		p_item->type = b_required ? BNX2X_MCAST_CMD_SET_ADD
306062306a36Sopenharmony_ci					  : BNX2X_MCAST_CMD_SET_DEL;
306162306a36Sopenharmony_ci		list_add_tail(&p_item->link , &cmd_pos->data.macs_head);
306262306a36Sopenharmony_ci		cnt++;
306362306a36Sopenharmony_ci		offset++;
306462306a36Sopenharmony_ci		if (offset == MCAST_MAC_ELEMS_PER_PG) {
306562306a36Sopenharmony_ci			offset = 0;
306662306a36Sopenharmony_ci			elem_group = list_next_entry(elem_group,
306762306a36Sopenharmony_ci						     mcast_group_link);
306862306a36Sopenharmony_ci		}
306962306a36Sopenharmony_ci	}
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	/* We now definitely know how many commands are hiding here.
307262306a36Sopenharmony_ci	 * Also need to correct the disruption we've added to guarantee this
307362306a36Sopenharmony_ci	 * would be enqueued.
307462306a36Sopenharmony_ci	 */
307562306a36Sopenharmony_ci	o->total_pending_num -= (o->max_cmd_len + mac_cnt);
307662306a36Sopenharmony_ci	o->total_pending_num += cnt;
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "o->total_pending_num=%d\n", o->total_pending_num);
307962306a36Sopenharmony_ci}
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_cistatic void
308262306a36Sopenharmony_cibnx2x_mcast_hdl_pending_set_e2(struct bnx2x *bp,
308362306a36Sopenharmony_ci			       struct bnx2x_mcast_obj *o,
308462306a36Sopenharmony_ci			       struct bnx2x_pending_mcast_cmd *cmd_pos,
308562306a36Sopenharmony_ci			       int *cnt)
308662306a36Sopenharmony_ci{
308762306a36Sopenharmony_ci	union bnx2x_mcast_config_data cfg_data = {NULL};
308862306a36Sopenharmony_ci	struct bnx2x_mcast_bin_elem *p_item, *p_item_n;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	/* This is actually a 2-part scheme - it starts by converting the MACs
309162306a36Sopenharmony_ci	 * into a list of bins to be added/removed, and correcting the numbers
309262306a36Sopenharmony_ci	 * on the object. this is now allowed, as we're now sure that all
309362306a36Sopenharmony_ci	 * previous configured requests have already applied.
309462306a36Sopenharmony_ci	 * The second part is actually adding rules for the newly introduced
309562306a36Sopenharmony_ci	 * entries [like all the rest of the hdl_pending functions].
309662306a36Sopenharmony_ci	 */
309762306a36Sopenharmony_ci	if (!cmd_pos->set_convert)
309862306a36Sopenharmony_ci		bnx2x_mcast_hdl_pending_set_e2_convert(bp, o, cmd_pos);
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	list_for_each_entry_safe(p_item, p_item_n, &cmd_pos->data.macs_head,
310162306a36Sopenharmony_ci				 link) {
310262306a36Sopenharmony_ci		cfg_data.bin = (u8)p_item->bin;
310362306a36Sopenharmony_ci		o->set_one_rule(bp, o, *cnt, &cfg_data, p_item->type);
310462306a36Sopenharmony_ci		(*cnt)++;
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci		list_del(&p_item->link);
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci		/* Break if we reached the maximum number of rules. */
310962306a36Sopenharmony_ci		if (*cnt >= o->max_cmd_len)
311062306a36Sopenharmony_ci			break;
311162306a36Sopenharmony_ci	}
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	/* if no more MACs to configure - we are done */
311462306a36Sopenharmony_ci	if (list_empty(&cmd_pos->data.macs_head))
311562306a36Sopenharmony_ci		cmd_pos->done = true;
311662306a36Sopenharmony_ci}
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_cistatic inline int bnx2x_mcast_handle_pending_cmds_e2(struct bnx2x *bp,
311962306a36Sopenharmony_ci				struct bnx2x_mcast_ramrod_params *p)
312062306a36Sopenharmony_ci{
312162306a36Sopenharmony_ci	struct bnx2x_pending_mcast_cmd *cmd_pos, *cmd_pos_n;
312262306a36Sopenharmony_ci	int cnt = 0;
312362306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	list_for_each_entry_safe(cmd_pos, cmd_pos_n, &o->pending_cmds_head,
312662306a36Sopenharmony_ci				 link) {
312762306a36Sopenharmony_ci		switch (cmd_pos->type) {
312862306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_ADD:
312962306a36Sopenharmony_ci			bnx2x_mcast_hdl_pending_add_e2(bp, o, cmd_pos, &cnt);
313062306a36Sopenharmony_ci			break;
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_DEL:
313362306a36Sopenharmony_ci			bnx2x_mcast_hdl_pending_del_e2(bp, o, cmd_pos, &cnt);
313462306a36Sopenharmony_ci			break;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_RESTORE:
313762306a36Sopenharmony_ci			bnx2x_mcast_hdl_pending_restore_e2(bp, o, cmd_pos,
313862306a36Sopenharmony_ci							   &cnt);
313962306a36Sopenharmony_ci			break;
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_SET:
314262306a36Sopenharmony_ci			bnx2x_mcast_hdl_pending_set_e2(bp, o, cmd_pos, &cnt);
314362306a36Sopenharmony_ci			break;
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci		default:
314662306a36Sopenharmony_ci			BNX2X_ERR("Unknown command: %d\n", cmd_pos->type);
314762306a36Sopenharmony_ci			return -EINVAL;
314862306a36Sopenharmony_ci		}
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci		/* If the command has been completed - remove it from the list
315162306a36Sopenharmony_ci		 * and free the memory
315262306a36Sopenharmony_ci		 */
315362306a36Sopenharmony_ci		if (cmd_pos->done) {
315462306a36Sopenharmony_ci			list_del(&cmd_pos->link);
315562306a36Sopenharmony_ci			bnx2x_free_groups(&cmd_pos->group_head);
315662306a36Sopenharmony_ci			kfree(cmd_pos);
315762306a36Sopenharmony_ci		}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci		/* Break if we reached the maximum number of rules */
316062306a36Sopenharmony_ci		if (cnt >= o->max_cmd_len)
316162306a36Sopenharmony_ci			break;
316262306a36Sopenharmony_ci	}
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	return cnt;
316562306a36Sopenharmony_ci}
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_add(struct bnx2x *bp,
316862306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p,
316962306a36Sopenharmony_ci	int *line_idx)
317062306a36Sopenharmony_ci{
317162306a36Sopenharmony_ci	struct bnx2x_mcast_list_elem *mlist_pos;
317262306a36Sopenharmony_ci	union bnx2x_mcast_config_data cfg_data = {NULL};
317362306a36Sopenharmony_ci	int cnt = *line_idx;
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	list_for_each_entry(mlist_pos, &p->mcast_list, link) {
317662306a36Sopenharmony_ci		cfg_data.mac = mlist_pos->mac;
317762306a36Sopenharmony_ci		o->set_one_rule(bp, o, cnt, &cfg_data, BNX2X_MCAST_CMD_ADD);
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci		cnt++;
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
318262306a36Sopenharmony_ci		   mlist_pos->mac);
318362306a36Sopenharmony_ci	}
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	*line_idx = cnt;
318662306a36Sopenharmony_ci}
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_del(struct bnx2x *bp,
318962306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p,
319062306a36Sopenharmony_ci	int *line_idx)
319162306a36Sopenharmony_ci{
319262306a36Sopenharmony_ci	int cnt = *line_idx, i;
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	for (i = 0; i < p->mcast_list_len; i++) {
319562306a36Sopenharmony_ci		o->set_one_rule(bp, o, cnt, NULL, BNX2X_MCAST_CMD_DEL);
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci		cnt++;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Deleting MAC. %d left\n",
320062306a36Sopenharmony_ci				 p->mcast_list_len - i - 1);
320162306a36Sopenharmony_ci	}
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	*line_idx = cnt;
320462306a36Sopenharmony_ci}
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci/**
320762306a36Sopenharmony_ci * bnx2x_mcast_handle_current_cmd - send command if room
320862306a36Sopenharmony_ci *
320962306a36Sopenharmony_ci * @bp:		device handle
321062306a36Sopenharmony_ci * @p:		ramrod mcast info
321162306a36Sopenharmony_ci * @cmd:	command
321262306a36Sopenharmony_ci * @start_cnt:	first line in the ramrod data that may be used
321362306a36Sopenharmony_ci *
321462306a36Sopenharmony_ci * This function is called iff there is enough place for the current command in
321562306a36Sopenharmony_ci * the ramrod data.
321662306a36Sopenharmony_ci * Returns number of lines filled in the ramrod data in total.
321762306a36Sopenharmony_ci */
321862306a36Sopenharmony_cistatic inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp,
321962306a36Sopenharmony_ci			struct bnx2x_mcast_ramrod_params *p,
322062306a36Sopenharmony_ci			enum bnx2x_mcast_cmd cmd,
322162306a36Sopenharmony_ci			int start_cnt)
322262306a36Sopenharmony_ci{
322362306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
322462306a36Sopenharmony_ci	int cnt = start_cnt;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "p->mcast_list_len=%d\n", p->mcast_list_len);
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	switch (cmd) {
322962306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_ADD:
323062306a36Sopenharmony_ci		bnx2x_mcast_hdl_add(bp, o, p, &cnt);
323162306a36Sopenharmony_ci		break;
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_DEL:
323462306a36Sopenharmony_ci		bnx2x_mcast_hdl_del(bp, o, p, &cnt);
323562306a36Sopenharmony_ci		break;
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_RESTORE:
323862306a36Sopenharmony_ci		o->hdl_restore(bp, o, 0, &cnt);
323962306a36Sopenharmony_ci		break;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	default:
324262306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", cmd);
324362306a36Sopenharmony_ci		return -EINVAL;
324462306a36Sopenharmony_ci	}
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	/* The current command has been handled */
324762306a36Sopenharmony_ci	p->mcast_list_len = 0;
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	return cnt;
325062306a36Sopenharmony_ci}
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_cistatic int bnx2x_mcast_validate_e2(struct bnx2x *bp,
325362306a36Sopenharmony_ci				   struct bnx2x_mcast_ramrod_params *p,
325462306a36Sopenharmony_ci				   enum bnx2x_mcast_cmd cmd)
325562306a36Sopenharmony_ci{
325662306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
325762306a36Sopenharmony_ci	int reg_sz = o->get_registry_size(o);
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	switch (cmd) {
326062306a36Sopenharmony_ci	/* DEL command deletes all currently configured MACs */
326162306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_DEL:
326262306a36Sopenharmony_ci		o->set_registry_size(o, 0);
326362306a36Sopenharmony_ci		fallthrough;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	/* RESTORE command will restore the entire multicast configuration */
326662306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_RESTORE:
326762306a36Sopenharmony_ci		/* Here we set the approximate amount of work to do, which in
326862306a36Sopenharmony_ci		 * fact may be only less as some MACs in postponed ADD
326962306a36Sopenharmony_ci		 * command(s) scheduled before this command may fall into
327062306a36Sopenharmony_ci		 * the same bin and the actual number of bins set in the
327162306a36Sopenharmony_ci		 * registry would be less than we estimated here. See
327262306a36Sopenharmony_ci		 * bnx2x_mcast_set_one_rule_e2() for further details.
327362306a36Sopenharmony_ci		 */
327462306a36Sopenharmony_ci		p->mcast_list_len = reg_sz;
327562306a36Sopenharmony_ci		break;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_ADD:
327862306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_CONT:
327962306a36Sopenharmony_ci		/* Here we assume that all new MACs will fall into new bins.
328062306a36Sopenharmony_ci		 * However we will correct the real registry size after we
328162306a36Sopenharmony_ci		 * handle all pending commands.
328262306a36Sopenharmony_ci		 */
328362306a36Sopenharmony_ci		o->set_registry_size(o, reg_sz + p->mcast_list_len);
328462306a36Sopenharmony_ci		break;
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_SET:
328762306a36Sopenharmony_ci		/* We can only learn how many commands would actually be used
328862306a36Sopenharmony_ci		 * when this is being configured. So for now, simply guarantee
328962306a36Sopenharmony_ci		 * the command will be enqueued [to refrain from adding logic
329062306a36Sopenharmony_ci		 * that handles this and THEN learns it needs several ramrods].
329162306a36Sopenharmony_ci		 * Just like for ADD/Cont, the mcast_list_len might be an over
329262306a36Sopenharmony_ci		 * estimation; or even more so, since we don't take into
329362306a36Sopenharmony_ci		 * account the possibility of removal of existing bins.
329462306a36Sopenharmony_ci		 */
329562306a36Sopenharmony_ci		o->set_registry_size(o, reg_sz + p->mcast_list_len);
329662306a36Sopenharmony_ci		o->total_pending_num += o->max_cmd_len;
329762306a36Sopenharmony_ci		break;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	default:
330062306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", cmd);
330162306a36Sopenharmony_ci		return -EINVAL;
330262306a36Sopenharmony_ci	}
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	/* Increase the total number of MACs pending to be configured */
330562306a36Sopenharmony_ci	o->total_pending_num += p->mcast_list_len;
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci	return 0;
330862306a36Sopenharmony_ci}
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_cistatic void bnx2x_mcast_revert_e2(struct bnx2x *bp,
331162306a36Sopenharmony_ci				      struct bnx2x_mcast_ramrod_params *p,
331262306a36Sopenharmony_ci				  int old_num_bins,
331362306a36Sopenharmony_ci				  enum bnx2x_mcast_cmd cmd)
331462306a36Sopenharmony_ci{
331562306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci	o->set_registry_size(o, old_num_bins);
331862306a36Sopenharmony_ci	o->total_pending_num -= p->mcast_list_len;
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	if (cmd == BNX2X_MCAST_CMD_SET)
332162306a36Sopenharmony_ci		o->total_pending_num -= o->max_cmd_len;
332262306a36Sopenharmony_ci}
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci/**
332562306a36Sopenharmony_ci * bnx2x_mcast_set_rdata_hdr_e2 - sets a header values
332662306a36Sopenharmony_ci *
332762306a36Sopenharmony_ci * @bp:		device handle
332862306a36Sopenharmony_ci * @p:		ramrod parameters
332962306a36Sopenharmony_ci * @len:	number of rules to handle
333062306a36Sopenharmony_ci */
333162306a36Sopenharmony_cistatic inline void bnx2x_mcast_set_rdata_hdr_e2(struct bnx2x *bp,
333262306a36Sopenharmony_ci					struct bnx2x_mcast_ramrod_params *p,
333362306a36Sopenharmony_ci					u8 len)
333462306a36Sopenharmony_ci{
333562306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &p->mcast_obj->raw;
333662306a36Sopenharmony_ci	struct eth_multicast_rules_ramrod_data *data =
333762306a36Sopenharmony_ci		(struct eth_multicast_rules_ramrod_data *)(r->rdata);
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	data->header.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
334062306a36Sopenharmony_ci					(BNX2X_FILTER_MCAST_PENDING <<
334162306a36Sopenharmony_ci					 BNX2X_SWCID_SHIFT));
334262306a36Sopenharmony_ci	data->header.rule_cnt = len;
334362306a36Sopenharmony_ci}
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci/**
334662306a36Sopenharmony_ci * bnx2x_mcast_refresh_registry_e2 - recalculate the actual number of set bins
334762306a36Sopenharmony_ci *
334862306a36Sopenharmony_ci * @bp:		device handle
334962306a36Sopenharmony_ci * @o:
335062306a36Sopenharmony_ci *
335162306a36Sopenharmony_ci * Recalculate the actual number of set bins in the registry using Brian
335262306a36Sopenharmony_ci * Kernighan's algorithm: it's execution complexity is as a number of set bins.
335362306a36Sopenharmony_ci *
335462306a36Sopenharmony_ci * returns 0 for the compliance with bnx2x_mcast_refresh_registry_e1().
335562306a36Sopenharmony_ci */
335662306a36Sopenharmony_cistatic inline int bnx2x_mcast_refresh_registry_e2(struct bnx2x *bp,
335762306a36Sopenharmony_ci						  struct bnx2x_mcast_obj *o)
335862306a36Sopenharmony_ci{
335962306a36Sopenharmony_ci	int i, cnt = 0;
336062306a36Sopenharmony_ci	u64 elem;
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci	for (i = 0; i < BNX2X_MCAST_VEC_SZ; i++) {
336362306a36Sopenharmony_ci		elem = o->registry.aprox_match.vec[i];
336462306a36Sopenharmony_ci		for (; elem; cnt++)
336562306a36Sopenharmony_ci			elem &= elem - 1;
336662306a36Sopenharmony_ci	}
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	o->set_registry_size(o, cnt);
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	return 0;
337162306a36Sopenharmony_ci}
337262306a36Sopenharmony_ci
337362306a36Sopenharmony_cistatic int bnx2x_mcast_setup_e2(struct bnx2x *bp,
337462306a36Sopenharmony_ci				struct bnx2x_mcast_ramrod_params *p,
337562306a36Sopenharmony_ci				enum bnx2x_mcast_cmd cmd)
337662306a36Sopenharmony_ci{
337762306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &p->mcast_obj->raw;
337862306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
337962306a36Sopenharmony_ci	struct eth_multicast_rules_ramrod_data *data =
338062306a36Sopenharmony_ci		(struct eth_multicast_rules_ramrod_data *)(raw->rdata);
338162306a36Sopenharmony_ci	int cnt = 0, rc;
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	/* Reset the ramrod data buffer */
338462306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	cnt = bnx2x_mcast_handle_pending_cmds_e2(bp, p);
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	/* If there are no more pending commands - clear SCHEDULED state */
338962306a36Sopenharmony_ci	if (list_empty(&o->pending_cmds_head))
339062306a36Sopenharmony_ci		o->clear_sched(o);
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	/* The below may be true iff there was enough room in ramrod
339362306a36Sopenharmony_ci	 * data for all pending commands and for the current
339462306a36Sopenharmony_ci	 * command. Otherwise the current command would have been added
339562306a36Sopenharmony_ci	 * to the pending commands and p->mcast_list_len would have been
339662306a36Sopenharmony_ci	 * zeroed.
339762306a36Sopenharmony_ci	 */
339862306a36Sopenharmony_ci	if (p->mcast_list_len > 0)
339962306a36Sopenharmony_ci		cnt = bnx2x_mcast_handle_current_cmd(bp, p, cmd, cnt);
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	/* We've pulled out some MACs - update the total number of
340262306a36Sopenharmony_ci	 * outstanding.
340362306a36Sopenharmony_ci	 */
340462306a36Sopenharmony_ci	o->total_pending_num -= cnt;
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	/* send a ramrod */
340762306a36Sopenharmony_ci	WARN_ON(o->total_pending_num < 0);
340862306a36Sopenharmony_ci	WARN_ON(cnt > o->max_cmd_len);
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	bnx2x_mcast_set_rdata_hdr_e2(bp, p, (u8)cnt);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	/* Update a registry size if there are no more pending operations.
341362306a36Sopenharmony_ci	 *
341462306a36Sopenharmony_ci	 * We don't want to change the value of the registry size if there are
341562306a36Sopenharmony_ci	 * pending operations because we want it to always be equal to the
341662306a36Sopenharmony_ci	 * exact or the approximate number (see bnx2x_mcast_validate_e2()) of
341762306a36Sopenharmony_ci	 * set bins after the last requested operation in order to properly
341862306a36Sopenharmony_ci	 * evaluate the size of the next DEL/RESTORE operation.
341962306a36Sopenharmony_ci	 *
342062306a36Sopenharmony_ci	 * Note that we update the registry itself during command(s) handling
342162306a36Sopenharmony_ci	 * - see bnx2x_mcast_set_one_rule_e2(). That's because for 57712 we
342262306a36Sopenharmony_ci	 * aggregate multiple commands (ADD/DEL/RESTORE) into one ramrod but
342362306a36Sopenharmony_ci	 * with a limited amount of update commands (per MAC/bin) and we don't
342462306a36Sopenharmony_ci	 * know in this scope what the actual state of bins configuration is
342562306a36Sopenharmony_ci	 * going to be after this ramrod.
342662306a36Sopenharmony_ci	 */
342762306a36Sopenharmony_ci	if (!o->total_pending_num)
342862306a36Sopenharmony_ci		bnx2x_mcast_refresh_registry_e2(bp, o);
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci	/* If CLEAR_ONLY was requested - don't send a ramrod and clear
343162306a36Sopenharmony_ci	 * RAMROD_PENDING status immediately. due to the SET option, it's also
343262306a36Sopenharmony_ci	 * possible that after evaluating the differences there's no need for
343362306a36Sopenharmony_ci	 * a ramrod. In that case, we can skip it as well.
343462306a36Sopenharmony_ci	 */
343562306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags) || !cnt) {
343662306a36Sopenharmony_ci		raw->clear_pending(raw);
343762306a36Sopenharmony_ci		return 0;
343862306a36Sopenharmony_ci	} else {
343962306a36Sopenharmony_ci		/* No need for an explicit memory barrier here as long as we
344062306a36Sopenharmony_ci		 * ensure the ordering of writing to the SPQ element
344162306a36Sopenharmony_ci		 * and updating of the SPQ producer which involves a memory
344262306a36Sopenharmony_ci		 * read. If the memory read is removed we will have to put a
344362306a36Sopenharmony_ci		 * full memory barrier there (inside bnx2x_sp_post()).
344462306a36Sopenharmony_ci		 */
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		/* Send a ramrod */
344762306a36Sopenharmony_ci		rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_MULTICAST_RULES,
344862306a36Sopenharmony_ci				   raw->cid, U64_HI(raw->rdata_mapping),
344962306a36Sopenharmony_ci				   U64_LO(raw->rdata_mapping),
345062306a36Sopenharmony_ci				   ETH_CONNECTION_TYPE);
345162306a36Sopenharmony_ci		if (rc)
345262306a36Sopenharmony_ci			return rc;
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci		/* Ramrod completion is pending */
345562306a36Sopenharmony_ci		return 1;
345662306a36Sopenharmony_ci	}
345762306a36Sopenharmony_ci}
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_cistatic int bnx2x_mcast_validate_e1h(struct bnx2x *bp,
346062306a36Sopenharmony_ci				    struct bnx2x_mcast_ramrod_params *p,
346162306a36Sopenharmony_ci				    enum bnx2x_mcast_cmd cmd)
346262306a36Sopenharmony_ci{
346362306a36Sopenharmony_ci	if (cmd == BNX2X_MCAST_CMD_SET) {
346462306a36Sopenharmony_ci		BNX2X_ERR("Can't use `set' command on e1h!\n");
346562306a36Sopenharmony_ci		return -EINVAL;
346662306a36Sopenharmony_ci	}
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	/* Mark, that there is a work to do */
346962306a36Sopenharmony_ci	if ((cmd == BNX2X_MCAST_CMD_DEL) || (cmd == BNX2X_MCAST_CMD_RESTORE))
347062306a36Sopenharmony_ci		p->mcast_list_len = 1;
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	return 0;
347362306a36Sopenharmony_ci}
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_cistatic void bnx2x_mcast_revert_e1h(struct bnx2x *bp,
347662306a36Sopenharmony_ci				       struct bnx2x_mcast_ramrod_params *p,
347762306a36Sopenharmony_ci				       int old_num_bins,
347862306a36Sopenharmony_ci				       enum bnx2x_mcast_cmd cmd)
347962306a36Sopenharmony_ci{
348062306a36Sopenharmony_ci	/* Do nothing */
348162306a36Sopenharmony_ci}
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci#define BNX2X_57711_SET_MC_FILTER(filter, bit) \
348462306a36Sopenharmony_cido { \
348562306a36Sopenharmony_ci	(filter)[(bit) >> 5] |= (1 << ((bit) & 0x1f)); \
348662306a36Sopenharmony_ci} while (0)
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_add_e1h(struct bnx2x *bp,
348962306a36Sopenharmony_ci					   struct bnx2x_mcast_obj *o,
349062306a36Sopenharmony_ci					   struct bnx2x_mcast_ramrod_params *p,
349162306a36Sopenharmony_ci					   u32 *mc_filter)
349262306a36Sopenharmony_ci{
349362306a36Sopenharmony_ci	struct bnx2x_mcast_list_elem *mlist_pos;
349462306a36Sopenharmony_ci	int bit;
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	list_for_each_entry(mlist_pos, &p->mcast_list, link) {
349762306a36Sopenharmony_ci		bit = bnx2x_mcast_bin_from_mac(mlist_pos->mac);
349862306a36Sopenharmony_ci		BNX2X_57711_SET_MC_FILTER(mc_filter, bit);
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC, bin %d\n",
350162306a36Sopenharmony_ci		   mlist_pos->mac, bit);
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci		/* bookkeeping... */
350462306a36Sopenharmony_ci		BIT_VEC64_SET_BIT(o->registry.aprox_match.vec,
350562306a36Sopenharmony_ci				  bit);
350662306a36Sopenharmony_ci	}
350762306a36Sopenharmony_ci}
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_cistatic inline void bnx2x_mcast_hdl_restore_e1h(struct bnx2x *bp,
351062306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p,
351162306a36Sopenharmony_ci	u32 *mc_filter)
351262306a36Sopenharmony_ci{
351362306a36Sopenharmony_ci	int bit;
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	for (bit = bnx2x_mcast_get_next_bin(o, 0);
351662306a36Sopenharmony_ci	     bit >= 0;
351762306a36Sopenharmony_ci	     bit = bnx2x_mcast_get_next_bin(o, bit + 1)) {
351862306a36Sopenharmony_ci		BNX2X_57711_SET_MC_FILTER(mc_filter, bit);
351962306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to set bin %d\n", bit);
352062306a36Sopenharmony_ci	}
352162306a36Sopenharmony_ci}
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci/* On 57711 we write the multicast MACs' approximate match
352462306a36Sopenharmony_ci * table by directly into the TSTORM's internal RAM. So we don't
352562306a36Sopenharmony_ci * really need to handle any tricks to make it work.
352662306a36Sopenharmony_ci */
352762306a36Sopenharmony_cistatic int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
352862306a36Sopenharmony_ci				 struct bnx2x_mcast_ramrod_params *p,
352962306a36Sopenharmony_ci				 enum bnx2x_mcast_cmd cmd)
353062306a36Sopenharmony_ci{
353162306a36Sopenharmony_ci	int i;
353262306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
353362306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci	/* If CLEAR_ONLY has been requested - clear the registry
353662306a36Sopenharmony_ci	 * and clear a pending bit.
353762306a36Sopenharmony_ci	 */
353862306a36Sopenharmony_ci	if (!test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) {
353962306a36Sopenharmony_ci		u32 mc_filter[MC_HASH_SIZE] = {0};
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci		/* Set the multicast filter bits before writing it into
354262306a36Sopenharmony_ci		 * the internal memory.
354362306a36Sopenharmony_ci		 */
354462306a36Sopenharmony_ci		switch (cmd) {
354562306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_ADD:
354662306a36Sopenharmony_ci			bnx2x_mcast_hdl_add_e1h(bp, o, p, mc_filter);
354762306a36Sopenharmony_ci			break;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_DEL:
355062306a36Sopenharmony_ci			DP(BNX2X_MSG_SP,
355162306a36Sopenharmony_ci			   "Invalidating multicast MACs configuration\n");
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci			/* clear the registry */
355462306a36Sopenharmony_ci			memset(o->registry.aprox_match.vec, 0,
355562306a36Sopenharmony_ci			       sizeof(o->registry.aprox_match.vec));
355662306a36Sopenharmony_ci			break;
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci		case BNX2X_MCAST_CMD_RESTORE:
355962306a36Sopenharmony_ci			bnx2x_mcast_hdl_restore_e1h(bp, o, p, mc_filter);
356062306a36Sopenharmony_ci			break;
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci		default:
356362306a36Sopenharmony_ci			BNX2X_ERR("Unknown command: %d\n", cmd);
356462306a36Sopenharmony_ci			return -EINVAL;
356562306a36Sopenharmony_ci		}
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci		/* Set the mcast filter in the internal memory */
356862306a36Sopenharmony_ci		for (i = 0; i < MC_HASH_SIZE; i++)
356962306a36Sopenharmony_ci			REG_WR(bp, MC_HASH_OFFSET(bp, i), mc_filter[i]);
357062306a36Sopenharmony_ci	} else
357162306a36Sopenharmony_ci		/* clear the registry */
357262306a36Sopenharmony_ci		memset(o->registry.aprox_match.vec, 0,
357362306a36Sopenharmony_ci		       sizeof(o->registry.aprox_match.vec));
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	/* We are done */
357662306a36Sopenharmony_ci	r->clear_pending(r);
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci	return 0;
357962306a36Sopenharmony_ci}
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_cistatic int bnx2x_mcast_validate_e1(struct bnx2x *bp,
358262306a36Sopenharmony_ci				   struct bnx2x_mcast_ramrod_params *p,
358362306a36Sopenharmony_ci				   enum bnx2x_mcast_cmd cmd)
358462306a36Sopenharmony_ci{
358562306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
358662306a36Sopenharmony_ci	int reg_sz = o->get_registry_size(o);
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	if (cmd == BNX2X_MCAST_CMD_SET) {
358962306a36Sopenharmony_ci		BNX2X_ERR("Can't use `set' command on e1!\n");
359062306a36Sopenharmony_ci		return -EINVAL;
359162306a36Sopenharmony_ci	}
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	switch (cmd) {
359462306a36Sopenharmony_ci	/* DEL command deletes all currently configured MACs */
359562306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_DEL:
359662306a36Sopenharmony_ci		o->set_registry_size(o, 0);
359762306a36Sopenharmony_ci		fallthrough;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	/* RESTORE command will restore the entire multicast configuration */
360062306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_RESTORE:
360162306a36Sopenharmony_ci		p->mcast_list_len = reg_sz;
360262306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Command %d, p->mcast_list_len=%d\n",
360362306a36Sopenharmony_ci		   cmd, p->mcast_list_len);
360462306a36Sopenharmony_ci		break;
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_ADD:
360762306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_CONT:
360862306a36Sopenharmony_ci		/* Multicast MACs on 57710 are configured as unicast MACs and
360962306a36Sopenharmony_ci		 * there is only a limited number of CAM entries for that
361062306a36Sopenharmony_ci		 * matter.
361162306a36Sopenharmony_ci		 */
361262306a36Sopenharmony_ci		if (p->mcast_list_len > o->max_cmd_len) {
361362306a36Sopenharmony_ci			BNX2X_ERR("Can't configure more than %d multicast MACs on 57710\n",
361462306a36Sopenharmony_ci				  o->max_cmd_len);
361562306a36Sopenharmony_ci			return -EINVAL;
361662306a36Sopenharmony_ci		}
361762306a36Sopenharmony_ci		/* Every configured MAC should be cleared if DEL command is
361862306a36Sopenharmony_ci		 * called. Only the last ADD command is relevant as long as
361962306a36Sopenharmony_ci		 * every ADD commands overrides the previous configuration.
362062306a36Sopenharmony_ci		 */
362162306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "p->mcast_list_len=%d\n", p->mcast_list_len);
362262306a36Sopenharmony_ci		if (p->mcast_list_len > 0)
362362306a36Sopenharmony_ci			o->set_registry_size(o, p->mcast_list_len);
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci		break;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	default:
362862306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", cmd);
362962306a36Sopenharmony_ci		return -EINVAL;
363062306a36Sopenharmony_ci	}
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_ci	/* We want to ensure that commands are executed one by one for 57710.
363362306a36Sopenharmony_ci	 * Therefore each none-empty command will consume o->max_cmd_len.
363462306a36Sopenharmony_ci	 */
363562306a36Sopenharmony_ci	if (p->mcast_list_len)
363662306a36Sopenharmony_ci		o->total_pending_num += o->max_cmd_len;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	return 0;
363962306a36Sopenharmony_ci}
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_cistatic void bnx2x_mcast_revert_e1(struct bnx2x *bp,
364262306a36Sopenharmony_ci				      struct bnx2x_mcast_ramrod_params *p,
364362306a36Sopenharmony_ci				   int old_num_macs,
364462306a36Sopenharmony_ci				   enum bnx2x_mcast_cmd cmd)
364562306a36Sopenharmony_ci{
364662306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci	o->set_registry_size(o, old_num_macs);
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	/* If current command hasn't been handled yet and we are
365162306a36Sopenharmony_ci	 * here means that it's meant to be dropped and we have to
365262306a36Sopenharmony_ci	 * update the number of outstanding MACs accordingly.
365362306a36Sopenharmony_ci	 */
365462306a36Sopenharmony_ci	if (p->mcast_list_len)
365562306a36Sopenharmony_ci		o->total_pending_num -= o->max_cmd_len;
365662306a36Sopenharmony_ci}
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_cistatic void bnx2x_mcast_set_one_rule_e1(struct bnx2x *bp,
365962306a36Sopenharmony_ci					struct bnx2x_mcast_obj *o, int idx,
366062306a36Sopenharmony_ci					union bnx2x_mcast_config_data *cfg_data,
366162306a36Sopenharmony_ci					enum bnx2x_mcast_cmd cmd)
366262306a36Sopenharmony_ci{
366362306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
366462306a36Sopenharmony_ci	struct mac_configuration_cmd *data =
366562306a36Sopenharmony_ci		(struct mac_configuration_cmd *)(r->rdata);
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	/* copy mac */
366862306a36Sopenharmony_ci	if ((cmd == BNX2X_MCAST_CMD_ADD) || (cmd == BNX2X_MCAST_CMD_RESTORE)) {
366962306a36Sopenharmony_ci		bnx2x_set_fw_mac_addr(&data->config_table[idx].msb_mac_addr,
367062306a36Sopenharmony_ci				      &data->config_table[idx].middle_mac_addr,
367162306a36Sopenharmony_ci				      &data->config_table[idx].lsb_mac_addr,
367262306a36Sopenharmony_ci				      cfg_data->mac);
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci		data->config_table[idx].vlan_id = 0;
367562306a36Sopenharmony_ci		data->config_table[idx].pf_id = r->func_id;
367662306a36Sopenharmony_ci		data->config_table[idx].clients_bit_vector =
367762306a36Sopenharmony_ci			cpu_to_le32(1 << r->cl_id);
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ci		SET_FLAG(data->config_table[idx].flags,
368062306a36Sopenharmony_ci			 MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
368162306a36Sopenharmony_ci			 T_ETH_MAC_COMMAND_SET);
368262306a36Sopenharmony_ci	}
368362306a36Sopenharmony_ci}
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci/**
368662306a36Sopenharmony_ci * bnx2x_mcast_set_rdata_hdr_e1  - set header values in mac_configuration_cmd
368762306a36Sopenharmony_ci *
368862306a36Sopenharmony_ci * @bp:		device handle
368962306a36Sopenharmony_ci * @p:		ramrod parameters
369062306a36Sopenharmony_ci * @len:	number of rules to handle
369162306a36Sopenharmony_ci */
369262306a36Sopenharmony_cistatic inline void bnx2x_mcast_set_rdata_hdr_e1(struct bnx2x *bp,
369362306a36Sopenharmony_ci					struct bnx2x_mcast_ramrod_params *p,
369462306a36Sopenharmony_ci					u8 len)
369562306a36Sopenharmony_ci{
369662306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &p->mcast_obj->raw;
369762306a36Sopenharmony_ci	struct mac_configuration_cmd *data =
369862306a36Sopenharmony_ci		(struct mac_configuration_cmd *)(r->rdata);
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	u8 offset = (CHIP_REV_IS_SLOW(bp) ?
370162306a36Sopenharmony_ci		     BNX2X_MAX_EMUL_MULTI*(1 + r->func_id) :
370262306a36Sopenharmony_ci		     BNX2X_MAX_MULTICAST*(1 + r->func_id));
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	data->hdr.offset = offset;
370562306a36Sopenharmony_ci	data->hdr.client_id = cpu_to_le16(0xff);
370662306a36Sopenharmony_ci	data->hdr.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
370762306a36Sopenharmony_ci				     (BNX2X_FILTER_MCAST_PENDING <<
370862306a36Sopenharmony_ci				      BNX2X_SWCID_SHIFT));
370962306a36Sopenharmony_ci	data->hdr.length = len;
371062306a36Sopenharmony_ci}
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci/**
371362306a36Sopenharmony_ci * bnx2x_mcast_handle_restore_cmd_e1 - restore command for 57710
371462306a36Sopenharmony_ci *
371562306a36Sopenharmony_ci * @bp:		device handle
371662306a36Sopenharmony_ci * @o:		multicast info
371762306a36Sopenharmony_ci * @start_idx:	index in the registry to start from
371862306a36Sopenharmony_ci * @rdata_idx:	index in the ramrod data to start from
371962306a36Sopenharmony_ci *
372062306a36Sopenharmony_ci * restore command for 57710 is like all other commands - always a stand alone
372162306a36Sopenharmony_ci * command - start_idx and rdata_idx will always be 0. This function will always
372262306a36Sopenharmony_ci * succeed.
372362306a36Sopenharmony_ci * returns -1 to comply with 57712 variant.
372462306a36Sopenharmony_ci */
372562306a36Sopenharmony_cistatic inline int bnx2x_mcast_handle_restore_cmd_e1(
372662306a36Sopenharmony_ci	struct bnx2x *bp, struct bnx2x_mcast_obj *o , int start_idx,
372762306a36Sopenharmony_ci	int *rdata_idx)
372862306a36Sopenharmony_ci{
372962306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem *elem;
373062306a36Sopenharmony_ci	int i = 0;
373162306a36Sopenharmony_ci	union bnx2x_mcast_config_data cfg_data = {NULL};
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	/* go through the registry and configure the MACs from it. */
373462306a36Sopenharmony_ci	list_for_each_entry(elem, &o->registry.exact_match.macs, link) {
373562306a36Sopenharmony_ci		cfg_data.mac = &elem->mac[0];
373662306a36Sopenharmony_ci		o->set_one_rule(bp, o, i, &cfg_data, BNX2X_MCAST_CMD_RESTORE);
373762306a36Sopenharmony_ci
373862306a36Sopenharmony_ci		i++;
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
374162306a36Sopenharmony_ci		   cfg_data.mac);
374262306a36Sopenharmony_ci	}
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	*rdata_idx = i;
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci	return -1;
374762306a36Sopenharmony_ci}
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_cistatic inline int bnx2x_mcast_handle_pending_cmds_e1(
375062306a36Sopenharmony_ci	struct bnx2x *bp, struct bnx2x_mcast_ramrod_params *p)
375162306a36Sopenharmony_ci{
375262306a36Sopenharmony_ci	struct bnx2x_pending_mcast_cmd *cmd_pos;
375362306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem *pmac_pos;
375462306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
375562306a36Sopenharmony_ci	union bnx2x_mcast_config_data cfg_data = {NULL};
375662306a36Sopenharmony_ci	int cnt = 0;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	/* If nothing to be done - return */
375962306a36Sopenharmony_ci	if (list_empty(&o->pending_cmds_head))
376062306a36Sopenharmony_ci		return 0;
376162306a36Sopenharmony_ci
376262306a36Sopenharmony_ci	/* Handle the first command */
376362306a36Sopenharmony_ci	cmd_pos = list_first_entry(&o->pending_cmds_head,
376462306a36Sopenharmony_ci				   struct bnx2x_pending_mcast_cmd, link);
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_ci	switch (cmd_pos->type) {
376762306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_ADD:
376862306a36Sopenharmony_ci		list_for_each_entry(pmac_pos, &cmd_pos->data.macs_head, link) {
376962306a36Sopenharmony_ci			cfg_data.mac = &pmac_pos->mac[0];
377062306a36Sopenharmony_ci			o->set_one_rule(bp, o, cnt, &cfg_data, cmd_pos->type);
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci			cnt++;
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
377562306a36Sopenharmony_ci			   pmac_pos->mac);
377662306a36Sopenharmony_ci		}
377762306a36Sopenharmony_ci		break;
377862306a36Sopenharmony_ci
377962306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_DEL:
378062306a36Sopenharmony_ci		cnt = cmd_pos->data.macs_num;
378162306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "About to delete %d multicast MACs\n", cnt);
378262306a36Sopenharmony_ci		break;
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	case BNX2X_MCAST_CMD_RESTORE:
378562306a36Sopenharmony_ci		o->hdl_restore(bp, o, 0, &cnt);
378662306a36Sopenharmony_ci		break;
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	default:
378962306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", cmd_pos->type);
379062306a36Sopenharmony_ci		return -EINVAL;
379162306a36Sopenharmony_ci	}
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	list_del(&cmd_pos->link);
379462306a36Sopenharmony_ci	bnx2x_free_groups(&cmd_pos->group_head);
379562306a36Sopenharmony_ci	kfree(cmd_pos);
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	return cnt;
379862306a36Sopenharmony_ci}
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci/**
380162306a36Sopenharmony_ci * bnx2x_get_fw_mac_addr - revert the bnx2x_set_fw_mac_addr().
380262306a36Sopenharmony_ci *
380362306a36Sopenharmony_ci * @fw_hi: address
380462306a36Sopenharmony_ci * @fw_mid: address
380562306a36Sopenharmony_ci * @fw_lo: address
380662306a36Sopenharmony_ci * @mac: mac address
380762306a36Sopenharmony_ci */
380862306a36Sopenharmony_cistatic inline void bnx2x_get_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid,
380962306a36Sopenharmony_ci					 __le16 *fw_lo, u8 *mac)
381062306a36Sopenharmony_ci{
381162306a36Sopenharmony_ci	mac[1] = ((u8 *)fw_hi)[0];
381262306a36Sopenharmony_ci	mac[0] = ((u8 *)fw_hi)[1];
381362306a36Sopenharmony_ci	mac[3] = ((u8 *)fw_mid)[0];
381462306a36Sopenharmony_ci	mac[2] = ((u8 *)fw_mid)[1];
381562306a36Sopenharmony_ci	mac[5] = ((u8 *)fw_lo)[0];
381662306a36Sopenharmony_ci	mac[4] = ((u8 *)fw_lo)[1];
381762306a36Sopenharmony_ci}
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci/**
382062306a36Sopenharmony_ci * bnx2x_mcast_refresh_registry_e1 -
382162306a36Sopenharmony_ci *
382262306a36Sopenharmony_ci * @bp:		device handle
382362306a36Sopenharmony_ci * @o:		multicast info
382462306a36Sopenharmony_ci *
382562306a36Sopenharmony_ci * Check the ramrod data first entry flag to see if it's a DELETE or ADD command
382662306a36Sopenharmony_ci * and update the registry correspondingly: if ADD - allocate a memory and add
382762306a36Sopenharmony_ci * the entries to the registry (list), if DELETE - clear the registry and free
382862306a36Sopenharmony_ci * the memory.
382962306a36Sopenharmony_ci */
383062306a36Sopenharmony_cistatic inline int bnx2x_mcast_refresh_registry_e1(struct bnx2x *bp,
383162306a36Sopenharmony_ci						  struct bnx2x_mcast_obj *o)
383262306a36Sopenharmony_ci{
383362306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
383462306a36Sopenharmony_ci	struct bnx2x_mcast_mac_elem *elem;
383562306a36Sopenharmony_ci	struct mac_configuration_cmd *data =
383662306a36Sopenharmony_ci			(struct mac_configuration_cmd *)(raw->rdata);
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	/* If first entry contains a SET bit - the command was ADD,
383962306a36Sopenharmony_ci	 * otherwise - DEL_ALL
384062306a36Sopenharmony_ci	 */
384162306a36Sopenharmony_ci	if (GET_FLAG(data->config_table[0].flags,
384262306a36Sopenharmony_ci			MAC_CONFIGURATION_ENTRY_ACTION_TYPE)) {
384362306a36Sopenharmony_ci		int i, len = data->hdr.length;
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci		/* Break if it was a RESTORE command */
384662306a36Sopenharmony_ci		if (!list_empty(&o->registry.exact_match.macs))
384762306a36Sopenharmony_ci			return 0;
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci		elem = kcalloc(len, sizeof(*elem), GFP_ATOMIC);
385062306a36Sopenharmony_ci		if (!elem) {
385162306a36Sopenharmony_ci			BNX2X_ERR("Failed to allocate registry memory\n");
385262306a36Sopenharmony_ci			return -ENOMEM;
385362306a36Sopenharmony_ci		}
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ci		for (i = 0; i < len; i++, elem++) {
385662306a36Sopenharmony_ci			bnx2x_get_fw_mac_addr(
385762306a36Sopenharmony_ci				&data->config_table[i].msb_mac_addr,
385862306a36Sopenharmony_ci				&data->config_table[i].middle_mac_addr,
385962306a36Sopenharmony_ci				&data->config_table[i].lsb_mac_addr,
386062306a36Sopenharmony_ci				elem->mac);
386162306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "Adding registry entry for [%pM]\n",
386262306a36Sopenharmony_ci			   elem->mac);
386362306a36Sopenharmony_ci			list_add_tail(&elem->link,
386462306a36Sopenharmony_ci				      &o->registry.exact_match.macs);
386562306a36Sopenharmony_ci		}
386662306a36Sopenharmony_ci	} else {
386762306a36Sopenharmony_ci		elem = list_first_entry(&o->registry.exact_match.macs,
386862306a36Sopenharmony_ci					struct bnx2x_mcast_mac_elem, link);
386962306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Deleting a registry\n");
387062306a36Sopenharmony_ci		kfree(elem);
387162306a36Sopenharmony_ci		INIT_LIST_HEAD(&o->registry.exact_match.macs);
387262306a36Sopenharmony_ci	}
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	return 0;
387562306a36Sopenharmony_ci}
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_cistatic int bnx2x_mcast_setup_e1(struct bnx2x *bp,
387862306a36Sopenharmony_ci				struct bnx2x_mcast_ramrod_params *p,
387962306a36Sopenharmony_ci				enum bnx2x_mcast_cmd cmd)
388062306a36Sopenharmony_ci{
388162306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
388262306a36Sopenharmony_ci	struct bnx2x_raw_obj *raw = &o->raw;
388362306a36Sopenharmony_ci	struct mac_configuration_cmd *data =
388462306a36Sopenharmony_ci		(struct mac_configuration_cmd *)(raw->rdata);
388562306a36Sopenharmony_ci	int cnt = 0, i, rc;
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	/* Reset the ramrod data buffer */
388862306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci	/* First set all entries as invalid */
389162306a36Sopenharmony_ci	for (i = 0; i < o->max_cmd_len ; i++)
389262306a36Sopenharmony_ci		SET_FLAG(data->config_table[i].flags,
389362306a36Sopenharmony_ci			 MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
389462306a36Sopenharmony_ci			 T_ETH_MAC_COMMAND_INVALIDATE);
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci	/* Handle pending commands first */
389762306a36Sopenharmony_ci	cnt = bnx2x_mcast_handle_pending_cmds_e1(bp, p);
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ci	/* If there are no more pending commands - clear SCHEDULED state */
390062306a36Sopenharmony_ci	if (list_empty(&o->pending_cmds_head))
390162306a36Sopenharmony_ci		o->clear_sched(o);
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	/* The below may be true iff there were no pending commands */
390462306a36Sopenharmony_ci	if (!cnt)
390562306a36Sopenharmony_ci		cnt = bnx2x_mcast_handle_current_cmd(bp, p, cmd, 0);
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci	/* For 57710 every command has o->max_cmd_len length to ensure that
390862306a36Sopenharmony_ci	 * commands are done one at a time.
390962306a36Sopenharmony_ci	 */
391062306a36Sopenharmony_ci	o->total_pending_num -= o->max_cmd_len;
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	/* send a ramrod */
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_ci	WARN_ON(cnt > o->max_cmd_len);
391562306a36Sopenharmony_ci
391662306a36Sopenharmony_ci	/* Set ramrod header (in particular, a number of entries to update) */
391762306a36Sopenharmony_ci	bnx2x_mcast_set_rdata_hdr_e1(bp, p, (u8)cnt);
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	/* update a registry: we need the registry contents to be always up
392062306a36Sopenharmony_ci	 * to date in order to be able to execute a RESTORE opcode. Here
392162306a36Sopenharmony_ci	 * we use the fact that for 57710 we sent one command at a time
392262306a36Sopenharmony_ci	 * hence we may take the registry update out of the command handling
392362306a36Sopenharmony_ci	 * and do it in a simpler way here.
392462306a36Sopenharmony_ci	 */
392562306a36Sopenharmony_ci	rc = bnx2x_mcast_refresh_registry_e1(bp, o);
392662306a36Sopenharmony_ci	if (rc)
392762306a36Sopenharmony_ci		return rc;
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	/* If CLEAR_ONLY was requested - don't send a ramrod and clear
393062306a36Sopenharmony_ci	 * RAMROD_PENDING status immediately.
393162306a36Sopenharmony_ci	 */
393262306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) {
393362306a36Sopenharmony_ci		raw->clear_pending(raw);
393462306a36Sopenharmony_ci		return 0;
393562306a36Sopenharmony_ci	} else {
393662306a36Sopenharmony_ci		/* No need for an explicit memory barrier here as long as we
393762306a36Sopenharmony_ci		 * ensure the ordering of writing to the SPQ element
393862306a36Sopenharmony_ci		 * and updating of the SPQ producer which involves a memory
393962306a36Sopenharmony_ci		 * read. If the memory read is removed we will have to put a
394062306a36Sopenharmony_ci		 * full memory barrier there (inside bnx2x_sp_post()).
394162306a36Sopenharmony_ci		 */
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci		/* Send a ramrod */
394462306a36Sopenharmony_ci		rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, raw->cid,
394562306a36Sopenharmony_ci				   U64_HI(raw->rdata_mapping),
394662306a36Sopenharmony_ci				   U64_LO(raw->rdata_mapping),
394762306a36Sopenharmony_ci				   ETH_CONNECTION_TYPE);
394862306a36Sopenharmony_ci		if (rc)
394962306a36Sopenharmony_ci			return rc;
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci		/* Ramrod completion is pending */
395262306a36Sopenharmony_ci		return 1;
395362306a36Sopenharmony_ci	}
395462306a36Sopenharmony_ci}
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_cistatic int bnx2x_mcast_get_registry_size_exact(struct bnx2x_mcast_obj *o)
395762306a36Sopenharmony_ci{
395862306a36Sopenharmony_ci	return o->registry.exact_match.num_macs_set;
395962306a36Sopenharmony_ci}
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_cistatic int bnx2x_mcast_get_registry_size_aprox(struct bnx2x_mcast_obj *o)
396262306a36Sopenharmony_ci{
396362306a36Sopenharmony_ci	return o->registry.aprox_match.num_bins_set;
396462306a36Sopenharmony_ci}
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_cistatic void bnx2x_mcast_set_registry_size_exact(struct bnx2x_mcast_obj *o,
396762306a36Sopenharmony_ci						int n)
396862306a36Sopenharmony_ci{
396962306a36Sopenharmony_ci	o->registry.exact_match.num_macs_set = n;
397062306a36Sopenharmony_ci}
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_cistatic void bnx2x_mcast_set_registry_size_aprox(struct bnx2x_mcast_obj *o,
397362306a36Sopenharmony_ci						int n)
397462306a36Sopenharmony_ci{
397562306a36Sopenharmony_ci	o->registry.aprox_match.num_bins_set = n;
397662306a36Sopenharmony_ci}
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ciint bnx2x_config_mcast(struct bnx2x *bp,
397962306a36Sopenharmony_ci		       struct bnx2x_mcast_ramrod_params *p,
398062306a36Sopenharmony_ci		       enum bnx2x_mcast_cmd cmd)
398162306a36Sopenharmony_ci{
398262306a36Sopenharmony_ci	struct bnx2x_mcast_obj *o = p->mcast_obj;
398362306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
398462306a36Sopenharmony_ci	int rc = 0, old_reg_size;
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	/* This is needed to recover number of currently configured mcast macs
398762306a36Sopenharmony_ci	 * in case of failure.
398862306a36Sopenharmony_ci	 */
398962306a36Sopenharmony_ci	old_reg_size = o->get_registry_size(o);
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci	/* Do some calculations and checks */
399262306a36Sopenharmony_ci	rc = o->validate(bp, p, cmd);
399362306a36Sopenharmony_ci	if (rc)
399462306a36Sopenharmony_ci		return rc;
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	/* Return if there is no work to do */
399762306a36Sopenharmony_ci	if ((!p->mcast_list_len) && (!o->check_sched(o)))
399862306a36Sopenharmony_ci		return 0;
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "o->total_pending_num=%d p->mcast_list_len=%d o->max_cmd_len=%d\n",
400162306a36Sopenharmony_ci	   o->total_pending_num, p->mcast_list_len, o->max_cmd_len);
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci	/* Enqueue the current command to the pending list if we can't complete
400462306a36Sopenharmony_ci	 * it in the current iteration
400562306a36Sopenharmony_ci	 */
400662306a36Sopenharmony_ci	if (r->check_pending(r) ||
400762306a36Sopenharmony_ci	    ((o->max_cmd_len > 0) && (o->total_pending_num > o->max_cmd_len))) {
400862306a36Sopenharmony_ci		rc = o->enqueue_cmd(bp, p->mcast_obj, p, cmd);
400962306a36Sopenharmony_ci		if (rc < 0)
401062306a36Sopenharmony_ci			goto error_exit1;
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci		/* As long as the current command is in a command list we
401362306a36Sopenharmony_ci		 * don't need to handle it separately.
401462306a36Sopenharmony_ci		 */
401562306a36Sopenharmony_ci		p->mcast_list_len = 0;
401662306a36Sopenharmony_ci	}
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_ci	if (!r->check_pending(r)) {
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci		/* Set 'pending' state */
402162306a36Sopenharmony_ci		r->set_pending(r);
402262306a36Sopenharmony_ci
402362306a36Sopenharmony_ci		/* Configure the new classification in the chip */
402462306a36Sopenharmony_ci		rc = o->config_mcast(bp, p, cmd);
402562306a36Sopenharmony_ci		if (rc < 0)
402662306a36Sopenharmony_ci			goto error_exit2;
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci		/* Wait for a ramrod completion if was requested */
402962306a36Sopenharmony_ci		if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags))
403062306a36Sopenharmony_ci			rc = o->wait_comp(bp, o);
403162306a36Sopenharmony_ci	}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci	return rc;
403462306a36Sopenharmony_ci
403562306a36Sopenharmony_cierror_exit2:
403662306a36Sopenharmony_ci	r->clear_pending(r);
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_cierror_exit1:
403962306a36Sopenharmony_ci	o->revert(bp, p, old_reg_size, cmd);
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci	return rc;
404262306a36Sopenharmony_ci}
404362306a36Sopenharmony_ci
404462306a36Sopenharmony_cistatic void bnx2x_mcast_clear_sched(struct bnx2x_mcast_obj *o)
404562306a36Sopenharmony_ci{
404662306a36Sopenharmony_ci	smp_mb__before_atomic();
404762306a36Sopenharmony_ci	clear_bit(o->sched_state, o->raw.pstate);
404862306a36Sopenharmony_ci	smp_mb__after_atomic();
404962306a36Sopenharmony_ci}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_cistatic void bnx2x_mcast_set_sched(struct bnx2x_mcast_obj *o)
405262306a36Sopenharmony_ci{
405362306a36Sopenharmony_ci	smp_mb__before_atomic();
405462306a36Sopenharmony_ci	set_bit(o->sched_state, o->raw.pstate);
405562306a36Sopenharmony_ci	smp_mb__after_atomic();
405662306a36Sopenharmony_ci}
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_cistatic bool bnx2x_mcast_check_sched(struct bnx2x_mcast_obj *o)
405962306a36Sopenharmony_ci{
406062306a36Sopenharmony_ci	return !!test_bit(o->sched_state, o->raw.pstate);
406162306a36Sopenharmony_ci}
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_cistatic bool bnx2x_mcast_check_pending(struct bnx2x_mcast_obj *o)
406462306a36Sopenharmony_ci{
406562306a36Sopenharmony_ci	return o->raw.check_pending(&o->raw) || o->check_sched(o);
406662306a36Sopenharmony_ci}
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_civoid bnx2x_init_mcast_obj(struct bnx2x *bp,
406962306a36Sopenharmony_ci			  struct bnx2x_mcast_obj *mcast_obj,
407062306a36Sopenharmony_ci			  u8 mcast_cl_id, u32 mcast_cid, u8 func_id,
407162306a36Sopenharmony_ci			  u8 engine_id, void *rdata, dma_addr_t rdata_mapping,
407262306a36Sopenharmony_ci			  int state, unsigned long *pstate, bnx2x_obj_type type)
407362306a36Sopenharmony_ci{
407462306a36Sopenharmony_ci	memset(mcast_obj, 0, sizeof(*mcast_obj));
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	bnx2x_init_raw_obj(&mcast_obj->raw, mcast_cl_id, mcast_cid, func_id,
407762306a36Sopenharmony_ci			   rdata, rdata_mapping, state, pstate, type);
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	mcast_obj->engine_id = engine_id;
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ci	INIT_LIST_HEAD(&mcast_obj->pending_cmds_head);
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	mcast_obj->sched_state = BNX2X_FILTER_MCAST_SCHED;
408462306a36Sopenharmony_ci	mcast_obj->check_sched = bnx2x_mcast_check_sched;
408562306a36Sopenharmony_ci	mcast_obj->set_sched = bnx2x_mcast_set_sched;
408662306a36Sopenharmony_ci	mcast_obj->clear_sched = bnx2x_mcast_clear_sched;
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	if (CHIP_IS_E1(bp)) {
408962306a36Sopenharmony_ci		mcast_obj->config_mcast      = bnx2x_mcast_setup_e1;
409062306a36Sopenharmony_ci		mcast_obj->enqueue_cmd       = bnx2x_mcast_enqueue_cmd;
409162306a36Sopenharmony_ci		mcast_obj->hdl_restore       =
409262306a36Sopenharmony_ci			bnx2x_mcast_handle_restore_cmd_e1;
409362306a36Sopenharmony_ci		mcast_obj->check_pending     = bnx2x_mcast_check_pending;
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_ci		if (CHIP_REV_IS_SLOW(bp))
409662306a36Sopenharmony_ci			mcast_obj->max_cmd_len = BNX2X_MAX_EMUL_MULTI;
409762306a36Sopenharmony_ci		else
409862306a36Sopenharmony_ci			mcast_obj->max_cmd_len = BNX2X_MAX_MULTICAST;
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_ci		mcast_obj->wait_comp         = bnx2x_mcast_wait;
410162306a36Sopenharmony_ci		mcast_obj->set_one_rule      = bnx2x_mcast_set_one_rule_e1;
410262306a36Sopenharmony_ci		mcast_obj->validate          = bnx2x_mcast_validate_e1;
410362306a36Sopenharmony_ci		mcast_obj->revert            = bnx2x_mcast_revert_e1;
410462306a36Sopenharmony_ci		mcast_obj->get_registry_size =
410562306a36Sopenharmony_ci			bnx2x_mcast_get_registry_size_exact;
410662306a36Sopenharmony_ci		mcast_obj->set_registry_size =
410762306a36Sopenharmony_ci			bnx2x_mcast_set_registry_size_exact;
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_ci		/* 57710 is the only chip that uses the exact match for mcast
411062306a36Sopenharmony_ci		 * at the moment.
411162306a36Sopenharmony_ci		 */
411262306a36Sopenharmony_ci		INIT_LIST_HEAD(&mcast_obj->registry.exact_match.macs);
411362306a36Sopenharmony_ci
411462306a36Sopenharmony_ci	} else if (CHIP_IS_E1H(bp)) {
411562306a36Sopenharmony_ci		mcast_obj->config_mcast  = bnx2x_mcast_setup_e1h;
411662306a36Sopenharmony_ci		mcast_obj->enqueue_cmd   = NULL;
411762306a36Sopenharmony_ci		mcast_obj->hdl_restore   = NULL;
411862306a36Sopenharmony_ci		mcast_obj->check_pending = bnx2x_mcast_check_pending;
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci		/* 57711 doesn't send a ramrod, so it has unlimited credit
412162306a36Sopenharmony_ci		 * for one command.
412262306a36Sopenharmony_ci		 */
412362306a36Sopenharmony_ci		mcast_obj->max_cmd_len       = -1;
412462306a36Sopenharmony_ci		mcast_obj->wait_comp         = bnx2x_mcast_wait;
412562306a36Sopenharmony_ci		mcast_obj->set_one_rule      = NULL;
412662306a36Sopenharmony_ci		mcast_obj->validate          = bnx2x_mcast_validate_e1h;
412762306a36Sopenharmony_ci		mcast_obj->revert            = bnx2x_mcast_revert_e1h;
412862306a36Sopenharmony_ci		mcast_obj->get_registry_size =
412962306a36Sopenharmony_ci			bnx2x_mcast_get_registry_size_aprox;
413062306a36Sopenharmony_ci		mcast_obj->set_registry_size =
413162306a36Sopenharmony_ci			bnx2x_mcast_set_registry_size_aprox;
413262306a36Sopenharmony_ci	} else {
413362306a36Sopenharmony_ci		mcast_obj->config_mcast      = bnx2x_mcast_setup_e2;
413462306a36Sopenharmony_ci		mcast_obj->enqueue_cmd       = bnx2x_mcast_enqueue_cmd;
413562306a36Sopenharmony_ci		mcast_obj->hdl_restore       =
413662306a36Sopenharmony_ci			bnx2x_mcast_handle_restore_cmd_e2;
413762306a36Sopenharmony_ci		mcast_obj->check_pending     = bnx2x_mcast_check_pending;
413862306a36Sopenharmony_ci		/* TODO: There should be a proper HSI define for this number!!!
413962306a36Sopenharmony_ci		 */
414062306a36Sopenharmony_ci		mcast_obj->max_cmd_len       = 16;
414162306a36Sopenharmony_ci		mcast_obj->wait_comp         = bnx2x_mcast_wait;
414262306a36Sopenharmony_ci		mcast_obj->set_one_rule      = bnx2x_mcast_set_one_rule_e2;
414362306a36Sopenharmony_ci		mcast_obj->validate          = bnx2x_mcast_validate_e2;
414462306a36Sopenharmony_ci		mcast_obj->revert            = bnx2x_mcast_revert_e2;
414562306a36Sopenharmony_ci		mcast_obj->get_registry_size =
414662306a36Sopenharmony_ci			bnx2x_mcast_get_registry_size_aprox;
414762306a36Sopenharmony_ci		mcast_obj->set_registry_size =
414862306a36Sopenharmony_ci			bnx2x_mcast_set_registry_size_aprox;
414962306a36Sopenharmony_ci	}
415062306a36Sopenharmony_ci}
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci/*************************** Credit handling **********************************/
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci/**
415562306a36Sopenharmony_ci * __atomic_add_ifless - add if the result is less than a given value.
415662306a36Sopenharmony_ci *
415762306a36Sopenharmony_ci * @v:	pointer of type atomic_t
415862306a36Sopenharmony_ci * @a:	the amount to add to v...
415962306a36Sopenharmony_ci * @u:	...if (v + a) is less than u.
416062306a36Sopenharmony_ci *
416162306a36Sopenharmony_ci * returns true if (v + a) was less than u, and false otherwise.
416262306a36Sopenharmony_ci *
416362306a36Sopenharmony_ci */
416462306a36Sopenharmony_cistatic inline bool __atomic_add_ifless(atomic_t *v, int a, int u)
416562306a36Sopenharmony_ci{
416662306a36Sopenharmony_ci	int c, old;
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci	c = atomic_read(v);
416962306a36Sopenharmony_ci	for (;;) {
417062306a36Sopenharmony_ci		if (unlikely(c + a >= u))
417162306a36Sopenharmony_ci			return false;
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_ci		old = atomic_cmpxchg((v), c, c + a);
417462306a36Sopenharmony_ci		if (likely(old == c))
417562306a36Sopenharmony_ci			break;
417662306a36Sopenharmony_ci		c = old;
417762306a36Sopenharmony_ci	}
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci	return true;
418062306a36Sopenharmony_ci}
418162306a36Sopenharmony_ci
418262306a36Sopenharmony_ci/**
418362306a36Sopenharmony_ci * __atomic_dec_ifmoe - dec if the result is more or equal than a given value.
418462306a36Sopenharmony_ci *
418562306a36Sopenharmony_ci * @v:	pointer of type atomic_t
418662306a36Sopenharmony_ci * @a:	the amount to dec from v...
418762306a36Sopenharmony_ci * @u:	...if (v - a) is more or equal than u.
418862306a36Sopenharmony_ci *
418962306a36Sopenharmony_ci * returns true if (v - a) was more or equal than u, and false
419062306a36Sopenharmony_ci * otherwise.
419162306a36Sopenharmony_ci */
419262306a36Sopenharmony_cistatic inline bool __atomic_dec_ifmoe(atomic_t *v, int a, int u)
419362306a36Sopenharmony_ci{
419462306a36Sopenharmony_ci	int c, old;
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci	c = atomic_read(v);
419762306a36Sopenharmony_ci	for (;;) {
419862306a36Sopenharmony_ci		if (unlikely(c - a < u))
419962306a36Sopenharmony_ci			return false;
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci		old = atomic_cmpxchg((v), c, c - a);
420262306a36Sopenharmony_ci		if (likely(old == c))
420362306a36Sopenharmony_ci			break;
420462306a36Sopenharmony_ci		c = old;
420562306a36Sopenharmony_ci	}
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_ci	return true;
420862306a36Sopenharmony_ci}
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_cistatic bool bnx2x_credit_pool_get(struct bnx2x_credit_pool_obj *o, int cnt)
421162306a36Sopenharmony_ci{
421262306a36Sopenharmony_ci	bool rc;
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_ci	smp_mb();
421562306a36Sopenharmony_ci	rc = __atomic_dec_ifmoe(&o->credit, cnt, 0);
421662306a36Sopenharmony_ci	smp_mb();
421762306a36Sopenharmony_ci
421862306a36Sopenharmony_ci	return rc;
421962306a36Sopenharmony_ci}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_cistatic bool bnx2x_credit_pool_put(struct bnx2x_credit_pool_obj *o, int cnt)
422262306a36Sopenharmony_ci{
422362306a36Sopenharmony_ci	bool rc;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	smp_mb();
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	/* Don't let to refill if credit + cnt > pool_sz */
422862306a36Sopenharmony_ci	rc = __atomic_add_ifless(&o->credit, cnt, o->pool_sz + 1);
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_ci	smp_mb();
423162306a36Sopenharmony_ci
423262306a36Sopenharmony_ci	return rc;
423362306a36Sopenharmony_ci}
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_cistatic int bnx2x_credit_pool_check(struct bnx2x_credit_pool_obj *o)
423662306a36Sopenharmony_ci{
423762306a36Sopenharmony_ci	int cur_credit;
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci	smp_mb();
424062306a36Sopenharmony_ci	cur_credit = atomic_read(&o->credit);
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	return cur_credit;
424362306a36Sopenharmony_ci}
424462306a36Sopenharmony_ci
424562306a36Sopenharmony_cistatic bool bnx2x_credit_pool_always_true(struct bnx2x_credit_pool_obj *o,
424662306a36Sopenharmony_ci					  int cnt)
424762306a36Sopenharmony_ci{
424862306a36Sopenharmony_ci	return true;
424962306a36Sopenharmony_ci}
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_cistatic bool bnx2x_credit_pool_get_entry(
425262306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *o,
425362306a36Sopenharmony_ci	int *offset)
425462306a36Sopenharmony_ci{
425562306a36Sopenharmony_ci	int idx, vec, i;
425662306a36Sopenharmony_ci
425762306a36Sopenharmony_ci	*offset = -1;
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_ci	/* Find "internal cam-offset" then add to base for this object... */
426062306a36Sopenharmony_ci	for (vec = 0; vec < BNX2X_POOL_VEC_SIZE; vec++) {
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci		/* Skip the current vector if there are no free entries in it */
426362306a36Sopenharmony_ci		if (!o->pool_mirror[vec])
426462306a36Sopenharmony_ci			continue;
426562306a36Sopenharmony_ci
426662306a36Sopenharmony_ci		/* If we've got here we are going to find a free entry */
426762306a36Sopenharmony_ci		for (idx = vec * BIT_VEC64_ELEM_SZ, i = 0;
426862306a36Sopenharmony_ci		      i < BIT_VEC64_ELEM_SZ; idx++, i++)
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci			if (BIT_VEC64_TEST_BIT(o->pool_mirror, idx)) {
427162306a36Sopenharmony_ci				/* Got one!! */
427262306a36Sopenharmony_ci				BIT_VEC64_CLEAR_BIT(o->pool_mirror, idx);
427362306a36Sopenharmony_ci				*offset = o->base_pool_offset + idx;
427462306a36Sopenharmony_ci				return true;
427562306a36Sopenharmony_ci			}
427662306a36Sopenharmony_ci	}
427762306a36Sopenharmony_ci
427862306a36Sopenharmony_ci	return false;
427962306a36Sopenharmony_ci}
428062306a36Sopenharmony_ci
428162306a36Sopenharmony_cistatic bool bnx2x_credit_pool_put_entry(
428262306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *o,
428362306a36Sopenharmony_ci	int offset)
428462306a36Sopenharmony_ci{
428562306a36Sopenharmony_ci	if (offset < o->base_pool_offset)
428662306a36Sopenharmony_ci		return false;
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	offset -= o->base_pool_offset;
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci	if (offset >= o->pool_sz)
429162306a36Sopenharmony_ci		return false;
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci	/* Return the entry to the pool */
429462306a36Sopenharmony_ci	BIT_VEC64_SET_BIT(o->pool_mirror, offset);
429562306a36Sopenharmony_ci
429662306a36Sopenharmony_ci	return true;
429762306a36Sopenharmony_ci}
429862306a36Sopenharmony_ci
429962306a36Sopenharmony_cistatic bool bnx2x_credit_pool_put_entry_always_true(
430062306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *o,
430162306a36Sopenharmony_ci	int offset)
430262306a36Sopenharmony_ci{
430362306a36Sopenharmony_ci	return true;
430462306a36Sopenharmony_ci}
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_cistatic bool bnx2x_credit_pool_get_entry_always_true(
430762306a36Sopenharmony_ci	struct bnx2x_credit_pool_obj *o,
430862306a36Sopenharmony_ci	int *offset)
430962306a36Sopenharmony_ci{
431062306a36Sopenharmony_ci	*offset = -1;
431162306a36Sopenharmony_ci	return true;
431262306a36Sopenharmony_ci}
431362306a36Sopenharmony_ci/**
431462306a36Sopenharmony_ci * bnx2x_init_credit_pool - initialize credit pool internals.
431562306a36Sopenharmony_ci *
431662306a36Sopenharmony_ci * @p:		credit pool
431762306a36Sopenharmony_ci * @base:	Base entry in the CAM to use.
431862306a36Sopenharmony_ci * @credit:	pool size.
431962306a36Sopenharmony_ci *
432062306a36Sopenharmony_ci * If base is negative no CAM entries handling will be performed.
432162306a36Sopenharmony_ci * If credit is negative pool operations will always succeed (unlimited pool).
432262306a36Sopenharmony_ci *
432362306a36Sopenharmony_ci */
432462306a36Sopenharmony_civoid bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p,
432562306a36Sopenharmony_ci			    int base, int credit)
432662306a36Sopenharmony_ci{
432762306a36Sopenharmony_ci	/* Zero the object first */
432862306a36Sopenharmony_ci	memset(p, 0, sizeof(*p));
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci	/* Set the table to all 1s */
433162306a36Sopenharmony_ci	memset(&p->pool_mirror, 0xff, sizeof(p->pool_mirror));
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	/* Init a pool as full */
433462306a36Sopenharmony_ci	atomic_set(&p->credit, credit);
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	/* The total poll size */
433762306a36Sopenharmony_ci	p->pool_sz = credit;
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci	p->base_pool_offset = base;
434062306a36Sopenharmony_ci
434162306a36Sopenharmony_ci	/* Commit the change */
434262306a36Sopenharmony_ci	smp_mb();
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_ci	p->check = bnx2x_credit_pool_check;
434562306a36Sopenharmony_ci
434662306a36Sopenharmony_ci	/* if pool credit is negative - disable the checks */
434762306a36Sopenharmony_ci	if (credit >= 0) {
434862306a36Sopenharmony_ci		p->put      = bnx2x_credit_pool_put;
434962306a36Sopenharmony_ci		p->get      = bnx2x_credit_pool_get;
435062306a36Sopenharmony_ci		p->put_entry = bnx2x_credit_pool_put_entry;
435162306a36Sopenharmony_ci		p->get_entry = bnx2x_credit_pool_get_entry;
435262306a36Sopenharmony_ci	} else {
435362306a36Sopenharmony_ci		p->put      = bnx2x_credit_pool_always_true;
435462306a36Sopenharmony_ci		p->get      = bnx2x_credit_pool_always_true;
435562306a36Sopenharmony_ci		p->put_entry = bnx2x_credit_pool_put_entry_always_true;
435662306a36Sopenharmony_ci		p->get_entry = bnx2x_credit_pool_get_entry_always_true;
435762306a36Sopenharmony_ci	}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	/* If base is negative - disable entries handling */
436062306a36Sopenharmony_ci	if (base < 0) {
436162306a36Sopenharmony_ci		p->put_entry = bnx2x_credit_pool_put_entry_always_true;
436262306a36Sopenharmony_ci		p->get_entry = bnx2x_credit_pool_get_entry_always_true;
436362306a36Sopenharmony_ci	}
436462306a36Sopenharmony_ci}
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_civoid bnx2x_init_mac_credit_pool(struct bnx2x *bp,
436762306a36Sopenharmony_ci				struct bnx2x_credit_pool_obj *p, u8 func_id,
436862306a36Sopenharmony_ci				u8 func_num)
436962306a36Sopenharmony_ci{
437062306a36Sopenharmony_ci/* TODO: this will be defined in consts as well... */
437162306a36Sopenharmony_ci#define BNX2X_CAM_SIZE_EMUL 5
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	int cam_sz;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	if (CHIP_IS_E1(bp)) {
437662306a36Sopenharmony_ci		/* In E1, Multicast is saved in cam... */
437762306a36Sopenharmony_ci		if (!CHIP_REV_IS_SLOW(bp))
437862306a36Sopenharmony_ci			cam_sz = (MAX_MAC_CREDIT_E1 / 2) - BNX2X_MAX_MULTICAST;
437962306a36Sopenharmony_ci		else
438062306a36Sopenharmony_ci			cam_sz = BNX2X_CAM_SIZE_EMUL - BNX2X_MAX_EMUL_MULTI;
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci		bnx2x_init_credit_pool(p, func_id * cam_sz, cam_sz);
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	} else if (CHIP_IS_E1H(bp)) {
438562306a36Sopenharmony_ci		/* CAM credit is equaly divided between all active functions
438662306a36Sopenharmony_ci		 * on the PORT!.
438762306a36Sopenharmony_ci		 */
438862306a36Sopenharmony_ci		if ((func_num > 0)) {
438962306a36Sopenharmony_ci			if (!CHIP_REV_IS_SLOW(bp))
439062306a36Sopenharmony_ci				cam_sz = (MAX_MAC_CREDIT_E1H / (2*func_num));
439162306a36Sopenharmony_ci			else
439262306a36Sopenharmony_ci				cam_sz = BNX2X_CAM_SIZE_EMUL;
439362306a36Sopenharmony_ci			bnx2x_init_credit_pool(p, func_id * cam_sz, cam_sz);
439462306a36Sopenharmony_ci		} else {
439562306a36Sopenharmony_ci			/* this should never happen! Block MAC operations. */
439662306a36Sopenharmony_ci			bnx2x_init_credit_pool(p, 0, 0);
439762306a36Sopenharmony_ci		}
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_ci	} else {
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci		/* CAM credit is equaly divided between all active functions
440262306a36Sopenharmony_ci		 * on the PATH.
440362306a36Sopenharmony_ci		 */
440462306a36Sopenharmony_ci		if (func_num > 0) {
440562306a36Sopenharmony_ci			if (!CHIP_REV_IS_SLOW(bp))
440662306a36Sopenharmony_ci				cam_sz = PF_MAC_CREDIT_E2(bp, func_num);
440762306a36Sopenharmony_ci			else
440862306a36Sopenharmony_ci				cam_sz = BNX2X_CAM_SIZE_EMUL;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci			/* No need for CAM entries handling for 57712 and
441162306a36Sopenharmony_ci			 * newer.
441262306a36Sopenharmony_ci			 */
441362306a36Sopenharmony_ci			bnx2x_init_credit_pool(p, -1, cam_sz);
441462306a36Sopenharmony_ci		} else {
441562306a36Sopenharmony_ci			/* this should never happen! Block MAC operations. */
441662306a36Sopenharmony_ci			bnx2x_init_credit_pool(p, 0, 0);
441762306a36Sopenharmony_ci		}
441862306a36Sopenharmony_ci	}
441962306a36Sopenharmony_ci}
442062306a36Sopenharmony_ci
442162306a36Sopenharmony_civoid bnx2x_init_vlan_credit_pool(struct bnx2x *bp,
442262306a36Sopenharmony_ci				 struct bnx2x_credit_pool_obj *p,
442362306a36Sopenharmony_ci				 u8 func_id,
442462306a36Sopenharmony_ci				 u8 func_num)
442562306a36Sopenharmony_ci{
442662306a36Sopenharmony_ci	if (CHIP_IS_E1x(bp)) {
442762306a36Sopenharmony_ci		/* There is no VLAN credit in HW on 57710 and 57711 only
442862306a36Sopenharmony_ci		 * MAC / MAC-VLAN can be set
442962306a36Sopenharmony_ci		 */
443062306a36Sopenharmony_ci		bnx2x_init_credit_pool(p, 0, -1);
443162306a36Sopenharmony_ci	} else {
443262306a36Sopenharmony_ci		/* CAM credit is equally divided between all active functions
443362306a36Sopenharmony_ci		 * on the PATH.
443462306a36Sopenharmony_ci		 */
443562306a36Sopenharmony_ci		if (func_num > 0) {
443662306a36Sopenharmony_ci			int credit = PF_VLAN_CREDIT_E2(bp, func_num);
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_ci			bnx2x_init_credit_pool(p, -1/*unused for E2*/, credit);
443962306a36Sopenharmony_ci		} else
444062306a36Sopenharmony_ci			/* this should never happen! Block VLAN operations. */
444162306a36Sopenharmony_ci			bnx2x_init_credit_pool(p, 0, 0);
444262306a36Sopenharmony_ci	}
444362306a36Sopenharmony_ci}
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci/****************** RSS Configuration ******************/
444662306a36Sopenharmony_ci/**
444762306a36Sopenharmony_ci * bnx2x_debug_print_ind_table - prints the indirection table configuration.
444862306a36Sopenharmony_ci *
444962306a36Sopenharmony_ci * @bp:		driver handle
445062306a36Sopenharmony_ci * @p:		pointer to rss configuration
445162306a36Sopenharmony_ci *
445262306a36Sopenharmony_ci * Prints it when NETIF_MSG_IFUP debug level is configured.
445362306a36Sopenharmony_ci */
445462306a36Sopenharmony_cistatic inline void bnx2x_debug_print_ind_table(struct bnx2x *bp,
445562306a36Sopenharmony_ci					struct bnx2x_config_rss_params *p)
445662306a36Sopenharmony_ci{
445762306a36Sopenharmony_ci	int i;
445862306a36Sopenharmony_ci
445962306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Setting indirection table to:\n");
446062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "0x0000: ");
446162306a36Sopenharmony_ci	for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
446262306a36Sopenharmony_ci		DP_CONT(BNX2X_MSG_SP, "0x%02x ", p->ind_table[i]);
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci		/* Print 4 bytes in a line */
446562306a36Sopenharmony_ci		if ((i + 1 < T_ETH_INDIRECTION_TABLE_SIZE) &&
446662306a36Sopenharmony_ci		    (((i + 1) & 0x3) == 0)) {
446762306a36Sopenharmony_ci			DP_CONT(BNX2X_MSG_SP, "\n");
446862306a36Sopenharmony_ci			DP(BNX2X_MSG_SP, "0x%04x: ", i + 1);
446962306a36Sopenharmony_ci		}
447062306a36Sopenharmony_ci	}
447162306a36Sopenharmony_ci
447262306a36Sopenharmony_ci	DP_CONT(BNX2X_MSG_SP, "\n");
447362306a36Sopenharmony_ci}
447462306a36Sopenharmony_ci
447562306a36Sopenharmony_ci/**
447662306a36Sopenharmony_ci * bnx2x_setup_rss - configure RSS
447762306a36Sopenharmony_ci *
447862306a36Sopenharmony_ci * @bp:		device handle
447962306a36Sopenharmony_ci * @p:		rss configuration
448062306a36Sopenharmony_ci *
448162306a36Sopenharmony_ci * sends on UPDATE ramrod for that matter.
448262306a36Sopenharmony_ci */
448362306a36Sopenharmony_cistatic int bnx2x_setup_rss(struct bnx2x *bp,
448462306a36Sopenharmony_ci			   struct bnx2x_config_rss_params *p)
448562306a36Sopenharmony_ci{
448662306a36Sopenharmony_ci	struct bnx2x_rss_config_obj *o = p->rss_obj;
448762306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
448862306a36Sopenharmony_ci	struct eth_rss_update_ramrod_data *data =
448962306a36Sopenharmony_ci		(struct eth_rss_update_ramrod_data *)(r->rdata);
449062306a36Sopenharmony_ci	u16 caps = 0;
449162306a36Sopenharmony_ci	u8 rss_mode = 0;
449262306a36Sopenharmony_ci	int rc;
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Configuring RSS\n");
449762306a36Sopenharmony_ci
449862306a36Sopenharmony_ci	/* Set an echo field */
449962306a36Sopenharmony_ci	data->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
450062306a36Sopenharmony_ci				 (r->state << BNX2X_SWCID_SHIFT));
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	/* RSS mode */
450362306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_MODE_DISABLED, &p->rss_flags))
450462306a36Sopenharmony_ci		rss_mode = ETH_RSS_MODE_DISABLED;
450562306a36Sopenharmony_ci	else if (test_bit(BNX2X_RSS_MODE_REGULAR, &p->rss_flags))
450662306a36Sopenharmony_ci		rss_mode = ETH_RSS_MODE_REGULAR;
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	data->rss_mode = rss_mode;
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "rss_mode=%d\n", rss_mode);
451162306a36Sopenharmony_ci
451262306a36Sopenharmony_ci	/* RSS capabilities */
451362306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV4, &p->rss_flags))
451462306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY;
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV4_TCP, &p->rss_flags))
451762306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
451862306a36Sopenharmony_ci
451962306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags))
452062306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
452162306a36Sopenharmony_ci
452262306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags))
452362306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV6_TCP, &p->rss_flags))
452662306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
452762306a36Sopenharmony_ci
452862306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags))
452962306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
453062306a36Sopenharmony_ci
453162306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV4_VXLAN, &p->rss_flags))
453262306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY;
453362306a36Sopenharmony_ci
453462306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_IPV6_VXLAN, &p->rss_flags))
453562306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY;
453662306a36Sopenharmony_ci
453762306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_TUNN_INNER_HDRS, &p->rss_flags))
453862306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY;
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci	/* RSS keys */
454162306a36Sopenharmony_ci	if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) {
454262306a36Sopenharmony_ci		u8 *dst = (u8 *)(data->rss_key) + sizeof(data->rss_key);
454362306a36Sopenharmony_ci		const u8 *src = (const u8 *)p->rss_key;
454462306a36Sopenharmony_ci		int i;
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci		/* Apparently, bnx2x reads this array in reverse order
454762306a36Sopenharmony_ci		 * We need to byte swap rss_key to comply with Toeplitz specs.
454862306a36Sopenharmony_ci		 */
454962306a36Sopenharmony_ci		for (i = 0; i < sizeof(data->rss_key); i++)
455062306a36Sopenharmony_ci			*--dst = *src++;
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci		caps |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
455362306a36Sopenharmony_ci	}
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci	data->capabilities = cpu_to_le16(caps);
455662306a36Sopenharmony_ci
455762306a36Sopenharmony_ci	/* Hashing mask */
455862306a36Sopenharmony_ci	data->rss_result_mask = p->rss_result_mask;
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	/* RSS engine ID */
456162306a36Sopenharmony_ci	data->rss_engine_id = o->engine_id;
456262306a36Sopenharmony_ci
456362306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "rss_engine_id=%d\n", data->rss_engine_id);
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	/* Indirection table */
456662306a36Sopenharmony_ci	memcpy(data->indirection_table, p->ind_table,
456762306a36Sopenharmony_ci		  T_ETH_INDIRECTION_TABLE_SIZE);
456862306a36Sopenharmony_ci
456962306a36Sopenharmony_ci	/* Remember the last configuration */
457062306a36Sopenharmony_ci	memcpy(o->ind_table, p->ind_table, T_ETH_INDIRECTION_TABLE_SIZE);
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci	/* Print the indirection table */
457362306a36Sopenharmony_ci	if (netif_msg_ifup(bp))
457462306a36Sopenharmony_ci		bnx2x_debug_print_ind_table(bp, p);
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
457762306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
457862306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
457962306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
458062306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
458162306a36Sopenharmony_ci	 */
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_ci	/* Send a ramrod */
458462306a36Sopenharmony_ci	rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_RSS_UPDATE, r->cid,
458562306a36Sopenharmony_ci			   U64_HI(r->rdata_mapping),
458662306a36Sopenharmony_ci			   U64_LO(r->rdata_mapping),
458762306a36Sopenharmony_ci			   ETH_CONNECTION_TYPE);
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	if (rc < 0)
459062306a36Sopenharmony_ci		return rc;
459162306a36Sopenharmony_ci
459262306a36Sopenharmony_ci	return 1;
459362306a36Sopenharmony_ci}
459462306a36Sopenharmony_ci
459562306a36Sopenharmony_civoid bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj,
459662306a36Sopenharmony_ci			     u8 *ind_table)
459762306a36Sopenharmony_ci{
459862306a36Sopenharmony_ci	memcpy(ind_table, rss_obj->ind_table, sizeof(rss_obj->ind_table));
459962306a36Sopenharmony_ci}
460062306a36Sopenharmony_ci
460162306a36Sopenharmony_ciint bnx2x_config_rss(struct bnx2x *bp,
460262306a36Sopenharmony_ci		     struct bnx2x_config_rss_params *p)
460362306a36Sopenharmony_ci{
460462306a36Sopenharmony_ci	int rc;
460562306a36Sopenharmony_ci	struct bnx2x_rss_config_obj *o = p->rss_obj;
460662306a36Sopenharmony_ci	struct bnx2x_raw_obj *r = &o->raw;
460762306a36Sopenharmony_ci
460862306a36Sopenharmony_ci	/* Do nothing if only driver cleanup was requested */
460962306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) {
461062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Not configuring RSS ramrod_flags=%lx\n",
461162306a36Sopenharmony_ci		   p->ramrod_flags);
461262306a36Sopenharmony_ci		return 0;
461362306a36Sopenharmony_ci	}
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci	r->set_pending(r);
461662306a36Sopenharmony_ci
461762306a36Sopenharmony_ci	rc = o->config_rss(bp, p);
461862306a36Sopenharmony_ci	if (rc < 0) {
461962306a36Sopenharmony_ci		r->clear_pending(r);
462062306a36Sopenharmony_ci		return rc;
462162306a36Sopenharmony_ci	}
462262306a36Sopenharmony_ci
462362306a36Sopenharmony_ci	if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags))
462462306a36Sopenharmony_ci		rc = r->wait_comp(bp, r);
462562306a36Sopenharmony_ci
462662306a36Sopenharmony_ci	return rc;
462762306a36Sopenharmony_ci}
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_civoid bnx2x_init_rss_config_obj(struct bnx2x *bp,
463062306a36Sopenharmony_ci			       struct bnx2x_rss_config_obj *rss_obj,
463162306a36Sopenharmony_ci			       u8 cl_id, u32 cid, u8 func_id, u8 engine_id,
463262306a36Sopenharmony_ci			       void *rdata, dma_addr_t rdata_mapping,
463362306a36Sopenharmony_ci			       int state, unsigned long *pstate,
463462306a36Sopenharmony_ci			       bnx2x_obj_type type)
463562306a36Sopenharmony_ci{
463662306a36Sopenharmony_ci	bnx2x_init_raw_obj(&rss_obj->raw, cl_id, cid, func_id, rdata,
463762306a36Sopenharmony_ci			   rdata_mapping, state, pstate, type);
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci	rss_obj->engine_id  = engine_id;
464062306a36Sopenharmony_ci	rss_obj->config_rss = bnx2x_setup_rss;
464162306a36Sopenharmony_ci}
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_ci/********************** Queue state object ***********************************/
464462306a36Sopenharmony_ci
464562306a36Sopenharmony_ci/**
464662306a36Sopenharmony_ci * bnx2x_queue_state_change - perform Queue state change transition
464762306a36Sopenharmony_ci *
464862306a36Sopenharmony_ci * @bp:		device handle
464962306a36Sopenharmony_ci * @params:	parameters to perform the transition
465062306a36Sopenharmony_ci *
465162306a36Sopenharmony_ci * returns 0 in case of successfully completed transition, negative error
465262306a36Sopenharmony_ci * code in case of failure, positive (EBUSY) value if there is a completion
465362306a36Sopenharmony_ci * to that is still pending (possible only if RAMROD_COMP_WAIT is
465462306a36Sopenharmony_ci * not set in params->ramrod_flags for asynchronous commands).
465562306a36Sopenharmony_ci *
465662306a36Sopenharmony_ci */
465762306a36Sopenharmony_ciint bnx2x_queue_state_change(struct bnx2x *bp,
465862306a36Sopenharmony_ci			     struct bnx2x_queue_state_params *params)
465962306a36Sopenharmony_ci{
466062306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
466162306a36Sopenharmony_ci	int rc, pending_bit;
466262306a36Sopenharmony_ci	unsigned long *pending = &o->pending;
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_ci	/* Check that the requested transition is legal */
466562306a36Sopenharmony_ci	rc = o->check_transition(bp, o, params);
466662306a36Sopenharmony_ci	if (rc) {
466762306a36Sopenharmony_ci		BNX2X_ERR("check transition returned an error. rc %d\n", rc);
466862306a36Sopenharmony_ci		return -EINVAL;
466962306a36Sopenharmony_ci	}
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	/* Set "pending" bit */
467262306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "pending bit was=%lx\n", o->pending);
467362306a36Sopenharmony_ci	pending_bit = o->set_pending(o, params);
467462306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "pending bit now=%lx\n", o->pending);
467562306a36Sopenharmony_ci
467662306a36Sopenharmony_ci	/* Don't send a command if only driver cleanup was requested */
467762306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags))
467862306a36Sopenharmony_ci		o->complete_cmd(bp, o, pending_bit);
467962306a36Sopenharmony_ci	else {
468062306a36Sopenharmony_ci		/* Send a ramrod */
468162306a36Sopenharmony_ci		rc = o->send_cmd(bp, params);
468262306a36Sopenharmony_ci		if (rc) {
468362306a36Sopenharmony_ci			o->next_state = BNX2X_Q_STATE_MAX;
468462306a36Sopenharmony_ci			clear_bit(pending_bit, pending);
468562306a36Sopenharmony_ci			smp_mb__after_atomic();
468662306a36Sopenharmony_ci			return rc;
468762306a36Sopenharmony_ci		}
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ci		if (test_bit(RAMROD_COMP_WAIT, &params->ramrod_flags)) {
469062306a36Sopenharmony_ci			rc = o->wait_comp(bp, o, pending_bit);
469162306a36Sopenharmony_ci			if (rc)
469262306a36Sopenharmony_ci				return rc;
469362306a36Sopenharmony_ci
469462306a36Sopenharmony_ci			return 0;
469562306a36Sopenharmony_ci		}
469662306a36Sopenharmony_ci	}
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_ci	return !!test_bit(pending_bit, pending);
469962306a36Sopenharmony_ci}
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_cistatic int bnx2x_queue_set_pending(struct bnx2x_queue_sp_obj *obj,
470262306a36Sopenharmony_ci				   struct bnx2x_queue_state_params *params)
470362306a36Sopenharmony_ci{
470462306a36Sopenharmony_ci	enum bnx2x_queue_cmd cmd = params->cmd, bit;
470562306a36Sopenharmony_ci
470662306a36Sopenharmony_ci	/* ACTIVATE and DEACTIVATE commands are implemented on top of
470762306a36Sopenharmony_ci	 * UPDATE command.
470862306a36Sopenharmony_ci	 */
470962306a36Sopenharmony_ci	if ((cmd == BNX2X_Q_CMD_ACTIVATE) ||
471062306a36Sopenharmony_ci	    (cmd == BNX2X_Q_CMD_DEACTIVATE))
471162306a36Sopenharmony_ci		bit = BNX2X_Q_CMD_UPDATE;
471262306a36Sopenharmony_ci	else
471362306a36Sopenharmony_ci		bit = cmd;
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_ci	set_bit(bit, &obj->pending);
471662306a36Sopenharmony_ci	return bit;
471762306a36Sopenharmony_ci}
471862306a36Sopenharmony_ci
471962306a36Sopenharmony_cistatic int bnx2x_queue_wait_comp(struct bnx2x *bp,
472062306a36Sopenharmony_ci				 struct bnx2x_queue_sp_obj *o,
472162306a36Sopenharmony_ci				 enum bnx2x_queue_cmd cmd)
472262306a36Sopenharmony_ci{
472362306a36Sopenharmony_ci	return bnx2x_state_wait(bp, cmd, &o->pending);
472462306a36Sopenharmony_ci}
472562306a36Sopenharmony_ci
472662306a36Sopenharmony_ci/**
472762306a36Sopenharmony_ci * bnx2x_queue_comp_cmd - complete the state change command.
472862306a36Sopenharmony_ci *
472962306a36Sopenharmony_ci * @bp:		device handle
473062306a36Sopenharmony_ci * @o:		queue info
473162306a36Sopenharmony_ci * @cmd:	command to exec
473262306a36Sopenharmony_ci *
473362306a36Sopenharmony_ci * Checks that the arrived completion is expected.
473462306a36Sopenharmony_ci */
473562306a36Sopenharmony_cistatic int bnx2x_queue_comp_cmd(struct bnx2x *bp,
473662306a36Sopenharmony_ci				struct bnx2x_queue_sp_obj *o,
473762306a36Sopenharmony_ci				enum bnx2x_queue_cmd cmd)
473862306a36Sopenharmony_ci{
473962306a36Sopenharmony_ci	unsigned long cur_pending = o->pending;
474062306a36Sopenharmony_ci
474162306a36Sopenharmony_ci	if (!test_and_clear_bit(cmd, &cur_pending)) {
474262306a36Sopenharmony_ci		BNX2X_ERR("Bad MC reply %d for queue %d in state %d pending 0x%lx, next_state %d\n",
474362306a36Sopenharmony_ci			  cmd, o->cids[BNX2X_PRIMARY_CID_INDEX],
474462306a36Sopenharmony_ci			  o->state, cur_pending, o->next_state);
474562306a36Sopenharmony_ci		return -EINVAL;
474662306a36Sopenharmony_ci	}
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci	if (o->next_tx_only >= o->max_cos)
474962306a36Sopenharmony_ci		/* >= because tx only must always be smaller than cos since the
475062306a36Sopenharmony_ci		 * primary connection supports COS 0
475162306a36Sopenharmony_ci		 */
475262306a36Sopenharmony_ci		BNX2X_ERR("illegal value for next tx_only: %d. max cos was %d",
475362306a36Sopenharmony_ci			   o->next_tx_only, o->max_cos);
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ci	DP(BNX2X_MSG_SP,
475662306a36Sopenharmony_ci	   "Completing command %d for queue %d, setting state to %d\n",
475762306a36Sopenharmony_ci	   cmd, o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_state);
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_ci	if (o->next_tx_only)  /* print num tx-only if any exist */
476062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "primary cid %d: num tx-only cons %d\n",
476162306a36Sopenharmony_ci		   o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_tx_only);
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	o->state = o->next_state;
476462306a36Sopenharmony_ci	o->num_tx_only = o->next_tx_only;
476562306a36Sopenharmony_ci	o->next_state = BNX2X_Q_STATE_MAX;
476662306a36Sopenharmony_ci
476762306a36Sopenharmony_ci	/* It's important that o->state and o->next_state are
476862306a36Sopenharmony_ci	 * updated before o->pending.
476962306a36Sopenharmony_ci	 */
477062306a36Sopenharmony_ci	wmb();
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci	clear_bit(cmd, &o->pending);
477362306a36Sopenharmony_ci	smp_mb__after_atomic();
477462306a36Sopenharmony_ci
477562306a36Sopenharmony_ci	return 0;
477662306a36Sopenharmony_ci}
477762306a36Sopenharmony_ci
477862306a36Sopenharmony_cistatic void bnx2x_q_fill_setup_data_e2(struct bnx2x *bp,
477962306a36Sopenharmony_ci				struct bnx2x_queue_state_params *cmd_params,
478062306a36Sopenharmony_ci				struct client_init_ramrod_data *data)
478162306a36Sopenharmony_ci{
478262306a36Sopenharmony_ci	struct bnx2x_queue_setup_params *params = &cmd_params->params.setup;
478362306a36Sopenharmony_ci
478462306a36Sopenharmony_ci	/* Rx data */
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci	/* IPv6 TPA supported for E2 and above only */
478762306a36Sopenharmony_ci	data->rx.tpa_en |= test_bit(BNX2X_Q_FLG_TPA_IPV6, &params->flags) *
478862306a36Sopenharmony_ci				CLIENT_INIT_RX_DATA_TPA_EN_IPV6;
478962306a36Sopenharmony_ci}
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_cistatic void bnx2x_q_fill_init_general_data(struct bnx2x *bp,
479262306a36Sopenharmony_ci				struct bnx2x_queue_sp_obj *o,
479362306a36Sopenharmony_ci				struct bnx2x_general_setup_params *params,
479462306a36Sopenharmony_ci				struct client_init_general_data *gen_data,
479562306a36Sopenharmony_ci				unsigned long *flags)
479662306a36Sopenharmony_ci{
479762306a36Sopenharmony_ci	gen_data->client_id = o->cl_id;
479862306a36Sopenharmony_ci
479962306a36Sopenharmony_ci	if (test_bit(BNX2X_Q_FLG_STATS, flags)) {
480062306a36Sopenharmony_ci		gen_data->statistics_counter_id =
480162306a36Sopenharmony_ci					params->stat_id;
480262306a36Sopenharmony_ci		gen_data->statistics_en_flg = 1;
480362306a36Sopenharmony_ci		gen_data->statistics_zero_flg =
480462306a36Sopenharmony_ci			test_bit(BNX2X_Q_FLG_ZERO_STATS, flags);
480562306a36Sopenharmony_ci	} else
480662306a36Sopenharmony_ci		gen_data->statistics_counter_id =
480762306a36Sopenharmony_ci					DISABLE_STATISTIC_COUNTER_ID_VALUE;
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ci	gen_data->is_fcoe_flg = test_bit(BNX2X_Q_FLG_FCOE, flags);
481062306a36Sopenharmony_ci	gen_data->activate_flg = test_bit(BNX2X_Q_FLG_ACTIVE, flags);
481162306a36Sopenharmony_ci	gen_data->sp_client_id = params->spcl_id;
481262306a36Sopenharmony_ci	gen_data->mtu = cpu_to_le16(params->mtu);
481362306a36Sopenharmony_ci	gen_data->func_id = o->func_id;
481462306a36Sopenharmony_ci
481562306a36Sopenharmony_ci	gen_data->cos = params->cos;
481662306a36Sopenharmony_ci
481762306a36Sopenharmony_ci	gen_data->traffic_type =
481862306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_FCOE, flags) ?
481962306a36Sopenharmony_ci		LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW;
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci	gen_data->fp_hsi_ver = params->fp_hsi;
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d\n",
482462306a36Sopenharmony_ci	   gen_data->activate_flg, gen_data->cos, gen_data->statistics_en_flg);
482562306a36Sopenharmony_ci}
482662306a36Sopenharmony_ci
482762306a36Sopenharmony_cistatic void bnx2x_q_fill_init_tx_data(struct bnx2x_queue_sp_obj *o,
482862306a36Sopenharmony_ci				struct bnx2x_txq_setup_params *params,
482962306a36Sopenharmony_ci				struct client_init_tx_data *tx_data,
483062306a36Sopenharmony_ci				unsigned long *flags)
483162306a36Sopenharmony_ci{
483262306a36Sopenharmony_ci	tx_data->enforce_security_flg =
483362306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_TX_SEC, flags);
483462306a36Sopenharmony_ci	tx_data->default_vlan =
483562306a36Sopenharmony_ci		cpu_to_le16(params->default_vlan);
483662306a36Sopenharmony_ci	tx_data->default_vlan_flg =
483762306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_DEF_VLAN, flags);
483862306a36Sopenharmony_ci	tx_data->tx_switching_flg =
483962306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_TX_SWITCH, flags);
484062306a36Sopenharmony_ci	tx_data->anti_spoofing_flg =
484162306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_ANTI_SPOOF, flags);
484262306a36Sopenharmony_ci	tx_data->force_default_pri_flg =
484362306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_FORCE_DEFAULT_PRI, flags);
484462306a36Sopenharmony_ci	tx_data->refuse_outband_vlan_flg =
484562306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_REFUSE_OUTBAND_VLAN, flags);
484662306a36Sopenharmony_ci	tx_data->tunnel_lso_inc_ip_id =
484762306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, flags);
484862306a36Sopenharmony_ci	tx_data->tunnel_non_lso_pcsum_location =
484962306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? CSUM_ON_PKT :
485062306a36Sopenharmony_ci							    CSUM_ON_BD;
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_ci	tx_data->tx_status_block_id = params->fw_sb_id;
485362306a36Sopenharmony_ci	tx_data->tx_sb_index_number = params->sb_cq_index;
485462306a36Sopenharmony_ci	tx_data->tss_leading_client_id = params->tss_leading_cl_id;
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_ci	tx_data->tx_bd_page_base.lo =
485762306a36Sopenharmony_ci		cpu_to_le32(U64_LO(params->dscr_map));
485862306a36Sopenharmony_ci	tx_data->tx_bd_page_base.hi =
485962306a36Sopenharmony_ci		cpu_to_le32(U64_HI(params->dscr_map));
486062306a36Sopenharmony_ci
486162306a36Sopenharmony_ci	/* Don't configure any Tx switching mode during queue SETUP */
486262306a36Sopenharmony_ci	tx_data->state = 0;
486362306a36Sopenharmony_ci}
486462306a36Sopenharmony_ci
486562306a36Sopenharmony_cistatic void bnx2x_q_fill_init_pause_data(struct bnx2x_queue_sp_obj *o,
486662306a36Sopenharmony_ci				struct rxq_pause_params *params,
486762306a36Sopenharmony_ci				struct client_init_rx_data *rx_data)
486862306a36Sopenharmony_ci{
486962306a36Sopenharmony_ci	/* flow control data */
487062306a36Sopenharmony_ci	rx_data->cqe_pause_thr_low = cpu_to_le16(params->rcq_th_lo);
487162306a36Sopenharmony_ci	rx_data->cqe_pause_thr_high = cpu_to_le16(params->rcq_th_hi);
487262306a36Sopenharmony_ci	rx_data->bd_pause_thr_low = cpu_to_le16(params->bd_th_lo);
487362306a36Sopenharmony_ci	rx_data->bd_pause_thr_high = cpu_to_le16(params->bd_th_hi);
487462306a36Sopenharmony_ci	rx_data->sge_pause_thr_low = cpu_to_le16(params->sge_th_lo);
487562306a36Sopenharmony_ci	rx_data->sge_pause_thr_high = cpu_to_le16(params->sge_th_hi);
487662306a36Sopenharmony_ci	rx_data->rx_cos_mask = cpu_to_le16(params->pri_map);
487762306a36Sopenharmony_ci}
487862306a36Sopenharmony_ci
487962306a36Sopenharmony_cistatic void bnx2x_q_fill_init_rx_data(struct bnx2x_queue_sp_obj *o,
488062306a36Sopenharmony_ci				struct bnx2x_rxq_setup_params *params,
488162306a36Sopenharmony_ci				struct client_init_rx_data *rx_data,
488262306a36Sopenharmony_ci				unsigned long *flags)
488362306a36Sopenharmony_ci{
488462306a36Sopenharmony_ci	rx_data->tpa_en = test_bit(BNX2X_Q_FLG_TPA, flags) *
488562306a36Sopenharmony_ci				CLIENT_INIT_RX_DATA_TPA_EN_IPV4;
488662306a36Sopenharmony_ci	rx_data->tpa_en |= test_bit(BNX2X_Q_FLG_TPA_GRO, flags) *
488762306a36Sopenharmony_ci				CLIENT_INIT_RX_DATA_TPA_MODE;
488862306a36Sopenharmony_ci	rx_data->vmqueue_mode_en_flg = 0;
488962306a36Sopenharmony_ci
489062306a36Sopenharmony_ci	rx_data->cache_line_alignment_log_size =
489162306a36Sopenharmony_ci		params->cache_line_log;
489262306a36Sopenharmony_ci	rx_data->enable_dynamic_hc =
489362306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_DHC, flags);
489462306a36Sopenharmony_ci	rx_data->max_sges_for_packet = params->max_sges_pkt;
489562306a36Sopenharmony_ci	rx_data->client_qzone_id = params->cl_qzone_id;
489662306a36Sopenharmony_ci	rx_data->max_agg_size = cpu_to_le16(params->tpa_agg_sz);
489762306a36Sopenharmony_ci
489862306a36Sopenharmony_ci	/* Always start in DROP_ALL mode */
489962306a36Sopenharmony_ci	rx_data->state = cpu_to_le16(CLIENT_INIT_RX_DATA_UCAST_DROP_ALL |
490062306a36Sopenharmony_ci				     CLIENT_INIT_RX_DATA_MCAST_DROP_ALL);
490162306a36Sopenharmony_ci
490262306a36Sopenharmony_ci	/* We don't set drop flags */
490362306a36Sopenharmony_ci	rx_data->drop_ip_cs_err_flg = 0;
490462306a36Sopenharmony_ci	rx_data->drop_tcp_cs_err_flg = 0;
490562306a36Sopenharmony_ci	rx_data->drop_ttl0_flg = 0;
490662306a36Sopenharmony_ci	rx_data->drop_udp_cs_err_flg = 0;
490762306a36Sopenharmony_ci	rx_data->inner_vlan_removal_enable_flg =
490862306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_VLAN, flags);
490962306a36Sopenharmony_ci	rx_data->outer_vlan_removal_enable_flg =
491062306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_OV, flags);
491162306a36Sopenharmony_ci	rx_data->status_block_id = params->fw_sb_id;
491262306a36Sopenharmony_ci	rx_data->rx_sb_index_number = params->sb_cq_index;
491362306a36Sopenharmony_ci	rx_data->max_tpa_queues = params->max_tpa_queues;
491462306a36Sopenharmony_ci	rx_data->max_bytes_on_bd = cpu_to_le16(params->buf_sz);
491562306a36Sopenharmony_ci	rx_data->sge_buff_size = cpu_to_le16(params->sge_buf_sz);
491662306a36Sopenharmony_ci	rx_data->bd_page_base.lo =
491762306a36Sopenharmony_ci		cpu_to_le32(U64_LO(params->dscr_map));
491862306a36Sopenharmony_ci	rx_data->bd_page_base.hi =
491962306a36Sopenharmony_ci		cpu_to_le32(U64_HI(params->dscr_map));
492062306a36Sopenharmony_ci	rx_data->sge_page_base.lo =
492162306a36Sopenharmony_ci		cpu_to_le32(U64_LO(params->sge_map));
492262306a36Sopenharmony_ci	rx_data->sge_page_base.hi =
492362306a36Sopenharmony_ci		cpu_to_le32(U64_HI(params->sge_map));
492462306a36Sopenharmony_ci	rx_data->cqe_page_base.lo =
492562306a36Sopenharmony_ci		cpu_to_le32(U64_LO(params->rcq_map));
492662306a36Sopenharmony_ci	rx_data->cqe_page_base.hi =
492762306a36Sopenharmony_ci		cpu_to_le32(U64_HI(params->rcq_map));
492862306a36Sopenharmony_ci	rx_data->is_leading_rss = test_bit(BNX2X_Q_FLG_LEADING_RSS, flags);
492962306a36Sopenharmony_ci
493062306a36Sopenharmony_ci	if (test_bit(BNX2X_Q_FLG_MCAST, flags)) {
493162306a36Sopenharmony_ci		rx_data->approx_mcast_engine_id = params->mcast_engine_id;
493262306a36Sopenharmony_ci		rx_data->is_approx_mcast = 1;
493362306a36Sopenharmony_ci	}
493462306a36Sopenharmony_ci
493562306a36Sopenharmony_ci	rx_data->rss_engine_id = params->rss_engine_id;
493662306a36Sopenharmony_ci
493762306a36Sopenharmony_ci	/* silent vlan removal */
493862306a36Sopenharmony_ci	rx_data->silent_vlan_removal_flg =
493962306a36Sopenharmony_ci		test_bit(BNX2X_Q_FLG_SILENT_VLAN_REM, flags);
494062306a36Sopenharmony_ci	rx_data->silent_vlan_value =
494162306a36Sopenharmony_ci		cpu_to_le16(params->silent_removal_value);
494262306a36Sopenharmony_ci	rx_data->silent_vlan_mask =
494362306a36Sopenharmony_ci		cpu_to_le16(params->silent_removal_mask);
494462306a36Sopenharmony_ci}
494562306a36Sopenharmony_ci
494662306a36Sopenharmony_ci/* initialize the general, tx and rx parts of a queue object */
494762306a36Sopenharmony_cistatic void bnx2x_q_fill_setup_data_cmn(struct bnx2x *bp,
494862306a36Sopenharmony_ci				struct bnx2x_queue_state_params *cmd_params,
494962306a36Sopenharmony_ci				struct client_init_ramrod_data *data)
495062306a36Sopenharmony_ci{
495162306a36Sopenharmony_ci	bnx2x_q_fill_init_general_data(bp, cmd_params->q_obj,
495262306a36Sopenharmony_ci				       &cmd_params->params.setup.gen_params,
495362306a36Sopenharmony_ci				       &data->general,
495462306a36Sopenharmony_ci				       &cmd_params->params.setup.flags);
495562306a36Sopenharmony_ci
495662306a36Sopenharmony_ci	bnx2x_q_fill_init_tx_data(cmd_params->q_obj,
495762306a36Sopenharmony_ci				  &cmd_params->params.setup.txq_params,
495862306a36Sopenharmony_ci				  &data->tx,
495962306a36Sopenharmony_ci				  &cmd_params->params.setup.flags);
496062306a36Sopenharmony_ci
496162306a36Sopenharmony_ci	bnx2x_q_fill_init_rx_data(cmd_params->q_obj,
496262306a36Sopenharmony_ci				  &cmd_params->params.setup.rxq_params,
496362306a36Sopenharmony_ci				  &data->rx,
496462306a36Sopenharmony_ci				  &cmd_params->params.setup.flags);
496562306a36Sopenharmony_ci
496662306a36Sopenharmony_ci	bnx2x_q_fill_init_pause_data(cmd_params->q_obj,
496762306a36Sopenharmony_ci				     &cmd_params->params.setup.pause_params,
496862306a36Sopenharmony_ci				     &data->rx);
496962306a36Sopenharmony_ci}
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_ci/* initialize the general and tx parts of a tx-only queue object */
497262306a36Sopenharmony_cistatic void bnx2x_q_fill_setup_tx_only(struct bnx2x *bp,
497362306a36Sopenharmony_ci				struct bnx2x_queue_state_params *cmd_params,
497462306a36Sopenharmony_ci				struct tx_queue_init_ramrod_data *data)
497562306a36Sopenharmony_ci{
497662306a36Sopenharmony_ci	bnx2x_q_fill_init_general_data(bp, cmd_params->q_obj,
497762306a36Sopenharmony_ci				       &cmd_params->params.tx_only.gen_params,
497862306a36Sopenharmony_ci				       &data->general,
497962306a36Sopenharmony_ci				       &cmd_params->params.tx_only.flags);
498062306a36Sopenharmony_ci
498162306a36Sopenharmony_ci	bnx2x_q_fill_init_tx_data(cmd_params->q_obj,
498262306a36Sopenharmony_ci				  &cmd_params->params.tx_only.txq_params,
498362306a36Sopenharmony_ci				  &data->tx,
498462306a36Sopenharmony_ci				  &cmd_params->params.tx_only.flags);
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "cid %d, tx bd page lo %x hi %x",
498762306a36Sopenharmony_ci			 cmd_params->q_obj->cids[0],
498862306a36Sopenharmony_ci			 data->tx.tx_bd_page_base.lo,
498962306a36Sopenharmony_ci			 data->tx.tx_bd_page_base.hi);
499062306a36Sopenharmony_ci}
499162306a36Sopenharmony_ci
499262306a36Sopenharmony_ci/**
499362306a36Sopenharmony_ci * bnx2x_q_init - init HW/FW queue
499462306a36Sopenharmony_ci *
499562306a36Sopenharmony_ci * @bp:		device handle
499662306a36Sopenharmony_ci * @params:
499762306a36Sopenharmony_ci *
499862306a36Sopenharmony_ci * HW/FW initial Queue configuration:
499962306a36Sopenharmony_ci *      - HC: Rx and Tx
500062306a36Sopenharmony_ci *      - CDU context validation
500162306a36Sopenharmony_ci *
500262306a36Sopenharmony_ci */
500362306a36Sopenharmony_cistatic inline int bnx2x_q_init(struct bnx2x *bp,
500462306a36Sopenharmony_ci			       struct bnx2x_queue_state_params *params)
500562306a36Sopenharmony_ci{
500662306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
500762306a36Sopenharmony_ci	struct bnx2x_queue_init_params *init = &params->params.init;
500862306a36Sopenharmony_ci	u16 hc_usec;
500962306a36Sopenharmony_ci	u8 cos;
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	/* Tx HC configuration */
501262306a36Sopenharmony_ci	if (test_bit(BNX2X_Q_TYPE_HAS_TX, &o->type) &&
501362306a36Sopenharmony_ci	    test_bit(BNX2X_Q_FLG_HC, &init->tx.flags)) {
501462306a36Sopenharmony_ci		hc_usec = init->tx.hc_rate ? 1000000 / init->tx.hc_rate : 0;
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_ci		bnx2x_update_coalesce_sb_index(bp, init->tx.fw_sb_id,
501762306a36Sopenharmony_ci			init->tx.sb_cq_index,
501862306a36Sopenharmony_ci			!test_bit(BNX2X_Q_FLG_HC_EN, &init->tx.flags),
501962306a36Sopenharmony_ci			hc_usec);
502062306a36Sopenharmony_ci	}
502162306a36Sopenharmony_ci
502262306a36Sopenharmony_ci	/* Rx HC configuration */
502362306a36Sopenharmony_ci	if (test_bit(BNX2X_Q_TYPE_HAS_RX, &o->type) &&
502462306a36Sopenharmony_ci	    test_bit(BNX2X_Q_FLG_HC, &init->rx.flags)) {
502562306a36Sopenharmony_ci		hc_usec = init->rx.hc_rate ? 1000000 / init->rx.hc_rate : 0;
502662306a36Sopenharmony_ci
502762306a36Sopenharmony_ci		bnx2x_update_coalesce_sb_index(bp, init->rx.fw_sb_id,
502862306a36Sopenharmony_ci			init->rx.sb_cq_index,
502962306a36Sopenharmony_ci			!test_bit(BNX2X_Q_FLG_HC_EN, &init->rx.flags),
503062306a36Sopenharmony_ci			hc_usec);
503162306a36Sopenharmony_ci	}
503262306a36Sopenharmony_ci
503362306a36Sopenharmony_ci	/* Set CDU context validation values */
503462306a36Sopenharmony_ci	for (cos = 0; cos < o->max_cos; cos++) {
503562306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "setting context validation. cid %d, cos %d\n",
503662306a36Sopenharmony_ci				 o->cids[cos], cos);
503762306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "context pointer %p\n", init->cxts[cos]);
503862306a36Sopenharmony_ci		bnx2x_set_ctx_validation(bp, init->cxts[cos], o->cids[cos]);
503962306a36Sopenharmony_ci	}
504062306a36Sopenharmony_ci
504162306a36Sopenharmony_ci	/* As no ramrod is sent, complete the command immediately  */
504262306a36Sopenharmony_ci	o->complete_cmd(bp, o, BNX2X_Q_CMD_INIT);
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	smp_mb();
504562306a36Sopenharmony_ci
504662306a36Sopenharmony_ci	return 0;
504762306a36Sopenharmony_ci}
504862306a36Sopenharmony_ci
504962306a36Sopenharmony_cistatic inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp,
505062306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
505162306a36Sopenharmony_ci{
505262306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
505362306a36Sopenharmony_ci	struct client_init_ramrod_data *rdata =
505462306a36Sopenharmony_ci		(struct client_init_ramrod_data *)o->rdata;
505562306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
505662306a36Sopenharmony_ci	int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP;
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	/* Clear the ramrod data */
505962306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_ci	/* Fill the ramrod data */
506262306a36Sopenharmony_ci	bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
506362306a36Sopenharmony_ci
506462306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
506562306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
506662306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
506762306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
506862306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
506962306a36Sopenharmony_ci	 */
507062306a36Sopenharmony_ci	return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
507162306a36Sopenharmony_ci			     U64_HI(data_mapping),
507262306a36Sopenharmony_ci			     U64_LO(data_mapping), ETH_CONNECTION_TYPE);
507362306a36Sopenharmony_ci}
507462306a36Sopenharmony_ci
507562306a36Sopenharmony_cistatic inline int bnx2x_q_send_setup_e2(struct bnx2x *bp,
507662306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
507762306a36Sopenharmony_ci{
507862306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
507962306a36Sopenharmony_ci	struct client_init_ramrod_data *rdata =
508062306a36Sopenharmony_ci		(struct client_init_ramrod_data *)o->rdata;
508162306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
508262306a36Sopenharmony_ci	int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP;
508362306a36Sopenharmony_ci
508462306a36Sopenharmony_ci	/* Clear the ramrod data */
508562306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
508662306a36Sopenharmony_ci
508762306a36Sopenharmony_ci	/* Fill the ramrod data */
508862306a36Sopenharmony_ci	bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
508962306a36Sopenharmony_ci	bnx2x_q_fill_setup_data_e2(bp, params, rdata);
509062306a36Sopenharmony_ci
509162306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
509262306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
509362306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
509462306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
509562306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
509662306a36Sopenharmony_ci	 */
509762306a36Sopenharmony_ci	return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
509862306a36Sopenharmony_ci			     U64_HI(data_mapping),
509962306a36Sopenharmony_ci			     U64_LO(data_mapping), ETH_CONNECTION_TYPE);
510062306a36Sopenharmony_ci}
510162306a36Sopenharmony_ci
510262306a36Sopenharmony_cistatic inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
510362306a36Sopenharmony_ci				  struct bnx2x_queue_state_params *params)
510462306a36Sopenharmony_ci{
510562306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
510662306a36Sopenharmony_ci	struct tx_queue_init_ramrod_data *rdata =
510762306a36Sopenharmony_ci		(struct tx_queue_init_ramrod_data *)o->rdata;
510862306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
510962306a36Sopenharmony_ci	int ramrod = RAMROD_CMD_ID_ETH_TX_QUEUE_SETUP;
511062306a36Sopenharmony_ci	struct bnx2x_queue_setup_tx_only_params *tx_only_params =
511162306a36Sopenharmony_ci		&params->params.tx_only;
511262306a36Sopenharmony_ci	u8 cid_index = tx_only_params->cid_index;
511362306a36Sopenharmony_ci
511462306a36Sopenharmony_ci	if (cid_index >= o->max_cos) {
511562306a36Sopenharmony_ci		BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n",
511662306a36Sopenharmony_ci			  o->cl_id, cid_index);
511762306a36Sopenharmony_ci		return -EINVAL;
511862306a36Sopenharmony_ci	}
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "parameters received: cos: %d sp-id: %d\n",
512162306a36Sopenharmony_ci			 tx_only_params->gen_params.cos,
512262306a36Sopenharmony_ci			 tx_only_params->gen_params.spcl_id);
512362306a36Sopenharmony_ci
512462306a36Sopenharmony_ci	/* Clear the ramrod data */
512562306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
512662306a36Sopenharmony_ci
512762306a36Sopenharmony_ci	/* Fill the ramrod data */
512862306a36Sopenharmony_ci	bnx2x_q_fill_setup_tx_only(bp, params, rdata);
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "sending tx-only ramrod: cid %d, client-id %d, sp-client id %d, cos %d\n",
513162306a36Sopenharmony_ci			 o->cids[cid_index], rdata->general.client_id,
513262306a36Sopenharmony_ci			 rdata->general.sp_client_id, rdata->general.cos);
513362306a36Sopenharmony_ci
513462306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
513562306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
513662306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
513762306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
513862306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
513962306a36Sopenharmony_ci	 */
514062306a36Sopenharmony_ci	return bnx2x_sp_post(bp, ramrod, o->cids[cid_index],
514162306a36Sopenharmony_ci			     U64_HI(data_mapping),
514262306a36Sopenharmony_ci			     U64_LO(data_mapping), ETH_CONNECTION_TYPE);
514362306a36Sopenharmony_ci}
514462306a36Sopenharmony_ci
514562306a36Sopenharmony_cistatic void bnx2x_q_fill_update_data(struct bnx2x *bp,
514662306a36Sopenharmony_ci				     struct bnx2x_queue_sp_obj *obj,
514762306a36Sopenharmony_ci				     struct bnx2x_queue_update_params *params,
514862306a36Sopenharmony_ci				     struct client_update_ramrod_data *data)
514962306a36Sopenharmony_ci{
515062306a36Sopenharmony_ci	/* Client ID of the client to update */
515162306a36Sopenharmony_ci	data->client_id = obj->cl_id;
515262306a36Sopenharmony_ci
515362306a36Sopenharmony_ci	/* Function ID of the client to update */
515462306a36Sopenharmony_ci	data->func_id = obj->func_id;
515562306a36Sopenharmony_ci
515662306a36Sopenharmony_ci	/* Default VLAN value */
515762306a36Sopenharmony_ci	data->default_vlan = cpu_to_le16(params->def_vlan);
515862306a36Sopenharmony_ci
515962306a36Sopenharmony_ci	/* Inner VLAN stripping */
516062306a36Sopenharmony_ci	data->inner_vlan_removal_enable_flg =
516162306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM, &params->update_flags);
516262306a36Sopenharmony_ci	data->inner_vlan_removal_change_flg =
516362306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM_CHNG,
516462306a36Sopenharmony_ci			 &params->update_flags);
516562306a36Sopenharmony_ci
516662306a36Sopenharmony_ci	/* Outer VLAN stripping */
516762306a36Sopenharmony_ci	data->outer_vlan_removal_enable_flg =
516862306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM, &params->update_flags);
516962306a36Sopenharmony_ci	data->outer_vlan_removal_change_flg =
517062306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM_CHNG,
517162306a36Sopenharmony_ci			 &params->update_flags);
517262306a36Sopenharmony_ci
517362306a36Sopenharmony_ci	/* Drop packets that have source MAC that doesn't belong to this
517462306a36Sopenharmony_ci	 * Queue.
517562306a36Sopenharmony_ci	 */
517662306a36Sopenharmony_ci	data->anti_spoofing_enable_flg =
517762306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF, &params->update_flags);
517862306a36Sopenharmony_ci	data->anti_spoofing_change_flg =
517962306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG, &params->update_flags);
518062306a36Sopenharmony_ci
518162306a36Sopenharmony_ci	/* Activate/Deactivate */
518262306a36Sopenharmony_ci	data->activate_flg =
518362306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_ACTIVATE, &params->update_flags);
518462306a36Sopenharmony_ci	data->activate_change_flg =
518562306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &params->update_flags);
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	/* Enable default VLAN */
518862306a36Sopenharmony_ci	data->default_vlan_enable_flg =
518962306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, &params->update_flags);
519062306a36Sopenharmony_ci	data->default_vlan_change_flg =
519162306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG,
519262306a36Sopenharmony_ci			 &params->update_flags);
519362306a36Sopenharmony_ci
519462306a36Sopenharmony_ci	/* silent vlan removal */
519562306a36Sopenharmony_ci	data->silent_vlan_change_flg =
519662306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
519762306a36Sopenharmony_ci			 &params->update_flags);
519862306a36Sopenharmony_ci	data->silent_vlan_removal_flg =
519962306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, &params->update_flags);
520062306a36Sopenharmony_ci	data->silent_vlan_value = cpu_to_le16(params->silent_removal_value);
520162306a36Sopenharmony_ci	data->silent_vlan_mask = cpu_to_le16(params->silent_removal_mask);
520262306a36Sopenharmony_ci
520362306a36Sopenharmony_ci	/* tx switching */
520462306a36Sopenharmony_ci	data->tx_switching_flg =
520562306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_TX_SWITCHING, &params->update_flags);
520662306a36Sopenharmony_ci	data->tx_switching_change_flg =
520762306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
520862306a36Sopenharmony_ci			 &params->update_flags);
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci	/* PTP */
521162306a36Sopenharmony_ci	data->handle_ptp_pkts_flg =
521262306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_PTP_PKTS, &params->update_flags);
521362306a36Sopenharmony_ci	data->handle_ptp_pkts_change_flg =
521462306a36Sopenharmony_ci		test_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG, &params->update_flags);
521562306a36Sopenharmony_ci}
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_cistatic inline int bnx2x_q_send_update(struct bnx2x *bp,
521862306a36Sopenharmony_ci				      struct bnx2x_queue_state_params *params)
521962306a36Sopenharmony_ci{
522062306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
522162306a36Sopenharmony_ci	struct client_update_ramrod_data *rdata =
522262306a36Sopenharmony_ci		(struct client_update_ramrod_data *)o->rdata;
522362306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
522462306a36Sopenharmony_ci	struct bnx2x_queue_update_params *update_params =
522562306a36Sopenharmony_ci		&params->params.update;
522662306a36Sopenharmony_ci	u8 cid_index = update_params->cid_index;
522762306a36Sopenharmony_ci
522862306a36Sopenharmony_ci	if (cid_index >= o->max_cos) {
522962306a36Sopenharmony_ci		BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n",
523062306a36Sopenharmony_ci			  o->cl_id, cid_index);
523162306a36Sopenharmony_ci		return -EINVAL;
523262306a36Sopenharmony_ci	}
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_ci	/* Clear the ramrod data */
523562306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
523662306a36Sopenharmony_ci
523762306a36Sopenharmony_ci	/* Fill the ramrod data */
523862306a36Sopenharmony_ci	bnx2x_q_fill_update_data(bp, o, update_params, rdata);
523962306a36Sopenharmony_ci
524062306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
524162306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
524262306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
524362306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
524462306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
524562306a36Sopenharmony_ci	 */
524662306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE,
524762306a36Sopenharmony_ci			     o->cids[cid_index], U64_HI(data_mapping),
524862306a36Sopenharmony_ci			     U64_LO(data_mapping), ETH_CONNECTION_TYPE);
524962306a36Sopenharmony_ci}
525062306a36Sopenharmony_ci
525162306a36Sopenharmony_ci/**
525262306a36Sopenharmony_ci * bnx2x_q_send_deactivate - send DEACTIVATE command
525362306a36Sopenharmony_ci *
525462306a36Sopenharmony_ci * @bp:		device handle
525562306a36Sopenharmony_ci * @params:
525662306a36Sopenharmony_ci *
525762306a36Sopenharmony_ci * implemented using the UPDATE command.
525862306a36Sopenharmony_ci */
525962306a36Sopenharmony_cistatic inline int bnx2x_q_send_deactivate(struct bnx2x *bp,
526062306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
526162306a36Sopenharmony_ci{
526262306a36Sopenharmony_ci	struct bnx2x_queue_update_params *update = &params->params.update;
526362306a36Sopenharmony_ci
526462306a36Sopenharmony_ci	memset(update, 0, sizeof(*update));
526562306a36Sopenharmony_ci
526662306a36Sopenharmony_ci	__set_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &update->update_flags);
526762306a36Sopenharmony_ci
526862306a36Sopenharmony_ci	return bnx2x_q_send_update(bp, params);
526962306a36Sopenharmony_ci}
527062306a36Sopenharmony_ci
527162306a36Sopenharmony_ci/**
527262306a36Sopenharmony_ci * bnx2x_q_send_activate - send ACTIVATE command
527362306a36Sopenharmony_ci *
527462306a36Sopenharmony_ci * @bp:		device handle
527562306a36Sopenharmony_ci * @params:
527662306a36Sopenharmony_ci *
527762306a36Sopenharmony_ci * implemented using the UPDATE command.
527862306a36Sopenharmony_ci */
527962306a36Sopenharmony_cistatic inline int bnx2x_q_send_activate(struct bnx2x *bp,
528062306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
528162306a36Sopenharmony_ci{
528262306a36Sopenharmony_ci	struct bnx2x_queue_update_params *update = &params->params.update;
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	memset(update, 0, sizeof(*update));
528562306a36Sopenharmony_ci
528662306a36Sopenharmony_ci	__set_bit(BNX2X_Q_UPDATE_ACTIVATE, &update->update_flags);
528762306a36Sopenharmony_ci	__set_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &update->update_flags);
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci	return bnx2x_q_send_update(bp, params);
529062306a36Sopenharmony_ci}
529162306a36Sopenharmony_ci
529262306a36Sopenharmony_cistatic void bnx2x_q_fill_update_tpa_data(struct bnx2x *bp,
529362306a36Sopenharmony_ci				struct bnx2x_queue_sp_obj *obj,
529462306a36Sopenharmony_ci				struct bnx2x_queue_update_tpa_params *params,
529562306a36Sopenharmony_ci				struct tpa_update_ramrod_data *data)
529662306a36Sopenharmony_ci{
529762306a36Sopenharmony_ci	data->client_id = obj->cl_id;
529862306a36Sopenharmony_ci	data->complete_on_both_clients = params->complete_on_both_clients;
529962306a36Sopenharmony_ci	data->dont_verify_rings_pause_thr_flg =
530062306a36Sopenharmony_ci		params->dont_verify_thr;
530162306a36Sopenharmony_ci	data->max_agg_size = cpu_to_le16(params->max_agg_sz);
530262306a36Sopenharmony_ci	data->max_sges_for_packet = params->max_sges_pkt;
530362306a36Sopenharmony_ci	data->max_tpa_queues = params->max_tpa_queues;
530462306a36Sopenharmony_ci	data->sge_buff_size = cpu_to_le16(params->sge_buff_sz);
530562306a36Sopenharmony_ci	data->sge_page_base_hi = cpu_to_le32(U64_HI(params->sge_map));
530662306a36Sopenharmony_ci	data->sge_page_base_lo = cpu_to_le32(U64_LO(params->sge_map));
530762306a36Sopenharmony_ci	data->sge_pause_thr_high = cpu_to_le16(params->sge_pause_thr_high);
530862306a36Sopenharmony_ci	data->sge_pause_thr_low = cpu_to_le16(params->sge_pause_thr_low);
530962306a36Sopenharmony_ci	data->tpa_mode = params->tpa_mode;
531062306a36Sopenharmony_ci	data->update_ipv4 = params->update_ipv4;
531162306a36Sopenharmony_ci	data->update_ipv6 = params->update_ipv6;
531262306a36Sopenharmony_ci}
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_cistatic inline int bnx2x_q_send_update_tpa(struct bnx2x *bp,
531562306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
531662306a36Sopenharmony_ci{
531762306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
531862306a36Sopenharmony_ci	struct tpa_update_ramrod_data *rdata =
531962306a36Sopenharmony_ci		(struct tpa_update_ramrod_data *)o->rdata;
532062306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
532162306a36Sopenharmony_ci	struct bnx2x_queue_update_tpa_params *update_tpa_params =
532262306a36Sopenharmony_ci		&params->params.update_tpa;
532362306a36Sopenharmony_ci	u16 type;
532462306a36Sopenharmony_ci
532562306a36Sopenharmony_ci	/* Clear the ramrod data */
532662306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
532762306a36Sopenharmony_ci
532862306a36Sopenharmony_ci	/* Fill the ramrod data */
532962306a36Sopenharmony_ci	bnx2x_q_fill_update_tpa_data(bp, o, update_tpa_params, rdata);
533062306a36Sopenharmony_ci
533162306a36Sopenharmony_ci	/* Add the function id inside the type, so that sp post function
533262306a36Sopenharmony_ci	 * doesn't automatically add the PF func-id, this is required
533362306a36Sopenharmony_ci	 * for operations done by PFs on behalf of their VFs
533462306a36Sopenharmony_ci	 */
533562306a36Sopenharmony_ci	type = ETH_CONNECTION_TYPE |
533662306a36Sopenharmony_ci		((o->func_id) << SPE_HDR_FUNCTION_ID_SHIFT);
533762306a36Sopenharmony_ci
533862306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
533962306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
534062306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
534162306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
534262306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
534362306a36Sopenharmony_ci	 */
534462306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TPA_UPDATE,
534562306a36Sopenharmony_ci			     o->cids[BNX2X_PRIMARY_CID_INDEX],
534662306a36Sopenharmony_ci			     U64_HI(data_mapping),
534762306a36Sopenharmony_ci			     U64_LO(data_mapping), type);
534862306a36Sopenharmony_ci}
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_cistatic inline int bnx2x_q_send_halt(struct bnx2x *bp,
535162306a36Sopenharmony_ci				    struct bnx2x_queue_state_params *params)
535262306a36Sopenharmony_ci{
535362306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT,
535662306a36Sopenharmony_ci			     o->cids[BNX2X_PRIMARY_CID_INDEX], 0, o->cl_id,
535762306a36Sopenharmony_ci			     ETH_CONNECTION_TYPE);
535862306a36Sopenharmony_ci}
535962306a36Sopenharmony_ci
536062306a36Sopenharmony_cistatic inline int bnx2x_q_send_cfc_del(struct bnx2x *bp,
536162306a36Sopenharmony_ci				       struct bnx2x_queue_state_params *params)
536262306a36Sopenharmony_ci{
536362306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
536462306a36Sopenharmony_ci	u8 cid_idx = params->params.cfc_del.cid_index;
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci	if (cid_idx >= o->max_cos) {
536762306a36Sopenharmony_ci		BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n",
536862306a36Sopenharmony_ci			  o->cl_id, cid_idx);
536962306a36Sopenharmony_ci		return -EINVAL;
537062306a36Sopenharmony_ci	}
537162306a36Sopenharmony_ci
537262306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_CFC_DEL,
537362306a36Sopenharmony_ci			     o->cids[cid_idx], 0, 0, NONE_CONNECTION_TYPE);
537462306a36Sopenharmony_ci}
537562306a36Sopenharmony_ci
537662306a36Sopenharmony_cistatic inline int bnx2x_q_send_terminate(struct bnx2x *bp,
537762306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
537862306a36Sopenharmony_ci{
537962306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
538062306a36Sopenharmony_ci	u8 cid_index = params->params.terminate.cid_index;
538162306a36Sopenharmony_ci
538262306a36Sopenharmony_ci	if (cid_index >= o->max_cos) {
538362306a36Sopenharmony_ci		BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n",
538462306a36Sopenharmony_ci			  o->cl_id, cid_index);
538562306a36Sopenharmony_ci		return -EINVAL;
538662306a36Sopenharmony_ci	}
538762306a36Sopenharmony_ci
538862306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TERMINATE,
538962306a36Sopenharmony_ci			     o->cids[cid_index], 0, 0, ETH_CONNECTION_TYPE);
539062306a36Sopenharmony_ci}
539162306a36Sopenharmony_ci
539262306a36Sopenharmony_cistatic inline int bnx2x_q_send_empty(struct bnx2x *bp,
539362306a36Sopenharmony_ci				     struct bnx2x_queue_state_params *params)
539462306a36Sopenharmony_ci{
539562306a36Sopenharmony_ci	struct bnx2x_queue_sp_obj *o = params->q_obj;
539662306a36Sopenharmony_ci
539762306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_EMPTY,
539862306a36Sopenharmony_ci			     o->cids[BNX2X_PRIMARY_CID_INDEX], 0, 0,
539962306a36Sopenharmony_ci			     ETH_CONNECTION_TYPE);
540062306a36Sopenharmony_ci}
540162306a36Sopenharmony_ci
540262306a36Sopenharmony_cistatic inline int bnx2x_queue_send_cmd_cmn(struct bnx2x *bp,
540362306a36Sopenharmony_ci					struct bnx2x_queue_state_params *params)
540462306a36Sopenharmony_ci{
540562306a36Sopenharmony_ci	switch (params->cmd) {
540662306a36Sopenharmony_ci	case BNX2X_Q_CMD_INIT:
540762306a36Sopenharmony_ci		return bnx2x_q_init(bp, params);
540862306a36Sopenharmony_ci	case BNX2X_Q_CMD_SETUP_TX_ONLY:
540962306a36Sopenharmony_ci		return bnx2x_q_send_setup_tx_only(bp, params);
541062306a36Sopenharmony_ci	case BNX2X_Q_CMD_DEACTIVATE:
541162306a36Sopenharmony_ci		return bnx2x_q_send_deactivate(bp, params);
541262306a36Sopenharmony_ci	case BNX2X_Q_CMD_ACTIVATE:
541362306a36Sopenharmony_ci		return bnx2x_q_send_activate(bp, params);
541462306a36Sopenharmony_ci	case BNX2X_Q_CMD_UPDATE:
541562306a36Sopenharmony_ci		return bnx2x_q_send_update(bp, params);
541662306a36Sopenharmony_ci	case BNX2X_Q_CMD_UPDATE_TPA:
541762306a36Sopenharmony_ci		return bnx2x_q_send_update_tpa(bp, params);
541862306a36Sopenharmony_ci	case BNX2X_Q_CMD_HALT:
541962306a36Sopenharmony_ci		return bnx2x_q_send_halt(bp, params);
542062306a36Sopenharmony_ci	case BNX2X_Q_CMD_CFC_DEL:
542162306a36Sopenharmony_ci		return bnx2x_q_send_cfc_del(bp, params);
542262306a36Sopenharmony_ci	case BNX2X_Q_CMD_TERMINATE:
542362306a36Sopenharmony_ci		return bnx2x_q_send_terminate(bp, params);
542462306a36Sopenharmony_ci	case BNX2X_Q_CMD_EMPTY:
542562306a36Sopenharmony_ci		return bnx2x_q_send_empty(bp, params);
542662306a36Sopenharmony_ci	default:
542762306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", params->cmd);
542862306a36Sopenharmony_ci		return -EINVAL;
542962306a36Sopenharmony_ci	}
543062306a36Sopenharmony_ci}
543162306a36Sopenharmony_ci
543262306a36Sopenharmony_cistatic int bnx2x_queue_send_cmd_e1x(struct bnx2x *bp,
543362306a36Sopenharmony_ci				    struct bnx2x_queue_state_params *params)
543462306a36Sopenharmony_ci{
543562306a36Sopenharmony_ci	switch (params->cmd) {
543662306a36Sopenharmony_ci	case BNX2X_Q_CMD_SETUP:
543762306a36Sopenharmony_ci		return bnx2x_q_send_setup_e1x(bp, params);
543862306a36Sopenharmony_ci	case BNX2X_Q_CMD_INIT:
543962306a36Sopenharmony_ci	case BNX2X_Q_CMD_SETUP_TX_ONLY:
544062306a36Sopenharmony_ci	case BNX2X_Q_CMD_DEACTIVATE:
544162306a36Sopenharmony_ci	case BNX2X_Q_CMD_ACTIVATE:
544262306a36Sopenharmony_ci	case BNX2X_Q_CMD_UPDATE:
544362306a36Sopenharmony_ci	case BNX2X_Q_CMD_UPDATE_TPA:
544462306a36Sopenharmony_ci	case BNX2X_Q_CMD_HALT:
544562306a36Sopenharmony_ci	case BNX2X_Q_CMD_CFC_DEL:
544662306a36Sopenharmony_ci	case BNX2X_Q_CMD_TERMINATE:
544762306a36Sopenharmony_ci	case BNX2X_Q_CMD_EMPTY:
544862306a36Sopenharmony_ci		return bnx2x_queue_send_cmd_cmn(bp, params);
544962306a36Sopenharmony_ci	default:
545062306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", params->cmd);
545162306a36Sopenharmony_ci		return -EINVAL;
545262306a36Sopenharmony_ci	}
545362306a36Sopenharmony_ci}
545462306a36Sopenharmony_ci
545562306a36Sopenharmony_cistatic int bnx2x_queue_send_cmd_e2(struct bnx2x *bp,
545662306a36Sopenharmony_ci				   struct bnx2x_queue_state_params *params)
545762306a36Sopenharmony_ci{
545862306a36Sopenharmony_ci	switch (params->cmd) {
545962306a36Sopenharmony_ci	case BNX2X_Q_CMD_SETUP:
546062306a36Sopenharmony_ci		return bnx2x_q_send_setup_e2(bp, params);
546162306a36Sopenharmony_ci	case BNX2X_Q_CMD_INIT:
546262306a36Sopenharmony_ci	case BNX2X_Q_CMD_SETUP_TX_ONLY:
546362306a36Sopenharmony_ci	case BNX2X_Q_CMD_DEACTIVATE:
546462306a36Sopenharmony_ci	case BNX2X_Q_CMD_ACTIVATE:
546562306a36Sopenharmony_ci	case BNX2X_Q_CMD_UPDATE:
546662306a36Sopenharmony_ci	case BNX2X_Q_CMD_UPDATE_TPA:
546762306a36Sopenharmony_ci	case BNX2X_Q_CMD_HALT:
546862306a36Sopenharmony_ci	case BNX2X_Q_CMD_CFC_DEL:
546962306a36Sopenharmony_ci	case BNX2X_Q_CMD_TERMINATE:
547062306a36Sopenharmony_ci	case BNX2X_Q_CMD_EMPTY:
547162306a36Sopenharmony_ci		return bnx2x_queue_send_cmd_cmn(bp, params);
547262306a36Sopenharmony_ci	default:
547362306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", params->cmd);
547462306a36Sopenharmony_ci		return -EINVAL;
547562306a36Sopenharmony_ci	}
547662306a36Sopenharmony_ci}
547762306a36Sopenharmony_ci
547862306a36Sopenharmony_ci/**
547962306a36Sopenharmony_ci * bnx2x_queue_chk_transition - check state machine of a regular Queue
548062306a36Sopenharmony_ci *
548162306a36Sopenharmony_ci * @bp:		device handle
548262306a36Sopenharmony_ci * @o:		queue info
548362306a36Sopenharmony_ci * @params:	queue state
548462306a36Sopenharmony_ci *
548562306a36Sopenharmony_ci * (not Forwarding)
548662306a36Sopenharmony_ci * It both checks if the requested command is legal in a current
548762306a36Sopenharmony_ci * state and, if it's legal, sets a `next_state' in the object
548862306a36Sopenharmony_ci * that will be used in the completion flow to set the `state'
548962306a36Sopenharmony_ci * of the object.
549062306a36Sopenharmony_ci *
549162306a36Sopenharmony_ci * returns 0 if a requested command is a legal transition,
549262306a36Sopenharmony_ci *         -EINVAL otherwise.
549362306a36Sopenharmony_ci */
549462306a36Sopenharmony_cistatic int bnx2x_queue_chk_transition(struct bnx2x *bp,
549562306a36Sopenharmony_ci				      struct bnx2x_queue_sp_obj *o,
549662306a36Sopenharmony_ci				      struct bnx2x_queue_state_params *params)
549762306a36Sopenharmony_ci{
549862306a36Sopenharmony_ci	enum bnx2x_q_state state = o->state, next_state = BNX2X_Q_STATE_MAX;
549962306a36Sopenharmony_ci	enum bnx2x_queue_cmd cmd = params->cmd;
550062306a36Sopenharmony_ci	struct bnx2x_queue_update_params *update_params =
550162306a36Sopenharmony_ci		 &params->params.update;
550262306a36Sopenharmony_ci	u8 next_tx_only = o->num_tx_only;
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	/* Forget all pending for completion commands if a driver only state
550562306a36Sopenharmony_ci	 * transition has been requested.
550662306a36Sopenharmony_ci	 */
550762306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
550862306a36Sopenharmony_ci		o->pending = 0;
550962306a36Sopenharmony_ci		o->next_state = BNX2X_Q_STATE_MAX;
551062306a36Sopenharmony_ci	}
551162306a36Sopenharmony_ci
551262306a36Sopenharmony_ci	/* Don't allow a next state transition if we are in the middle of
551362306a36Sopenharmony_ci	 * the previous one.
551462306a36Sopenharmony_ci	 */
551562306a36Sopenharmony_ci	if (o->pending) {
551662306a36Sopenharmony_ci		BNX2X_ERR("Blocking transition since pending was %lx\n",
551762306a36Sopenharmony_ci			  o->pending);
551862306a36Sopenharmony_ci		return -EBUSY;
551962306a36Sopenharmony_ci	}
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	switch (state) {
552262306a36Sopenharmony_ci	case BNX2X_Q_STATE_RESET:
552362306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_INIT)
552462306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_INITIALIZED;
552562306a36Sopenharmony_ci
552662306a36Sopenharmony_ci		break;
552762306a36Sopenharmony_ci	case BNX2X_Q_STATE_INITIALIZED:
552862306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_SETUP) {
552962306a36Sopenharmony_ci			if (test_bit(BNX2X_Q_FLG_ACTIVE,
553062306a36Sopenharmony_ci				     &params->params.setup.flags))
553162306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_ACTIVE;
553262306a36Sopenharmony_ci			else
553362306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_INACTIVE;
553462306a36Sopenharmony_ci		}
553562306a36Sopenharmony_ci
553662306a36Sopenharmony_ci		break;
553762306a36Sopenharmony_ci	case BNX2X_Q_STATE_ACTIVE:
553862306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_DEACTIVATE)
553962306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_INACTIVE;
554062306a36Sopenharmony_ci
554162306a36Sopenharmony_ci		else if ((cmd == BNX2X_Q_CMD_EMPTY) ||
554262306a36Sopenharmony_ci			 (cmd == BNX2X_Q_CMD_UPDATE_TPA))
554362306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_ACTIVE;
554462306a36Sopenharmony_ci
554562306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_SETUP_TX_ONLY) {
554662306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_MULTI_COS;
554762306a36Sopenharmony_ci			next_tx_only = 1;
554862306a36Sopenharmony_ci		}
554962306a36Sopenharmony_ci
555062306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_HALT)
555162306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_STOPPED;
555262306a36Sopenharmony_ci
555362306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_UPDATE) {
555462306a36Sopenharmony_ci			/* If "active" state change is requested, update the
555562306a36Sopenharmony_ci			 *  state accordingly.
555662306a36Sopenharmony_ci			 */
555762306a36Sopenharmony_ci			if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG,
555862306a36Sopenharmony_ci				     &update_params->update_flags) &&
555962306a36Sopenharmony_ci			    !test_bit(BNX2X_Q_UPDATE_ACTIVATE,
556062306a36Sopenharmony_ci				      &update_params->update_flags))
556162306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_INACTIVE;
556262306a36Sopenharmony_ci			else
556362306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_ACTIVE;
556462306a36Sopenharmony_ci		}
556562306a36Sopenharmony_ci
556662306a36Sopenharmony_ci		break;
556762306a36Sopenharmony_ci	case BNX2X_Q_STATE_MULTI_COS:
556862306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_TERMINATE)
556962306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_MCOS_TERMINATED;
557062306a36Sopenharmony_ci
557162306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_SETUP_TX_ONLY) {
557262306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_MULTI_COS;
557362306a36Sopenharmony_ci			next_tx_only = o->num_tx_only + 1;
557462306a36Sopenharmony_ci		}
557562306a36Sopenharmony_ci
557662306a36Sopenharmony_ci		else if ((cmd == BNX2X_Q_CMD_EMPTY) ||
557762306a36Sopenharmony_ci			 (cmd == BNX2X_Q_CMD_UPDATE_TPA))
557862306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_MULTI_COS;
557962306a36Sopenharmony_ci
558062306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_UPDATE) {
558162306a36Sopenharmony_ci			/* If "active" state change is requested, update the
558262306a36Sopenharmony_ci			 *  state accordingly.
558362306a36Sopenharmony_ci			 */
558462306a36Sopenharmony_ci			if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG,
558562306a36Sopenharmony_ci				     &update_params->update_flags) &&
558662306a36Sopenharmony_ci			    !test_bit(BNX2X_Q_UPDATE_ACTIVATE,
558762306a36Sopenharmony_ci				      &update_params->update_flags))
558862306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_INACTIVE;
558962306a36Sopenharmony_ci			else
559062306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_MULTI_COS;
559162306a36Sopenharmony_ci		}
559262306a36Sopenharmony_ci
559362306a36Sopenharmony_ci		break;
559462306a36Sopenharmony_ci	case BNX2X_Q_STATE_MCOS_TERMINATED:
559562306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_CFC_DEL) {
559662306a36Sopenharmony_ci			next_tx_only = o->num_tx_only - 1;
559762306a36Sopenharmony_ci			if (next_tx_only == 0)
559862306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_ACTIVE;
559962306a36Sopenharmony_ci			else
560062306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_MULTI_COS;
560162306a36Sopenharmony_ci		}
560262306a36Sopenharmony_ci
560362306a36Sopenharmony_ci		break;
560462306a36Sopenharmony_ci	case BNX2X_Q_STATE_INACTIVE:
560562306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_ACTIVATE)
560662306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_ACTIVE;
560762306a36Sopenharmony_ci
560862306a36Sopenharmony_ci		else if ((cmd == BNX2X_Q_CMD_EMPTY) ||
560962306a36Sopenharmony_ci			 (cmd == BNX2X_Q_CMD_UPDATE_TPA))
561062306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_INACTIVE;
561162306a36Sopenharmony_ci
561262306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_HALT)
561362306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_STOPPED;
561462306a36Sopenharmony_ci
561562306a36Sopenharmony_ci		else if (cmd == BNX2X_Q_CMD_UPDATE) {
561662306a36Sopenharmony_ci			/* If "active" state change is requested, update the
561762306a36Sopenharmony_ci			 * state accordingly.
561862306a36Sopenharmony_ci			 */
561962306a36Sopenharmony_ci			if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG,
562062306a36Sopenharmony_ci				     &update_params->update_flags) &&
562162306a36Sopenharmony_ci			    test_bit(BNX2X_Q_UPDATE_ACTIVATE,
562262306a36Sopenharmony_ci				     &update_params->update_flags)){
562362306a36Sopenharmony_ci				if (o->num_tx_only == 0)
562462306a36Sopenharmony_ci					next_state = BNX2X_Q_STATE_ACTIVE;
562562306a36Sopenharmony_ci				else /* tx only queues exist for this queue */
562662306a36Sopenharmony_ci					next_state = BNX2X_Q_STATE_MULTI_COS;
562762306a36Sopenharmony_ci			} else
562862306a36Sopenharmony_ci				next_state = BNX2X_Q_STATE_INACTIVE;
562962306a36Sopenharmony_ci		}
563062306a36Sopenharmony_ci
563162306a36Sopenharmony_ci		break;
563262306a36Sopenharmony_ci	case BNX2X_Q_STATE_STOPPED:
563362306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_TERMINATE)
563462306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_TERMINATED;
563562306a36Sopenharmony_ci
563662306a36Sopenharmony_ci		break;
563762306a36Sopenharmony_ci	case BNX2X_Q_STATE_TERMINATED:
563862306a36Sopenharmony_ci		if (cmd == BNX2X_Q_CMD_CFC_DEL)
563962306a36Sopenharmony_ci			next_state = BNX2X_Q_STATE_RESET;
564062306a36Sopenharmony_ci
564162306a36Sopenharmony_ci		break;
564262306a36Sopenharmony_ci	default:
564362306a36Sopenharmony_ci		BNX2X_ERR("Illegal state: %d\n", state);
564462306a36Sopenharmony_ci	}
564562306a36Sopenharmony_ci
564662306a36Sopenharmony_ci	/* Transition is assured */
564762306a36Sopenharmony_ci	if (next_state != BNX2X_Q_STATE_MAX) {
564862306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Good state transition: %d(%d)->%d\n",
564962306a36Sopenharmony_ci				 state, cmd, next_state);
565062306a36Sopenharmony_ci		o->next_state = next_state;
565162306a36Sopenharmony_ci		o->next_tx_only = next_tx_only;
565262306a36Sopenharmony_ci		return 0;
565362306a36Sopenharmony_ci	}
565462306a36Sopenharmony_ci
565562306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Bad state transition request: %d %d\n", state, cmd);
565662306a36Sopenharmony_ci
565762306a36Sopenharmony_ci	return -EINVAL;
565862306a36Sopenharmony_ci}
565962306a36Sopenharmony_ci
566062306a36Sopenharmony_civoid bnx2x_init_queue_obj(struct bnx2x *bp,
566162306a36Sopenharmony_ci			  struct bnx2x_queue_sp_obj *obj,
566262306a36Sopenharmony_ci			  u8 cl_id, u32 *cids, u8 cid_cnt, u8 func_id,
566362306a36Sopenharmony_ci			  void *rdata,
566462306a36Sopenharmony_ci			  dma_addr_t rdata_mapping, unsigned long type)
566562306a36Sopenharmony_ci{
566662306a36Sopenharmony_ci	memset(obj, 0, sizeof(*obj));
566762306a36Sopenharmony_ci
566862306a36Sopenharmony_ci	/* We support only BNX2X_MULTI_TX_COS Tx CoS at the moment */
566962306a36Sopenharmony_ci	BUG_ON(BNX2X_MULTI_TX_COS < cid_cnt);
567062306a36Sopenharmony_ci
567162306a36Sopenharmony_ci	memcpy(obj->cids, cids, sizeof(obj->cids[0]) * cid_cnt);
567262306a36Sopenharmony_ci	obj->max_cos = cid_cnt;
567362306a36Sopenharmony_ci	obj->cl_id = cl_id;
567462306a36Sopenharmony_ci	obj->func_id = func_id;
567562306a36Sopenharmony_ci	obj->rdata = rdata;
567662306a36Sopenharmony_ci	obj->rdata_mapping = rdata_mapping;
567762306a36Sopenharmony_ci	obj->type = type;
567862306a36Sopenharmony_ci	obj->next_state = BNX2X_Q_STATE_MAX;
567962306a36Sopenharmony_ci
568062306a36Sopenharmony_ci	if (CHIP_IS_E1x(bp))
568162306a36Sopenharmony_ci		obj->send_cmd = bnx2x_queue_send_cmd_e1x;
568262306a36Sopenharmony_ci	else
568362306a36Sopenharmony_ci		obj->send_cmd = bnx2x_queue_send_cmd_e2;
568462306a36Sopenharmony_ci
568562306a36Sopenharmony_ci	obj->check_transition = bnx2x_queue_chk_transition;
568662306a36Sopenharmony_ci
568762306a36Sopenharmony_ci	obj->complete_cmd = bnx2x_queue_comp_cmd;
568862306a36Sopenharmony_ci	obj->wait_comp = bnx2x_queue_wait_comp;
568962306a36Sopenharmony_ci	obj->set_pending = bnx2x_queue_set_pending;
569062306a36Sopenharmony_ci}
569162306a36Sopenharmony_ci
569262306a36Sopenharmony_ci/* return a queue object's logical state*/
569362306a36Sopenharmony_ciint bnx2x_get_q_logical_state(struct bnx2x *bp,
569462306a36Sopenharmony_ci			       struct bnx2x_queue_sp_obj *obj)
569562306a36Sopenharmony_ci{
569662306a36Sopenharmony_ci	switch (obj->state) {
569762306a36Sopenharmony_ci	case BNX2X_Q_STATE_ACTIVE:
569862306a36Sopenharmony_ci	case BNX2X_Q_STATE_MULTI_COS:
569962306a36Sopenharmony_ci		return BNX2X_Q_LOGICAL_STATE_ACTIVE;
570062306a36Sopenharmony_ci	case BNX2X_Q_STATE_RESET:
570162306a36Sopenharmony_ci	case BNX2X_Q_STATE_INITIALIZED:
570262306a36Sopenharmony_ci	case BNX2X_Q_STATE_MCOS_TERMINATED:
570362306a36Sopenharmony_ci	case BNX2X_Q_STATE_INACTIVE:
570462306a36Sopenharmony_ci	case BNX2X_Q_STATE_STOPPED:
570562306a36Sopenharmony_ci	case BNX2X_Q_STATE_TERMINATED:
570662306a36Sopenharmony_ci	case BNX2X_Q_STATE_FLRED:
570762306a36Sopenharmony_ci		return BNX2X_Q_LOGICAL_STATE_STOPPED;
570862306a36Sopenharmony_ci	default:
570962306a36Sopenharmony_ci		return -EINVAL;
571062306a36Sopenharmony_ci	}
571162306a36Sopenharmony_ci}
571262306a36Sopenharmony_ci
571362306a36Sopenharmony_ci/********************** Function state object *********************************/
571462306a36Sopenharmony_cienum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
571562306a36Sopenharmony_ci					   struct bnx2x_func_sp_obj *o)
571662306a36Sopenharmony_ci{
571762306a36Sopenharmony_ci	/* in the middle of transaction - return INVALID state */
571862306a36Sopenharmony_ci	if (o->pending)
571962306a36Sopenharmony_ci		return BNX2X_F_STATE_MAX;
572062306a36Sopenharmony_ci
572162306a36Sopenharmony_ci	/* unsure the order of reading of o->pending and o->state
572262306a36Sopenharmony_ci	 * o->pending should be read first
572362306a36Sopenharmony_ci	 */
572462306a36Sopenharmony_ci	rmb();
572562306a36Sopenharmony_ci
572662306a36Sopenharmony_ci	return o->state;
572762306a36Sopenharmony_ci}
572862306a36Sopenharmony_ci
572962306a36Sopenharmony_cistatic int bnx2x_func_wait_comp(struct bnx2x *bp,
573062306a36Sopenharmony_ci				struct bnx2x_func_sp_obj *o,
573162306a36Sopenharmony_ci				enum bnx2x_func_cmd cmd)
573262306a36Sopenharmony_ci{
573362306a36Sopenharmony_ci	return bnx2x_state_wait(bp, cmd, &o->pending);
573462306a36Sopenharmony_ci}
573562306a36Sopenharmony_ci
573662306a36Sopenharmony_ci/**
573762306a36Sopenharmony_ci * bnx2x_func_state_change_comp - complete the state machine transition
573862306a36Sopenharmony_ci *
573962306a36Sopenharmony_ci * @bp:		device handle
574062306a36Sopenharmony_ci * @o:		function info
574162306a36Sopenharmony_ci * @cmd:	more info
574262306a36Sopenharmony_ci *
574362306a36Sopenharmony_ci * Called on state change transition. Completes the state
574462306a36Sopenharmony_ci * machine transition only - no HW interaction.
574562306a36Sopenharmony_ci */
574662306a36Sopenharmony_cistatic inline int bnx2x_func_state_change_comp(struct bnx2x *bp,
574762306a36Sopenharmony_ci					       struct bnx2x_func_sp_obj *o,
574862306a36Sopenharmony_ci					       enum bnx2x_func_cmd cmd)
574962306a36Sopenharmony_ci{
575062306a36Sopenharmony_ci	unsigned long cur_pending = o->pending;
575162306a36Sopenharmony_ci
575262306a36Sopenharmony_ci	if (!test_and_clear_bit(cmd, &cur_pending)) {
575362306a36Sopenharmony_ci		BNX2X_ERR("Bad MC reply %d for func %d in state %d pending 0x%lx, next_state %d\n",
575462306a36Sopenharmony_ci			  cmd, BP_FUNC(bp), o->state,
575562306a36Sopenharmony_ci			  cur_pending, o->next_state);
575662306a36Sopenharmony_ci		return -EINVAL;
575762306a36Sopenharmony_ci	}
575862306a36Sopenharmony_ci
575962306a36Sopenharmony_ci	DP(BNX2X_MSG_SP,
576062306a36Sopenharmony_ci	   "Completing command %d for func %d, setting state to %d\n",
576162306a36Sopenharmony_ci	   cmd, BP_FUNC(bp), o->next_state);
576262306a36Sopenharmony_ci
576362306a36Sopenharmony_ci	o->state = o->next_state;
576462306a36Sopenharmony_ci	o->next_state = BNX2X_F_STATE_MAX;
576562306a36Sopenharmony_ci
576662306a36Sopenharmony_ci	/* It's important that o->state and o->next_state are
576762306a36Sopenharmony_ci	 * updated before o->pending.
576862306a36Sopenharmony_ci	 */
576962306a36Sopenharmony_ci	wmb();
577062306a36Sopenharmony_ci
577162306a36Sopenharmony_ci	clear_bit(cmd, &o->pending);
577262306a36Sopenharmony_ci	smp_mb__after_atomic();
577362306a36Sopenharmony_ci
577462306a36Sopenharmony_ci	return 0;
577562306a36Sopenharmony_ci}
577662306a36Sopenharmony_ci
577762306a36Sopenharmony_ci/**
577862306a36Sopenharmony_ci * bnx2x_func_comp_cmd - complete the state change command
577962306a36Sopenharmony_ci *
578062306a36Sopenharmony_ci * @bp:		device handle
578162306a36Sopenharmony_ci * @o:		function info
578262306a36Sopenharmony_ci * @cmd:	more info
578362306a36Sopenharmony_ci *
578462306a36Sopenharmony_ci * Checks that the arrived completion is expected.
578562306a36Sopenharmony_ci */
578662306a36Sopenharmony_cistatic int bnx2x_func_comp_cmd(struct bnx2x *bp,
578762306a36Sopenharmony_ci			       struct bnx2x_func_sp_obj *o,
578862306a36Sopenharmony_ci			       enum bnx2x_func_cmd cmd)
578962306a36Sopenharmony_ci{
579062306a36Sopenharmony_ci	/* Complete the state machine part first, check if it's a
579162306a36Sopenharmony_ci	 * legal completion.
579262306a36Sopenharmony_ci	 */
579362306a36Sopenharmony_ci	int rc = bnx2x_func_state_change_comp(bp, o, cmd);
579462306a36Sopenharmony_ci	return rc;
579562306a36Sopenharmony_ci}
579662306a36Sopenharmony_ci
579762306a36Sopenharmony_ci/**
579862306a36Sopenharmony_ci * bnx2x_func_chk_transition - perform function state machine transition
579962306a36Sopenharmony_ci *
580062306a36Sopenharmony_ci * @bp:		device handle
580162306a36Sopenharmony_ci * @o:		function info
580262306a36Sopenharmony_ci * @params:	state parameters
580362306a36Sopenharmony_ci *
580462306a36Sopenharmony_ci * It both checks if the requested command is legal in a current
580562306a36Sopenharmony_ci * state and, if it's legal, sets a `next_state' in the object
580662306a36Sopenharmony_ci * that will be used in the completion flow to set the `state'
580762306a36Sopenharmony_ci * of the object.
580862306a36Sopenharmony_ci *
580962306a36Sopenharmony_ci * returns 0 if a requested command is a legal transition,
581062306a36Sopenharmony_ci *         -EINVAL otherwise.
581162306a36Sopenharmony_ci */
581262306a36Sopenharmony_cistatic int bnx2x_func_chk_transition(struct bnx2x *bp,
581362306a36Sopenharmony_ci				     struct bnx2x_func_sp_obj *o,
581462306a36Sopenharmony_ci				     struct bnx2x_func_state_params *params)
581562306a36Sopenharmony_ci{
581662306a36Sopenharmony_ci	enum bnx2x_func_state state = o->state, next_state = BNX2X_F_STATE_MAX;
581762306a36Sopenharmony_ci	enum bnx2x_func_cmd cmd = params->cmd;
581862306a36Sopenharmony_ci
581962306a36Sopenharmony_ci	/* Forget all pending for completion commands if a driver only state
582062306a36Sopenharmony_ci	 * transition has been requested.
582162306a36Sopenharmony_ci	 */
582262306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
582362306a36Sopenharmony_ci		o->pending = 0;
582462306a36Sopenharmony_ci		o->next_state = BNX2X_F_STATE_MAX;
582562306a36Sopenharmony_ci	}
582662306a36Sopenharmony_ci
582762306a36Sopenharmony_ci	/* Don't allow a next state transition if we are in the middle of
582862306a36Sopenharmony_ci	 * the previous one.
582962306a36Sopenharmony_ci	 */
583062306a36Sopenharmony_ci	if (o->pending)
583162306a36Sopenharmony_ci		return -EBUSY;
583262306a36Sopenharmony_ci
583362306a36Sopenharmony_ci	switch (state) {
583462306a36Sopenharmony_ci	case BNX2X_F_STATE_RESET:
583562306a36Sopenharmony_ci		if (cmd == BNX2X_F_CMD_HW_INIT)
583662306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_INITIALIZED;
583762306a36Sopenharmony_ci
583862306a36Sopenharmony_ci		break;
583962306a36Sopenharmony_ci	case BNX2X_F_STATE_INITIALIZED:
584062306a36Sopenharmony_ci		if (cmd == BNX2X_F_CMD_START)
584162306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_STARTED;
584262306a36Sopenharmony_ci
584362306a36Sopenharmony_ci		else if (cmd == BNX2X_F_CMD_HW_RESET)
584462306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_RESET;
584562306a36Sopenharmony_ci
584662306a36Sopenharmony_ci		break;
584762306a36Sopenharmony_ci	case BNX2X_F_STATE_STARTED:
584862306a36Sopenharmony_ci		if (cmd == BNX2X_F_CMD_STOP)
584962306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_INITIALIZED;
585062306a36Sopenharmony_ci		/* afex ramrods can be sent only in started mode, and only
585162306a36Sopenharmony_ci		 * if not pending for function_stop ramrod completion
585262306a36Sopenharmony_ci		 * for these events - next state remained STARTED.
585362306a36Sopenharmony_ci		 */
585462306a36Sopenharmony_ci		else if ((cmd == BNX2X_F_CMD_AFEX_UPDATE) &&
585562306a36Sopenharmony_ci			 (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
585662306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_STARTED;
585762306a36Sopenharmony_ci
585862306a36Sopenharmony_ci		else if ((cmd == BNX2X_F_CMD_AFEX_VIFLISTS) &&
585962306a36Sopenharmony_ci			 (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
586062306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_STARTED;
586162306a36Sopenharmony_ci
586262306a36Sopenharmony_ci		/* Switch_update ramrod can be sent in either started or
586362306a36Sopenharmony_ci		 * tx_stopped state, and it doesn't change the state.
586462306a36Sopenharmony_ci		 */
586562306a36Sopenharmony_ci		else if ((cmd == BNX2X_F_CMD_SWITCH_UPDATE) &&
586662306a36Sopenharmony_ci			 (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
586762306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_STARTED;
586862306a36Sopenharmony_ci
586962306a36Sopenharmony_ci		else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) &&
587062306a36Sopenharmony_ci			 (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
587162306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_STARTED;
587262306a36Sopenharmony_ci
587362306a36Sopenharmony_ci		else if (cmd == BNX2X_F_CMD_TX_STOP)
587462306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_TX_STOPPED;
587562306a36Sopenharmony_ci
587662306a36Sopenharmony_ci		break;
587762306a36Sopenharmony_ci	case BNX2X_F_STATE_TX_STOPPED:
587862306a36Sopenharmony_ci		if ((cmd == BNX2X_F_CMD_SWITCH_UPDATE) &&
587962306a36Sopenharmony_ci		    (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
588062306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_TX_STOPPED;
588162306a36Sopenharmony_ci
588262306a36Sopenharmony_ci		else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) &&
588362306a36Sopenharmony_ci			 (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
588462306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_TX_STOPPED;
588562306a36Sopenharmony_ci
588662306a36Sopenharmony_ci		else if (cmd == BNX2X_F_CMD_TX_START)
588762306a36Sopenharmony_ci			next_state = BNX2X_F_STATE_STARTED;
588862306a36Sopenharmony_ci
588962306a36Sopenharmony_ci		break;
589062306a36Sopenharmony_ci	default:
589162306a36Sopenharmony_ci		BNX2X_ERR("Unknown state: %d\n", state);
589262306a36Sopenharmony_ci	}
589362306a36Sopenharmony_ci
589462306a36Sopenharmony_ci	/* Transition is assured */
589562306a36Sopenharmony_ci	if (next_state != BNX2X_F_STATE_MAX) {
589662306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "Good function state transition: %d(%d)->%d\n",
589762306a36Sopenharmony_ci				 state, cmd, next_state);
589862306a36Sopenharmony_ci		o->next_state = next_state;
589962306a36Sopenharmony_ci		return 0;
590062306a36Sopenharmony_ci	}
590162306a36Sopenharmony_ci
590262306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Bad function state transition request: %d %d\n",
590362306a36Sopenharmony_ci			 state, cmd);
590462306a36Sopenharmony_ci
590562306a36Sopenharmony_ci	return -EINVAL;
590662306a36Sopenharmony_ci}
590762306a36Sopenharmony_ci
590862306a36Sopenharmony_ci/**
590962306a36Sopenharmony_ci * bnx2x_func_init_func - performs HW init at function stage
591062306a36Sopenharmony_ci *
591162306a36Sopenharmony_ci * @bp:		device handle
591262306a36Sopenharmony_ci * @drv:
591362306a36Sopenharmony_ci *
591462306a36Sopenharmony_ci * Init HW when the current phase is
591562306a36Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_FUNCTION: initialize only FUNCTION-only
591662306a36Sopenharmony_ci * HW blocks.
591762306a36Sopenharmony_ci */
591862306a36Sopenharmony_cistatic inline int bnx2x_func_init_func(struct bnx2x *bp,
591962306a36Sopenharmony_ci				       const struct bnx2x_func_sp_drv_ops *drv)
592062306a36Sopenharmony_ci{
592162306a36Sopenharmony_ci	return drv->init_hw_func(bp);
592262306a36Sopenharmony_ci}
592362306a36Sopenharmony_ci
592462306a36Sopenharmony_ci/**
592562306a36Sopenharmony_ci * bnx2x_func_init_port - performs HW init at port stage
592662306a36Sopenharmony_ci *
592762306a36Sopenharmony_ci * @bp:		device handle
592862306a36Sopenharmony_ci * @drv:
592962306a36Sopenharmony_ci *
593062306a36Sopenharmony_ci * Init HW when the current phase is
593162306a36Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_PORT: initialize PORT-only and
593262306a36Sopenharmony_ci * FUNCTION-only HW blocks.
593362306a36Sopenharmony_ci *
593462306a36Sopenharmony_ci */
593562306a36Sopenharmony_cistatic inline int bnx2x_func_init_port(struct bnx2x *bp,
593662306a36Sopenharmony_ci				       const struct bnx2x_func_sp_drv_ops *drv)
593762306a36Sopenharmony_ci{
593862306a36Sopenharmony_ci	int rc = drv->init_hw_port(bp);
593962306a36Sopenharmony_ci	if (rc)
594062306a36Sopenharmony_ci		return rc;
594162306a36Sopenharmony_ci
594262306a36Sopenharmony_ci	return bnx2x_func_init_func(bp, drv);
594362306a36Sopenharmony_ci}
594462306a36Sopenharmony_ci
594562306a36Sopenharmony_ci/**
594662306a36Sopenharmony_ci * bnx2x_func_init_cmn_chip - performs HW init at chip-common stage
594762306a36Sopenharmony_ci *
594862306a36Sopenharmony_ci * @bp:		device handle
594962306a36Sopenharmony_ci * @drv:
595062306a36Sopenharmony_ci *
595162306a36Sopenharmony_ci * Init HW when the current phase is
595262306a36Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: initialize COMMON_CHIP,
595362306a36Sopenharmony_ci * PORT-only and FUNCTION-only HW blocks.
595462306a36Sopenharmony_ci */
595562306a36Sopenharmony_cistatic inline int bnx2x_func_init_cmn_chip(struct bnx2x *bp,
595662306a36Sopenharmony_ci					const struct bnx2x_func_sp_drv_ops *drv)
595762306a36Sopenharmony_ci{
595862306a36Sopenharmony_ci	int rc = drv->init_hw_cmn_chip(bp);
595962306a36Sopenharmony_ci	if (rc)
596062306a36Sopenharmony_ci		return rc;
596162306a36Sopenharmony_ci
596262306a36Sopenharmony_ci	return bnx2x_func_init_port(bp, drv);
596362306a36Sopenharmony_ci}
596462306a36Sopenharmony_ci
596562306a36Sopenharmony_ci/**
596662306a36Sopenharmony_ci * bnx2x_func_init_cmn - performs HW init at common stage
596762306a36Sopenharmony_ci *
596862306a36Sopenharmony_ci * @bp:		device handle
596962306a36Sopenharmony_ci * @drv:
597062306a36Sopenharmony_ci *
597162306a36Sopenharmony_ci * Init HW when the current phase is
597262306a36Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: initialize COMMON,
597362306a36Sopenharmony_ci * PORT-only and FUNCTION-only HW blocks.
597462306a36Sopenharmony_ci */
597562306a36Sopenharmony_cistatic inline int bnx2x_func_init_cmn(struct bnx2x *bp,
597662306a36Sopenharmony_ci				      const struct bnx2x_func_sp_drv_ops *drv)
597762306a36Sopenharmony_ci{
597862306a36Sopenharmony_ci	int rc = drv->init_hw_cmn(bp);
597962306a36Sopenharmony_ci	if (rc)
598062306a36Sopenharmony_ci		return rc;
598162306a36Sopenharmony_ci
598262306a36Sopenharmony_ci	return bnx2x_func_init_port(bp, drv);
598362306a36Sopenharmony_ci}
598462306a36Sopenharmony_ci
598562306a36Sopenharmony_cistatic int bnx2x_func_hw_init(struct bnx2x *bp,
598662306a36Sopenharmony_ci			      struct bnx2x_func_state_params *params)
598762306a36Sopenharmony_ci{
598862306a36Sopenharmony_ci	u32 load_code = params->params.hw_init.load_phase;
598962306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
599062306a36Sopenharmony_ci	const struct bnx2x_func_sp_drv_ops *drv = o->drv;
599162306a36Sopenharmony_ci	int rc = 0;
599262306a36Sopenharmony_ci
599362306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "function %d  load_code %x\n",
599462306a36Sopenharmony_ci			 BP_ABS_FUNC(bp), load_code);
599562306a36Sopenharmony_ci
599662306a36Sopenharmony_ci	/* Prepare buffers for unzipping the FW */
599762306a36Sopenharmony_ci	rc = drv->gunzip_init(bp);
599862306a36Sopenharmony_ci	if (rc)
599962306a36Sopenharmony_ci		return rc;
600062306a36Sopenharmony_ci
600162306a36Sopenharmony_ci	/* Prepare FW */
600262306a36Sopenharmony_ci	rc = drv->init_fw(bp);
600362306a36Sopenharmony_ci	if (rc) {
600462306a36Sopenharmony_ci		BNX2X_ERR("Error loading firmware\n");
600562306a36Sopenharmony_ci		goto init_err;
600662306a36Sopenharmony_ci	}
600762306a36Sopenharmony_ci
600862306a36Sopenharmony_ci	/* Handle the beginning of COMMON_XXX pases separately... */
600962306a36Sopenharmony_ci	switch (load_code) {
601062306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP:
601162306a36Sopenharmony_ci		rc = bnx2x_func_init_cmn_chip(bp, drv);
601262306a36Sopenharmony_ci		if (rc)
601362306a36Sopenharmony_ci			goto init_err;
601462306a36Sopenharmony_ci
601562306a36Sopenharmony_ci		break;
601662306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_LOAD_COMMON:
601762306a36Sopenharmony_ci		rc = bnx2x_func_init_cmn(bp, drv);
601862306a36Sopenharmony_ci		if (rc)
601962306a36Sopenharmony_ci			goto init_err;
602062306a36Sopenharmony_ci
602162306a36Sopenharmony_ci		break;
602262306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_LOAD_PORT:
602362306a36Sopenharmony_ci		rc = bnx2x_func_init_port(bp, drv);
602462306a36Sopenharmony_ci		if (rc)
602562306a36Sopenharmony_ci			goto init_err;
602662306a36Sopenharmony_ci
602762306a36Sopenharmony_ci		break;
602862306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_LOAD_FUNCTION:
602962306a36Sopenharmony_ci		rc = bnx2x_func_init_func(bp, drv);
603062306a36Sopenharmony_ci		if (rc)
603162306a36Sopenharmony_ci			goto init_err;
603262306a36Sopenharmony_ci
603362306a36Sopenharmony_ci		break;
603462306a36Sopenharmony_ci	default:
603562306a36Sopenharmony_ci		BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code);
603662306a36Sopenharmony_ci		rc = -EINVAL;
603762306a36Sopenharmony_ci	}
603862306a36Sopenharmony_ci
603962306a36Sopenharmony_ciinit_err:
604062306a36Sopenharmony_ci	drv->gunzip_end(bp);
604162306a36Sopenharmony_ci
604262306a36Sopenharmony_ci	/* In case of success, complete the command immediately: no ramrods
604362306a36Sopenharmony_ci	 * have been sent.
604462306a36Sopenharmony_ci	 */
604562306a36Sopenharmony_ci	if (!rc)
604662306a36Sopenharmony_ci		o->complete_cmd(bp, o, BNX2X_F_CMD_HW_INIT);
604762306a36Sopenharmony_ci
604862306a36Sopenharmony_ci	return rc;
604962306a36Sopenharmony_ci}
605062306a36Sopenharmony_ci
605162306a36Sopenharmony_ci/**
605262306a36Sopenharmony_ci * bnx2x_func_reset_func - reset HW at function stage
605362306a36Sopenharmony_ci *
605462306a36Sopenharmony_ci * @bp:		device handle
605562306a36Sopenharmony_ci * @drv:
605662306a36Sopenharmony_ci *
605762306a36Sopenharmony_ci * Reset HW at FW_MSG_CODE_DRV_UNLOAD_FUNCTION stage: reset only
605862306a36Sopenharmony_ci * FUNCTION-only HW blocks.
605962306a36Sopenharmony_ci */
606062306a36Sopenharmony_cistatic inline void bnx2x_func_reset_func(struct bnx2x *bp,
606162306a36Sopenharmony_ci					const struct bnx2x_func_sp_drv_ops *drv)
606262306a36Sopenharmony_ci{
606362306a36Sopenharmony_ci	drv->reset_hw_func(bp);
606462306a36Sopenharmony_ci}
606562306a36Sopenharmony_ci
606662306a36Sopenharmony_ci/**
606762306a36Sopenharmony_ci * bnx2x_func_reset_port - reset HW at port stage
606862306a36Sopenharmony_ci *
606962306a36Sopenharmony_ci * @bp:		device handle
607062306a36Sopenharmony_ci * @drv:
607162306a36Sopenharmony_ci *
607262306a36Sopenharmony_ci * Reset HW at FW_MSG_CODE_DRV_UNLOAD_PORT stage: reset
607362306a36Sopenharmony_ci * FUNCTION-only and PORT-only HW blocks.
607462306a36Sopenharmony_ci *
607562306a36Sopenharmony_ci *                 !!!IMPORTANT!!!
607662306a36Sopenharmony_ci *
607762306a36Sopenharmony_ci * It's important to call reset_port before reset_func() as the last thing
607862306a36Sopenharmony_ci * reset_func does is pf_disable() thus disabling PGLUE_B, which
607962306a36Sopenharmony_ci * makes impossible any DMAE transactions.
608062306a36Sopenharmony_ci */
608162306a36Sopenharmony_cistatic inline void bnx2x_func_reset_port(struct bnx2x *bp,
608262306a36Sopenharmony_ci					const struct bnx2x_func_sp_drv_ops *drv)
608362306a36Sopenharmony_ci{
608462306a36Sopenharmony_ci	drv->reset_hw_port(bp);
608562306a36Sopenharmony_ci	bnx2x_func_reset_func(bp, drv);
608662306a36Sopenharmony_ci}
608762306a36Sopenharmony_ci
608862306a36Sopenharmony_ci/**
608962306a36Sopenharmony_ci * bnx2x_func_reset_cmn - reset HW at common stage
609062306a36Sopenharmony_ci *
609162306a36Sopenharmony_ci * @bp:		device handle
609262306a36Sopenharmony_ci * @drv:
609362306a36Sopenharmony_ci *
609462306a36Sopenharmony_ci * Reset HW at FW_MSG_CODE_DRV_UNLOAD_COMMON and
609562306a36Sopenharmony_ci * FW_MSG_CODE_DRV_UNLOAD_COMMON_CHIP stages: reset COMMON,
609662306a36Sopenharmony_ci * COMMON_CHIP, FUNCTION-only and PORT-only HW blocks.
609762306a36Sopenharmony_ci */
609862306a36Sopenharmony_cistatic inline void bnx2x_func_reset_cmn(struct bnx2x *bp,
609962306a36Sopenharmony_ci					const struct bnx2x_func_sp_drv_ops *drv)
610062306a36Sopenharmony_ci{
610162306a36Sopenharmony_ci	bnx2x_func_reset_port(bp, drv);
610262306a36Sopenharmony_ci	drv->reset_hw_cmn(bp);
610362306a36Sopenharmony_ci}
610462306a36Sopenharmony_ci
610562306a36Sopenharmony_cistatic inline int bnx2x_func_hw_reset(struct bnx2x *bp,
610662306a36Sopenharmony_ci				      struct bnx2x_func_state_params *params)
610762306a36Sopenharmony_ci{
610862306a36Sopenharmony_ci	u32 reset_phase = params->params.hw_reset.reset_phase;
610962306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
611062306a36Sopenharmony_ci	const struct bnx2x_func_sp_drv_ops *drv = o->drv;
611162306a36Sopenharmony_ci
611262306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "function %d  reset_phase %x\n", BP_ABS_FUNC(bp),
611362306a36Sopenharmony_ci			 reset_phase);
611462306a36Sopenharmony_ci
611562306a36Sopenharmony_ci	switch (reset_phase) {
611662306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_UNLOAD_COMMON:
611762306a36Sopenharmony_ci		bnx2x_func_reset_cmn(bp, drv);
611862306a36Sopenharmony_ci		break;
611962306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_UNLOAD_PORT:
612062306a36Sopenharmony_ci		bnx2x_func_reset_port(bp, drv);
612162306a36Sopenharmony_ci		break;
612262306a36Sopenharmony_ci	case FW_MSG_CODE_DRV_UNLOAD_FUNCTION:
612362306a36Sopenharmony_ci		bnx2x_func_reset_func(bp, drv);
612462306a36Sopenharmony_ci		break;
612562306a36Sopenharmony_ci	default:
612662306a36Sopenharmony_ci		BNX2X_ERR("Unknown reset_phase (0x%x) from MCP\n",
612762306a36Sopenharmony_ci			   reset_phase);
612862306a36Sopenharmony_ci		break;
612962306a36Sopenharmony_ci	}
613062306a36Sopenharmony_ci
613162306a36Sopenharmony_ci	/* Complete the command immediately: no ramrods have been sent. */
613262306a36Sopenharmony_ci	o->complete_cmd(bp, o, BNX2X_F_CMD_HW_RESET);
613362306a36Sopenharmony_ci
613462306a36Sopenharmony_ci	return 0;
613562306a36Sopenharmony_ci}
613662306a36Sopenharmony_ci
613762306a36Sopenharmony_cistatic inline int bnx2x_func_send_start(struct bnx2x *bp,
613862306a36Sopenharmony_ci					struct bnx2x_func_state_params *params)
613962306a36Sopenharmony_ci{
614062306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
614162306a36Sopenharmony_ci	struct function_start_data *rdata =
614262306a36Sopenharmony_ci		(struct function_start_data *)o->rdata;
614362306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
614462306a36Sopenharmony_ci	struct bnx2x_func_start_params *start_params = &params->params.start;
614562306a36Sopenharmony_ci
614662306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
614762306a36Sopenharmony_ci
614862306a36Sopenharmony_ci	/* Fill the ramrod data with provided parameters */
614962306a36Sopenharmony_ci	rdata->function_mode	= (u8)start_params->mf_mode;
615062306a36Sopenharmony_ci	rdata->sd_vlan_tag	= cpu_to_le16(start_params->sd_vlan_tag);
615162306a36Sopenharmony_ci	rdata->path_id		= BP_PATH(bp);
615262306a36Sopenharmony_ci	rdata->network_cos_mode	= start_params->network_cos_mode;
615362306a36Sopenharmony_ci	rdata->dmae_cmd_id	= BNX2X_FW_DMAE_C;
615462306a36Sopenharmony_ci
615562306a36Sopenharmony_ci	rdata->vxlan_dst_port	= cpu_to_le16(start_params->vxlan_dst_port);
615662306a36Sopenharmony_ci	rdata->geneve_dst_port	= cpu_to_le16(start_params->geneve_dst_port);
615762306a36Sopenharmony_ci	rdata->inner_clss_l2gre	= start_params->inner_clss_l2gre;
615862306a36Sopenharmony_ci	rdata->inner_clss_l2geneve = start_params->inner_clss_l2geneve;
615962306a36Sopenharmony_ci	rdata->inner_clss_vxlan	= start_params->inner_clss_vxlan;
616062306a36Sopenharmony_ci	rdata->inner_rss	= start_params->inner_rss;
616162306a36Sopenharmony_ci
616262306a36Sopenharmony_ci	rdata->sd_accept_mf_clss_fail = start_params->class_fail;
616362306a36Sopenharmony_ci	if (start_params->class_fail_ethtype) {
616462306a36Sopenharmony_ci		rdata->sd_accept_mf_clss_fail_match_ethtype = 1;
616562306a36Sopenharmony_ci		rdata->sd_accept_mf_clss_fail_ethtype =
616662306a36Sopenharmony_ci			cpu_to_le16(start_params->class_fail_ethtype);
616762306a36Sopenharmony_ci	}
616862306a36Sopenharmony_ci
616962306a36Sopenharmony_ci	rdata->sd_vlan_force_pri_flg = start_params->sd_vlan_force_pri;
617062306a36Sopenharmony_ci	rdata->sd_vlan_force_pri_val = start_params->sd_vlan_force_pri_val;
617162306a36Sopenharmony_ci	if (start_params->sd_vlan_eth_type)
617262306a36Sopenharmony_ci		rdata->sd_vlan_eth_type =
617362306a36Sopenharmony_ci			cpu_to_le16(start_params->sd_vlan_eth_type);
617462306a36Sopenharmony_ci	else
617562306a36Sopenharmony_ci		rdata->sd_vlan_eth_type =
617662306a36Sopenharmony_ci			cpu_to_le16(0x8100);
617762306a36Sopenharmony_ci
617862306a36Sopenharmony_ci	rdata->no_added_tags = start_params->no_added_tags;
617962306a36Sopenharmony_ci
618062306a36Sopenharmony_ci	rdata->c2s_pri_tt_valid = start_params->c2s_pri_valid;
618162306a36Sopenharmony_ci	if (rdata->c2s_pri_tt_valid) {
618262306a36Sopenharmony_ci		memcpy(rdata->c2s_pri_trans_table.val,
618362306a36Sopenharmony_ci		       start_params->c2s_pri,
618462306a36Sopenharmony_ci		       MAX_VLAN_PRIORITIES);
618562306a36Sopenharmony_ci		rdata->c2s_pri_default = start_params->c2s_pri_default;
618662306a36Sopenharmony_ci	}
618762306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long we would
618862306a36Sopenharmony_ci	 * need to ensure the ordering of writing to the SPQ element
618962306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
619062306a36Sopenharmony_ci	 * read and we will have to put a full memory barrier there
619162306a36Sopenharmony_ci	 * (inside bnx2x_sp_post()).
619262306a36Sopenharmony_ci	 */
619362306a36Sopenharmony_ci
619462306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_START, 0,
619562306a36Sopenharmony_ci			     U64_HI(data_mapping),
619662306a36Sopenharmony_ci			     U64_LO(data_mapping), NONE_CONNECTION_TYPE);
619762306a36Sopenharmony_ci}
619862306a36Sopenharmony_ci
619962306a36Sopenharmony_cistatic inline int bnx2x_func_send_switch_update(struct bnx2x *bp,
620062306a36Sopenharmony_ci					struct bnx2x_func_state_params *params)
620162306a36Sopenharmony_ci{
620262306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
620362306a36Sopenharmony_ci	struct function_update_data *rdata =
620462306a36Sopenharmony_ci		(struct function_update_data *)o->rdata;
620562306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
620662306a36Sopenharmony_ci	struct bnx2x_func_switch_update_params *switch_update_params =
620762306a36Sopenharmony_ci		&params->params.switch_update;
620862306a36Sopenharmony_ci
620962306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
621062306a36Sopenharmony_ci
621162306a36Sopenharmony_ci	/* Fill the ramrod data with provided parameters */
621262306a36Sopenharmony_ci	if (test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
621362306a36Sopenharmony_ci		     &switch_update_params->changes)) {
621462306a36Sopenharmony_ci		rdata->tx_switch_suspend_change_flg = 1;
621562306a36Sopenharmony_ci		rdata->tx_switch_suspend =
621662306a36Sopenharmony_ci			test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
621762306a36Sopenharmony_ci				 &switch_update_params->changes);
621862306a36Sopenharmony_ci	}
621962306a36Sopenharmony_ci
622062306a36Sopenharmony_ci	if (test_bit(BNX2X_F_UPDATE_SD_VLAN_TAG_CHNG,
622162306a36Sopenharmony_ci		     &switch_update_params->changes)) {
622262306a36Sopenharmony_ci		rdata->sd_vlan_tag_change_flg = 1;
622362306a36Sopenharmony_ci		rdata->sd_vlan_tag =
622462306a36Sopenharmony_ci			cpu_to_le16(switch_update_params->vlan);
622562306a36Sopenharmony_ci	}
622662306a36Sopenharmony_ci
622762306a36Sopenharmony_ci	if (test_bit(BNX2X_F_UPDATE_SD_VLAN_ETH_TYPE_CHNG,
622862306a36Sopenharmony_ci		     &switch_update_params->changes)) {
622962306a36Sopenharmony_ci		rdata->sd_vlan_eth_type_change_flg = 1;
623062306a36Sopenharmony_ci		rdata->sd_vlan_eth_type =
623162306a36Sopenharmony_ci			cpu_to_le16(switch_update_params->vlan_eth_type);
623262306a36Sopenharmony_ci	}
623362306a36Sopenharmony_ci
623462306a36Sopenharmony_ci	if (test_bit(BNX2X_F_UPDATE_VLAN_FORCE_PRIO_CHNG,
623562306a36Sopenharmony_ci		     &switch_update_params->changes)) {
623662306a36Sopenharmony_ci		rdata->sd_vlan_force_pri_change_flg = 1;
623762306a36Sopenharmony_ci		if (test_bit(BNX2X_F_UPDATE_VLAN_FORCE_PRIO_FLAG,
623862306a36Sopenharmony_ci			     &switch_update_params->changes))
623962306a36Sopenharmony_ci			rdata->sd_vlan_force_pri_flg = 1;
624062306a36Sopenharmony_ci		rdata->sd_vlan_force_pri_flg =
624162306a36Sopenharmony_ci			switch_update_params->vlan_force_prio;
624262306a36Sopenharmony_ci	}
624362306a36Sopenharmony_ci
624462306a36Sopenharmony_ci	if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
624562306a36Sopenharmony_ci		     &switch_update_params->changes)) {
624662306a36Sopenharmony_ci		rdata->update_tunn_cfg_flg = 1;
624762306a36Sopenharmony_ci		if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GRE,
624862306a36Sopenharmony_ci			     &switch_update_params->changes))
624962306a36Sopenharmony_ci			rdata->inner_clss_l2gre = 1;
625062306a36Sopenharmony_ci		if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_VXLAN,
625162306a36Sopenharmony_ci			     &switch_update_params->changes))
625262306a36Sopenharmony_ci			rdata->inner_clss_vxlan = 1;
625362306a36Sopenharmony_ci		if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GENEVE,
625462306a36Sopenharmony_ci			     &switch_update_params->changes))
625562306a36Sopenharmony_ci			rdata->inner_clss_l2geneve = 1;
625662306a36Sopenharmony_ci		if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_RSS,
625762306a36Sopenharmony_ci			     &switch_update_params->changes))
625862306a36Sopenharmony_ci			rdata->inner_rss = 1;
625962306a36Sopenharmony_ci		rdata->vxlan_dst_port =
626062306a36Sopenharmony_ci			cpu_to_le16(switch_update_params->vxlan_dst_port);
626162306a36Sopenharmony_ci		rdata->geneve_dst_port =
626262306a36Sopenharmony_ci			cpu_to_le16(switch_update_params->geneve_dst_port);
626362306a36Sopenharmony_ci	}
626462306a36Sopenharmony_ci
626562306a36Sopenharmony_ci	rdata->echo = SWITCH_UPDATE;
626662306a36Sopenharmony_ci
626762306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
626862306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
626962306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
627062306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
627162306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
627262306a36Sopenharmony_ci	 */
627362306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0,
627462306a36Sopenharmony_ci			     U64_HI(data_mapping),
627562306a36Sopenharmony_ci			     U64_LO(data_mapping), NONE_CONNECTION_TYPE);
627662306a36Sopenharmony_ci}
627762306a36Sopenharmony_ci
627862306a36Sopenharmony_cistatic inline int bnx2x_func_send_afex_update(struct bnx2x *bp,
627962306a36Sopenharmony_ci					 struct bnx2x_func_state_params *params)
628062306a36Sopenharmony_ci{
628162306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
628262306a36Sopenharmony_ci	struct function_update_data *rdata =
628362306a36Sopenharmony_ci		(struct function_update_data *)o->afex_rdata;
628462306a36Sopenharmony_ci	dma_addr_t data_mapping = o->afex_rdata_mapping;
628562306a36Sopenharmony_ci	struct bnx2x_func_afex_update_params *afex_update_params =
628662306a36Sopenharmony_ci		&params->params.afex_update;
628762306a36Sopenharmony_ci
628862306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
628962306a36Sopenharmony_ci
629062306a36Sopenharmony_ci	/* Fill the ramrod data with provided parameters */
629162306a36Sopenharmony_ci	rdata->vif_id_change_flg = 1;
629262306a36Sopenharmony_ci	rdata->vif_id = cpu_to_le16(afex_update_params->vif_id);
629362306a36Sopenharmony_ci	rdata->afex_default_vlan_change_flg = 1;
629462306a36Sopenharmony_ci	rdata->afex_default_vlan =
629562306a36Sopenharmony_ci		cpu_to_le16(afex_update_params->afex_default_vlan);
629662306a36Sopenharmony_ci	rdata->allowed_priorities_change_flg = 1;
629762306a36Sopenharmony_ci	rdata->allowed_priorities = afex_update_params->allowed_priorities;
629862306a36Sopenharmony_ci	rdata->echo = AFEX_UPDATE;
629962306a36Sopenharmony_ci
630062306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
630162306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
630262306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
630362306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
630462306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
630562306a36Sopenharmony_ci	 */
630662306a36Sopenharmony_ci	DP(BNX2X_MSG_SP,
630762306a36Sopenharmony_ci	   "afex: sending func_update vif_id 0x%x dvlan 0x%x prio 0x%x\n",
630862306a36Sopenharmony_ci	   rdata->vif_id,
630962306a36Sopenharmony_ci	   rdata->afex_default_vlan, rdata->allowed_priorities);
631062306a36Sopenharmony_ci
631162306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0,
631262306a36Sopenharmony_ci			     U64_HI(data_mapping),
631362306a36Sopenharmony_ci			     U64_LO(data_mapping), NONE_CONNECTION_TYPE);
631462306a36Sopenharmony_ci}
631562306a36Sopenharmony_ci
631662306a36Sopenharmony_cistatic
631762306a36Sopenharmony_ciinline int bnx2x_func_send_afex_viflists(struct bnx2x *bp,
631862306a36Sopenharmony_ci					 struct bnx2x_func_state_params *params)
631962306a36Sopenharmony_ci{
632062306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
632162306a36Sopenharmony_ci	struct afex_vif_list_ramrod_data *rdata =
632262306a36Sopenharmony_ci		(struct afex_vif_list_ramrod_data *)o->afex_rdata;
632362306a36Sopenharmony_ci	struct bnx2x_func_afex_viflists_params *afex_vif_params =
632462306a36Sopenharmony_ci		&params->params.afex_viflists;
632562306a36Sopenharmony_ci	u64 *p_rdata = (u64 *)rdata;
632662306a36Sopenharmony_ci
632762306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
632862306a36Sopenharmony_ci
632962306a36Sopenharmony_ci	/* Fill the ramrod data with provided parameters */
633062306a36Sopenharmony_ci	rdata->vif_list_index = cpu_to_le16(afex_vif_params->vif_list_index);
633162306a36Sopenharmony_ci	rdata->func_bit_map          = afex_vif_params->func_bit_map;
633262306a36Sopenharmony_ci	rdata->afex_vif_list_command = afex_vif_params->afex_vif_list_command;
633362306a36Sopenharmony_ci	rdata->func_to_clear         = afex_vif_params->func_to_clear;
633462306a36Sopenharmony_ci
633562306a36Sopenharmony_ci	/* send in echo type of sub command */
633662306a36Sopenharmony_ci	rdata->echo = afex_vif_params->afex_vif_list_command;
633762306a36Sopenharmony_ci
633862306a36Sopenharmony_ci	/*  No need for an explicit memory barrier here as long we would
633962306a36Sopenharmony_ci	 *  need to ensure the ordering of writing to the SPQ element
634062306a36Sopenharmony_ci	 *  and updating of the SPQ producer which involves a memory
634162306a36Sopenharmony_ci	 *  read and we will have to put a full memory barrier there
634262306a36Sopenharmony_ci	 *  (inside bnx2x_sp_post()).
634362306a36Sopenharmony_ci	 */
634462306a36Sopenharmony_ci
634562306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "afex: ramrod lists, cmd 0x%x index 0x%x func_bit_map 0x%x func_to_clr 0x%x\n",
634662306a36Sopenharmony_ci	   rdata->afex_vif_list_command, rdata->vif_list_index,
634762306a36Sopenharmony_ci	   rdata->func_bit_map, rdata->func_to_clear);
634862306a36Sopenharmony_ci
634962306a36Sopenharmony_ci	/* this ramrod sends data directly and not through DMA mapping */
635062306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_AFEX_VIF_LISTS, 0,
635162306a36Sopenharmony_ci			     U64_HI(*p_rdata), U64_LO(*p_rdata),
635262306a36Sopenharmony_ci			     NONE_CONNECTION_TYPE);
635362306a36Sopenharmony_ci}
635462306a36Sopenharmony_ci
635562306a36Sopenharmony_cistatic inline int bnx2x_func_send_stop(struct bnx2x *bp,
635662306a36Sopenharmony_ci				       struct bnx2x_func_state_params *params)
635762306a36Sopenharmony_ci{
635862306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_STOP, 0, 0, 0,
635962306a36Sopenharmony_ci			     NONE_CONNECTION_TYPE);
636062306a36Sopenharmony_ci}
636162306a36Sopenharmony_ci
636262306a36Sopenharmony_cistatic inline int bnx2x_func_send_tx_stop(struct bnx2x *bp,
636362306a36Sopenharmony_ci				       struct bnx2x_func_state_params *params)
636462306a36Sopenharmony_ci{
636562306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC, 0, 0, 0,
636662306a36Sopenharmony_ci			     NONE_CONNECTION_TYPE);
636762306a36Sopenharmony_ci}
636862306a36Sopenharmony_cistatic inline int bnx2x_func_send_tx_start(struct bnx2x *bp,
636962306a36Sopenharmony_ci				       struct bnx2x_func_state_params *params)
637062306a36Sopenharmony_ci{
637162306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
637262306a36Sopenharmony_ci	struct flow_control_configuration *rdata =
637362306a36Sopenharmony_ci		(struct flow_control_configuration *)o->rdata;
637462306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
637562306a36Sopenharmony_ci	struct bnx2x_func_tx_start_params *tx_start_params =
637662306a36Sopenharmony_ci		&params->params.tx_start;
637762306a36Sopenharmony_ci	int i;
637862306a36Sopenharmony_ci
637962306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
638062306a36Sopenharmony_ci
638162306a36Sopenharmony_ci	rdata->dcb_enabled = tx_start_params->dcb_enabled;
638262306a36Sopenharmony_ci	rdata->dcb_version = tx_start_params->dcb_version;
638362306a36Sopenharmony_ci	rdata->dont_add_pri_0_en = tx_start_params->dont_add_pri_0_en;
638462306a36Sopenharmony_ci
638562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rdata->traffic_type_to_priority_cos); i++)
638662306a36Sopenharmony_ci		rdata->traffic_type_to_priority_cos[i] =
638762306a36Sopenharmony_ci			tx_start_params->traffic_type_to_priority_cos[i];
638862306a36Sopenharmony_ci
638962306a36Sopenharmony_ci	for (i = 0; i < MAX_TRAFFIC_TYPES; i++)
639062306a36Sopenharmony_ci		rdata->dcb_outer_pri[i] = tx_start_params->dcb_outer_pri[i];
639162306a36Sopenharmony_ci	/* No need for an explicit memory barrier here as long as we
639262306a36Sopenharmony_ci	 * ensure the ordering of writing to the SPQ element
639362306a36Sopenharmony_ci	 * and updating of the SPQ producer which involves a memory
639462306a36Sopenharmony_ci	 * read. If the memory read is removed we will have to put a
639562306a36Sopenharmony_ci	 * full memory barrier there (inside bnx2x_sp_post()).
639662306a36Sopenharmony_ci	 */
639762306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0,
639862306a36Sopenharmony_ci			     U64_HI(data_mapping),
639962306a36Sopenharmony_ci			     U64_LO(data_mapping), NONE_CONNECTION_TYPE);
640062306a36Sopenharmony_ci}
640162306a36Sopenharmony_ci
640262306a36Sopenharmony_cistatic inline
640362306a36Sopenharmony_ciint bnx2x_func_send_set_timesync(struct bnx2x *bp,
640462306a36Sopenharmony_ci				 struct bnx2x_func_state_params *params)
640562306a36Sopenharmony_ci{
640662306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
640762306a36Sopenharmony_ci	struct set_timesync_ramrod_data *rdata =
640862306a36Sopenharmony_ci		(struct set_timesync_ramrod_data *)o->rdata;
640962306a36Sopenharmony_ci	dma_addr_t data_mapping = o->rdata_mapping;
641062306a36Sopenharmony_ci	struct bnx2x_func_set_timesync_params *set_timesync_params =
641162306a36Sopenharmony_ci		&params->params.set_timesync;
641262306a36Sopenharmony_ci
641362306a36Sopenharmony_ci	memset(rdata, 0, sizeof(*rdata));
641462306a36Sopenharmony_ci
641562306a36Sopenharmony_ci	/* Fill the ramrod data with provided parameters */
641662306a36Sopenharmony_ci	rdata->drift_adjust_cmd = set_timesync_params->drift_adjust_cmd;
641762306a36Sopenharmony_ci	rdata->offset_cmd = set_timesync_params->offset_cmd;
641862306a36Sopenharmony_ci	rdata->add_sub_drift_adjust_value =
641962306a36Sopenharmony_ci		set_timesync_params->add_sub_drift_adjust_value;
642062306a36Sopenharmony_ci	rdata->drift_adjust_value = set_timesync_params->drift_adjust_value;
642162306a36Sopenharmony_ci	rdata->drift_adjust_period = set_timesync_params->drift_adjust_period;
642262306a36Sopenharmony_ci	rdata->offset_delta.lo =
642362306a36Sopenharmony_ci		cpu_to_le32(U64_LO(set_timesync_params->offset_delta));
642462306a36Sopenharmony_ci	rdata->offset_delta.hi =
642562306a36Sopenharmony_ci		cpu_to_le32(U64_HI(set_timesync_params->offset_delta));
642662306a36Sopenharmony_ci
642762306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "Set timesync command params: drift_cmd = %d, offset_cmd = %d, add_sub_drift = %d, drift_val = %d, drift_period = %d, offset_lo = %d, offset_hi = %d\n",
642862306a36Sopenharmony_ci	   rdata->drift_adjust_cmd, rdata->offset_cmd,
642962306a36Sopenharmony_ci	   rdata->add_sub_drift_adjust_value, rdata->drift_adjust_value,
643062306a36Sopenharmony_ci	   rdata->drift_adjust_period, rdata->offset_delta.lo,
643162306a36Sopenharmony_ci	   rdata->offset_delta.hi);
643262306a36Sopenharmony_ci
643362306a36Sopenharmony_ci	return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_TIMESYNC, 0,
643462306a36Sopenharmony_ci			     U64_HI(data_mapping),
643562306a36Sopenharmony_ci			     U64_LO(data_mapping), NONE_CONNECTION_TYPE);
643662306a36Sopenharmony_ci}
643762306a36Sopenharmony_ci
643862306a36Sopenharmony_cistatic int bnx2x_func_send_cmd(struct bnx2x *bp,
643962306a36Sopenharmony_ci			       struct bnx2x_func_state_params *params)
644062306a36Sopenharmony_ci{
644162306a36Sopenharmony_ci	switch (params->cmd) {
644262306a36Sopenharmony_ci	case BNX2X_F_CMD_HW_INIT:
644362306a36Sopenharmony_ci		return bnx2x_func_hw_init(bp, params);
644462306a36Sopenharmony_ci	case BNX2X_F_CMD_START:
644562306a36Sopenharmony_ci		return bnx2x_func_send_start(bp, params);
644662306a36Sopenharmony_ci	case BNX2X_F_CMD_STOP:
644762306a36Sopenharmony_ci		return bnx2x_func_send_stop(bp, params);
644862306a36Sopenharmony_ci	case BNX2X_F_CMD_HW_RESET:
644962306a36Sopenharmony_ci		return bnx2x_func_hw_reset(bp, params);
645062306a36Sopenharmony_ci	case BNX2X_F_CMD_AFEX_UPDATE:
645162306a36Sopenharmony_ci		return bnx2x_func_send_afex_update(bp, params);
645262306a36Sopenharmony_ci	case BNX2X_F_CMD_AFEX_VIFLISTS:
645362306a36Sopenharmony_ci		return bnx2x_func_send_afex_viflists(bp, params);
645462306a36Sopenharmony_ci	case BNX2X_F_CMD_TX_STOP:
645562306a36Sopenharmony_ci		return bnx2x_func_send_tx_stop(bp, params);
645662306a36Sopenharmony_ci	case BNX2X_F_CMD_TX_START:
645762306a36Sopenharmony_ci		return bnx2x_func_send_tx_start(bp, params);
645862306a36Sopenharmony_ci	case BNX2X_F_CMD_SWITCH_UPDATE:
645962306a36Sopenharmony_ci		return bnx2x_func_send_switch_update(bp, params);
646062306a36Sopenharmony_ci	case BNX2X_F_CMD_SET_TIMESYNC:
646162306a36Sopenharmony_ci		return bnx2x_func_send_set_timesync(bp, params);
646262306a36Sopenharmony_ci	default:
646362306a36Sopenharmony_ci		BNX2X_ERR("Unknown command: %d\n", params->cmd);
646462306a36Sopenharmony_ci		return -EINVAL;
646562306a36Sopenharmony_ci	}
646662306a36Sopenharmony_ci}
646762306a36Sopenharmony_ci
646862306a36Sopenharmony_civoid bnx2x_init_func_obj(struct bnx2x *bp,
646962306a36Sopenharmony_ci			 struct bnx2x_func_sp_obj *obj,
647062306a36Sopenharmony_ci			 void *rdata, dma_addr_t rdata_mapping,
647162306a36Sopenharmony_ci			 void *afex_rdata, dma_addr_t afex_rdata_mapping,
647262306a36Sopenharmony_ci			 struct bnx2x_func_sp_drv_ops *drv_iface)
647362306a36Sopenharmony_ci{
647462306a36Sopenharmony_ci	memset(obj, 0, sizeof(*obj));
647562306a36Sopenharmony_ci
647662306a36Sopenharmony_ci	mutex_init(&obj->one_pending_mutex);
647762306a36Sopenharmony_ci
647862306a36Sopenharmony_ci	obj->rdata = rdata;
647962306a36Sopenharmony_ci	obj->rdata_mapping = rdata_mapping;
648062306a36Sopenharmony_ci	obj->afex_rdata = afex_rdata;
648162306a36Sopenharmony_ci	obj->afex_rdata_mapping = afex_rdata_mapping;
648262306a36Sopenharmony_ci	obj->send_cmd = bnx2x_func_send_cmd;
648362306a36Sopenharmony_ci	obj->check_transition = bnx2x_func_chk_transition;
648462306a36Sopenharmony_ci	obj->complete_cmd = bnx2x_func_comp_cmd;
648562306a36Sopenharmony_ci	obj->wait_comp = bnx2x_func_wait_comp;
648662306a36Sopenharmony_ci
648762306a36Sopenharmony_ci	obj->drv = drv_iface;
648862306a36Sopenharmony_ci}
648962306a36Sopenharmony_ci
649062306a36Sopenharmony_ci/**
649162306a36Sopenharmony_ci * bnx2x_func_state_change - perform Function state change transition
649262306a36Sopenharmony_ci *
649362306a36Sopenharmony_ci * @bp:		device handle
649462306a36Sopenharmony_ci * @params:	parameters to perform the transaction
649562306a36Sopenharmony_ci *
649662306a36Sopenharmony_ci * returns 0 in case of successfully completed transition,
649762306a36Sopenharmony_ci *         negative error code in case of failure, positive
649862306a36Sopenharmony_ci *         (EBUSY) value if there is a completion to that is
649962306a36Sopenharmony_ci *         still pending (possible only if RAMROD_COMP_WAIT is
650062306a36Sopenharmony_ci *         not set in params->ramrod_flags for asynchronous
650162306a36Sopenharmony_ci *         commands).
650262306a36Sopenharmony_ci */
650362306a36Sopenharmony_ciint bnx2x_func_state_change(struct bnx2x *bp,
650462306a36Sopenharmony_ci			    struct bnx2x_func_state_params *params)
650562306a36Sopenharmony_ci{
650662306a36Sopenharmony_ci	struct bnx2x_func_sp_obj *o = params->f_obj;
650762306a36Sopenharmony_ci	int rc, cnt = 300;
650862306a36Sopenharmony_ci	enum bnx2x_func_cmd cmd = params->cmd;
650962306a36Sopenharmony_ci	unsigned long *pending = &o->pending;
651062306a36Sopenharmony_ci
651162306a36Sopenharmony_ci	mutex_lock(&o->one_pending_mutex);
651262306a36Sopenharmony_ci
651362306a36Sopenharmony_ci	/* Check that the requested transition is legal */
651462306a36Sopenharmony_ci	rc = o->check_transition(bp, o, params);
651562306a36Sopenharmony_ci	if ((rc == -EBUSY) &&
651662306a36Sopenharmony_ci	    (test_bit(RAMROD_RETRY, &params->ramrod_flags))) {
651762306a36Sopenharmony_ci		while ((rc == -EBUSY) && (--cnt > 0)) {
651862306a36Sopenharmony_ci			mutex_unlock(&o->one_pending_mutex);
651962306a36Sopenharmony_ci			msleep(10);
652062306a36Sopenharmony_ci			mutex_lock(&o->one_pending_mutex);
652162306a36Sopenharmony_ci			rc = o->check_transition(bp, o, params);
652262306a36Sopenharmony_ci		}
652362306a36Sopenharmony_ci		if (rc == -EBUSY) {
652462306a36Sopenharmony_ci			mutex_unlock(&o->one_pending_mutex);
652562306a36Sopenharmony_ci			BNX2X_ERR("timeout waiting for previous ramrod completion\n");
652662306a36Sopenharmony_ci			return rc;
652762306a36Sopenharmony_ci		}
652862306a36Sopenharmony_ci	} else if (rc) {
652962306a36Sopenharmony_ci		mutex_unlock(&o->one_pending_mutex);
653062306a36Sopenharmony_ci		return rc;
653162306a36Sopenharmony_ci	}
653262306a36Sopenharmony_ci
653362306a36Sopenharmony_ci	/* Set "pending" bit */
653462306a36Sopenharmony_ci	set_bit(cmd, pending);
653562306a36Sopenharmony_ci
653662306a36Sopenharmony_ci	/* Don't send a command if only driver cleanup was requested */
653762306a36Sopenharmony_ci	if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
653862306a36Sopenharmony_ci		bnx2x_func_state_change_comp(bp, o, cmd);
653962306a36Sopenharmony_ci		mutex_unlock(&o->one_pending_mutex);
654062306a36Sopenharmony_ci	} else {
654162306a36Sopenharmony_ci		/* Send a ramrod */
654262306a36Sopenharmony_ci		rc = o->send_cmd(bp, params);
654362306a36Sopenharmony_ci
654462306a36Sopenharmony_ci		mutex_unlock(&o->one_pending_mutex);
654562306a36Sopenharmony_ci
654662306a36Sopenharmony_ci		if (rc) {
654762306a36Sopenharmony_ci			o->next_state = BNX2X_F_STATE_MAX;
654862306a36Sopenharmony_ci			clear_bit(cmd, pending);
654962306a36Sopenharmony_ci			smp_mb__after_atomic();
655062306a36Sopenharmony_ci			return rc;
655162306a36Sopenharmony_ci		}
655262306a36Sopenharmony_ci
655362306a36Sopenharmony_ci		if (test_bit(RAMROD_COMP_WAIT, &params->ramrod_flags)) {
655462306a36Sopenharmony_ci			rc = o->wait_comp(bp, o, cmd);
655562306a36Sopenharmony_ci			if (rc)
655662306a36Sopenharmony_ci				return rc;
655762306a36Sopenharmony_ci
655862306a36Sopenharmony_ci			return 0;
655962306a36Sopenharmony_ci		}
656062306a36Sopenharmony_ci	}
656162306a36Sopenharmony_ci
656262306a36Sopenharmony_ci	return !!test_bit(cmd, pending);
656362306a36Sopenharmony_ci}
6564