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, ®_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(®_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 ®_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(®_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(®_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(®_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(¤t_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, ¶ms->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, ¶ms->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, ¶ms->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 = ¶ms->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 ¶ms->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, ¶ms->update_flags); 516262306a36Sopenharmony_ci data->inner_vlan_removal_change_flg = 516362306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM_CHNG, 516462306a36Sopenharmony_ci ¶ms->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, ¶ms->update_flags); 516962306a36Sopenharmony_ci data->outer_vlan_removal_change_flg = 517062306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM_CHNG, 517162306a36Sopenharmony_ci ¶ms->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, ¶ms->update_flags); 517862306a36Sopenharmony_ci data->anti_spoofing_change_flg = 517962306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG, ¶ms->update_flags); 518062306a36Sopenharmony_ci 518162306a36Sopenharmony_ci /* Activate/Deactivate */ 518262306a36Sopenharmony_ci data->activate_flg = 518362306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ACTIVATE, ¶ms->update_flags); 518462306a36Sopenharmony_ci data->activate_change_flg = 518562306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, ¶ms->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, ¶ms->update_flags); 519062306a36Sopenharmony_ci data->default_vlan_change_flg = 519162306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, 519262306a36Sopenharmony_ci ¶ms->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 ¶ms->update_flags); 519862306a36Sopenharmony_ci data->silent_vlan_removal_flg = 519962306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, ¶ms->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, ¶ms->update_flags); 520662306a36Sopenharmony_ci data->tx_switching_change_flg = 520762306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG, 520862306a36Sopenharmony_ci ¶ms->update_flags); 520962306a36Sopenharmony_ci 521062306a36Sopenharmony_ci /* PTP */ 521162306a36Sopenharmony_ci data->handle_ptp_pkts_flg = 521262306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_PTP_PKTS, ¶ms->update_flags); 521362306a36Sopenharmony_ci data->handle_ptp_pkts_change_flg = 521462306a36Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG, ¶ms->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 ¶ms->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 = ¶ms->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 = ¶ms->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 ¶ms->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 ¶ms->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, ¶ms->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 ¶ms->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, ¶ms->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 = ¶ms->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 ¶ms->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 ¶ms->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 ¶ms->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 ¶ms->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 ¶ms->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, ¶ms->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, ¶ms->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, ¶ms->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