18c2ecf20Sopenharmony_ci/* bnx2x_sp.c: Qlogic Everest network driver. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright 2011-2013 Broadcom Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2014 QLogic Corporation 58c2ecf20Sopenharmony_ci * All rights reserved 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Unless you and Qlogic execute a separate written software license 88c2ecf20Sopenharmony_ci * agreement governing use of this software, this software is licensed to you 98c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License version 2, available 108c2ecf20Sopenharmony_ci * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Notwithstanding the above, under no circumstances may you combine this 138c2ecf20Sopenharmony_ci * software in any way with any other Qlogic software provided under a 148c2ecf20Sopenharmony_ci * license other than the GPL, without Qlogic's express prior written 158c2ecf20Sopenharmony_ci * consent. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com> 188c2ecf20Sopenharmony_ci * Written by: Vladislav Zolotarov 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/module.h> 258c2ecf20Sopenharmony_ci#include <linux/crc32.h> 268c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 278c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 288c2ecf20Sopenharmony_ci#include <linux/crc32c.h> 298c2ecf20Sopenharmony_ci#include "bnx2x.h" 308c2ecf20Sopenharmony_ci#include "bnx2x_cmn.h" 318c2ecf20Sopenharmony_ci#include "bnx2x_sp.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define BNX2X_MAX_EMUL_MULTI 16 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/**** Exe Queue interfaces ****/ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/** 388c2ecf20Sopenharmony_ci * bnx2x_exe_queue_init - init the Exe Queue object 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * @bp: driver handle 418c2ecf20Sopenharmony_ci * @o: pointer to the object 428c2ecf20Sopenharmony_ci * @exe_len: length 438c2ecf20Sopenharmony_ci * @owner: pointer to the owner 448c2ecf20Sopenharmony_ci * @validate: validate function pointer 458c2ecf20Sopenharmony_ci * @remove: remove function pointer 468c2ecf20Sopenharmony_ci * @optimize: optimize function pointer 478c2ecf20Sopenharmony_ci * @exec: execute function pointer 488c2ecf20Sopenharmony_ci * @get: get function pointer 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_cistatic inline void bnx2x_exe_queue_init(struct bnx2x *bp, 518c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o, 528c2ecf20Sopenharmony_ci int exe_len, 538c2ecf20Sopenharmony_ci union bnx2x_qable_obj *owner, 548c2ecf20Sopenharmony_ci exe_q_validate validate, 558c2ecf20Sopenharmony_ci exe_q_remove remove, 568c2ecf20Sopenharmony_ci exe_q_optimize optimize, 578c2ecf20Sopenharmony_ci exe_q_execute exec, 588c2ecf20Sopenharmony_ci exe_q_get get) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci memset(o, 0, sizeof(*o)); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&o->exe_queue); 638c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&o->pending_comp); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci spin_lock_init(&o->lock); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci o->exe_chunk_len = exe_len; 688c2ecf20Sopenharmony_ci o->owner = owner; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Owner specific callbacks */ 718c2ecf20Sopenharmony_ci o->validate = validate; 728c2ecf20Sopenharmony_ci o->remove = remove; 738c2ecf20Sopenharmony_ci o->optimize = optimize; 748c2ecf20Sopenharmony_ci o->execute = exec; 758c2ecf20Sopenharmony_ci o->get = get; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Setup the execution queue with the chunk length of %d\n", 788c2ecf20Sopenharmony_ci exe_len); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void bnx2x_exe_queue_free_elem(struct bnx2x *bp, 828c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Deleting an exe_queue element\n"); 858c2ecf20Sopenharmony_ci kfree(elem); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic inline int bnx2x_exe_queue_length(struct bnx2x_exe_queue_obj *o) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem; 918c2ecf20Sopenharmony_ci int cnt = 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci spin_lock_bh(&o->lock); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci list_for_each_entry(elem, &o->exe_queue, link) 968c2ecf20Sopenharmony_ci cnt++; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci spin_unlock_bh(&o->lock); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return cnt; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * bnx2x_exe_queue_add - add a new element to the execution queue 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * @bp: driver handle 1078c2ecf20Sopenharmony_ci * @o: queue 1088c2ecf20Sopenharmony_ci * @elem: new command to add 1098c2ecf20Sopenharmony_ci * @restore: true - do not optimize the command 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * If the element is optimized or is illegal, frees it. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_cistatic inline int bnx2x_exe_queue_add(struct bnx2x *bp, 1148c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o, 1158c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, 1168c2ecf20Sopenharmony_ci bool restore) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int rc; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci spin_lock_bh(&o->lock); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (!restore) { 1238c2ecf20Sopenharmony_ci /* Try to cancel this element queue */ 1248c2ecf20Sopenharmony_ci rc = o->optimize(bp, o->owner, elem); 1258c2ecf20Sopenharmony_ci if (rc) 1268c2ecf20Sopenharmony_ci goto free_and_exit; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* Check if this request is ok */ 1298c2ecf20Sopenharmony_ci rc = o->validate(bp, o->owner, elem); 1308c2ecf20Sopenharmony_ci if (rc) { 1318c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Preamble failed: %d\n", rc); 1328c2ecf20Sopenharmony_ci goto free_and_exit; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* If so, add it to the execution queue */ 1378c2ecf20Sopenharmony_ci list_add_tail(&elem->link, &o->exe_queue); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci spin_unlock_bh(&o->lock); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cifree_and_exit: 1448c2ecf20Sopenharmony_ci bnx2x_exe_queue_free_elem(bp, elem); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci spin_unlock_bh(&o->lock); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return rc; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void __bnx2x_exe_queue_reset_pending( 1528c2ecf20Sopenharmony_ci struct bnx2x *bp, 1538c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci while (!list_empty(&o->pending_comp)) { 1588c2ecf20Sopenharmony_ci elem = list_first_entry(&o->pending_comp, 1598c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem, link); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci list_del(&elem->link); 1628c2ecf20Sopenharmony_ci bnx2x_exe_queue_free_elem(bp, elem); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * bnx2x_exe_queue_step - execute one execution chunk atomically 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * @bp: driver handle 1708c2ecf20Sopenharmony_ci * @o: queue 1718c2ecf20Sopenharmony_ci * @ramrod_flags: flags 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * (Should be called while holding the exe_queue->lock). 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic inline int bnx2x_exe_queue_step(struct bnx2x *bp, 1768c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o, 1778c2ecf20Sopenharmony_ci unsigned long *ramrod_flags) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, spacer; 1808c2ecf20Sopenharmony_ci int cur_len = 0, rc; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci memset(&spacer, 0, sizeof(spacer)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Next step should not be performed until the current is finished, 1858c2ecf20Sopenharmony_ci * unless a DRV_CLEAR_ONLY bit is set. In this case we just want to 1868c2ecf20Sopenharmony_ci * properly clear object internals without sending any command to the FW 1878c2ecf20Sopenharmony_ci * which also implies there won't be any completion to clear the 1888c2ecf20Sopenharmony_ci * 'pending' list. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci if (!list_empty(&o->pending_comp)) { 1918c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags)) { 1928c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: resetting a pending_comp list\n"); 1938c2ecf20Sopenharmony_ci __bnx2x_exe_queue_reset_pending(bp, o); 1948c2ecf20Sopenharmony_ci } else { 1958c2ecf20Sopenharmony_ci return 1; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Run through the pending commands list and create a next 2008c2ecf20Sopenharmony_ci * execution chunk. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci while (!list_empty(&o->exe_queue)) { 2038c2ecf20Sopenharmony_ci elem = list_first_entry(&o->exe_queue, struct bnx2x_exeq_elem, 2048c2ecf20Sopenharmony_ci link); 2058c2ecf20Sopenharmony_ci WARN_ON(!elem->cmd_len); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (cur_len + elem->cmd_len <= o->exe_chunk_len) { 2088c2ecf20Sopenharmony_ci cur_len += elem->cmd_len; 2098c2ecf20Sopenharmony_ci /* Prevent from both lists being empty when moving an 2108c2ecf20Sopenharmony_ci * element. This will allow the call of 2118c2ecf20Sopenharmony_ci * bnx2x_exe_queue_empty() without locking. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci list_add_tail(&spacer.link, &o->pending_comp); 2148c2ecf20Sopenharmony_ci mb(); 2158c2ecf20Sopenharmony_ci list_move_tail(&elem->link, &o->pending_comp); 2168c2ecf20Sopenharmony_ci list_del(&spacer.link); 2178c2ecf20Sopenharmony_ci } else 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Sanity check */ 2228c2ecf20Sopenharmony_ci if (!cur_len) 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags); 2268c2ecf20Sopenharmony_ci if (rc < 0) 2278c2ecf20Sopenharmony_ci /* In case of an error return the commands back to the queue 2288c2ecf20Sopenharmony_ci * and reset the pending_comp. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci list_splice_init(&o->pending_comp, &o->exe_queue); 2318c2ecf20Sopenharmony_ci else if (!rc) 2328c2ecf20Sopenharmony_ci /* If zero is returned, means there are no outstanding pending 2338c2ecf20Sopenharmony_ci * completions and we may dismiss the pending list. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci __bnx2x_exe_queue_reset_pending(bp, o); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return rc; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic inline bool bnx2x_exe_queue_empty(struct bnx2x_exe_queue_obj *o) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci bool empty = list_empty(&o->exe_queue); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Don't reorder!!! */ 2458c2ecf20Sopenharmony_ci mb(); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return empty && list_empty(&o->pending_comp); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic inline struct bnx2x_exeq_elem *bnx2x_exe_queue_alloc_elem( 2518c2ecf20Sopenharmony_ci struct bnx2x *bp) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Allocating a new exe_queue element\n"); 2548c2ecf20Sopenharmony_ci return kzalloc(sizeof(struct bnx2x_exeq_elem), GFP_ATOMIC); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/************************ raw_obj functions ***********************************/ 2588c2ecf20Sopenharmony_cistatic bool bnx2x_raw_check_pending(struct bnx2x_raw_obj *o) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci return !!test_bit(o->state, o->pstate); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void bnx2x_raw_clear_pending(struct bnx2x_raw_obj *o) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 2668c2ecf20Sopenharmony_ci clear_bit(o->state, o->pstate); 2678c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void bnx2x_raw_set_pending(struct bnx2x_raw_obj *o) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 2738c2ecf20Sopenharmony_ci set_bit(o->state, o->pstate); 2748c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/** 2788c2ecf20Sopenharmony_ci * bnx2x_state_wait - wait until the given bit(state) is cleared 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * @bp: device handle 2818c2ecf20Sopenharmony_ci * @state: state which is to be cleared 2828c2ecf20Sopenharmony_ci * @pstate: state buffer 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic inline int bnx2x_state_wait(struct bnx2x *bp, int state, 2868c2ecf20Sopenharmony_ci unsigned long *pstate) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci /* can take a while if any port is running */ 2898c2ecf20Sopenharmony_ci int cnt = 5000; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (CHIP_REV_IS_EMUL(bp)) 2928c2ecf20Sopenharmony_ci cnt *= 20; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "waiting for state to become %d\n", state); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci might_sleep(); 2978c2ecf20Sopenharmony_ci while (cnt--) { 2988c2ecf20Sopenharmony_ci if (!test_bit(state, pstate)) { 2998c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 3008c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "exit (cnt %d)\n", 5000 - cnt); 3018c2ecf20Sopenharmony_ci#endif 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (bp->panic) 3088c2ecf20Sopenharmony_ci return -EIO; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* timeout! */ 3128c2ecf20Sopenharmony_ci BNX2X_ERR("timeout waiting for state %d\n", state); 3138c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 3148c2ecf20Sopenharmony_ci bnx2x_panic(); 3158c2ecf20Sopenharmony_ci#endif 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return -EBUSY; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int bnx2x_raw_wait(struct bnx2x *bp, struct bnx2x_raw_obj *raw) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci return bnx2x_state_wait(bp, raw->state, raw->pstate); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/***************** Classification verbs: Set/Del MAC/VLAN/VLAN-MAC ************/ 3268c2ecf20Sopenharmony_ci/* credit handling callbacks */ 3278c2ecf20Sopenharmony_cistatic bool bnx2x_get_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int *offset) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *mp = o->macs_pool; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci WARN_ON(!mp); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return mp->get_entry(mp, offset); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic bool bnx2x_get_credit_mac(struct bnx2x_vlan_mac_obj *o) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *mp = o->macs_pool; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci WARN_ON(!mp); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return mp->get(mp, 1); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic bool bnx2x_get_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int *offset) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vp = o->vlans_pool; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci WARN_ON(!vp); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return vp->get_entry(vp, offset); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vp = o->vlans_pool; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci WARN_ON(!vp); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return vp->get(vp, 1); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *mp = o->macs_pool; 3668c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vp = o->vlans_pool; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (!mp->get(mp, 1)) 3698c2ecf20Sopenharmony_ci return false; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (!vp->get(vp, 1)) { 3728c2ecf20Sopenharmony_ci mp->put(mp, 1); 3738c2ecf20Sopenharmony_ci return false; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return true; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *mp = o->macs_pool; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return mp->put_entry(mp, offset); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic bool bnx2x_put_credit_mac(struct bnx2x_vlan_mac_obj *o) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *mp = o->macs_pool; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return mp->put(mp, 1); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic bool bnx2x_put_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int offset) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vp = o->vlans_pool; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return vp->put_entry(vp, offset); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vp = o->vlans_pool; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return vp->put(vp, 1); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *mp = o->macs_pool; 4108c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vp = o->vlans_pool; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (!mp->put(mp, 1)) 4138c2ecf20Sopenharmony_ci return false; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (!vp->put(vp, 1)) { 4168c2ecf20Sopenharmony_ci mp->get(mp, 1); 4178c2ecf20Sopenharmony_ci return false; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return true; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/** 4248c2ecf20Sopenharmony_ci * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * @bp: device handle 4278c2ecf20Sopenharmony_ci * @o: vlan_mac object 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * Context: Non-blocking implementation; should be called under execution 4308c2ecf20Sopenharmony_ci * queue lock. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_cistatic int __bnx2x_vlan_mac_h_write_trylock(struct bnx2x *bp, 4338c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci if (o->head_reader) { 4368c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock writer - There are readers; Busy\n"); 4378c2ecf20Sopenharmony_ci return -EBUSY; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock writer - Taken\n"); 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/** 4458c2ecf20Sopenharmony_ci * __bnx2x_vlan_mac_h_exec_pending - execute step instead of a previous step 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * @bp: device handle 4488c2ecf20Sopenharmony_ci * @o: vlan_mac object 4498c2ecf20Sopenharmony_ci * 4508c2ecf20Sopenharmony_ci * details Should be called under execution queue lock; notice it might release 4518c2ecf20Sopenharmony_ci * and reclaim it during its run. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_cistatic void __bnx2x_vlan_mac_h_exec_pending(struct bnx2x *bp, 4548c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci int rc; 4578c2ecf20Sopenharmony_ci unsigned long ramrod_flags = o->saved_ramrod_flags; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock execute pending command with ramrod flags %lu\n", 4608c2ecf20Sopenharmony_ci ramrod_flags); 4618c2ecf20Sopenharmony_ci o->head_exe_request = false; 4628c2ecf20Sopenharmony_ci o->saved_ramrod_flags = 0; 4638c2ecf20Sopenharmony_ci rc = bnx2x_exe_queue_step(bp, &o->exe_queue, &ramrod_flags); 4648c2ecf20Sopenharmony_ci if ((rc != 0) && (rc != 1)) { 4658c2ecf20Sopenharmony_ci BNX2X_ERR("execution of pending commands failed with rc %d\n", 4668c2ecf20Sopenharmony_ci rc); 4678c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 4688c2ecf20Sopenharmony_ci bnx2x_panic(); 4698c2ecf20Sopenharmony_ci#endif 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/** 4748c2ecf20Sopenharmony_ci * __bnx2x_vlan_mac_h_pend - Pend an execution step which couldn't run 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * @bp: device handle 4778c2ecf20Sopenharmony_ci * @o: vlan_mac object 4788c2ecf20Sopenharmony_ci * @ramrod_flags: ramrod flags of missed execution 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci * Context: Should be called under execution queue lock. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_cistatic void __bnx2x_vlan_mac_h_pend(struct bnx2x *bp, 4838c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 4848c2ecf20Sopenharmony_ci unsigned long ramrod_flags) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci o->head_exe_request = true; 4878c2ecf20Sopenharmony_ci o->saved_ramrod_flags = ramrod_flags; 4888c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Placing pending execution with ramrod flags %lu\n", 4898c2ecf20Sopenharmony_ci ramrod_flags); 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/** 4938c2ecf20Sopenharmony_ci * __bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci * @bp: device handle 4968c2ecf20Sopenharmony_ci * @o: vlan_mac object 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * Context: Should be called under execution queue lock. Notice if a pending 4998c2ecf20Sopenharmony_ci * execution exists, it would perform it - possibly releasing and 5008c2ecf20Sopenharmony_ci * reclaiming the execution queue lock. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, 5038c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci /* It's possible a new pending execution was added since this writer 5068c2ecf20Sopenharmony_ci * executed. If so, execute again. [Ad infinitum] 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci while (o->head_exe_request) { 5098c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock - writer release encountered a pending request\n"); 5108c2ecf20Sopenharmony_ci __bnx2x_vlan_mac_h_exec_pending(bp, o); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/** 5168c2ecf20Sopenharmony_ci * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock 5178c2ecf20Sopenharmony_ci * 5188c2ecf20Sopenharmony_ci * @bp: device handle 5198c2ecf20Sopenharmony_ci * @o: vlan_mac object 5208c2ecf20Sopenharmony_ci * 5218c2ecf20Sopenharmony_ci * Context: Should be called under the execution queue lock. May sleep. May 5228c2ecf20Sopenharmony_ci * release and reclaim execution queue lock during its run. 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_cistatic int __bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, 5258c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci /* If we got here, we're holding lock --> no WRITER exists */ 5288c2ecf20Sopenharmony_ci o->head_reader++; 5298c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock - locked reader - number %d\n", 5308c2ecf20Sopenharmony_ci o->head_reader); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/** 5368c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock 5378c2ecf20Sopenharmony_ci * 5388c2ecf20Sopenharmony_ci * @bp: device handle 5398c2ecf20Sopenharmony_ci * @o: vlan_mac object 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * Context: May sleep. Claims and releases execution queue lock during its run. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ciint bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, 5448c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int rc; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci spin_lock_bh(&o->exe_queue.lock); 5498c2ecf20Sopenharmony_ci rc = __bnx2x_vlan_mac_h_read_lock(bp, o); 5508c2ecf20Sopenharmony_ci spin_unlock_bh(&o->exe_queue.lock); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return rc; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/** 5568c2ecf20Sopenharmony_ci * __bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock 5578c2ecf20Sopenharmony_ci * 5588c2ecf20Sopenharmony_ci * @bp: device handle 5598c2ecf20Sopenharmony_ci * @o: vlan_mac object 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * Context: Should be called under execution queue lock. Notice if a pending 5628c2ecf20Sopenharmony_ci * execution exists, it would be performed if this was the last 5638c2ecf20Sopenharmony_ci * reader. possibly releasing and reclaiming the execution queue lock. 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_cistatic void __bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, 5668c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci if (!o->head_reader) { 5698c2ecf20Sopenharmony_ci BNX2X_ERR("Need to release vlan mac reader lock, but lock isn't taken\n"); 5708c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 5718c2ecf20Sopenharmony_ci bnx2x_panic(); 5728c2ecf20Sopenharmony_ci#endif 5738c2ecf20Sopenharmony_ci } else { 5748c2ecf20Sopenharmony_ci o->head_reader--; 5758c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock - decreased readers to %d\n", 5768c2ecf20Sopenharmony_ci o->head_reader); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* It's possible a new pending execution was added, and that this reader 5808c2ecf20Sopenharmony_ci * was last - if so we need to execute the command. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci if (!o->head_reader && o->head_exe_request) { 5838c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_lock - reader release encountered a pending request\n"); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Writer release will do the trick */ 5868c2ecf20Sopenharmony_ci __bnx2x_vlan_mac_h_write_unlock(bp, o); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/** 5918c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock 5928c2ecf20Sopenharmony_ci * 5938c2ecf20Sopenharmony_ci * @bp: device handle 5948c2ecf20Sopenharmony_ci * @o: vlan_mac object 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Context: Notice if a pending execution exists, it would be performed if this 5978c2ecf20Sopenharmony_ci * was the last reader. Claims and releases the execution queue lock 5988c2ecf20Sopenharmony_ci * during its run. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_civoid bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, 6018c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci spin_lock_bh(&o->exe_queue.lock); 6048c2ecf20Sopenharmony_ci __bnx2x_vlan_mac_h_read_unlock(bp, o); 6058c2ecf20Sopenharmony_ci spin_unlock_bh(&o->exe_queue.lock); 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o, 6098c2ecf20Sopenharmony_ci int n, u8 *base, u8 stride, u8 size) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 6128c2ecf20Sopenharmony_ci u8 *next = base; 6138c2ecf20Sopenharmony_ci int counter = 0; 6148c2ecf20Sopenharmony_ci int read_lock; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "get_n_elements - taking vlan_mac_lock (reader)\n"); 6178c2ecf20Sopenharmony_ci read_lock = bnx2x_vlan_mac_h_read_lock(bp, o); 6188c2ecf20Sopenharmony_ci if (read_lock != 0) 6198c2ecf20Sopenharmony_ci BNX2X_ERR("get_n_elements failed to get vlan mac reader lock; Access without lock\n"); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* traverse list */ 6228c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) { 6238c2ecf20Sopenharmony_ci if (counter < n) { 6248c2ecf20Sopenharmony_ci memcpy(next, &pos->u, size); 6258c2ecf20Sopenharmony_ci counter++; 6268c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "copied element number %d to address %p element was:\n", 6278c2ecf20Sopenharmony_ci counter, next); 6288c2ecf20Sopenharmony_ci next += stride + size; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (read_lock == 0) { 6338c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "get_n_elements - releasing vlan_mac_lock (reader)\n"); 6348c2ecf20Sopenharmony_ci bnx2x_vlan_mac_h_read_unlock(bp, o); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return counter * ETH_ALEN; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci/* check_add() callbacks */ 6418c2ecf20Sopenharmony_cistatic int bnx2x_check_mac_add(struct bnx2x *bp, 6428c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 6438c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Checking MAC %pM for ADD command\n", data->mac.mac); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(data->mac.mac)) 6508c2ecf20Sopenharmony_ci return -EINVAL; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Check if a requested MAC already exists */ 6538c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) 6548c2ecf20Sopenharmony_ci if (ether_addr_equal(data->mac.mac, pos->u.mac.mac) && 6558c2ecf20Sopenharmony_ci (data->mac.is_inner_mac == pos->u.mac.is_inner_mac)) 6568c2ecf20Sopenharmony_ci return -EEXIST; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int bnx2x_check_vlan_add(struct bnx2x *bp, 6628c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 6638c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Checking VLAN %d for ADD command\n", data->vlan.vlan); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) 6708c2ecf20Sopenharmony_ci if (data->vlan.vlan == pos->u.vlan.vlan) 6718c2ecf20Sopenharmony_ci return -EEXIST; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int bnx2x_check_vlan_mac_add(struct bnx2x *bp, 6778c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 6788c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for ADD command\n", 6838c2ecf20Sopenharmony_ci data->vlan_mac.mac, data->vlan_mac.vlan); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) 6868c2ecf20Sopenharmony_ci if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && 6878c2ecf20Sopenharmony_ci (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac, 6888c2ecf20Sopenharmony_ci ETH_ALEN)) && 6898c2ecf20Sopenharmony_ci (data->vlan_mac.is_inner_mac == 6908c2ecf20Sopenharmony_ci pos->u.vlan_mac.is_inner_mac)) 6918c2ecf20Sopenharmony_ci return -EEXIST; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/* check_del() callbacks */ 6978c2ecf20Sopenharmony_cistatic struct bnx2x_vlan_mac_registry_elem * 6988c2ecf20Sopenharmony_ci bnx2x_check_mac_del(struct bnx2x *bp, 6998c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 7008c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Checking MAC %pM for DEL command\n", data->mac.mac); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) 7078c2ecf20Sopenharmony_ci if (ether_addr_equal(data->mac.mac, pos->u.mac.mac) && 7088c2ecf20Sopenharmony_ci (data->mac.is_inner_mac == pos->u.mac.is_inner_mac)) 7098c2ecf20Sopenharmony_ci return pos; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return NULL; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic struct bnx2x_vlan_mac_registry_elem * 7158c2ecf20Sopenharmony_ci bnx2x_check_vlan_del(struct bnx2x *bp, 7168c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 7178c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Checking VLAN %d for DEL command\n", data->vlan.vlan); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) 7248c2ecf20Sopenharmony_ci if (data->vlan.vlan == pos->u.vlan.vlan) 7258c2ecf20Sopenharmony_ci return pos; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return NULL; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic struct bnx2x_vlan_mac_registry_elem * 7318c2ecf20Sopenharmony_ci bnx2x_check_vlan_mac_del(struct bnx2x *bp, 7328c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 7338c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for DEL command\n", 7388c2ecf20Sopenharmony_ci data->vlan_mac.mac, data->vlan_mac.vlan); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) 7418c2ecf20Sopenharmony_ci if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && 7428c2ecf20Sopenharmony_ci (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac, 7438c2ecf20Sopenharmony_ci ETH_ALEN)) && 7448c2ecf20Sopenharmony_ci (data->vlan_mac.is_inner_mac == 7458c2ecf20Sopenharmony_ci pos->u.vlan_mac.is_inner_mac)) 7468c2ecf20Sopenharmony_ci return pos; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return NULL; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci/* check_move() callback */ 7528c2ecf20Sopenharmony_cistatic bool bnx2x_check_move(struct bnx2x *bp, 7538c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *src_o, 7548c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *dst_o, 7558c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 7588c2ecf20Sopenharmony_ci int rc; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Check if we can delete the requested configuration from the first 7618c2ecf20Sopenharmony_ci * object. 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_ci pos = src_o->check_del(bp, src_o, data); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* check if configuration can be added */ 7668c2ecf20Sopenharmony_ci rc = dst_o->check_add(bp, dst_o, data); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* If this classification can not be added (is already set) 7698c2ecf20Sopenharmony_ci * or can't be deleted - return an error. 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci if (rc || !pos) 7728c2ecf20Sopenharmony_ci return false; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return true; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic bool bnx2x_check_move_always_err( 7788c2ecf20Sopenharmony_ci struct bnx2x *bp, 7798c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *src_o, 7808c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *dst_o, 7818c2ecf20Sopenharmony_ci union bnx2x_classification_ramrod_data *data) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci return false; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 7898c2ecf20Sopenharmony_ci u8 rx_tx_flag = 0; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if ((raw->obj_type == BNX2X_OBJ_TYPE_TX) || 7928c2ecf20Sopenharmony_ci (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) 7938c2ecf20Sopenharmony_ci rx_tx_flag |= ETH_CLASSIFY_CMD_HEADER_TX_CMD; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if ((raw->obj_type == BNX2X_OBJ_TYPE_RX) || 7968c2ecf20Sopenharmony_ci (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) 7978c2ecf20Sopenharmony_ci rx_tx_flag |= ETH_CLASSIFY_CMD_HEADER_RX_CMD; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return rx_tx_flag; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic void bnx2x_set_mac_in_nig(struct bnx2x *bp, 8038c2ecf20Sopenharmony_ci bool add, unsigned char *dev_addr, int index) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci u32 wb_data[2]; 8068c2ecf20Sopenharmony_ci u32 reg_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM : 8078c2ecf20Sopenharmony_ci NIG_REG_LLH0_FUNC_MEM; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (!IS_MF_SI(bp) && !IS_MF_AFEX(bp)) 8108c2ecf20Sopenharmony_ci return; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (index > BNX2X_LLH_CAM_MAX_PF_LINE) 8138c2ecf20Sopenharmony_ci return; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Going to %s LLH configuration at entry %d\n", 8168c2ecf20Sopenharmony_ci (add ? "ADD" : "DELETE"), index); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (add) { 8198c2ecf20Sopenharmony_ci /* LLH_FUNC_MEM is a u64 WB register */ 8208c2ecf20Sopenharmony_ci reg_offset += 8*index; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci wb_data[0] = ((dev_addr[2] << 24) | (dev_addr[3] << 16) | 8238c2ecf20Sopenharmony_ci (dev_addr[4] << 8) | dev_addr[5]); 8248c2ecf20Sopenharmony_ci wb_data[1] = ((dev_addr[0] << 8) | dev_addr[1]); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci REG_WR_DMAE(bp, reg_offset, wb_data, 2); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci REG_WR(bp, (BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM_ENABLE : 8308c2ecf20Sopenharmony_ci NIG_REG_LLH0_FUNC_MEM_ENABLE) + 4*index, add); 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci/** 8348c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_set_cmd_hdr_e2 - set a header in a single classify ramrod 8358c2ecf20Sopenharmony_ci * 8368c2ecf20Sopenharmony_ci * @bp: device handle 8378c2ecf20Sopenharmony_ci * @o: queue for which we want to configure this rule 8388c2ecf20Sopenharmony_ci * @add: if true the command is an ADD command, DEL otherwise 8398c2ecf20Sopenharmony_ci * @opcode: CLASSIFY_RULE_OPCODE_XXX 8408c2ecf20Sopenharmony_ci * @hdr: pointer to a header to setup 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_cmd_hdr_e2(struct bnx2x *bp, 8448c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, bool add, int opcode, 8458c2ecf20Sopenharmony_ci struct eth_classify_cmd_header *hdr) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci hdr->client_id = raw->cl_id; 8508c2ecf20Sopenharmony_ci hdr->func_id = raw->func_id; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* Rx or/and Tx (internal switching) configuration ? */ 8538c2ecf20Sopenharmony_ci hdr->cmd_general_data |= 8548c2ecf20Sopenharmony_ci bnx2x_vlan_mac_get_rx_tx_flag(o); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (add) 8578c2ecf20Sopenharmony_ci hdr->cmd_general_data |= ETH_CLASSIFY_CMD_HEADER_IS_ADD; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci hdr->cmd_general_data |= 8608c2ecf20Sopenharmony_ci (opcode << ETH_CLASSIFY_CMD_HEADER_OPCODE_SHIFT); 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci/** 8648c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_set_rdata_hdr_e2 - set the classify ramrod data header 8658c2ecf20Sopenharmony_ci * 8668c2ecf20Sopenharmony_ci * @cid: connection id 8678c2ecf20Sopenharmony_ci * @type: BNX2X_FILTER_XXX_PENDING 8688c2ecf20Sopenharmony_ci * @hdr: pointer to header to setup 8698c2ecf20Sopenharmony_ci * @rule_cnt: 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * currently we always configure one rule and echo field to contain a CID and an 8728c2ecf20Sopenharmony_ci * opcode type. 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type, 8758c2ecf20Sopenharmony_ci struct eth_classify_header *hdr, int rule_cnt) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci hdr->echo = cpu_to_le32((cid & BNX2X_SWCID_MASK) | 8788c2ecf20Sopenharmony_ci (type << BNX2X_SWCID_SHIFT)); 8798c2ecf20Sopenharmony_ci hdr->rule_cnt = (u8)rule_cnt; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci/* hw_config() callbacks */ 8838c2ecf20Sopenharmony_cistatic void bnx2x_set_one_mac_e2(struct bnx2x *bp, 8848c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 8858c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, int rule_idx, 8868c2ecf20Sopenharmony_ci int cam_offset) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 8898c2ecf20Sopenharmony_ci struct eth_classify_rules_ramrod_data *data = 8908c2ecf20Sopenharmony_ci (struct eth_classify_rules_ramrod_data *)(raw->rdata); 8918c2ecf20Sopenharmony_ci int rule_cnt = rule_idx + 1, cmd = elem->cmd_data.vlan_mac.cmd; 8928c2ecf20Sopenharmony_ci union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; 8938c2ecf20Sopenharmony_ci bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; 8948c2ecf20Sopenharmony_ci unsigned long *vlan_mac_flags = &elem->cmd_data.vlan_mac.vlan_mac_flags; 8958c2ecf20Sopenharmony_ci u8 *mac = elem->cmd_data.vlan_mac.u.mac.mac; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Set LLH CAM entry: currently only iSCSI and ETH macs are 8988c2ecf20Sopenharmony_ci * relevant. In addition, current implementation is tuned for a 8998c2ecf20Sopenharmony_ci * single ETH MAC. 9008c2ecf20Sopenharmony_ci * 9018c2ecf20Sopenharmony_ci * When multiple unicast ETH MACs PF configuration in switch 9028c2ecf20Sopenharmony_ci * independent mode is required (NetQ, multiple netdev MACs, 9038c2ecf20Sopenharmony_ci * etc.), consider better utilisation of 8 per function MAC 9048c2ecf20Sopenharmony_ci * entries in the LLH register. There is also 9058c2ecf20Sopenharmony_ci * NIG_REG_P[01]_LLH_FUNC_MEM2 registers that complete the 9068c2ecf20Sopenharmony_ci * total number of CAM entries to 16. 9078c2ecf20Sopenharmony_ci * 9088c2ecf20Sopenharmony_ci * Currently we won't configure NIG for MACs other than a primary ETH 9098c2ecf20Sopenharmony_ci * MAC and iSCSI L2 MAC. 9108c2ecf20Sopenharmony_ci * 9118c2ecf20Sopenharmony_ci * If this MAC is moving from one Queue to another, no need to change 9128c2ecf20Sopenharmony_ci * NIG configuration. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci if (cmd != BNX2X_VLAN_MAC_MOVE) { 9158c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ISCSI_ETH_MAC, vlan_mac_flags)) 9168c2ecf20Sopenharmony_ci bnx2x_set_mac_in_nig(bp, add, mac, 9178c2ecf20Sopenharmony_ci BNX2X_LLH_CAM_ISCSI_ETH_LINE); 9188c2ecf20Sopenharmony_ci else if (test_bit(BNX2X_ETH_MAC, vlan_mac_flags)) 9198c2ecf20Sopenharmony_ci bnx2x_set_mac_in_nig(bp, add, mac, 9208c2ecf20Sopenharmony_ci BNX2X_LLH_CAM_ETH_LINE); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer for the first rule */ 9248c2ecf20Sopenharmony_ci if (rule_idx == 0) 9258c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* Setup a command header */ 9288c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_MAC, 9298c2ecf20Sopenharmony_ci &rule_entry->mac.header); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to %s MAC %pM for Queue %d\n", 9328c2ecf20Sopenharmony_ci (add ? "add" : "delete"), mac, raw->cl_id); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* Set a MAC itself */ 9358c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb, 9368c2ecf20Sopenharmony_ci &rule_entry->mac.mac_mid, 9378c2ecf20Sopenharmony_ci &rule_entry->mac.mac_lsb, mac); 9388c2ecf20Sopenharmony_ci rule_entry->mac.inner_mac = 9398c2ecf20Sopenharmony_ci cpu_to_le16(elem->cmd_data.vlan_mac.u.mac.is_inner_mac); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* MOVE: Add a rule that will add this MAC to the target Queue */ 9428c2ecf20Sopenharmony_ci if (cmd == BNX2X_VLAN_MAC_MOVE) { 9438c2ecf20Sopenharmony_ci rule_entry++; 9448c2ecf20Sopenharmony_ci rule_cnt++; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* Setup ramrod data */ 9478c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cmd_hdr_e2(bp, 9488c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.target_obj, 9498c2ecf20Sopenharmony_ci true, CLASSIFY_RULE_OPCODE_MAC, 9508c2ecf20Sopenharmony_ci &rule_entry->mac.header); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* Set a MAC itself */ 9538c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb, 9548c2ecf20Sopenharmony_ci &rule_entry->mac.mac_mid, 9558c2ecf20Sopenharmony_ci &rule_entry->mac.mac_lsb, mac); 9568c2ecf20Sopenharmony_ci rule_entry->mac.inner_mac = 9578c2ecf20Sopenharmony_ci cpu_to_le16(elem->cmd_data.vlan_mac. 9588c2ecf20Sopenharmony_ci u.mac.is_inner_mac); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* Set the ramrod data header */ 9628c2ecf20Sopenharmony_ci /* TODO: take this to the higher level in order to prevent multiple 9638c2ecf20Sopenharmony_ci writing */ 9648c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, 9658c2ecf20Sopenharmony_ci rule_cnt); 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/** 9698c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_set_rdata_hdr_e1x - set a header in a single classify ramrod 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * @bp: device handle 9728c2ecf20Sopenharmony_ci * @o: queue 9738c2ecf20Sopenharmony_ci * @type: the type of echo 9748c2ecf20Sopenharmony_ci * @cam_offset: offset in cam memory 9758c2ecf20Sopenharmony_ci * @hdr: pointer to a header to setup 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * E1/E1H 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_rdata_hdr_e1x(struct bnx2x *bp, 9808c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, int type, int cam_offset, 9818c2ecf20Sopenharmony_ci struct mac_configuration_hdr *hdr) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci hdr->length = 1; 9868c2ecf20Sopenharmony_ci hdr->offset = (u8)cam_offset; 9878c2ecf20Sopenharmony_ci hdr->client_id = cpu_to_le16(0xff); 9888c2ecf20Sopenharmony_ci hdr->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) | 9898c2ecf20Sopenharmony_ci (type << BNX2X_SWCID_SHIFT)); 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_cfg_entry_e1x(struct bnx2x *bp, 9938c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, bool add, int opcode, u8 *mac, 9948c2ecf20Sopenharmony_ci u16 vlan_id, struct mac_configuration_entry *cfg_entry) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 9978c2ecf20Sopenharmony_ci u32 cl_bit_vec = (1 << r->cl_id); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci cfg_entry->clients_bit_vector = cpu_to_le32(cl_bit_vec); 10008c2ecf20Sopenharmony_ci cfg_entry->pf_id = r->func_id; 10018c2ecf20Sopenharmony_ci cfg_entry->vlan_id = cpu_to_le16(vlan_id); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (add) { 10048c2ecf20Sopenharmony_ci SET_FLAG(cfg_entry->flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE, 10058c2ecf20Sopenharmony_ci T_ETH_MAC_COMMAND_SET); 10068c2ecf20Sopenharmony_ci SET_FLAG(cfg_entry->flags, 10078c2ecf20Sopenharmony_ci MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE, opcode); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* Set a MAC in a ramrod data */ 10108c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&cfg_entry->msb_mac_addr, 10118c2ecf20Sopenharmony_ci &cfg_entry->middle_mac_addr, 10128c2ecf20Sopenharmony_ci &cfg_entry->lsb_mac_addr, mac); 10138c2ecf20Sopenharmony_ci } else 10148c2ecf20Sopenharmony_ci SET_FLAG(cfg_entry->flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE, 10158c2ecf20Sopenharmony_ci T_ETH_MAC_COMMAND_INVALIDATE); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic inline void bnx2x_vlan_mac_set_rdata_e1x(struct bnx2x *bp, 10198c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, int type, int cam_offset, bool add, 10208c2ecf20Sopenharmony_ci u8 *mac, u16 vlan_id, int opcode, struct mac_configuration_cmd *config) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct mac_configuration_entry *cfg_entry = &config->config_table[0]; 10238c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_rdata_hdr_e1x(bp, o, type, cam_offset, 10268c2ecf20Sopenharmony_ci &config->hdr); 10278c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cfg_entry_e1x(bp, o, add, opcode, mac, vlan_id, 10288c2ecf20Sopenharmony_ci cfg_entry); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "%s MAC %pM CLID %d CAM offset %d\n", 10318c2ecf20Sopenharmony_ci (add ? "setting" : "clearing"), 10328c2ecf20Sopenharmony_ci mac, raw->cl_id, cam_offset); 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci/** 10368c2ecf20Sopenharmony_ci * bnx2x_set_one_mac_e1x - fill a single MAC rule ramrod data 10378c2ecf20Sopenharmony_ci * 10388c2ecf20Sopenharmony_ci * @bp: device handle 10398c2ecf20Sopenharmony_ci * @o: bnx2x_vlan_mac_obj 10408c2ecf20Sopenharmony_ci * @elem: bnx2x_exeq_elem 10418c2ecf20Sopenharmony_ci * @rule_idx: rule_idx 10428c2ecf20Sopenharmony_ci * @cam_offset: cam_offset 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_cistatic void bnx2x_set_one_mac_e1x(struct bnx2x *bp, 10458c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 10468c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, int rule_idx, 10478c2ecf20Sopenharmony_ci int cam_offset) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 10508c2ecf20Sopenharmony_ci struct mac_configuration_cmd *config = 10518c2ecf20Sopenharmony_ci (struct mac_configuration_cmd *)(raw->rdata); 10528c2ecf20Sopenharmony_ci /* 57710 and 57711 do not support MOVE command, 10538c2ecf20Sopenharmony_ci * so it's either ADD or DEL 10548c2ecf20Sopenharmony_ci */ 10558c2ecf20Sopenharmony_ci bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? 10568c2ecf20Sopenharmony_ci true : false; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer */ 10598c2ecf20Sopenharmony_ci memset(config, 0, sizeof(*config)); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_rdata_e1x(bp, o, raw->state, 10628c2ecf20Sopenharmony_ci cam_offset, add, 10638c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.u.mac.mac, 0, 10648c2ecf20Sopenharmony_ci ETH_VLAN_FILTER_ANY_VLAN, config); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic void bnx2x_set_one_vlan_e2(struct bnx2x *bp, 10688c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 10698c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, int rule_idx, 10708c2ecf20Sopenharmony_ci int cam_offset) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 10738c2ecf20Sopenharmony_ci struct eth_classify_rules_ramrod_data *data = 10748c2ecf20Sopenharmony_ci (struct eth_classify_rules_ramrod_data *)(raw->rdata); 10758c2ecf20Sopenharmony_ci int rule_cnt = rule_idx + 1; 10768c2ecf20Sopenharmony_ci union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; 10778c2ecf20Sopenharmony_ci enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd; 10788c2ecf20Sopenharmony_ci bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; 10798c2ecf20Sopenharmony_ci u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer for the first rule */ 10828c2ecf20Sopenharmony_ci if (rule_idx == 0) 10838c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Set a rule header */ 10868c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_VLAN, 10878c2ecf20Sopenharmony_ci &rule_entry->vlan.header); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to %s VLAN %d\n", (add ? "add" : "delete"), 10908c2ecf20Sopenharmony_ci vlan); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* Set a VLAN itself */ 10938c2ecf20Sopenharmony_ci rule_entry->vlan.vlan = cpu_to_le16(vlan); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* MOVE: Add a rule that will add this MAC to the target Queue */ 10968c2ecf20Sopenharmony_ci if (cmd == BNX2X_VLAN_MAC_MOVE) { 10978c2ecf20Sopenharmony_ci rule_entry++; 10988c2ecf20Sopenharmony_ci rule_cnt++; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Setup ramrod data */ 11018c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cmd_hdr_e2(bp, 11028c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.target_obj, 11038c2ecf20Sopenharmony_ci true, CLASSIFY_RULE_OPCODE_VLAN, 11048c2ecf20Sopenharmony_ci &rule_entry->vlan.header); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* Set a VLAN itself */ 11078c2ecf20Sopenharmony_ci rule_entry->vlan.vlan = cpu_to_le16(vlan); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* Set the ramrod data header */ 11118c2ecf20Sopenharmony_ci /* TODO: take this to the higher level in order to prevent multiple 11128c2ecf20Sopenharmony_ci writing */ 11138c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, 11148c2ecf20Sopenharmony_ci rule_cnt); 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_cistatic void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp, 11188c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 11198c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, 11208c2ecf20Sopenharmony_ci int rule_idx, int cam_offset) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 11238c2ecf20Sopenharmony_ci struct eth_classify_rules_ramrod_data *data = 11248c2ecf20Sopenharmony_ci (struct eth_classify_rules_ramrod_data *)(raw->rdata); 11258c2ecf20Sopenharmony_ci int rule_cnt = rule_idx + 1; 11268c2ecf20Sopenharmony_ci union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; 11278c2ecf20Sopenharmony_ci enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd; 11288c2ecf20Sopenharmony_ci bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; 11298c2ecf20Sopenharmony_ci u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan; 11308c2ecf20Sopenharmony_ci u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac; 11318c2ecf20Sopenharmony_ci u16 inner_mac; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer for the first rule */ 11348c2ecf20Sopenharmony_ci if (rule_idx == 0) 11358c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* Set a rule header */ 11388c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR, 11398c2ecf20Sopenharmony_ci &rule_entry->pair.header); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* Set VLAN and MAC themselves */ 11428c2ecf20Sopenharmony_ci rule_entry->pair.vlan = cpu_to_le16(vlan); 11438c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, 11448c2ecf20Sopenharmony_ci &rule_entry->pair.mac_mid, 11458c2ecf20Sopenharmony_ci &rule_entry->pair.mac_lsb, mac); 11468c2ecf20Sopenharmony_ci inner_mac = elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac; 11478c2ecf20Sopenharmony_ci rule_entry->pair.inner_mac = cpu_to_le16(inner_mac); 11488c2ecf20Sopenharmony_ci /* MOVE: Add a rule that will add this MAC/VLAN to the target Queue */ 11498c2ecf20Sopenharmony_ci if (cmd == BNX2X_VLAN_MAC_MOVE) { 11508c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *target_obj; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci rule_entry++; 11538c2ecf20Sopenharmony_ci rule_cnt++; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* Setup ramrod data */ 11568c2ecf20Sopenharmony_ci target_obj = elem->cmd_data.vlan_mac.target_obj; 11578c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_cmd_hdr_e2(bp, target_obj, 11588c2ecf20Sopenharmony_ci true, CLASSIFY_RULE_OPCODE_PAIR, 11598c2ecf20Sopenharmony_ci &rule_entry->pair.header); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci /* Set a VLAN itself */ 11628c2ecf20Sopenharmony_ci rule_entry->pair.vlan = cpu_to_le16(vlan); 11638c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, 11648c2ecf20Sopenharmony_ci &rule_entry->pair.mac_mid, 11658c2ecf20Sopenharmony_ci &rule_entry->pair.mac_lsb, mac); 11668c2ecf20Sopenharmony_ci rule_entry->pair.inner_mac = cpu_to_le16(inner_mac); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* Set the ramrod data header */ 11708c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, 11718c2ecf20Sopenharmony_ci rule_cnt); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci/** 11758c2ecf20Sopenharmony_ci * bnx2x_set_one_vlan_mac_e1h - 11768c2ecf20Sopenharmony_ci * 11778c2ecf20Sopenharmony_ci * @bp: device handle 11788c2ecf20Sopenharmony_ci * @o: bnx2x_vlan_mac_obj 11798c2ecf20Sopenharmony_ci * @elem: bnx2x_exeq_elem 11808c2ecf20Sopenharmony_ci * @rule_idx: rule_idx 11818c2ecf20Sopenharmony_ci * @cam_offset: cam_offset 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_cistatic void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp, 11848c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 11858c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, 11868c2ecf20Sopenharmony_ci int rule_idx, int cam_offset) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 11898c2ecf20Sopenharmony_ci struct mac_configuration_cmd *config = 11908c2ecf20Sopenharmony_ci (struct mac_configuration_cmd *)(raw->rdata); 11918c2ecf20Sopenharmony_ci /* 57710 and 57711 do not support MOVE command, 11928c2ecf20Sopenharmony_ci * so it's either ADD or DEL 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_ci bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? 11958c2ecf20Sopenharmony_ci true : false; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer */ 11988c2ecf20Sopenharmony_ci memset(config, 0, sizeof(*config)); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING, 12018c2ecf20Sopenharmony_ci cam_offset, add, 12028c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.u.vlan_mac.mac, 12038c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.u.vlan_mac.vlan, 12048c2ecf20Sopenharmony_ci ETH_VLAN_FILTER_CLASSIFY, config); 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci/** 12088c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element 12098c2ecf20Sopenharmony_ci * 12108c2ecf20Sopenharmony_ci * @bp: device handle 12118c2ecf20Sopenharmony_ci * @p: command parameters 12128c2ecf20Sopenharmony_ci * @ppos: pointer to the cookie 12138c2ecf20Sopenharmony_ci * 12148c2ecf20Sopenharmony_ci * reconfigure next MAC/VLAN/VLAN-MAC element from the 12158c2ecf20Sopenharmony_ci * previously configured elements list. 12168c2ecf20Sopenharmony_ci * 12178c2ecf20Sopenharmony_ci * from command parameters only RAMROD_COMP_WAIT bit in ramrod_flags is taken 12188c2ecf20Sopenharmony_ci * into an account 12198c2ecf20Sopenharmony_ci * 12208c2ecf20Sopenharmony_ci * pointer to the cookie - that should be given back in the next call to make 12218c2ecf20Sopenharmony_ci * function handle the next element. If *ppos is set to NULL it will restart the 12228c2ecf20Sopenharmony_ci * iterator. If returned *ppos == NULL this means that the last element has been 12238c2ecf20Sopenharmony_ci * handled. 12248c2ecf20Sopenharmony_ci * 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_cistatic int bnx2x_vlan_mac_restore(struct bnx2x *bp, 12278c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_ramrod_params *p, 12288c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem **ppos) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 12318c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* If list is empty - there is nothing to do here */ 12348c2ecf20Sopenharmony_ci if (list_empty(&o->head)) { 12358c2ecf20Sopenharmony_ci *ppos = NULL; 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* make a step... */ 12408c2ecf20Sopenharmony_ci if (*ppos == NULL) 12418c2ecf20Sopenharmony_ci *ppos = list_first_entry(&o->head, 12428c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem, 12438c2ecf20Sopenharmony_ci link); 12448c2ecf20Sopenharmony_ci else 12458c2ecf20Sopenharmony_ci *ppos = list_next_entry(*ppos, link); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci pos = *ppos; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* If it's the last step - return NULL */ 12508c2ecf20Sopenharmony_ci if (list_is_last(&pos->link, &o->head)) 12518c2ecf20Sopenharmony_ci *ppos = NULL; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* Prepare a 'user_req' */ 12548c2ecf20Sopenharmony_ci memcpy(&p->user_req.u, &pos->u, sizeof(pos->u)); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* Set the command */ 12578c2ecf20Sopenharmony_ci p->user_req.cmd = BNX2X_VLAN_MAC_ADD; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* Set vlan_mac_flags */ 12608c2ecf20Sopenharmony_ci p->user_req.vlan_mac_flags = pos->vlan_mac_flags; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* Set a restore bit */ 12638c2ecf20Sopenharmony_ci __set_bit(RAMROD_RESTORE, &p->ramrod_flags); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci return bnx2x_config_vlan_mac(bp, p); 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci/* bnx2x_exeq_get_mac/bnx2x_exeq_get_vlan/bnx2x_exeq_get_vlan_mac return a 12698c2ecf20Sopenharmony_ci * pointer to an element with a specific criteria and NULL if such an element 12708c2ecf20Sopenharmony_ci * hasn't been found. 12718c2ecf20Sopenharmony_ci */ 12728c2ecf20Sopenharmony_cistatic struct bnx2x_exeq_elem *bnx2x_exeq_get_mac( 12738c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o, 12748c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *pos; 12778c2ecf20Sopenharmony_ci struct bnx2x_mac_ramrod_data *data = &elem->cmd_data.vlan_mac.u.mac; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* Check pending for execution commands */ 12808c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->exe_queue, link) 12818c2ecf20Sopenharmony_ci if (!memcmp(&pos->cmd_data.vlan_mac.u.mac, data, 12828c2ecf20Sopenharmony_ci sizeof(*data)) && 12838c2ecf20Sopenharmony_ci (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd)) 12848c2ecf20Sopenharmony_ci return pos; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci return NULL; 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan( 12908c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o, 12918c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *pos; 12948c2ecf20Sopenharmony_ci struct bnx2x_vlan_ramrod_data *data = &elem->cmd_data.vlan_mac.u.vlan; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* Check pending for execution commands */ 12978c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->exe_queue, link) 12988c2ecf20Sopenharmony_ci if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan, data, 12998c2ecf20Sopenharmony_ci sizeof(*data)) && 13008c2ecf20Sopenharmony_ci (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd)) 13018c2ecf20Sopenharmony_ci return pos; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci return NULL; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac( 13078c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *o, 13088c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *pos; 13118c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_ramrod_data *data = 13128c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.u.vlan_mac; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* Check pending for execution commands */ 13158c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->exe_queue, link) 13168c2ecf20Sopenharmony_ci if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data, 13178c2ecf20Sopenharmony_ci sizeof(*data)) && 13188c2ecf20Sopenharmony_ci (pos->cmd_data.vlan_mac.cmd == 13198c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.cmd)) 13208c2ecf20Sopenharmony_ci return pos; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci return NULL; 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci/** 13268c2ecf20Sopenharmony_ci * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed 13278c2ecf20Sopenharmony_ci * 13288c2ecf20Sopenharmony_ci * @bp: device handle 13298c2ecf20Sopenharmony_ci * @qo: bnx2x_qable_obj 13308c2ecf20Sopenharmony_ci * @elem: bnx2x_exeq_elem 13318c2ecf20Sopenharmony_ci * 13328c2ecf20Sopenharmony_ci * Checks that the requested configuration can be added. If yes and if 13338c2ecf20Sopenharmony_ci * requested, consume CAM credit. 13348c2ecf20Sopenharmony_ci * 13358c2ecf20Sopenharmony_ci * The 'validate' is run after the 'optimize'. 13368c2ecf20Sopenharmony_ci * 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_cistatic inline int bnx2x_validate_vlan_mac_add(struct bnx2x *bp, 13398c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 13408c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac; 13438c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; 13448c2ecf20Sopenharmony_ci int rc; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* Check the registry */ 13478c2ecf20Sopenharmony_ci rc = o->check_add(bp, o, &elem->cmd_data.vlan_mac.u); 13488c2ecf20Sopenharmony_ci if (rc) { 13498c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "ADD command is not allowed considering current registry state.\n"); 13508c2ecf20Sopenharmony_ci return rc; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci /* Check if there is a pending ADD command for this 13548c2ecf20Sopenharmony_ci * MAC/VLAN/VLAN-MAC. Return an error if there is. 13558c2ecf20Sopenharmony_ci */ 13568c2ecf20Sopenharmony_ci if (exeq->get(exeq, elem)) { 13578c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "There is a pending ADD command already\n"); 13588c2ecf20Sopenharmony_ci return -EEXIST; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci /* TODO: Check the pending MOVE from other objects where this 13628c2ecf20Sopenharmony_ci * object is a destination object. 13638c2ecf20Sopenharmony_ci */ 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* Consume the credit if not requested not to */ 13668c2ecf20Sopenharmony_ci if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, 13678c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.vlan_mac_flags) || 13688c2ecf20Sopenharmony_ci o->get_credit(o))) 13698c2ecf20Sopenharmony_ci return -EINVAL; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci return 0; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci/** 13758c2ecf20Sopenharmony_ci * bnx2x_validate_vlan_mac_del - check if the DEL command can be executed 13768c2ecf20Sopenharmony_ci * 13778c2ecf20Sopenharmony_ci * @bp: device handle 13788c2ecf20Sopenharmony_ci * @qo: quable object to check 13798c2ecf20Sopenharmony_ci * @elem: element that needs to be deleted 13808c2ecf20Sopenharmony_ci * 13818c2ecf20Sopenharmony_ci * Checks that the requested configuration can be deleted. If yes and if 13828c2ecf20Sopenharmony_ci * requested, returns a CAM credit. 13838c2ecf20Sopenharmony_ci * 13848c2ecf20Sopenharmony_ci * The 'validate' is run after the 'optimize'. 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_cistatic inline int bnx2x_validate_vlan_mac_del(struct bnx2x *bp, 13878c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 13888c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac; 13918c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos; 13928c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; 13938c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem query_elem; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* If this classification can not be deleted (doesn't exist) 13968c2ecf20Sopenharmony_ci * - return a BNX2X_EXIST. 13978c2ecf20Sopenharmony_ci */ 13988c2ecf20Sopenharmony_ci pos = o->check_del(bp, o, &elem->cmd_data.vlan_mac.u); 13998c2ecf20Sopenharmony_ci if (!pos) { 14008c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "DEL command is not allowed considering current registry state\n"); 14018c2ecf20Sopenharmony_ci return -EEXIST; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* Check if there are pending DEL or MOVE commands for this 14058c2ecf20Sopenharmony_ci * MAC/VLAN/VLAN-MAC. Return an error if so. 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_ci memcpy(&query_elem, elem, sizeof(query_elem)); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* Check for MOVE commands */ 14108c2ecf20Sopenharmony_ci query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_MOVE; 14118c2ecf20Sopenharmony_ci if (exeq->get(exeq, &query_elem)) { 14128c2ecf20Sopenharmony_ci BNX2X_ERR("There is a pending MOVE command already\n"); 14138c2ecf20Sopenharmony_ci return -EINVAL; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci /* Check for DEL commands */ 14178c2ecf20Sopenharmony_ci if (exeq->get(exeq, elem)) { 14188c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "There is a pending DEL command already\n"); 14198c2ecf20Sopenharmony_ci return -EEXIST; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci /* Return the credit to the credit pool if not requested not to */ 14238c2ecf20Sopenharmony_ci if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, 14248c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.vlan_mac_flags) || 14258c2ecf20Sopenharmony_ci o->put_credit(o))) { 14268c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to return a credit\n"); 14278c2ecf20Sopenharmony_ci return -EINVAL; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return 0; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci/** 14348c2ecf20Sopenharmony_ci * bnx2x_validate_vlan_mac_move - check if the MOVE command can be executed 14358c2ecf20Sopenharmony_ci * 14368c2ecf20Sopenharmony_ci * @bp: device handle 14378c2ecf20Sopenharmony_ci * @qo: quable object to check (source) 14388c2ecf20Sopenharmony_ci * @elem: element that needs to be moved 14398c2ecf20Sopenharmony_ci * 14408c2ecf20Sopenharmony_ci * Checks that the requested configuration can be moved. If yes and if 14418c2ecf20Sopenharmony_ci * requested, returns a CAM credit. 14428c2ecf20Sopenharmony_ci * 14438c2ecf20Sopenharmony_ci * The 'validate' is run after the 'optimize'. 14448c2ecf20Sopenharmony_ci */ 14458c2ecf20Sopenharmony_cistatic inline int bnx2x_validate_vlan_mac_move(struct bnx2x *bp, 14468c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 14478c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *src_o = &qo->vlan_mac; 14508c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *dest_o = elem->cmd_data.vlan_mac.target_obj; 14518c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem query_elem; 14528c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *src_exeq = &src_o->exe_queue; 14538c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *dest_exeq = &dest_o->exe_queue; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* Check if we can perform this operation based on the current registry 14568c2ecf20Sopenharmony_ci * state. 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ci if (!src_o->check_move(bp, src_o, dest_o, 14598c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.u)) { 14608c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "MOVE command is not allowed considering current registry state\n"); 14618c2ecf20Sopenharmony_ci return -EINVAL; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* Check if there is an already pending DEL or MOVE command for the 14658c2ecf20Sopenharmony_ci * source object or ADD command for a destination object. Return an 14668c2ecf20Sopenharmony_ci * error if so. 14678c2ecf20Sopenharmony_ci */ 14688c2ecf20Sopenharmony_ci memcpy(&query_elem, elem, sizeof(query_elem)); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* Check DEL on source */ 14718c2ecf20Sopenharmony_ci query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_DEL; 14728c2ecf20Sopenharmony_ci if (src_exeq->get(src_exeq, &query_elem)) { 14738c2ecf20Sopenharmony_ci BNX2X_ERR("There is a pending DEL command on the source queue already\n"); 14748c2ecf20Sopenharmony_ci return -EINVAL; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci /* Check MOVE on source */ 14788c2ecf20Sopenharmony_ci if (src_exeq->get(src_exeq, elem)) { 14798c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "There is a pending MOVE command already\n"); 14808c2ecf20Sopenharmony_ci return -EEXIST; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* Check ADD on destination */ 14848c2ecf20Sopenharmony_ci query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_ADD; 14858c2ecf20Sopenharmony_ci if (dest_exeq->get(dest_exeq, &query_elem)) { 14868c2ecf20Sopenharmony_ci BNX2X_ERR("There is a pending ADD command on the destination queue already\n"); 14878c2ecf20Sopenharmony_ci return -EINVAL; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* Consume the credit if not requested not to */ 14918c2ecf20Sopenharmony_ci if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT_DEST, 14928c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.vlan_mac_flags) || 14938c2ecf20Sopenharmony_ci dest_o->get_credit(dest_o))) 14948c2ecf20Sopenharmony_ci return -EINVAL; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, 14978c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.vlan_mac_flags) || 14988c2ecf20Sopenharmony_ci src_o->put_credit(src_o))) { 14998c2ecf20Sopenharmony_ci /* return the credit taken from dest... */ 15008c2ecf20Sopenharmony_ci dest_o->put_credit(dest_o); 15018c2ecf20Sopenharmony_ci return -EINVAL; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return 0; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic int bnx2x_validate_vlan_mac(struct bnx2x *bp, 15088c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 15098c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci switch (elem->cmd_data.vlan_mac.cmd) { 15128c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_ADD: 15138c2ecf20Sopenharmony_ci return bnx2x_validate_vlan_mac_add(bp, qo, elem); 15148c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_DEL: 15158c2ecf20Sopenharmony_ci return bnx2x_validate_vlan_mac_del(bp, qo, elem); 15168c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_MOVE: 15178c2ecf20Sopenharmony_ci return bnx2x_validate_vlan_mac_move(bp, qo, elem); 15188c2ecf20Sopenharmony_ci default: 15198c2ecf20Sopenharmony_ci return -EINVAL; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_cistatic int bnx2x_remove_vlan_mac(struct bnx2x *bp, 15248c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 15258c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci int rc = 0; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* If consumption wasn't required, nothing to do */ 15308c2ecf20Sopenharmony_ci if (test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, 15318c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.vlan_mac_flags)) 15328c2ecf20Sopenharmony_ci return 0; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci switch (elem->cmd_data.vlan_mac.cmd) { 15358c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_ADD: 15368c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_MOVE: 15378c2ecf20Sopenharmony_ci rc = qo->vlan_mac.put_credit(&qo->vlan_mac); 15388c2ecf20Sopenharmony_ci break; 15398c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_DEL: 15408c2ecf20Sopenharmony_ci rc = qo->vlan_mac.get_credit(&qo->vlan_mac); 15418c2ecf20Sopenharmony_ci break; 15428c2ecf20Sopenharmony_ci default: 15438c2ecf20Sopenharmony_ci return -EINVAL; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (rc != true) 15478c2ecf20Sopenharmony_ci return -EINVAL; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci return 0; 15508c2ecf20Sopenharmony_ci} 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci/** 15538c2ecf20Sopenharmony_ci * bnx2x_wait_vlan_mac - passively wait for 5 seconds until all work completes. 15548c2ecf20Sopenharmony_ci * 15558c2ecf20Sopenharmony_ci * @bp: device handle 15568c2ecf20Sopenharmony_ci * @o: bnx2x_vlan_mac_obj 15578c2ecf20Sopenharmony_ci * 15588c2ecf20Sopenharmony_ci */ 15598c2ecf20Sopenharmony_cistatic int bnx2x_wait_vlan_mac(struct bnx2x *bp, 15608c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci int cnt = 5000, rc; 15638c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; 15648c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci while (cnt--) { 15678c2ecf20Sopenharmony_ci /* Wait for the current command to complete */ 15688c2ecf20Sopenharmony_ci rc = raw->wait_comp(bp, raw); 15698c2ecf20Sopenharmony_ci if (rc) 15708c2ecf20Sopenharmony_ci return rc; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci /* Wait until there are no pending commands */ 15738c2ecf20Sopenharmony_ci if (!bnx2x_exe_queue_empty(exeq)) 15748c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 15758c2ecf20Sopenharmony_ci else 15768c2ecf20Sopenharmony_ci return 0; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci return -EBUSY; 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_cistatic int __bnx2x_vlan_mac_execute_step(struct bnx2x *bp, 15838c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 15848c2ecf20Sopenharmony_ci unsigned long *ramrod_flags) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci int rc = 0; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci spin_lock_bh(&o->exe_queue.lock); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_execute_step - trying to take writer lock\n"); 15918c2ecf20Sopenharmony_ci rc = __bnx2x_vlan_mac_h_write_trylock(bp, o); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (rc != 0) { 15948c2ecf20Sopenharmony_ci __bnx2x_vlan_mac_h_pend(bp, o, *ramrod_flags); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* Calling function should not differentiate between this case 15978c2ecf20Sopenharmony_ci * and the case in which there is already a pending ramrod 15988c2ecf20Sopenharmony_ci */ 15998c2ecf20Sopenharmony_ci rc = 1; 16008c2ecf20Sopenharmony_ci } else { 16018c2ecf20Sopenharmony_ci rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags); 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci spin_unlock_bh(&o->exe_queue.lock); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci return rc; 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci/** 16098c2ecf20Sopenharmony_ci * bnx2x_complete_vlan_mac - complete one VLAN-MAC ramrod 16108c2ecf20Sopenharmony_ci * 16118c2ecf20Sopenharmony_ci * @bp: device handle 16128c2ecf20Sopenharmony_ci * @o: bnx2x_vlan_mac_obj 16138c2ecf20Sopenharmony_ci * @cqe: completion element 16148c2ecf20Sopenharmony_ci * @ramrod_flags: if set schedule next execution chunk 16158c2ecf20Sopenharmony_ci * 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_cistatic int bnx2x_complete_vlan_mac(struct bnx2x *bp, 16188c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 16198c2ecf20Sopenharmony_ci union event_ring_elem *cqe, 16208c2ecf20Sopenharmony_ci unsigned long *ramrod_flags) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 16238c2ecf20Sopenharmony_ci int rc; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci /* Clearing the pending list & raw state should be made 16268c2ecf20Sopenharmony_ci * atomically (as execution flow assumes they represent the same). 16278c2ecf20Sopenharmony_ci */ 16288c2ecf20Sopenharmony_ci spin_lock_bh(&o->exe_queue.lock); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* Reset pending list */ 16318c2ecf20Sopenharmony_ci __bnx2x_exe_queue_reset_pending(bp, &o->exe_queue); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci /* Clear pending */ 16348c2ecf20Sopenharmony_ci r->clear_pending(r); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci spin_unlock_bh(&o->exe_queue.lock); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /* If ramrod failed this is most likely a SW bug */ 16398c2ecf20Sopenharmony_ci if (cqe->message.error) 16408c2ecf20Sopenharmony_ci return -EINVAL; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci /* Run the next bulk of pending commands if requested */ 16438c2ecf20Sopenharmony_ci if (test_bit(RAMROD_CONT, ramrod_flags)) { 16448c2ecf20Sopenharmony_ci rc = __bnx2x_vlan_mac_execute_step(bp, o, ramrod_flags); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (rc < 0) 16478c2ecf20Sopenharmony_ci return rc; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci /* If there is more work to do return PENDING */ 16518c2ecf20Sopenharmony_ci if (!bnx2x_exe_queue_empty(&o->exe_queue)) 16528c2ecf20Sopenharmony_ci return 1; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci return 0; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci/** 16588c2ecf20Sopenharmony_ci * bnx2x_optimize_vlan_mac - optimize ADD and DEL commands. 16598c2ecf20Sopenharmony_ci * 16608c2ecf20Sopenharmony_ci * @bp: device handle 16618c2ecf20Sopenharmony_ci * @qo: bnx2x_qable_obj 16628c2ecf20Sopenharmony_ci * @elem: bnx2x_exeq_elem 16638c2ecf20Sopenharmony_ci */ 16648c2ecf20Sopenharmony_cistatic int bnx2x_optimize_vlan_mac(struct bnx2x *bp, 16658c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 16668c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem query, *pos; 16698c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac; 16708c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci memcpy(&query, elem, sizeof(query)); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci switch (elem->cmd_data.vlan_mac.cmd) { 16758c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_ADD: 16768c2ecf20Sopenharmony_ci query.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_DEL; 16778c2ecf20Sopenharmony_ci break; 16788c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_DEL: 16798c2ecf20Sopenharmony_ci query.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_ADD; 16808c2ecf20Sopenharmony_ci break; 16818c2ecf20Sopenharmony_ci default: 16828c2ecf20Sopenharmony_ci /* Don't handle anything other than ADD or DEL */ 16838c2ecf20Sopenharmony_ci return 0; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* If we found the appropriate element - delete it */ 16878c2ecf20Sopenharmony_ci pos = exeq->get(exeq, &query); 16888c2ecf20Sopenharmony_ci if (pos) { 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci /* Return the credit of the optimized command */ 16918c2ecf20Sopenharmony_ci if (!test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, 16928c2ecf20Sopenharmony_ci &pos->cmd_data.vlan_mac.vlan_mac_flags)) { 16938c2ecf20Sopenharmony_ci if ((query.cmd_data.vlan_mac.cmd == 16948c2ecf20Sopenharmony_ci BNX2X_VLAN_MAC_ADD) && !o->put_credit(o)) { 16958c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to return the credit for the optimized ADD command\n"); 16968c2ecf20Sopenharmony_ci return -EINVAL; 16978c2ecf20Sopenharmony_ci } else if (!o->get_credit(o)) { /* VLAN_MAC_DEL */ 16988c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to recover the credit from the optimized DEL command\n"); 16998c2ecf20Sopenharmony_ci return -EINVAL; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Optimizing %s command\n", 17048c2ecf20Sopenharmony_ci (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? 17058c2ecf20Sopenharmony_ci "ADD" : "DEL"); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci list_del(&pos->link); 17088c2ecf20Sopenharmony_ci bnx2x_exe_queue_free_elem(bp, pos); 17098c2ecf20Sopenharmony_ci return 1; 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci return 0; 17138c2ecf20Sopenharmony_ci} 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci/** 17168c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_get_registry_elem - prepare a registry element 17178c2ecf20Sopenharmony_ci * 17188c2ecf20Sopenharmony_ci * @bp: device handle 17198c2ecf20Sopenharmony_ci * @o: vlan object 17208c2ecf20Sopenharmony_ci * @elem: element 17218c2ecf20Sopenharmony_ci * @restore: to restore or not 17228c2ecf20Sopenharmony_ci * @re: registry 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * prepare a registry element according to the current command request. 17258c2ecf20Sopenharmony_ci */ 17268c2ecf20Sopenharmony_cistatic inline int bnx2x_vlan_mac_get_registry_elem( 17278c2ecf20Sopenharmony_ci struct bnx2x *bp, 17288c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 17298c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem, 17308c2ecf20Sopenharmony_ci bool restore, 17318c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem **re) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd; 17348c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *reg_elem; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci /* Allocate a new registry element if needed. */ 17378c2ecf20Sopenharmony_ci if (!restore && 17388c2ecf20Sopenharmony_ci ((cmd == BNX2X_VLAN_MAC_ADD) || (cmd == BNX2X_VLAN_MAC_MOVE))) { 17398c2ecf20Sopenharmony_ci reg_elem = kzalloc(sizeof(*reg_elem), GFP_ATOMIC); 17408c2ecf20Sopenharmony_ci if (!reg_elem) 17418c2ecf20Sopenharmony_ci return -ENOMEM; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* Get a new CAM offset */ 17448c2ecf20Sopenharmony_ci if (!o->get_cam_offset(o, ®_elem->cam_offset)) { 17458c2ecf20Sopenharmony_ci /* This shall never happen, because we have checked the 17468c2ecf20Sopenharmony_ci * CAM availability in the 'validate'. 17478c2ecf20Sopenharmony_ci */ 17488c2ecf20Sopenharmony_ci WARN_ON(1); 17498c2ecf20Sopenharmony_ci kfree(reg_elem); 17508c2ecf20Sopenharmony_ci return -EINVAL; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Got cam offset %d\n", reg_elem->cam_offset); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* Set a VLAN-MAC data */ 17568c2ecf20Sopenharmony_ci memcpy(®_elem->u, &elem->cmd_data.vlan_mac.u, 17578c2ecf20Sopenharmony_ci sizeof(reg_elem->u)); 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci /* Copy the flags (needed for DEL and RESTORE flows) */ 17608c2ecf20Sopenharmony_ci reg_elem->vlan_mac_flags = 17618c2ecf20Sopenharmony_ci elem->cmd_data.vlan_mac.vlan_mac_flags; 17628c2ecf20Sopenharmony_ci } else /* DEL, RESTORE */ 17638c2ecf20Sopenharmony_ci reg_elem = o->check_del(bp, o, &elem->cmd_data.vlan_mac.u); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci *re = reg_elem; 17668c2ecf20Sopenharmony_ci return 0; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci/** 17708c2ecf20Sopenharmony_ci * bnx2x_execute_vlan_mac - execute vlan mac command 17718c2ecf20Sopenharmony_ci * 17728c2ecf20Sopenharmony_ci * @bp: device handle 17738c2ecf20Sopenharmony_ci * @qo: bnx2x_qable_obj pointer 17748c2ecf20Sopenharmony_ci * @exe_chunk: chunk 17758c2ecf20Sopenharmony_ci * @ramrod_flags: flags 17768c2ecf20Sopenharmony_ci * 17778c2ecf20Sopenharmony_ci * go and send a ramrod! 17788c2ecf20Sopenharmony_ci */ 17798c2ecf20Sopenharmony_cistatic int bnx2x_execute_vlan_mac(struct bnx2x *bp, 17808c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qo, 17818c2ecf20Sopenharmony_ci struct list_head *exe_chunk, 17828c2ecf20Sopenharmony_ci unsigned long *ramrod_flags) 17838c2ecf20Sopenharmony_ci{ 17848c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem; 17858c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac, *cam_obj; 17868c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 17878c2ecf20Sopenharmony_ci int rc, idx = 0; 17888c2ecf20Sopenharmony_ci bool restore = test_bit(RAMROD_RESTORE, ramrod_flags); 17898c2ecf20Sopenharmony_ci bool drv_only = test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags); 17908c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *reg_elem; 17918c2ecf20Sopenharmony_ci enum bnx2x_vlan_mac_cmd cmd; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci /* If DRIVER_ONLY execution is requested, cleanup a registry 17948c2ecf20Sopenharmony_ci * and exit. Otherwise send a ramrod to FW. 17958c2ecf20Sopenharmony_ci */ 17968c2ecf20Sopenharmony_ci if (!drv_only) { 17978c2ecf20Sopenharmony_ci WARN_ON(r->check_pending(r)); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci /* Set pending */ 18008c2ecf20Sopenharmony_ci r->set_pending(r); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci /* Fill the ramrod data */ 18038c2ecf20Sopenharmony_ci list_for_each_entry(elem, exe_chunk, link) { 18048c2ecf20Sopenharmony_ci cmd = elem->cmd_data.vlan_mac.cmd; 18058c2ecf20Sopenharmony_ci /* We will add to the target object in MOVE command, so 18068c2ecf20Sopenharmony_ci * change the object for a CAM search. 18078c2ecf20Sopenharmony_ci */ 18088c2ecf20Sopenharmony_ci if (cmd == BNX2X_VLAN_MAC_MOVE) 18098c2ecf20Sopenharmony_ci cam_obj = elem->cmd_data.vlan_mac.target_obj; 18108c2ecf20Sopenharmony_ci else 18118c2ecf20Sopenharmony_ci cam_obj = o; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci rc = bnx2x_vlan_mac_get_registry_elem(bp, cam_obj, 18148c2ecf20Sopenharmony_ci elem, restore, 18158c2ecf20Sopenharmony_ci ®_elem); 18168c2ecf20Sopenharmony_ci if (rc) 18178c2ecf20Sopenharmony_ci goto error_exit; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci WARN_ON(!reg_elem); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Push a new entry into the registry */ 18228c2ecf20Sopenharmony_ci if (!restore && 18238c2ecf20Sopenharmony_ci ((cmd == BNX2X_VLAN_MAC_ADD) || 18248c2ecf20Sopenharmony_ci (cmd == BNX2X_VLAN_MAC_MOVE))) 18258c2ecf20Sopenharmony_ci list_add(®_elem->link, &cam_obj->head); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* Configure a single command in a ramrod data buffer */ 18288c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, elem, idx, 18298c2ecf20Sopenharmony_ci reg_elem->cam_offset); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci /* MOVE command consumes 2 entries in the ramrod data */ 18328c2ecf20Sopenharmony_ci if (cmd == BNX2X_VLAN_MAC_MOVE) 18338c2ecf20Sopenharmony_ci idx += 2; 18348c2ecf20Sopenharmony_ci else 18358c2ecf20Sopenharmony_ci idx++; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long we would 18398c2ecf20Sopenharmony_ci * need to ensure the ordering of writing to the SPQ element 18408c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 18418c2ecf20Sopenharmony_ci * read and we will have to put a full memory barrier there 18428c2ecf20Sopenharmony_ci * (inside bnx2x_sp_post()). 18438c2ecf20Sopenharmony_ci */ 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci rc = bnx2x_sp_post(bp, o->ramrod_cmd, r->cid, 18468c2ecf20Sopenharmony_ci U64_HI(r->rdata_mapping), 18478c2ecf20Sopenharmony_ci U64_LO(r->rdata_mapping), 18488c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 18498c2ecf20Sopenharmony_ci if (rc) 18508c2ecf20Sopenharmony_ci goto error_exit; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci /* Now, when we are done with the ramrod - clean up the registry */ 18548c2ecf20Sopenharmony_ci list_for_each_entry(elem, exe_chunk, link) { 18558c2ecf20Sopenharmony_ci cmd = elem->cmd_data.vlan_mac.cmd; 18568c2ecf20Sopenharmony_ci if ((cmd == BNX2X_VLAN_MAC_DEL) || 18578c2ecf20Sopenharmony_ci (cmd == BNX2X_VLAN_MAC_MOVE)) { 18588c2ecf20Sopenharmony_ci reg_elem = o->check_del(bp, o, 18598c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.u); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci WARN_ON(!reg_elem); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci o->put_cam_offset(o, reg_elem->cam_offset); 18648c2ecf20Sopenharmony_ci list_del(®_elem->link); 18658c2ecf20Sopenharmony_ci kfree(reg_elem); 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci if (!drv_only) 18708c2ecf20Sopenharmony_ci return 1; 18718c2ecf20Sopenharmony_ci else 18728c2ecf20Sopenharmony_ci return 0; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_cierror_exit: 18758c2ecf20Sopenharmony_ci r->clear_pending(r); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci /* Cleanup a registry in case of a failure */ 18788c2ecf20Sopenharmony_ci list_for_each_entry(elem, exe_chunk, link) { 18798c2ecf20Sopenharmony_ci cmd = elem->cmd_data.vlan_mac.cmd; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (cmd == BNX2X_VLAN_MAC_MOVE) 18828c2ecf20Sopenharmony_ci cam_obj = elem->cmd_data.vlan_mac.target_obj; 18838c2ecf20Sopenharmony_ci else 18848c2ecf20Sopenharmony_ci cam_obj = o; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* Delete all newly added above entries */ 18878c2ecf20Sopenharmony_ci if (!restore && 18888c2ecf20Sopenharmony_ci ((cmd == BNX2X_VLAN_MAC_ADD) || 18898c2ecf20Sopenharmony_ci (cmd == BNX2X_VLAN_MAC_MOVE))) { 18908c2ecf20Sopenharmony_ci reg_elem = o->check_del(bp, cam_obj, 18918c2ecf20Sopenharmony_ci &elem->cmd_data.vlan_mac.u); 18928c2ecf20Sopenharmony_ci if (reg_elem) { 18938c2ecf20Sopenharmony_ci list_del(®_elem->link); 18948c2ecf20Sopenharmony_ci kfree(reg_elem); 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci return rc; 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic inline int bnx2x_vlan_mac_push_new_cmd( 19038c2ecf20Sopenharmony_ci struct bnx2x *bp, 19048c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_ramrod_params *p) 19058c2ecf20Sopenharmony_ci{ 19068c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *elem; 19078c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; 19088c2ecf20Sopenharmony_ci bool restore = test_bit(RAMROD_RESTORE, &p->ramrod_flags); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci /* Allocate the execution queue element */ 19118c2ecf20Sopenharmony_ci elem = bnx2x_exe_queue_alloc_elem(bp); 19128c2ecf20Sopenharmony_ci if (!elem) 19138c2ecf20Sopenharmony_ci return -ENOMEM; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci /* Set the command 'length' */ 19168c2ecf20Sopenharmony_ci switch (p->user_req.cmd) { 19178c2ecf20Sopenharmony_ci case BNX2X_VLAN_MAC_MOVE: 19188c2ecf20Sopenharmony_ci elem->cmd_len = 2; 19198c2ecf20Sopenharmony_ci break; 19208c2ecf20Sopenharmony_ci default: 19218c2ecf20Sopenharmony_ci elem->cmd_len = 1; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci /* Fill the object specific info */ 19258c2ecf20Sopenharmony_ci memcpy(&elem->cmd_data.vlan_mac, &p->user_req, sizeof(p->user_req)); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* Try to add a new command to the pending list */ 19288c2ecf20Sopenharmony_ci return bnx2x_exe_queue_add(bp, &o->exe_queue, elem, restore); 19298c2ecf20Sopenharmony_ci} 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci/** 19328c2ecf20Sopenharmony_ci * bnx2x_config_vlan_mac - configure VLAN/MAC/VLAN_MAC filtering rules. 19338c2ecf20Sopenharmony_ci * 19348c2ecf20Sopenharmony_ci * @bp: device handle 19358c2ecf20Sopenharmony_ci * @p: 19368c2ecf20Sopenharmony_ci * 19378c2ecf20Sopenharmony_ci */ 19388c2ecf20Sopenharmony_ciint bnx2x_config_vlan_mac(struct bnx2x *bp, 19398c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_ramrod_params *p) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci int rc = 0; 19428c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; 19438c2ecf20Sopenharmony_ci unsigned long *ramrod_flags = &p->ramrod_flags; 19448c2ecf20Sopenharmony_ci bool cont = test_bit(RAMROD_CONT, ramrod_flags); 19458c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* 19488c2ecf20Sopenharmony_ci * Add new elements to the execution list for commands that require it. 19498c2ecf20Sopenharmony_ci */ 19508c2ecf20Sopenharmony_ci if (!cont) { 19518c2ecf20Sopenharmony_ci rc = bnx2x_vlan_mac_push_new_cmd(bp, p); 19528c2ecf20Sopenharmony_ci if (rc) 19538c2ecf20Sopenharmony_ci return rc; 19548c2ecf20Sopenharmony_ci } 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci /* If nothing will be executed further in this iteration we want to 19578c2ecf20Sopenharmony_ci * return PENDING if there are pending commands 19588c2ecf20Sopenharmony_ci */ 19598c2ecf20Sopenharmony_ci if (!bnx2x_exe_queue_empty(&o->exe_queue)) 19608c2ecf20Sopenharmony_ci rc = 1; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags)) { 19638c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: clearing a pending bit.\n"); 19648c2ecf20Sopenharmony_ci raw->clear_pending(raw); 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci /* Execute commands if required */ 19688c2ecf20Sopenharmony_ci if (cont || test_bit(RAMROD_EXEC, ramrod_flags) || 19698c2ecf20Sopenharmony_ci test_bit(RAMROD_COMP_WAIT, ramrod_flags)) { 19708c2ecf20Sopenharmony_ci rc = __bnx2x_vlan_mac_execute_step(bp, p->vlan_mac_obj, 19718c2ecf20Sopenharmony_ci &p->ramrod_flags); 19728c2ecf20Sopenharmony_ci if (rc < 0) 19738c2ecf20Sopenharmony_ci return rc; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* RAMROD_COMP_WAIT is a superset of RAMROD_EXEC. If it was set 19778c2ecf20Sopenharmony_ci * then user want to wait until the last command is done. 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) { 19808c2ecf20Sopenharmony_ci /* Wait maximum for the current exe_queue length iterations plus 19818c2ecf20Sopenharmony_ci * one (for the current pending command). 19828c2ecf20Sopenharmony_ci */ 19838c2ecf20Sopenharmony_ci int max_iterations = bnx2x_exe_queue_length(&o->exe_queue) + 1; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci while (!bnx2x_exe_queue_empty(&o->exe_queue) && 19868c2ecf20Sopenharmony_ci max_iterations--) { 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* Wait for the current command to complete */ 19898c2ecf20Sopenharmony_ci rc = raw->wait_comp(bp, raw); 19908c2ecf20Sopenharmony_ci if (rc) 19918c2ecf20Sopenharmony_ci return rc; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* Make a next step */ 19948c2ecf20Sopenharmony_ci rc = __bnx2x_vlan_mac_execute_step(bp, 19958c2ecf20Sopenharmony_ci p->vlan_mac_obj, 19968c2ecf20Sopenharmony_ci &p->ramrod_flags); 19978c2ecf20Sopenharmony_ci if (rc < 0) 19988c2ecf20Sopenharmony_ci return rc; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci return 0; 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci return rc; 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci/** 20088c2ecf20Sopenharmony_ci * bnx2x_vlan_mac_del_all - delete elements with given vlan_mac_flags spec 20098c2ecf20Sopenharmony_ci * 20108c2ecf20Sopenharmony_ci * @bp: device handle 20118c2ecf20Sopenharmony_ci * @o: vlan object info 20128c2ecf20Sopenharmony_ci * @vlan_mac_flags: vlan flags 20138c2ecf20Sopenharmony_ci * @ramrod_flags: execution flags to be used for this deletion 20148c2ecf20Sopenharmony_ci * 20158c2ecf20Sopenharmony_ci * if the last operation has completed successfully and there are no 20168c2ecf20Sopenharmony_ci * more elements left, positive value if the last operation has completed 20178c2ecf20Sopenharmony_ci * successfully and there are more previously configured elements, negative 20188c2ecf20Sopenharmony_ci * value is current operation has failed. 20198c2ecf20Sopenharmony_ci */ 20208c2ecf20Sopenharmony_cistatic int bnx2x_vlan_mac_del_all(struct bnx2x *bp, 20218c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *o, 20228c2ecf20Sopenharmony_ci unsigned long *vlan_mac_flags, 20238c2ecf20Sopenharmony_ci unsigned long *ramrod_flags) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_registry_elem *pos = NULL; 20268c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_ramrod_params p; 20278c2ecf20Sopenharmony_ci struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; 20288c2ecf20Sopenharmony_ci struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n; 20298c2ecf20Sopenharmony_ci unsigned long flags; 20308c2ecf20Sopenharmony_ci int read_lock; 20318c2ecf20Sopenharmony_ci int rc = 0; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci /* Clear pending commands first */ 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci spin_lock_bh(&exeq->lock); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci list_for_each_entry_safe(exeq_pos, exeq_pos_n, &exeq->exe_queue, link) { 20388c2ecf20Sopenharmony_ci flags = exeq_pos->cmd_data.vlan_mac.vlan_mac_flags; 20398c2ecf20Sopenharmony_ci if (BNX2X_VLAN_MAC_CMP_FLAGS(flags) == 20408c2ecf20Sopenharmony_ci BNX2X_VLAN_MAC_CMP_FLAGS(*vlan_mac_flags)) { 20418c2ecf20Sopenharmony_ci rc = exeq->remove(bp, exeq->owner, exeq_pos); 20428c2ecf20Sopenharmony_ci if (rc) { 20438c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to remove command\n"); 20448c2ecf20Sopenharmony_ci spin_unlock_bh(&exeq->lock); 20458c2ecf20Sopenharmony_ci return rc; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci list_del(&exeq_pos->link); 20488c2ecf20Sopenharmony_ci bnx2x_exe_queue_free_elem(bp, exeq_pos); 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci spin_unlock_bh(&exeq->lock); 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci /* Prepare a command request */ 20558c2ecf20Sopenharmony_ci memset(&p, 0, sizeof(p)); 20568c2ecf20Sopenharmony_ci p.vlan_mac_obj = o; 20578c2ecf20Sopenharmony_ci p.ramrod_flags = *ramrod_flags; 20588c2ecf20Sopenharmony_ci p.user_req.cmd = BNX2X_VLAN_MAC_DEL; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* Add all but the last VLAN-MAC to the execution queue without actually 20618c2ecf20Sopenharmony_ci * execution anything. 20628c2ecf20Sopenharmony_ci */ 20638c2ecf20Sopenharmony_ci __clear_bit(RAMROD_COMP_WAIT, &p.ramrod_flags); 20648c2ecf20Sopenharmony_ci __clear_bit(RAMROD_EXEC, &p.ramrod_flags); 20658c2ecf20Sopenharmony_ci __clear_bit(RAMROD_CONT, &p.ramrod_flags); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_del_all -- taking vlan_mac_lock (reader)\n"); 20688c2ecf20Sopenharmony_ci read_lock = bnx2x_vlan_mac_h_read_lock(bp, o); 20698c2ecf20Sopenharmony_ci if (read_lock != 0) 20708c2ecf20Sopenharmony_ci return read_lock; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci list_for_each_entry(pos, &o->head, link) { 20738c2ecf20Sopenharmony_ci flags = pos->vlan_mac_flags; 20748c2ecf20Sopenharmony_ci if (BNX2X_VLAN_MAC_CMP_FLAGS(flags) == 20758c2ecf20Sopenharmony_ci BNX2X_VLAN_MAC_CMP_FLAGS(*vlan_mac_flags)) { 20768c2ecf20Sopenharmony_ci p.user_req.vlan_mac_flags = pos->vlan_mac_flags; 20778c2ecf20Sopenharmony_ci memcpy(&p.user_req.u, &pos->u, sizeof(pos->u)); 20788c2ecf20Sopenharmony_ci rc = bnx2x_config_vlan_mac(bp, &p); 20798c2ecf20Sopenharmony_ci if (rc < 0) { 20808c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to add a new DEL command\n"); 20818c2ecf20Sopenharmony_ci bnx2x_vlan_mac_h_read_unlock(bp, o); 20828c2ecf20Sopenharmony_ci return rc; 20838c2ecf20Sopenharmony_ci } 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "vlan_mac_del_all -- releasing vlan_mac_lock (reader)\n"); 20888c2ecf20Sopenharmony_ci bnx2x_vlan_mac_h_read_unlock(bp, o); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci p.ramrod_flags = *ramrod_flags; 20918c2ecf20Sopenharmony_ci __set_bit(RAMROD_CONT, &p.ramrod_flags); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci return bnx2x_config_vlan_mac(bp, &p); 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_cistatic inline void bnx2x_init_raw_obj(struct bnx2x_raw_obj *raw, u8 cl_id, 20978c2ecf20Sopenharmony_ci u32 cid, u8 func_id, void *rdata, dma_addr_t rdata_mapping, int state, 20988c2ecf20Sopenharmony_ci unsigned long *pstate, bnx2x_obj_type type) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci raw->func_id = func_id; 21018c2ecf20Sopenharmony_ci raw->cid = cid; 21028c2ecf20Sopenharmony_ci raw->cl_id = cl_id; 21038c2ecf20Sopenharmony_ci raw->rdata = rdata; 21048c2ecf20Sopenharmony_ci raw->rdata_mapping = rdata_mapping; 21058c2ecf20Sopenharmony_ci raw->state = state; 21068c2ecf20Sopenharmony_ci raw->pstate = pstate; 21078c2ecf20Sopenharmony_ci raw->obj_type = type; 21088c2ecf20Sopenharmony_ci raw->check_pending = bnx2x_raw_check_pending; 21098c2ecf20Sopenharmony_ci raw->clear_pending = bnx2x_raw_clear_pending; 21108c2ecf20Sopenharmony_ci raw->set_pending = bnx2x_raw_set_pending; 21118c2ecf20Sopenharmony_ci raw->wait_comp = bnx2x_raw_wait; 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_cistatic inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o, 21158c2ecf20Sopenharmony_ci u8 cl_id, u32 cid, u8 func_id, void *rdata, dma_addr_t rdata_mapping, 21168c2ecf20Sopenharmony_ci int state, unsigned long *pstate, bnx2x_obj_type type, 21178c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *macs_pool, 21188c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vlans_pool) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&o->head); 21218c2ecf20Sopenharmony_ci o->head_reader = 0; 21228c2ecf20Sopenharmony_ci o->head_exe_request = false; 21238c2ecf20Sopenharmony_ci o->saved_ramrod_flags = 0; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci o->macs_pool = macs_pool; 21268c2ecf20Sopenharmony_ci o->vlans_pool = vlans_pool; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci o->delete_all = bnx2x_vlan_mac_del_all; 21298c2ecf20Sopenharmony_ci o->restore = bnx2x_vlan_mac_restore; 21308c2ecf20Sopenharmony_ci o->complete = bnx2x_complete_vlan_mac; 21318c2ecf20Sopenharmony_ci o->wait = bnx2x_wait_vlan_mac; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci bnx2x_init_raw_obj(&o->raw, cl_id, cid, func_id, rdata, rdata_mapping, 21348c2ecf20Sopenharmony_ci state, pstate, type); 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_civoid bnx2x_init_mac_obj(struct bnx2x *bp, 21388c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *mac_obj, 21398c2ecf20Sopenharmony_ci u8 cl_id, u32 cid, u8 func_id, void *rdata, 21408c2ecf20Sopenharmony_ci dma_addr_t rdata_mapping, int state, 21418c2ecf20Sopenharmony_ci unsigned long *pstate, bnx2x_obj_type type, 21428c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *macs_pool) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qable_obj = (union bnx2x_qable_obj *)mac_obj; 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci bnx2x_init_vlan_mac_common(mac_obj, cl_id, cid, func_id, rdata, 21478c2ecf20Sopenharmony_ci rdata_mapping, state, pstate, type, 21488c2ecf20Sopenharmony_ci macs_pool, NULL); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* CAM credit pool handling */ 21518c2ecf20Sopenharmony_ci mac_obj->get_credit = bnx2x_get_credit_mac; 21528c2ecf20Sopenharmony_ci mac_obj->put_credit = bnx2x_put_credit_mac; 21538c2ecf20Sopenharmony_ci mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac; 21548c2ecf20Sopenharmony_ci mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp)) { 21578c2ecf20Sopenharmony_ci mac_obj->set_one_rule = bnx2x_set_one_mac_e1x; 21588c2ecf20Sopenharmony_ci mac_obj->check_del = bnx2x_check_mac_del; 21598c2ecf20Sopenharmony_ci mac_obj->check_add = bnx2x_check_mac_add; 21608c2ecf20Sopenharmony_ci mac_obj->check_move = bnx2x_check_move_always_err; 21618c2ecf20Sopenharmony_ci mac_obj->ramrod_cmd = RAMROD_CMD_ID_ETH_SET_MAC; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci /* Exe Queue */ 21648c2ecf20Sopenharmony_ci bnx2x_exe_queue_init(bp, 21658c2ecf20Sopenharmony_ci &mac_obj->exe_queue, 1, qable_obj, 21668c2ecf20Sopenharmony_ci bnx2x_validate_vlan_mac, 21678c2ecf20Sopenharmony_ci bnx2x_remove_vlan_mac, 21688c2ecf20Sopenharmony_ci bnx2x_optimize_vlan_mac, 21698c2ecf20Sopenharmony_ci bnx2x_execute_vlan_mac, 21708c2ecf20Sopenharmony_ci bnx2x_exeq_get_mac); 21718c2ecf20Sopenharmony_ci } else { 21728c2ecf20Sopenharmony_ci mac_obj->set_one_rule = bnx2x_set_one_mac_e2; 21738c2ecf20Sopenharmony_ci mac_obj->check_del = bnx2x_check_mac_del; 21748c2ecf20Sopenharmony_ci mac_obj->check_add = bnx2x_check_mac_add; 21758c2ecf20Sopenharmony_ci mac_obj->check_move = bnx2x_check_move; 21768c2ecf20Sopenharmony_ci mac_obj->ramrod_cmd = 21778c2ecf20Sopenharmony_ci RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; 21788c2ecf20Sopenharmony_ci mac_obj->get_n_elements = bnx2x_get_n_elements; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* Exe Queue */ 21818c2ecf20Sopenharmony_ci bnx2x_exe_queue_init(bp, 21828c2ecf20Sopenharmony_ci &mac_obj->exe_queue, CLASSIFY_RULES_COUNT, 21838c2ecf20Sopenharmony_ci qable_obj, bnx2x_validate_vlan_mac, 21848c2ecf20Sopenharmony_ci bnx2x_remove_vlan_mac, 21858c2ecf20Sopenharmony_ci bnx2x_optimize_vlan_mac, 21868c2ecf20Sopenharmony_ci bnx2x_execute_vlan_mac, 21878c2ecf20Sopenharmony_ci bnx2x_exeq_get_mac); 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci} 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_civoid bnx2x_init_vlan_obj(struct bnx2x *bp, 21928c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *vlan_obj, 21938c2ecf20Sopenharmony_ci u8 cl_id, u32 cid, u8 func_id, void *rdata, 21948c2ecf20Sopenharmony_ci dma_addr_t rdata_mapping, int state, 21958c2ecf20Sopenharmony_ci unsigned long *pstate, bnx2x_obj_type type, 21968c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vlans_pool) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qable_obj = (union bnx2x_qable_obj *)vlan_obj; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci bnx2x_init_vlan_mac_common(vlan_obj, cl_id, cid, func_id, rdata, 22018c2ecf20Sopenharmony_ci rdata_mapping, state, pstate, type, NULL, 22028c2ecf20Sopenharmony_ci vlans_pool); 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci vlan_obj->get_credit = bnx2x_get_credit_vlan; 22058c2ecf20Sopenharmony_ci vlan_obj->put_credit = bnx2x_put_credit_vlan; 22068c2ecf20Sopenharmony_ci vlan_obj->get_cam_offset = bnx2x_get_cam_offset_vlan; 22078c2ecf20Sopenharmony_ci vlan_obj->put_cam_offset = bnx2x_put_cam_offset_vlan; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp)) { 22108c2ecf20Sopenharmony_ci BNX2X_ERR("Do not support chips others than E2 and newer\n"); 22118c2ecf20Sopenharmony_ci BUG(); 22128c2ecf20Sopenharmony_ci } else { 22138c2ecf20Sopenharmony_ci vlan_obj->set_one_rule = bnx2x_set_one_vlan_e2; 22148c2ecf20Sopenharmony_ci vlan_obj->check_del = bnx2x_check_vlan_del; 22158c2ecf20Sopenharmony_ci vlan_obj->check_add = bnx2x_check_vlan_add; 22168c2ecf20Sopenharmony_ci vlan_obj->check_move = bnx2x_check_move; 22178c2ecf20Sopenharmony_ci vlan_obj->ramrod_cmd = 22188c2ecf20Sopenharmony_ci RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; 22198c2ecf20Sopenharmony_ci vlan_obj->get_n_elements = bnx2x_get_n_elements; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci /* Exe Queue */ 22228c2ecf20Sopenharmony_ci bnx2x_exe_queue_init(bp, 22238c2ecf20Sopenharmony_ci &vlan_obj->exe_queue, CLASSIFY_RULES_COUNT, 22248c2ecf20Sopenharmony_ci qable_obj, bnx2x_validate_vlan_mac, 22258c2ecf20Sopenharmony_ci bnx2x_remove_vlan_mac, 22268c2ecf20Sopenharmony_ci bnx2x_optimize_vlan_mac, 22278c2ecf20Sopenharmony_ci bnx2x_execute_vlan_mac, 22288c2ecf20Sopenharmony_ci bnx2x_exeq_get_vlan); 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_civoid bnx2x_init_vlan_mac_obj(struct bnx2x *bp, 22338c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *vlan_mac_obj, 22348c2ecf20Sopenharmony_ci u8 cl_id, u32 cid, u8 func_id, void *rdata, 22358c2ecf20Sopenharmony_ci dma_addr_t rdata_mapping, int state, 22368c2ecf20Sopenharmony_ci unsigned long *pstate, bnx2x_obj_type type, 22378c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *macs_pool, 22388c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *vlans_pool) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci union bnx2x_qable_obj *qable_obj = 22418c2ecf20Sopenharmony_ci (union bnx2x_qable_obj *)vlan_mac_obj; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata, 22448c2ecf20Sopenharmony_ci rdata_mapping, state, pstate, type, 22458c2ecf20Sopenharmony_ci macs_pool, vlans_pool); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci /* CAM pool handling */ 22488c2ecf20Sopenharmony_ci vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac; 22498c2ecf20Sopenharmony_ci vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac; 22508c2ecf20Sopenharmony_ci /* CAM offset is relevant for 57710 and 57711 chips only which have a 22518c2ecf20Sopenharmony_ci * single CAM for both MACs and VLAN-MAC pairs. So the offset 22528c2ecf20Sopenharmony_ci * will be taken from MACs' pool object only. 22538c2ecf20Sopenharmony_ci */ 22548c2ecf20Sopenharmony_ci vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac; 22558c2ecf20Sopenharmony_ci vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) { 22588c2ecf20Sopenharmony_ci BNX2X_ERR("Do not support chips others than E2\n"); 22598c2ecf20Sopenharmony_ci BUG(); 22608c2ecf20Sopenharmony_ci } else if (CHIP_IS_E1H(bp)) { 22618c2ecf20Sopenharmony_ci vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e1h; 22628c2ecf20Sopenharmony_ci vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; 22638c2ecf20Sopenharmony_ci vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; 22648c2ecf20Sopenharmony_ci vlan_mac_obj->check_move = bnx2x_check_move_always_err; 22658c2ecf20Sopenharmony_ci vlan_mac_obj->ramrod_cmd = RAMROD_CMD_ID_ETH_SET_MAC; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci /* Exe Queue */ 22688c2ecf20Sopenharmony_ci bnx2x_exe_queue_init(bp, 22698c2ecf20Sopenharmony_ci &vlan_mac_obj->exe_queue, 1, qable_obj, 22708c2ecf20Sopenharmony_ci bnx2x_validate_vlan_mac, 22718c2ecf20Sopenharmony_ci bnx2x_remove_vlan_mac, 22728c2ecf20Sopenharmony_ci bnx2x_optimize_vlan_mac, 22738c2ecf20Sopenharmony_ci bnx2x_execute_vlan_mac, 22748c2ecf20Sopenharmony_ci bnx2x_exeq_get_vlan_mac); 22758c2ecf20Sopenharmony_ci } else { 22768c2ecf20Sopenharmony_ci vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e2; 22778c2ecf20Sopenharmony_ci vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; 22788c2ecf20Sopenharmony_ci vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; 22798c2ecf20Sopenharmony_ci vlan_mac_obj->check_move = bnx2x_check_move; 22808c2ecf20Sopenharmony_ci vlan_mac_obj->ramrod_cmd = 22818c2ecf20Sopenharmony_ci RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci /* Exe Queue */ 22848c2ecf20Sopenharmony_ci bnx2x_exe_queue_init(bp, 22858c2ecf20Sopenharmony_ci &vlan_mac_obj->exe_queue, 22868c2ecf20Sopenharmony_ci CLASSIFY_RULES_COUNT, 22878c2ecf20Sopenharmony_ci qable_obj, bnx2x_validate_vlan_mac, 22888c2ecf20Sopenharmony_ci bnx2x_remove_vlan_mac, 22898c2ecf20Sopenharmony_ci bnx2x_optimize_vlan_mac, 22908c2ecf20Sopenharmony_ci bnx2x_execute_vlan_mac, 22918c2ecf20Sopenharmony_ci bnx2x_exeq_get_vlan_mac); 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci} 22948c2ecf20Sopenharmony_ci/* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */ 22958c2ecf20Sopenharmony_cistatic inline void __storm_memset_mac_filters(struct bnx2x *bp, 22968c2ecf20Sopenharmony_ci struct tstorm_eth_mac_filter_config *mac_filters, 22978c2ecf20Sopenharmony_ci u16 pf_id) 22988c2ecf20Sopenharmony_ci{ 22998c2ecf20Sopenharmony_ci size_t size = sizeof(struct tstorm_eth_mac_filter_config); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci u32 addr = BAR_TSTRORM_INTMEM + 23028c2ecf20Sopenharmony_ci TSTORM_MAC_FILTER_CONFIG_OFFSET(pf_id); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci __storm_memset_struct(bp, addr, size, (u32 *)mac_filters); 23058c2ecf20Sopenharmony_ci} 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_cistatic int bnx2x_set_rx_mode_e1x(struct bnx2x *bp, 23088c2ecf20Sopenharmony_ci struct bnx2x_rx_mode_ramrod_params *p) 23098c2ecf20Sopenharmony_ci{ 23108c2ecf20Sopenharmony_ci /* update the bp MAC filter structure */ 23118c2ecf20Sopenharmony_ci u32 mask = (1 << p->cl_id); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci struct tstorm_eth_mac_filter_config *mac_filters = 23148c2ecf20Sopenharmony_ci (struct tstorm_eth_mac_filter_config *)p->rdata; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci /* initial setting is drop-all */ 23178c2ecf20Sopenharmony_ci u8 drop_all_ucast = 1, drop_all_mcast = 1; 23188c2ecf20Sopenharmony_ci u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0; 23198c2ecf20Sopenharmony_ci u8 unmatched_unicast = 0; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci /* In e1x there we only take into account rx accept flag since tx switching 23228c2ecf20Sopenharmony_ci * isn't enabled. */ 23238c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_UNICAST, &p->rx_accept_flags)) 23248c2ecf20Sopenharmony_ci /* accept matched ucast */ 23258c2ecf20Sopenharmony_ci drop_all_ucast = 0; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_MULTICAST, &p->rx_accept_flags)) 23288c2ecf20Sopenharmony_ci /* accept matched mcast */ 23298c2ecf20Sopenharmony_ci drop_all_mcast = 0; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &p->rx_accept_flags)) { 23328c2ecf20Sopenharmony_ci /* accept all mcast */ 23338c2ecf20Sopenharmony_ci drop_all_ucast = 0; 23348c2ecf20Sopenharmony_ci accp_all_ucast = 1; 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &p->rx_accept_flags)) { 23378c2ecf20Sopenharmony_ci /* accept all mcast */ 23388c2ecf20Sopenharmony_ci drop_all_mcast = 0; 23398c2ecf20Sopenharmony_ci accp_all_mcast = 1; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_BROADCAST, &p->rx_accept_flags)) 23428c2ecf20Sopenharmony_ci /* accept (all) bcast */ 23438c2ecf20Sopenharmony_ci accp_all_bcast = 1; 23448c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_UNMATCHED, &p->rx_accept_flags)) 23458c2ecf20Sopenharmony_ci /* accept unmatched unicasts */ 23468c2ecf20Sopenharmony_ci unmatched_unicast = 1; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci mac_filters->ucast_drop_all = drop_all_ucast ? 23498c2ecf20Sopenharmony_ci mac_filters->ucast_drop_all | mask : 23508c2ecf20Sopenharmony_ci mac_filters->ucast_drop_all & ~mask; 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci mac_filters->mcast_drop_all = drop_all_mcast ? 23538c2ecf20Sopenharmony_ci mac_filters->mcast_drop_all | mask : 23548c2ecf20Sopenharmony_ci mac_filters->mcast_drop_all & ~mask; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci mac_filters->ucast_accept_all = accp_all_ucast ? 23578c2ecf20Sopenharmony_ci mac_filters->ucast_accept_all | mask : 23588c2ecf20Sopenharmony_ci mac_filters->ucast_accept_all & ~mask; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci mac_filters->mcast_accept_all = accp_all_mcast ? 23618c2ecf20Sopenharmony_ci mac_filters->mcast_accept_all | mask : 23628c2ecf20Sopenharmony_ci mac_filters->mcast_accept_all & ~mask; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci mac_filters->bcast_accept_all = accp_all_bcast ? 23658c2ecf20Sopenharmony_ci mac_filters->bcast_accept_all | mask : 23668c2ecf20Sopenharmony_ci mac_filters->bcast_accept_all & ~mask; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci mac_filters->unmatched_unicast = unmatched_unicast ? 23698c2ecf20Sopenharmony_ci mac_filters->unmatched_unicast | mask : 23708c2ecf20Sopenharmony_ci mac_filters->unmatched_unicast & ~mask; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "drop_ucast 0x%x\ndrop_mcast 0x%x\n accp_ucast 0x%x\n" 23738c2ecf20Sopenharmony_ci "accp_mcast 0x%x\naccp_bcast 0x%x\n", 23748c2ecf20Sopenharmony_ci mac_filters->ucast_drop_all, mac_filters->mcast_drop_all, 23758c2ecf20Sopenharmony_ci mac_filters->ucast_accept_all, mac_filters->mcast_accept_all, 23768c2ecf20Sopenharmony_ci mac_filters->bcast_accept_all); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci /* write the MAC filter structure*/ 23798c2ecf20Sopenharmony_ci __storm_memset_mac_filters(bp, mac_filters, p->func_id); 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci /* The operation is completed */ 23828c2ecf20Sopenharmony_ci clear_bit(p->state, p->pstate); 23838c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci return 0; 23868c2ecf20Sopenharmony_ci} 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci/* Setup ramrod data */ 23898c2ecf20Sopenharmony_cistatic inline void bnx2x_rx_mode_set_rdata_hdr_e2(u32 cid, 23908c2ecf20Sopenharmony_ci struct eth_classify_header *hdr, 23918c2ecf20Sopenharmony_ci u8 rule_cnt) 23928c2ecf20Sopenharmony_ci{ 23938c2ecf20Sopenharmony_ci hdr->echo = cpu_to_le32(cid); 23948c2ecf20Sopenharmony_ci hdr->rule_cnt = rule_cnt; 23958c2ecf20Sopenharmony_ci} 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_cistatic inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp, 23988c2ecf20Sopenharmony_ci unsigned long *accept_flags, 23998c2ecf20Sopenharmony_ci struct eth_filter_rules_cmd *cmd, 24008c2ecf20Sopenharmony_ci bool clear_accept_all) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci u16 state; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci /* start with 'drop-all' */ 24058c2ecf20Sopenharmony_ci state = ETH_FILTER_RULES_CMD_UCAST_DROP_ALL | 24068c2ecf20Sopenharmony_ci ETH_FILTER_RULES_CMD_MCAST_DROP_ALL; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_UNICAST, accept_flags)) 24098c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_MULTICAST, accept_flags)) 24128c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL; 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, accept_flags)) { 24158c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL; 24168c2ecf20Sopenharmony_ci state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL; 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, accept_flags)) { 24208c2ecf20Sopenharmony_ci state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL; 24218c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL; 24228c2ecf20Sopenharmony_ci } 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_BROADCAST, accept_flags)) 24258c2ecf20Sopenharmony_ci state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_UNMATCHED, accept_flags)) { 24288c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL; 24298c2ecf20Sopenharmony_ci state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED; 24308c2ecf20Sopenharmony_ci } 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci if (test_bit(BNX2X_ACCEPT_ANY_VLAN, accept_flags)) 24338c2ecf20Sopenharmony_ci state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci /* Clear ACCEPT_ALL_XXX flags for FCoE L2 Queue */ 24368c2ecf20Sopenharmony_ci if (clear_accept_all) { 24378c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL; 24388c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL; 24398c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL; 24408c2ecf20Sopenharmony_ci state &= ~ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED; 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci cmd->state = cpu_to_le16(state); 24448c2ecf20Sopenharmony_ci} 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_cistatic int bnx2x_set_rx_mode_e2(struct bnx2x *bp, 24478c2ecf20Sopenharmony_ci struct bnx2x_rx_mode_ramrod_params *p) 24488c2ecf20Sopenharmony_ci{ 24498c2ecf20Sopenharmony_ci struct eth_filter_rules_ramrod_data *data = p->rdata; 24508c2ecf20Sopenharmony_ci int rc; 24518c2ecf20Sopenharmony_ci u8 rule_idx = 0; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer */ 24548c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci /* Setup ramrod data */ 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci /* Tx (internal switching) */ 24598c2ecf20Sopenharmony_ci if (test_bit(RAMROD_TX, &p->ramrod_flags)) { 24608c2ecf20Sopenharmony_ci data->rules[rule_idx].client_id = p->cl_id; 24618c2ecf20Sopenharmony_ci data->rules[rule_idx].func_id = p->func_id; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci data->rules[rule_idx].cmd_general_data = 24648c2ecf20Sopenharmony_ci ETH_FILTER_RULES_CMD_TX_CMD; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags, 24678c2ecf20Sopenharmony_ci &(data->rules[rule_idx++]), 24688c2ecf20Sopenharmony_ci false); 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci /* Rx */ 24728c2ecf20Sopenharmony_ci if (test_bit(RAMROD_RX, &p->ramrod_flags)) { 24738c2ecf20Sopenharmony_ci data->rules[rule_idx].client_id = p->cl_id; 24748c2ecf20Sopenharmony_ci data->rules[rule_idx].func_id = p->func_id; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci data->rules[rule_idx].cmd_general_data = 24778c2ecf20Sopenharmony_ci ETH_FILTER_RULES_CMD_RX_CMD; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags, 24808c2ecf20Sopenharmony_ci &(data->rules[rule_idx++]), 24818c2ecf20Sopenharmony_ci false); 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci /* If FCoE Queue configuration has been requested configure the Rx and 24858c2ecf20Sopenharmony_ci * internal switching modes for this queue in separate rules. 24868c2ecf20Sopenharmony_ci * 24878c2ecf20Sopenharmony_ci * FCoE queue shell never be set to ACCEPT_ALL packets of any sort: 24888c2ecf20Sopenharmony_ci * MCAST_ALL, UCAST_ALL, BCAST_ALL and UNMATCHED. 24898c2ecf20Sopenharmony_ci */ 24908c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RX_MODE_FCOE_ETH, &p->rx_mode_flags)) { 24918c2ecf20Sopenharmony_ci /* Tx (internal switching) */ 24928c2ecf20Sopenharmony_ci if (test_bit(RAMROD_TX, &p->ramrod_flags)) { 24938c2ecf20Sopenharmony_ci data->rules[rule_idx].client_id = bnx2x_fcoe(bp, cl_id); 24948c2ecf20Sopenharmony_ci data->rules[rule_idx].func_id = p->func_id; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci data->rules[rule_idx].cmd_general_data = 24978c2ecf20Sopenharmony_ci ETH_FILTER_RULES_CMD_TX_CMD; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags, 25008c2ecf20Sopenharmony_ci &(data->rules[rule_idx]), 25018c2ecf20Sopenharmony_ci true); 25028c2ecf20Sopenharmony_ci rule_idx++; 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci /* Rx */ 25068c2ecf20Sopenharmony_ci if (test_bit(RAMROD_RX, &p->ramrod_flags)) { 25078c2ecf20Sopenharmony_ci data->rules[rule_idx].client_id = bnx2x_fcoe(bp, cl_id); 25088c2ecf20Sopenharmony_ci data->rules[rule_idx].func_id = p->func_id; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci data->rules[rule_idx].cmd_general_data = 25118c2ecf20Sopenharmony_ci ETH_FILTER_RULES_CMD_RX_CMD; 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags, 25148c2ecf20Sopenharmony_ci &(data->rules[rule_idx]), 25158c2ecf20Sopenharmony_ci true); 25168c2ecf20Sopenharmony_ci rule_idx++; 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci } 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci /* Set the ramrod header (most importantly - number of rules to 25218c2ecf20Sopenharmony_ci * configure). 25228c2ecf20Sopenharmony_ci */ 25238c2ecf20Sopenharmony_ci bnx2x_rx_mode_set_rdata_hdr_e2(p->cid, &data->header, rule_idx); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure %d rules, rx_accept_flags 0x%lx, tx_accept_flags 0x%lx\n", 25268c2ecf20Sopenharmony_ci data->header.rule_cnt, p->rx_accept_flags, 25278c2ecf20Sopenharmony_ci p->tx_accept_flags); 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 25308c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 25318c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 25328c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 25338c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 25348c2ecf20Sopenharmony_ci */ 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci /* Send a ramrod */ 25378c2ecf20Sopenharmony_ci rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_FILTER_RULES, p->cid, 25388c2ecf20Sopenharmony_ci U64_HI(p->rdata_mapping), 25398c2ecf20Sopenharmony_ci U64_LO(p->rdata_mapping), 25408c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 25418c2ecf20Sopenharmony_ci if (rc) 25428c2ecf20Sopenharmony_ci return rc; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci /* Ramrod completion is pending */ 25458c2ecf20Sopenharmony_ci return 1; 25468c2ecf20Sopenharmony_ci} 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_cistatic int bnx2x_wait_rx_mode_comp_e2(struct bnx2x *bp, 25498c2ecf20Sopenharmony_ci struct bnx2x_rx_mode_ramrod_params *p) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci return bnx2x_state_wait(bp, p->state, p->pstate); 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cistatic int bnx2x_empty_rx_mode_wait(struct bnx2x *bp, 25558c2ecf20Sopenharmony_ci struct bnx2x_rx_mode_ramrod_params *p) 25568c2ecf20Sopenharmony_ci{ 25578c2ecf20Sopenharmony_ci /* Do nothing */ 25588c2ecf20Sopenharmony_ci return 0; 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ciint bnx2x_config_rx_mode(struct bnx2x *bp, 25628c2ecf20Sopenharmony_ci struct bnx2x_rx_mode_ramrod_params *p) 25638c2ecf20Sopenharmony_ci{ 25648c2ecf20Sopenharmony_ci int rc; 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci /* Configure the new classification in the chip */ 25678c2ecf20Sopenharmony_ci rc = p->rx_mode_obj->config_rx_mode(bp, p); 25688c2ecf20Sopenharmony_ci if (rc < 0) 25698c2ecf20Sopenharmony_ci return rc; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci /* Wait for a ramrod completion if was requested */ 25728c2ecf20Sopenharmony_ci if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) { 25738c2ecf20Sopenharmony_ci rc = p->rx_mode_obj->wait_comp(bp, p); 25748c2ecf20Sopenharmony_ci if (rc) 25758c2ecf20Sopenharmony_ci return rc; 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci return rc; 25798c2ecf20Sopenharmony_ci} 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_civoid bnx2x_init_rx_mode_obj(struct bnx2x *bp, 25828c2ecf20Sopenharmony_ci struct bnx2x_rx_mode_obj *o) 25838c2ecf20Sopenharmony_ci{ 25848c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp)) { 25858c2ecf20Sopenharmony_ci o->wait_comp = bnx2x_empty_rx_mode_wait; 25868c2ecf20Sopenharmony_ci o->config_rx_mode = bnx2x_set_rx_mode_e1x; 25878c2ecf20Sopenharmony_ci } else { 25888c2ecf20Sopenharmony_ci o->wait_comp = bnx2x_wait_rx_mode_comp_e2; 25898c2ecf20Sopenharmony_ci o->config_rx_mode = bnx2x_set_rx_mode_e2; 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci} 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci/********************* Multicast verbs: SET, CLEAR ****************************/ 25948c2ecf20Sopenharmony_cistatic inline u8 bnx2x_mcast_bin_from_mac(u8 *mac) 25958c2ecf20Sopenharmony_ci{ 25968c2ecf20Sopenharmony_ci return (crc32c_le(0, mac, ETH_ALEN) >> 24) & 0xff; 25978c2ecf20Sopenharmony_ci} 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_cistruct bnx2x_mcast_mac_elem { 26008c2ecf20Sopenharmony_ci struct list_head link; 26018c2ecf20Sopenharmony_ci u8 mac[ETH_ALEN]; 26028c2ecf20Sopenharmony_ci u8 pad[2]; /* For a natural alignment of the following buffer */ 26038c2ecf20Sopenharmony_ci}; 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_cistruct bnx2x_mcast_bin_elem { 26068c2ecf20Sopenharmony_ci struct list_head link; 26078c2ecf20Sopenharmony_ci int bin; 26088c2ecf20Sopenharmony_ci int type; /* BNX2X_MCAST_CMD_SET_{ADD, DEL} */ 26098c2ecf20Sopenharmony_ci}; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ciunion bnx2x_mcast_elem { 26128c2ecf20Sopenharmony_ci struct bnx2x_mcast_bin_elem bin_elem; 26138c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem mac_elem; 26148c2ecf20Sopenharmony_ci}; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_cistruct bnx2x_mcast_elem_group { 26178c2ecf20Sopenharmony_ci struct list_head mcast_group_link; 26188c2ecf20Sopenharmony_ci union bnx2x_mcast_elem mcast_elems[]; 26198c2ecf20Sopenharmony_ci}; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci#define MCAST_MAC_ELEMS_PER_PG \ 26228c2ecf20Sopenharmony_ci ((PAGE_SIZE - sizeof(struct bnx2x_mcast_elem_group)) / \ 26238c2ecf20Sopenharmony_ci sizeof(union bnx2x_mcast_elem)) 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_cistruct bnx2x_pending_mcast_cmd { 26268c2ecf20Sopenharmony_ci struct list_head link; 26278c2ecf20Sopenharmony_ci struct list_head group_head; 26288c2ecf20Sopenharmony_ci int type; /* BNX2X_MCAST_CMD_X */ 26298c2ecf20Sopenharmony_ci union { 26308c2ecf20Sopenharmony_ci struct list_head macs_head; 26318c2ecf20Sopenharmony_ci u32 macs_num; /* Needed for DEL command */ 26328c2ecf20Sopenharmony_ci int next_bin; /* Needed for RESTORE flow with aprox match */ 26338c2ecf20Sopenharmony_ci } data; 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci bool set_convert; /* in case type == BNX2X_MCAST_CMD_SET, this is set 26368c2ecf20Sopenharmony_ci * when macs_head had been converted to a list of 26378c2ecf20Sopenharmony_ci * bnx2x_mcast_bin_elem. 26388c2ecf20Sopenharmony_ci */ 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci bool done; /* set to true, when the command has been handled, 26418c2ecf20Sopenharmony_ci * practically used in 57712 handling only, where one pending 26428c2ecf20Sopenharmony_ci * command may be handled in a few operations. As long as for 26438c2ecf20Sopenharmony_ci * other chips every operation handling is completed in a 26448c2ecf20Sopenharmony_ci * single ramrod, there is no need to utilize this field. 26458c2ecf20Sopenharmony_ci */ 26468c2ecf20Sopenharmony_ci}; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_cistatic int bnx2x_mcast_wait(struct bnx2x *bp, 26498c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o) 26508c2ecf20Sopenharmony_ci{ 26518c2ecf20Sopenharmony_ci if (bnx2x_state_wait(bp, o->sched_state, o->raw.pstate) || 26528c2ecf20Sopenharmony_ci o->raw.wait_comp(bp, &o->raw)) 26538c2ecf20Sopenharmony_ci return -EBUSY; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci return 0; 26568c2ecf20Sopenharmony_ci} 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_cistatic void bnx2x_free_groups(struct list_head *mcast_group_list) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci struct bnx2x_mcast_elem_group *current_mcast_group; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci while (!list_empty(mcast_group_list)) { 26638c2ecf20Sopenharmony_ci current_mcast_group = list_first_entry(mcast_group_list, 26648c2ecf20Sopenharmony_ci struct bnx2x_mcast_elem_group, 26658c2ecf20Sopenharmony_ci mcast_group_link); 26668c2ecf20Sopenharmony_ci list_del(¤t_mcast_group->mcast_group_link); 26678c2ecf20Sopenharmony_ci free_page((unsigned long)current_mcast_group); 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci} 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_cistatic int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp, 26728c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, 26738c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 26748c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 26758c2ecf20Sopenharmony_ci{ 26768c2ecf20Sopenharmony_ci struct bnx2x_pending_mcast_cmd *new_cmd; 26778c2ecf20Sopenharmony_ci struct bnx2x_mcast_list_elem *pos; 26788c2ecf20Sopenharmony_ci struct bnx2x_mcast_elem_group *elem_group; 26798c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem *mac_elem; 26808c2ecf20Sopenharmony_ci int total_elems = 0, macs_list_len = 0, offset = 0; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci /* When adding MACs we'll need to store their values */ 26838c2ecf20Sopenharmony_ci if (cmd == BNX2X_MCAST_CMD_ADD || cmd == BNX2X_MCAST_CMD_SET) 26848c2ecf20Sopenharmony_ci macs_list_len = p->mcast_list_len; 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci /* If the command is empty ("handle pending commands only"), break */ 26878c2ecf20Sopenharmony_ci if (!p->mcast_list_len) 26888c2ecf20Sopenharmony_ci return 0; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci /* Add mcast is called under spin_lock, thus calling with GFP_ATOMIC */ 26918c2ecf20Sopenharmony_ci new_cmd = kzalloc(sizeof(*new_cmd), GFP_ATOMIC); 26928c2ecf20Sopenharmony_ci if (!new_cmd) 26938c2ecf20Sopenharmony_ci return -ENOMEM; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new_cmd->data.macs_head); 26968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new_cmd->group_head); 26978c2ecf20Sopenharmony_ci new_cmd->type = cmd; 26988c2ecf20Sopenharmony_ci new_cmd->done = false; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to enqueue a new %d command. macs_list_len=%d\n", 27018c2ecf20Sopenharmony_ci cmd, macs_list_len); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci switch (cmd) { 27048c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 27058c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_SET: 27068c2ecf20Sopenharmony_ci /* For a set command, we need to allocate sufficient memory for 27078c2ecf20Sopenharmony_ci * all the bins, since we can't analyze at this point how much 27088c2ecf20Sopenharmony_ci * memory would be required. 27098c2ecf20Sopenharmony_ci */ 27108c2ecf20Sopenharmony_ci total_elems = macs_list_len; 27118c2ecf20Sopenharmony_ci if (cmd == BNX2X_MCAST_CMD_SET) { 27128c2ecf20Sopenharmony_ci if (total_elems < BNX2X_MCAST_BINS_NUM) 27138c2ecf20Sopenharmony_ci total_elems = BNX2X_MCAST_BINS_NUM; 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci while (total_elems > 0) { 27168c2ecf20Sopenharmony_ci elem_group = (struct bnx2x_mcast_elem_group *) 27178c2ecf20Sopenharmony_ci __get_free_page(GFP_ATOMIC | __GFP_ZERO); 27188c2ecf20Sopenharmony_ci if (!elem_group) { 27198c2ecf20Sopenharmony_ci bnx2x_free_groups(&new_cmd->group_head); 27208c2ecf20Sopenharmony_ci kfree(new_cmd); 27218c2ecf20Sopenharmony_ci return -ENOMEM; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci total_elems -= MCAST_MAC_ELEMS_PER_PG; 27248c2ecf20Sopenharmony_ci list_add_tail(&elem_group->mcast_group_link, 27258c2ecf20Sopenharmony_ci &new_cmd->group_head); 27268c2ecf20Sopenharmony_ci } 27278c2ecf20Sopenharmony_ci elem_group = list_first_entry(&new_cmd->group_head, 27288c2ecf20Sopenharmony_ci struct bnx2x_mcast_elem_group, 27298c2ecf20Sopenharmony_ci mcast_group_link); 27308c2ecf20Sopenharmony_ci list_for_each_entry(pos, &p->mcast_list, link) { 27318c2ecf20Sopenharmony_ci mac_elem = &elem_group->mcast_elems[offset].mac_elem; 27328c2ecf20Sopenharmony_ci memcpy(mac_elem->mac, pos->mac, ETH_ALEN); 27338c2ecf20Sopenharmony_ci /* Push the MACs of the current command into the pending 27348c2ecf20Sopenharmony_ci * command MACs list: FIFO 27358c2ecf20Sopenharmony_ci */ 27368c2ecf20Sopenharmony_ci list_add_tail(&mac_elem->link, 27378c2ecf20Sopenharmony_ci &new_cmd->data.macs_head); 27388c2ecf20Sopenharmony_ci offset++; 27398c2ecf20Sopenharmony_ci if (offset == MCAST_MAC_ELEMS_PER_PG) { 27408c2ecf20Sopenharmony_ci offset = 0; 27418c2ecf20Sopenharmony_ci elem_group = list_next_entry(elem_group, 27428c2ecf20Sopenharmony_ci mcast_group_link); 27438c2ecf20Sopenharmony_ci } 27448c2ecf20Sopenharmony_ci } 27458c2ecf20Sopenharmony_ci break; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 27488c2ecf20Sopenharmony_ci new_cmd->data.macs_num = p->mcast_list_len; 27498c2ecf20Sopenharmony_ci break; 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 27528c2ecf20Sopenharmony_ci new_cmd->data.next_bin = 0; 27538c2ecf20Sopenharmony_ci break; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci default: 27568c2ecf20Sopenharmony_ci kfree(new_cmd); 27578c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd); 27588c2ecf20Sopenharmony_ci return -EINVAL; 27598c2ecf20Sopenharmony_ci } 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci /* Push the new pending command to the tail of the pending list: FIFO */ 27628c2ecf20Sopenharmony_ci list_add_tail(&new_cmd->link, &o->pending_cmds_head); 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci o->set_sched(o); 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci return 1; 27678c2ecf20Sopenharmony_ci} 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci/** 27708c2ecf20Sopenharmony_ci * bnx2x_mcast_get_next_bin - get the next set bin (index) 27718c2ecf20Sopenharmony_ci * 27728c2ecf20Sopenharmony_ci * @o: multicast object info 27738c2ecf20Sopenharmony_ci * @last: index to start looking from (including) 27748c2ecf20Sopenharmony_ci * 27758c2ecf20Sopenharmony_ci * returns the next found (set) bin or a negative value if none is found. 27768c2ecf20Sopenharmony_ci */ 27778c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_get_next_bin(struct bnx2x_mcast_obj *o, int last) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci int i, j, inner_start = last % BIT_VEC64_ELEM_SZ; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci for (i = last / BIT_VEC64_ELEM_SZ; i < BNX2X_MCAST_VEC_SZ; i++) { 27828c2ecf20Sopenharmony_ci if (o->registry.aprox_match.vec[i]) 27838c2ecf20Sopenharmony_ci for (j = inner_start; j < BIT_VEC64_ELEM_SZ; j++) { 27848c2ecf20Sopenharmony_ci int cur_bit = j + BIT_VEC64_ELEM_SZ * i; 27858c2ecf20Sopenharmony_ci if (BIT_VEC64_TEST_BIT(o->registry.aprox_match. 27868c2ecf20Sopenharmony_ci vec, cur_bit)) { 27878c2ecf20Sopenharmony_ci return cur_bit; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci inner_start = 0; 27918c2ecf20Sopenharmony_ci } 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci /* None found */ 27948c2ecf20Sopenharmony_ci return -1; 27958c2ecf20Sopenharmony_ci} 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci/** 27988c2ecf20Sopenharmony_ci * bnx2x_mcast_clear_first_bin - find the first set bin and clear it 27998c2ecf20Sopenharmony_ci * 28008c2ecf20Sopenharmony_ci * @o: 28018c2ecf20Sopenharmony_ci * 28028c2ecf20Sopenharmony_ci * returns the index of the found bin or -1 if none is found 28038c2ecf20Sopenharmony_ci */ 28048c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_clear_first_bin(struct bnx2x_mcast_obj *o) 28058c2ecf20Sopenharmony_ci{ 28068c2ecf20Sopenharmony_ci int cur_bit = bnx2x_mcast_get_next_bin(o, 0); 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci if (cur_bit >= 0) 28098c2ecf20Sopenharmony_ci BIT_VEC64_CLEAR_BIT(o->registry.aprox_match.vec, cur_bit); 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci return cur_bit; 28128c2ecf20Sopenharmony_ci} 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_cistatic inline u8 bnx2x_mcast_get_rx_tx_flag(struct bnx2x_mcast_obj *o) 28158c2ecf20Sopenharmony_ci{ 28168c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 28178c2ecf20Sopenharmony_ci u8 rx_tx_flag = 0; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci if ((raw->obj_type == BNX2X_OBJ_TYPE_TX) || 28208c2ecf20Sopenharmony_ci (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) 28218c2ecf20Sopenharmony_ci rx_tx_flag |= ETH_MULTICAST_RULES_CMD_TX_CMD; 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci if ((raw->obj_type == BNX2X_OBJ_TYPE_RX) || 28248c2ecf20Sopenharmony_ci (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) 28258c2ecf20Sopenharmony_ci rx_tx_flag |= ETH_MULTICAST_RULES_CMD_RX_CMD; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci return rx_tx_flag; 28288c2ecf20Sopenharmony_ci} 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_cistatic void bnx2x_mcast_set_one_rule_e2(struct bnx2x *bp, 28318c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, int idx, 28328c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data *cfg_data, 28338c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 28348c2ecf20Sopenharmony_ci{ 28358c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 28368c2ecf20Sopenharmony_ci struct eth_multicast_rules_ramrod_data *data = 28378c2ecf20Sopenharmony_ci (struct eth_multicast_rules_ramrod_data *)(r->rdata); 28388c2ecf20Sopenharmony_ci u8 func_id = r->func_id; 28398c2ecf20Sopenharmony_ci u8 rx_tx_add_flag = bnx2x_mcast_get_rx_tx_flag(o); 28408c2ecf20Sopenharmony_ci int bin; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci if ((cmd == BNX2X_MCAST_CMD_ADD) || (cmd == BNX2X_MCAST_CMD_RESTORE) || 28438c2ecf20Sopenharmony_ci (cmd == BNX2X_MCAST_CMD_SET_ADD)) 28448c2ecf20Sopenharmony_ci rx_tx_add_flag |= ETH_MULTICAST_RULES_CMD_IS_ADD; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci data->rules[idx].cmd_general_data |= rx_tx_add_flag; 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci /* Get a bin and update a bins' vector */ 28498c2ecf20Sopenharmony_ci switch (cmd) { 28508c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 28518c2ecf20Sopenharmony_ci bin = bnx2x_mcast_bin_from_mac(cfg_data->mac); 28528c2ecf20Sopenharmony_ci BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, bin); 28538c2ecf20Sopenharmony_ci break; 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 28568c2ecf20Sopenharmony_ci /* If there were no more bins to clear 28578c2ecf20Sopenharmony_ci * (bnx2x_mcast_clear_first_bin() returns -1) then we would 28588c2ecf20Sopenharmony_ci * clear any (0xff) bin. 28598c2ecf20Sopenharmony_ci * See bnx2x_mcast_validate_e2() for explanation when it may 28608c2ecf20Sopenharmony_ci * happen. 28618c2ecf20Sopenharmony_ci */ 28628c2ecf20Sopenharmony_ci bin = bnx2x_mcast_clear_first_bin(o); 28638c2ecf20Sopenharmony_ci break; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 28668c2ecf20Sopenharmony_ci bin = cfg_data->bin; 28678c2ecf20Sopenharmony_ci break; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_SET_ADD: 28708c2ecf20Sopenharmony_ci bin = cfg_data->bin; 28718c2ecf20Sopenharmony_ci BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, bin); 28728c2ecf20Sopenharmony_ci break; 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_SET_DEL: 28758c2ecf20Sopenharmony_ci bin = cfg_data->bin; 28768c2ecf20Sopenharmony_ci BIT_VEC64_CLEAR_BIT(o->registry.aprox_match.vec, bin); 28778c2ecf20Sopenharmony_ci break; 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci default: 28808c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd); 28818c2ecf20Sopenharmony_ci return; 28828c2ecf20Sopenharmony_ci } 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "%s bin %d\n", 28858c2ecf20Sopenharmony_ci ((rx_tx_add_flag & ETH_MULTICAST_RULES_CMD_IS_ADD) ? 28868c2ecf20Sopenharmony_ci "Setting" : "Clearing"), bin); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci data->rules[idx].bin_id = (u8)bin; 28898c2ecf20Sopenharmony_ci data->rules[idx].func_id = func_id; 28908c2ecf20Sopenharmony_ci data->rules[idx].engine_id = o->engine_id; 28918c2ecf20Sopenharmony_ci} 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci/** 28948c2ecf20Sopenharmony_ci * bnx2x_mcast_handle_restore_cmd_e2 - restore configuration from the registry 28958c2ecf20Sopenharmony_ci * 28968c2ecf20Sopenharmony_ci * @bp: device handle 28978c2ecf20Sopenharmony_ci * @o: multicast object info 28988c2ecf20Sopenharmony_ci * @start_bin: index in the registry to start from (including) 28998c2ecf20Sopenharmony_ci * @rdata_idx: index in the ramrod data to start from 29008c2ecf20Sopenharmony_ci * 29018c2ecf20Sopenharmony_ci * returns last handled bin index or -1 if all bins have been handled 29028c2ecf20Sopenharmony_ci */ 29038c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_handle_restore_cmd_e2( 29048c2ecf20Sopenharmony_ci struct bnx2x *bp, struct bnx2x_mcast_obj *o , int start_bin, 29058c2ecf20Sopenharmony_ci int *rdata_idx) 29068c2ecf20Sopenharmony_ci{ 29078c2ecf20Sopenharmony_ci int cur_bin, cnt = *rdata_idx; 29088c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data cfg_data = {NULL}; 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci /* go through the registry and configure the bins from it */ 29118c2ecf20Sopenharmony_ci for (cur_bin = bnx2x_mcast_get_next_bin(o, start_bin); cur_bin >= 0; 29128c2ecf20Sopenharmony_ci cur_bin = bnx2x_mcast_get_next_bin(o, cur_bin + 1)) { 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci cfg_data.bin = (u8)cur_bin; 29158c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, cnt, &cfg_data, 29168c2ecf20Sopenharmony_ci BNX2X_MCAST_CMD_RESTORE); 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci cnt++; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure a bin %d\n", cur_bin); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci /* Break if we reached the maximum number 29238c2ecf20Sopenharmony_ci * of rules. 29248c2ecf20Sopenharmony_ci */ 29258c2ecf20Sopenharmony_ci if (cnt >= o->max_cmd_len) 29268c2ecf20Sopenharmony_ci break; 29278c2ecf20Sopenharmony_ci } 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci *rdata_idx = cnt; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci return cur_bin; 29328c2ecf20Sopenharmony_ci} 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_pending_add_e2(struct bnx2x *bp, 29358c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos, 29368c2ecf20Sopenharmony_ci int *line_idx) 29378c2ecf20Sopenharmony_ci{ 29388c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n; 29398c2ecf20Sopenharmony_ci int cnt = *line_idx; 29408c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data cfg_data = {NULL}; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head, 29438c2ecf20Sopenharmony_ci link) { 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci cfg_data.mac = &pmac_pos->mac[0]; 29468c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, cnt, &cfg_data, cmd_pos->type); 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci cnt++; 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n", 29518c2ecf20Sopenharmony_ci pmac_pos->mac); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci list_del(&pmac_pos->link); 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci /* Break if we reached the maximum number 29568c2ecf20Sopenharmony_ci * of rules. 29578c2ecf20Sopenharmony_ci */ 29588c2ecf20Sopenharmony_ci if (cnt >= o->max_cmd_len) 29598c2ecf20Sopenharmony_ci break; 29608c2ecf20Sopenharmony_ci } 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci *line_idx = cnt; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci /* if no more MACs to configure - we are done */ 29658c2ecf20Sopenharmony_ci if (list_empty(&cmd_pos->data.macs_head)) 29668c2ecf20Sopenharmony_ci cmd_pos->done = true; 29678c2ecf20Sopenharmony_ci} 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_pending_del_e2(struct bnx2x *bp, 29708c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos, 29718c2ecf20Sopenharmony_ci int *line_idx) 29728c2ecf20Sopenharmony_ci{ 29738c2ecf20Sopenharmony_ci int cnt = *line_idx; 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci while (cmd_pos->data.macs_num) { 29768c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, cnt, NULL, cmd_pos->type); 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci cnt++; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci cmd_pos->data.macs_num--; 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Deleting MAC. %d left,cnt is %d\n", 29838c2ecf20Sopenharmony_ci cmd_pos->data.macs_num, cnt); 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci /* Break if we reached the maximum 29868c2ecf20Sopenharmony_ci * number of rules. 29878c2ecf20Sopenharmony_ci */ 29888c2ecf20Sopenharmony_ci if (cnt >= o->max_cmd_len) 29898c2ecf20Sopenharmony_ci break; 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci *line_idx = cnt; 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci /* If we cleared all bins - we are done */ 29958c2ecf20Sopenharmony_ci if (!cmd_pos->data.macs_num) 29968c2ecf20Sopenharmony_ci cmd_pos->done = true; 29978c2ecf20Sopenharmony_ci} 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_pending_restore_e2(struct bnx2x *bp, 30008c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos, 30018c2ecf20Sopenharmony_ci int *line_idx) 30028c2ecf20Sopenharmony_ci{ 30038c2ecf20Sopenharmony_ci cmd_pos->data.next_bin = o->hdl_restore(bp, o, cmd_pos->data.next_bin, 30048c2ecf20Sopenharmony_ci line_idx); 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci if (cmd_pos->data.next_bin < 0) 30078c2ecf20Sopenharmony_ci /* If o->set_restore returned -1 we are done */ 30088c2ecf20Sopenharmony_ci cmd_pos->done = true; 30098c2ecf20Sopenharmony_ci else 30108c2ecf20Sopenharmony_ci /* Start from the next bin next time */ 30118c2ecf20Sopenharmony_ci cmd_pos->data.next_bin++; 30128c2ecf20Sopenharmony_ci} 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_cistatic void 30158c2ecf20Sopenharmony_cibnx2x_mcast_hdl_pending_set_e2_convert(struct bnx2x *bp, 30168c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, 30178c2ecf20Sopenharmony_ci struct bnx2x_pending_mcast_cmd *cmd_pos) 30188c2ecf20Sopenharmony_ci{ 30198c2ecf20Sopenharmony_ci u64 cur[BNX2X_MCAST_VEC_SZ], req[BNX2X_MCAST_VEC_SZ]; 30208c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n; 30218c2ecf20Sopenharmony_ci struct bnx2x_mcast_bin_elem *p_item; 30228c2ecf20Sopenharmony_ci struct bnx2x_mcast_elem_group *elem_group; 30238c2ecf20Sopenharmony_ci int cnt = 0, mac_cnt = 0, offset = 0, i; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci memset(req, 0, sizeof(u64) * BNX2X_MCAST_VEC_SZ); 30268c2ecf20Sopenharmony_ci memcpy(cur, o->registry.aprox_match.vec, 30278c2ecf20Sopenharmony_ci sizeof(u64) * BNX2X_MCAST_VEC_SZ); 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci /* Fill `current' with the required set of bins to configure */ 30308c2ecf20Sopenharmony_ci list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head, 30318c2ecf20Sopenharmony_ci link) { 30328c2ecf20Sopenharmony_ci int bin = bnx2x_mcast_bin_from_mac(pmac_pos->mac); 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Set contains %pM mcast MAC\n", 30358c2ecf20Sopenharmony_ci pmac_pos->mac); 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci BIT_VEC64_SET_BIT(req, bin); 30388c2ecf20Sopenharmony_ci list_del(&pmac_pos->link); 30398c2ecf20Sopenharmony_ci mac_cnt++; 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci /* We no longer have use for the MACs; Need to re-use memory for 30438c2ecf20Sopenharmony_ci * a list that will be used to configure bins. 30448c2ecf20Sopenharmony_ci */ 30458c2ecf20Sopenharmony_ci cmd_pos->set_convert = true; 30468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cmd_pos->data.macs_head); 30478c2ecf20Sopenharmony_ci elem_group = list_first_entry(&cmd_pos->group_head, 30488c2ecf20Sopenharmony_ci struct bnx2x_mcast_elem_group, 30498c2ecf20Sopenharmony_ci mcast_group_link); 30508c2ecf20Sopenharmony_ci for (i = 0; i < BNX2X_MCAST_BINS_NUM; i++) { 30518c2ecf20Sopenharmony_ci bool b_current = !!BIT_VEC64_TEST_BIT(cur, i); 30528c2ecf20Sopenharmony_ci bool b_required = !!BIT_VEC64_TEST_BIT(req, i); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci if (b_current == b_required) 30558c2ecf20Sopenharmony_ci continue; 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci p_item = &elem_group->mcast_elems[offset].bin_elem; 30588c2ecf20Sopenharmony_ci p_item->bin = i; 30598c2ecf20Sopenharmony_ci p_item->type = b_required ? BNX2X_MCAST_CMD_SET_ADD 30608c2ecf20Sopenharmony_ci : BNX2X_MCAST_CMD_SET_DEL; 30618c2ecf20Sopenharmony_ci list_add_tail(&p_item->link , &cmd_pos->data.macs_head); 30628c2ecf20Sopenharmony_ci cnt++; 30638c2ecf20Sopenharmony_ci offset++; 30648c2ecf20Sopenharmony_ci if (offset == MCAST_MAC_ELEMS_PER_PG) { 30658c2ecf20Sopenharmony_ci offset = 0; 30668c2ecf20Sopenharmony_ci elem_group = list_next_entry(elem_group, 30678c2ecf20Sopenharmony_ci mcast_group_link); 30688c2ecf20Sopenharmony_ci } 30698c2ecf20Sopenharmony_ci } 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci /* We now definitely know how many commands are hiding here. 30728c2ecf20Sopenharmony_ci * Also need to correct the disruption we've added to guarantee this 30738c2ecf20Sopenharmony_ci * would be enqueued. 30748c2ecf20Sopenharmony_ci */ 30758c2ecf20Sopenharmony_ci o->total_pending_num -= (o->max_cmd_len + mac_cnt); 30768c2ecf20Sopenharmony_ci o->total_pending_num += cnt; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "o->total_pending_num=%d\n", o->total_pending_num); 30798c2ecf20Sopenharmony_ci} 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_cistatic void 30828c2ecf20Sopenharmony_cibnx2x_mcast_hdl_pending_set_e2(struct bnx2x *bp, 30838c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, 30848c2ecf20Sopenharmony_ci struct bnx2x_pending_mcast_cmd *cmd_pos, 30858c2ecf20Sopenharmony_ci int *cnt) 30868c2ecf20Sopenharmony_ci{ 30878c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data cfg_data = {NULL}; 30888c2ecf20Sopenharmony_ci struct bnx2x_mcast_bin_elem *p_item, *p_item_n; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci /* This is actually a 2-part scheme - it starts by converting the MACs 30918c2ecf20Sopenharmony_ci * into a list of bins to be added/removed, and correcting the numbers 30928c2ecf20Sopenharmony_ci * on the object. this is now allowed, as we're now sure that all 30938c2ecf20Sopenharmony_ci * previous configured requests have already applied. 30948c2ecf20Sopenharmony_ci * The second part is actually adding rules for the newly introduced 30958c2ecf20Sopenharmony_ci * entries [like all the rest of the hdl_pending functions]. 30968c2ecf20Sopenharmony_ci */ 30978c2ecf20Sopenharmony_ci if (!cmd_pos->set_convert) 30988c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_pending_set_e2_convert(bp, o, cmd_pos); 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci list_for_each_entry_safe(p_item, p_item_n, &cmd_pos->data.macs_head, 31018c2ecf20Sopenharmony_ci link) { 31028c2ecf20Sopenharmony_ci cfg_data.bin = (u8)p_item->bin; 31038c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, *cnt, &cfg_data, p_item->type); 31048c2ecf20Sopenharmony_ci (*cnt)++; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci list_del(&p_item->link); 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci /* Break if we reached the maximum number of rules. */ 31098c2ecf20Sopenharmony_ci if (*cnt >= o->max_cmd_len) 31108c2ecf20Sopenharmony_ci break; 31118c2ecf20Sopenharmony_ci } 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci /* if no more MACs to configure - we are done */ 31148c2ecf20Sopenharmony_ci if (list_empty(&cmd_pos->data.macs_head)) 31158c2ecf20Sopenharmony_ci cmd_pos->done = true; 31168c2ecf20Sopenharmony_ci} 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_handle_pending_cmds_e2(struct bnx2x *bp, 31198c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p) 31208c2ecf20Sopenharmony_ci{ 31218c2ecf20Sopenharmony_ci struct bnx2x_pending_mcast_cmd *cmd_pos, *cmd_pos_n; 31228c2ecf20Sopenharmony_ci int cnt = 0; 31238c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd_pos, cmd_pos_n, &o->pending_cmds_head, 31268c2ecf20Sopenharmony_ci link) { 31278c2ecf20Sopenharmony_ci switch (cmd_pos->type) { 31288c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 31298c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_pending_add_e2(bp, o, cmd_pos, &cnt); 31308c2ecf20Sopenharmony_ci break; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 31338c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_pending_del_e2(bp, o, cmd_pos, &cnt); 31348c2ecf20Sopenharmony_ci break; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 31378c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_pending_restore_e2(bp, o, cmd_pos, 31388c2ecf20Sopenharmony_ci &cnt); 31398c2ecf20Sopenharmony_ci break; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_SET: 31428c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_pending_set_e2(bp, o, cmd_pos, &cnt); 31438c2ecf20Sopenharmony_ci break; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci default: 31468c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd_pos->type); 31478c2ecf20Sopenharmony_ci return -EINVAL; 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci /* If the command has been completed - remove it from the list 31518c2ecf20Sopenharmony_ci * and free the memory 31528c2ecf20Sopenharmony_ci */ 31538c2ecf20Sopenharmony_ci if (cmd_pos->done) { 31548c2ecf20Sopenharmony_ci list_del(&cmd_pos->link); 31558c2ecf20Sopenharmony_ci bnx2x_free_groups(&cmd_pos->group_head); 31568c2ecf20Sopenharmony_ci kfree(cmd_pos); 31578c2ecf20Sopenharmony_ci } 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci /* Break if we reached the maximum number of rules */ 31608c2ecf20Sopenharmony_ci if (cnt >= o->max_cmd_len) 31618c2ecf20Sopenharmony_ci break; 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci return cnt; 31658c2ecf20Sopenharmony_ci} 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_add(struct bnx2x *bp, 31688c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p, 31698c2ecf20Sopenharmony_ci int *line_idx) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci struct bnx2x_mcast_list_elem *mlist_pos; 31728c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data cfg_data = {NULL}; 31738c2ecf20Sopenharmony_ci int cnt = *line_idx; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci list_for_each_entry(mlist_pos, &p->mcast_list, link) { 31768c2ecf20Sopenharmony_ci cfg_data.mac = mlist_pos->mac; 31778c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, cnt, &cfg_data, BNX2X_MCAST_CMD_ADD); 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci cnt++; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n", 31828c2ecf20Sopenharmony_ci mlist_pos->mac); 31838c2ecf20Sopenharmony_ci } 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci *line_idx = cnt; 31868c2ecf20Sopenharmony_ci} 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_del(struct bnx2x *bp, 31898c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p, 31908c2ecf20Sopenharmony_ci int *line_idx) 31918c2ecf20Sopenharmony_ci{ 31928c2ecf20Sopenharmony_ci int cnt = *line_idx, i; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci for (i = 0; i < p->mcast_list_len; i++) { 31958c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, cnt, NULL, BNX2X_MCAST_CMD_DEL); 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci cnt++; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Deleting MAC. %d left\n", 32008c2ecf20Sopenharmony_ci p->mcast_list_len - i - 1); 32018c2ecf20Sopenharmony_ci } 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci *line_idx = cnt; 32048c2ecf20Sopenharmony_ci} 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci/** 32078c2ecf20Sopenharmony_ci * bnx2x_mcast_handle_current_cmd - send command if room 32088c2ecf20Sopenharmony_ci * 32098c2ecf20Sopenharmony_ci * @bp: device handle 32108c2ecf20Sopenharmony_ci * @p: ramrod mcast info 32118c2ecf20Sopenharmony_ci * @cmd: command 32128c2ecf20Sopenharmony_ci * @start_cnt: first line in the ramrod data that may be used 32138c2ecf20Sopenharmony_ci * 32148c2ecf20Sopenharmony_ci * This function is called iff there is enough place for the current command in 32158c2ecf20Sopenharmony_ci * the ramrod data. 32168c2ecf20Sopenharmony_ci * Returns number of lines filled in the ramrod data in total. 32178c2ecf20Sopenharmony_ci */ 32188c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp, 32198c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 32208c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd, 32218c2ecf20Sopenharmony_ci int start_cnt) 32228c2ecf20Sopenharmony_ci{ 32238c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 32248c2ecf20Sopenharmony_ci int cnt = start_cnt; 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "p->mcast_list_len=%d\n", p->mcast_list_len); 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci switch (cmd) { 32298c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 32308c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_add(bp, o, p, &cnt); 32318c2ecf20Sopenharmony_ci break; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 32348c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_del(bp, o, p, &cnt); 32358c2ecf20Sopenharmony_ci break; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 32388c2ecf20Sopenharmony_ci o->hdl_restore(bp, o, 0, &cnt); 32398c2ecf20Sopenharmony_ci break; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci default: 32428c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd); 32438c2ecf20Sopenharmony_ci return -EINVAL; 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci /* The current command has been handled */ 32478c2ecf20Sopenharmony_ci p->mcast_list_len = 0; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci return cnt; 32508c2ecf20Sopenharmony_ci} 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_cistatic int bnx2x_mcast_validate_e2(struct bnx2x *bp, 32538c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 32548c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 32558c2ecf20Sopenharmony_ci{ 32568c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 32578c2ecf20Sopenharmony_ci int reg_sz = o->get_registry_size(o); 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci switch (cmd) { 32608c2ecf20Sopenharmony_ci /* DEL command deletes all currently configured MACs */ 32618c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 32628c2ecf20Sopenharmony_ci o->set_registry_size(o, 0); 32638c2ecf20Sopenharmony_ci fallthrough; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci /* RESTORE command will restore the entire multicast configuration */ 32668c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 32678c2ecf20Sopenharmony_ci /* Here we set the approximate amount of work to do, which in 32688c2ecf20Sopenharmony_ci * fact may be only less as some MACs in postponed ADD 32698c2ecf20Sopenharmony_ci * command(s) scheduled before this command may fall into 32708c2ecf20Sopenharmony_ci * the same bin and the actual number of bins set in the 32718c2ecf20Sopenharmony_ci * registry would be less than we estimated here. See 32728c2ecf20Sopenharmony_ci * bnx2x_mcast_set_one_rule_e2() for further details. 32738c2ecf20Sopenharmony_ci */ 32748c2ecf20Sopenharmony_ci p->mcast_list_len = reg_sz; 32758c2ecf20Sopenharmony_ci break; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 32788c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_CONT: 32798c2ecf20Sopenharmony_ci /* Here we assume that all new MACs will fall into new bins. 32808c2ecf20Sopenharmony_ci * However we will correct the real registry size after we 32818c2ecf20Sopenharmony_ci * handle all pending commands. 32828c2ecf20Sopenharmony_ci */ 32838c2ecf20Sopenharmony_ci o->set_registry_size(o, reg_sz + p->mcast_list_len); 32848c2ecf20Sopenharmony_ci break; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_SET: 32878c2ecf20Sopenharmony_ci /* We can only learn how many commands would actually be used 32888c2ecf20Sopenharmony_ci * when this is being configured. So for now, simply guarantee 32898c2ecf20Sopenharmony_ci * the command will be enqueued [to refrain from adding logic 32908c2ecf20Sopenharmony_ci * that handles this and THEN learns it needs several ramrods]. 32918c2ecf20Sopenharmony_ci * Just like for ADD/Cont, the mcast_list_len might be an over 32928c2ecf20Sopenharmony_ci * estimation; or even more so, since we don't take into 32938c2ecf20Sopenharmony_ci * account the possibility of removal of existing bins. 32948c2ecf20Sopenharmony_ci */ 32958c2ecf20Sopenharmony_ci o->set_registry_size(o, reg_sz + p->mcast_list_len); 32968c2ecf20Sopenharmony_ci o->total_pending_num += o->max_cmd_len; 32978c2ecf20Sopenharmony_ci break; 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci default: 33008c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd); 33018c2ecf20Sopenharmony_ci return -EINVAL; 33028c2ecf20Sopenharmony_ci } 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci /* Increase the total number of MACs pending to be configured */ 33058c2ecf20Sopenharmony_ci o->total_pending_num += p->mcast_list_len; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci return 0; 33088c2ecf20Sopenharmony_ci} 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_cistatic void bnx2x_mcast_revert_e2(struct bnx2x *bp, 33118c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 33128c2ecf20Sopenharmony_ci int old_num_bins, 33138c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 33148c2ecf20Sopenharmony_ci{ 33158c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci o->set_registry_size(o, old_num_bins); 33188c2ecf20Sopenharmony_ci o->total_pending_num -= p->mcast_list_len; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if (cmd == BNX2X_MCAST_CMD_SET) 33218c2ecf20Sopenharmony_ci o->total_pending_num -= o->max_cmd_len; 33228c2ecf20Sopenharmony_ci} 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci/** 33258c2ecf20Sopenharmony_ci * bnx2x_mcast_set_rdata_hdr_e2 - sets a header values 33268c2ecf20Sopenharmony_ci * 33278c2ecf20Sopenharmony_ci * @bp: device handle 33288c2ecf20Sopenharmony_ci * @p: ramrod parameters 33298c2ecf20Sopenharmony_ci * @len: number of rules to handle 33308c2ecf20Sopenharmony_ci */ 33318c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_set_rdata_hdr_e2(struct bnx2x *bp, 33328c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 33338c2ecf20Sopenharmony_ci u8 len) 33348c2ecf20Sopenharmony_ci{ 33358c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &p->mcast_obj->raw; 33368c2ecf20Sopenharmony_ci struct eth_multicast_rules_ramrod_data *data = 33378c2ecf20Sopenharmony_ci (struct eth_multicast_rules_ramrod_data *)(r->rdata); 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci data->header.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) | 33408c2ecf20Sopenharmony_ci (BNX2X_FILTER_MCAST_PENDING << 33418c2ecf20Sopenharmony_ci BNX2X_SWCID_SHIFT)); 33428c2ecf20Sopenharmony_ci data->header.rule_cnt = len; 33438c2ecf20Sopenharmony_ci} 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci/** 33468c2ecf20Sopenharmony_ci * bnx2x_mcast_refresh_registry_e2 - recalculate the actual number of set bins 33478c2ecf20Sopenharmony_ci * 33488c2ecf20Sopenharmony_ci * @bp: device handle 33498c2ecf20Sopenharmony_ci * @o: 33508c2ecf20Sopenharmony_ci * 33518c2ecf20Sopenharmony_ci * Recalculate the actual number of set bins in the registry using Brian 33528c2ecf20Sopenharmony_ci * Kernighan's algorithm: it's execution complexity is as a number of set bins. 33538c2ecf20Sopenharmony_ci * 33548c2ecf20Sopenharmony_ci * returns 0 for the compliance with bnx2x_mcast_refresh_registry_e1(). 33558c2ecf20Sopenharmony_ci */ 33568c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_refresh_registry_e2(struct bnx2x *bp, 33578c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o) 33588c2ecf20Sopenharmony_ci{ 33598c2ecf20Sopenharmony_ci int i, cnt = 0; 33608c2ecf20Sopenharmony_ci u64 elem; 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_ci for (i = 0; i < BNX2X_MCAST_VEC_SZ; i++) { 33638c2ecf20Sopenharmony_ci elem = o->registry.aprox_match.vec[i]; 33648c2ecf20Sopenharmony_ci for (; elem; cnt++) 33658c2ecf20Sopenharmony_ci elem &= elem - 1; 33668c2ecf20Sopenharmony_ci } 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci o->set_registry_size(o, cnt); 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci return 0; 33718c2ecf20Sopenharmony_ci} 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_cistatic int bnx2x_mcast_setup_e2(struct bnx2x *bp, 33748c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 33758c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 33768c2ecf20Sopenharmony_ci{ 33778c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &p->mcast_obj->raw; 33788c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 33798c2ecf20Sopenharmony_ci struct eth_multicast_rules_ramrod_data *data = 33808c2ecf20Sopenharmony_ci (struct eth_multicast_rules_ramrod_data *)(raw->rdata); 33818c2ecf20Sopenharmony_ci int cnt = 0, rc; 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer */ 33848c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci cnt = bnx2x_mcast_handle_pending_cmds_e2(bp, p); 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci /* If there are no more pending commands - clear SCHEDULED state */ 33898c2ecf20Sopenharmony_ci if (list_empty(&o->pending_cmds_head)) 33908c2ecf20Sopenharmony_ci o->clear_sched(o); 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci /* The below may be true iff there was enough room in ramrod 33938c2ecf20Sopenharmony_ci * data for all pending commands and for the current 33948c2ecf20Sopenharmony_ci * command. Otherwise the current command would have been added 33958c2ecf20Sopenharmony_ci * to the pending commands and p->mcast_list_len would have been 33968c2ecf20Sopenharmony_ci * zeroed. 33978c2ecf20Sopenharmony_ci */ 33988c2ecf20Sopenharmony_ci if (p->mcast_list_len > 0) 33998c2ecf20Sopenharmony_ci cnt = bnx2x_mcast_handle_current_cmd(bp, p, cmd, cnt); 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci /* We've pulled out some MACs - update the total number of 34028c2ecf20Sopenharmony_ci * outstanding. 34038c2ecf20Sopenharmony_ci */ 34048c2ecf20Sopenharmony_ci o->total_pending_num -= cnt; 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci /* send a ramrod */ 34078c2ecf20Sopenharmony_ci WARN_ON(o->total_pending_num < 0); 34088c2ecf20Sopenharmony_ci WARN_ON(cnt > o->max_cmd_len); 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci bnx2x_mcast_set_rdata_hdr_e2(bp, p, (u8)cnt); 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci /* Update a registry size if there are no more pending operations. 34138c2ecf20Sopenharmony_ci * 34148c2ecf20Sopenharmony_ci * We don't want to change the value of the registry size if there are 34158c2ecf20Sopenharmony_ci * pending operations because we want it to always be equal to the 34168c2ecf20Sopenharmony_ci * exact or the approximate number (see bnx2x_mcast_validate_e2()) of 34178c2ecf20Sopenharmony_ci * set bins after the last requested operation in order to properly 34188c2ecf20Sopenharmony_ci * evaluate the size of the next DEL/RESTORE operation. 34198c2ecf20Sopenharmony_ci * 34208c2ecf20Sopenharmony_ci * Note that we update the registry itself during command(s) handling 34218c2ecf20Sopenharmony_ci * - see bnx2x_mcast_set_one_rule_e2(). That's because for 57712 we 34228c2ecf20Sopenharmony_ci * aggregate multiple commands (ADD/DEL/RESTORE) into one ramrod but 34238c2ecf20Sopenharmony_ci * with a limited amount of update commands (per MAC/bin) and we don't 34248c2ecf20Sopenharmony_ci * know in this scope what the actual state of bins configuration is 34258c2ecf20Sopenharmony_ci * going to be after this ramrod. 34268c2ecf20Sopenharmony_ci */ 34278c2ecf20Sopenharmony_ci if (!o->total_pending_num) 34288c2ecf20Sopenharmony_ci bnx2x_mcast_refresh_registry_e2(bp, o); 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci /* If CLEAR_ONLY was requested - don't send a ramrod and clear 34318c2ecf20Sopenharmony_ci * RAMROD_PENDING status immediately. due to the SET option, it's also 34328c2ecf20Sopenharmony_ci * possible that after evaluating the differences there's no need for 34338c2ecf20Sopenharmony_ci * a ramrod. In that case, we can skip it as well. 34348c2ecf20Sopenharmony_ci */ 34358c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags) || !cnt) { 34368c2ecf20Sopenharmony_ci raw->clear_pending(raw); 34378c2ecf20Sopenharmony_ci return 0; 34388c2ecf20Sopenharmony_ci } else { 34398c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 34408c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 34418c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 34428c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 34438c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 34448c2ecf20Sopenharmony_ci */ 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci /* Send a ramrod */ 34478c2ecf20Sopenharmony_ci rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_MULTICAST_RULES, 34488c2ecf20Sopenharmony_ci raw->cid, U64_HI(raw->rdata_mapping), 34498c2ecf20Sopenharmony_ci U64_LO(raw->rdata_mapping), 34508c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 34518c2ecf20Sopenharmony_ci if (rc) 34528c2ecf20Sopenharmony_ci return rc; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci /* Ramrod completion is pending */ 34558c2ecf20Sopenharmony_ci return 1; 34568c2ecf20Sopenharmony_ci } 34578c2ecf20Sopenharmony_ci} 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_cistatic int bnx2x_mcast_validate_e1h(struct bnx2x *bp, 34608c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 34618c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 34628c2ecf20Sopenharmony_ci{ 34638c2ecf20Sopenharmony_ci if (cmd == BNX2X_MCAST_CMD_SET) { 34648c2ecf20Sopenharmony_ci BNX2X_ERR("Can't use `set' command on e1h!\n"); 34658c2ecf20Sopenharmony_ci return -EINVAL; 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci /* Mark, that there is a work to do */ 34698c2ecf20Sopenharmony_ci if ((cmd == BNX2X_MCAST_CMD_DEL) || (cmd == BNX2X_MCAST_CMD_RESTORE)) 34708c2ecf20Sopenharmony_ci p->mcast_list_len = 1; 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci return 0; 34738c2ecf20Sopenharmony_ci} 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_cistatic void bnx2x_mcast_revert_e1h(struct bnx2x *bp, 34768c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 34778c2ecf20Sopenharmony_ci int old_num_bins, 34788c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 34798c2ecf20Sopenharmony_ci{ 34808c2ecf20Sopenharmony_ci /* Do nothing */ 34818c2ecf20Sopenharmony_ci} 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci#define BNX2X_57711_SET_MC_FILTER(filter, bit) \ 34848c2ecf20Sopenharmony_cido { \ 34858c2ecf20Sopenharmony_ci (filter)[(bit) >> 5] |= (1 << ((bit) & 0x1f)); \ 34868c2ecf20Sopenharmony_ci} while (0) 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_add_e1h(struct bnx2x *bp, 34898c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, 34908c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 34918c2ecf20Sopenharmony_ci u32 *mc_filter) 34928c2ecf20Sopenharmony_ci{ 34938c2ecf20Sopenharmony_ci struct bnx2x_mcast_list_elem *mlist_pos; 34948c2ecf20Sopenharmony_ci int bit; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci list_for_each_entry(mlist_pos, &p->mcast_list, link) { 34978c2ecf20Sopenharmony_ci bit = bnx2x_mcast_bin_from_mac(mlist_pos->mac); 34988c2ecf20Sopenharmony_ci BNX2X_57711_SET_MC_FILTER(mc_filter, bit); 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC, bin %d\n", 35018c2ecf20Sopenharmony_ci mlist_pos->mac, bit); 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci /* bookkeeping... */ 35048c2ecf20Sopenharmony_ci BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, 35058c2ecf20Sopenharmony_ci bit); 35068c2ecf20Sopenharmony_ci } 35078c2ecf20Sopenharmony_ci} 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_hdl_restore_e1h(struct bnx2x *bp, 35108c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p, 35118c2ecf20Sopenharmony_ci u32 *mc_filter) 35128c2ecf20Sopenharmony_ci{ 35138c2ecf20Sopenharmony_ci int bit; 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci for (bit = bnx2x_mcast_get_next_bin(o, 0); 35168c2ecf20Sopenharmony_ci bit >= 0; 35178c2ecf20Sopenharmony_ci bit = bnx2x_mcast_get_next_bin(o, bit + 1)) { 35188c2ecf20Sopenharmony_ci BNX2X_57711_SET_MC_FILTER(mc_filter, bit); 35198c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to set bin %d\n", bit); 35208c2ecf20Sopenharmony_ci } 35218c2ecf20Sopenharmony_ci} 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci/* On 57711 we write the multicast MACs' approximate match 35248c2ecf20Sopenharmony_ci * table by directly into the TSTORM's internal RAM. So we don't 35258c2ecf20Sopenharmony_ci * really need to handle any tricks to make it work. 35268c2ecf20Sopenharmony_ci */ 35278c2ecf20Sopenharmony_cistatic int bnx2x_mcast_setup_e1h(struct bnx2x *bp, 35288c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 35298c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 35308c2ecf20Sopenharmony_ci{ 35318c2ecf20Sopenharmony_ci int i; 35328c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 35338c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci /* If CLEAR_ONLY has been requested - clear the registry 35368c2ecf20Sopenharmony_ci * and clear a pending bit. 35378c2ecf20Sopenharmony_ci */ 35388c2ecf20Sopenharmony_ci if (!test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) { 35398c2ecf20Sopenharmony_ci u32 mc_filter[MC_HASH_SIZE] = {0}; 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci /* Set the multicast filter bits before writing it into 35428c2ecf20Sopenharmony_ci * the internal memory. 35438c2ecf20Sopenharmony_ci */ 35448c2ecf20Sopenharmony_ci switch (cmd) { 35458c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 35468c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_add_e1h(bp, o, p, mc_filter); 35478c2ecf20Sopenharmony_ci break; 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 35508c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, 35518c2ecf20Sopenharmony_ci "Invalidating multicast MACs configuration\n"); 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_ci /* clear the registry */ 35548c2ecf20Sopenharmony_ci memset(o->registry.aprox_match.vec, 0, 35558c2ecf20Sopenharmony_ci sizeof(o->registry.aprox_match.vec)); 35568c2ecf20Sopenharmony_ci break; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 35598c2ecf20Sopenharmony_ci bnx2x_mcast_hdl_restore_e1h(bp, o, p, mc_filter); 35608c2ecf20Sopenharmony_ci break; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci default: 35638c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd); 35648c2ecf20Sopenharmony_ci return -EINVAL; 35658c2ecf20Sopenharmony_ci } 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_ci /* Set the mcast filter in the internal memory */ 35688c2ecf20Sopenharmony_ci for (i = 0; i < MC_HASH_SIZE; i++) 35698c2ecf20Sopenharmony_ci REG_WR(bp, MC_HASH_OFFSET(bp, i), mc_filter[i]); 35708c2ecf20Sopenharmony_ci } else 35718c2ecf20Sopenharmony_ci /* clear the registry */ 35728c2ecf20Sopenharmony_ci memset(o->registry.aprox_match.vec, 0, 35738c2ecf20Sopenharmony_ci sizeof(o->registry.aprox_match.vec)); 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_ci /* We are done */ 35768c2ecf20Sopenharmony_ci r->clear_pending(r); 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci return 0; 35798c2ecf20Sopenharmony_ci} 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_cistatic int bnx2x_mcast_validate_e1(struct bnx2x *bp, 35828c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 35838c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 35848c2ecf20Sopenharmony_ci{ 35858c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 35868c2ecf20Sopenharmony_ci int reg_sz = o->get_registry_size(o); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci if (cmd == BNX2X_MCAST_CMD_SET) { 35898c2ecf20Sopenharmony_ci BNX2X_ERR("Can't use `set' command on e1!\n"); 35908c2ecf20Sopenharmony_ci return -EINVAL; 35918c2ecf20Sopenharmony_ci } 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci switch (cmd) { 35948c2ecf20Sopenharmony_ci /* DEL command deletes all currently configured MACs */ 35958c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 35968c2ecf20Sopenharmony_ci o->set_registry_size(o, 0); 35978c2ecf20Sopenharmony_ci fallthrough; 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci /* RESTORE command will restore the entire multicast configuration */ 36008c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 36018c2ecf20Sopenharmony_ci p->mcast_list_len = reg_sz; 36028c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Command %d, p->mcast_list_len=%d\n", 36038c2ecf20Sopenharmony_ci cmd, p->mcast_list_len); 36048c2ecf20Sopenharmony_ci break; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 36078c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_CONT: 36088c2ecf20Sopenharmony_ci /* Multicast MACs on 57710 are configured as unicast MACs and 36098c2ecf20Sopenharmony_ci * there is only a limited number of CAM entries for that 36108c2ecf20Sopenharmony_ci * matter. 36118c2ecf20Sopenharmony_ci */ 36128c2ecf20Sopenharmony_ci if (p->mcast_list_len > o->max_cmd_len) { 36138c2ecf20Sopenharmony_ci BNX2X_ERR("Can't configure more than %d multicast MACs on 57710\n", 36148c2ecf20Sopenharmony_ci o->max_cmd_len); 36158c2ecf20Sopenharmony_ci return -EINVAL; 36168c2ecf20Sopenharmony_ci } 36178c2ecf20Sopenharmony_ci /* Every configured MAC should be cleared if DEL command is 36188c2ecf20Sopenharmony_ci * called. Only the last ADD command is relevant as long as 36198c2ecf20Sopenharmony_ci * every ADD commands overrides the previous configuration. 36208c2ecf20Sopenharmony_ci */ 36218c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "p->mcast_list_len=%d\n", p->mcast_list_len); 36228c2ecf20Sopenharmony_ci if (p->mcast_list_len > 0) 36238c2ecf20Sopenharmony_ci o->set_registry_size(o, p->mcast_list_len); 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci break; 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci default: 36288c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd); 36298c2ecf20Sopenharmony_ci return -EINVAL; 36308c2ecf20Sopenharmony_ci } 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci /* We want to ensure that commands are executed one by one for 57710. 36338c2ecf20Sopenharmony_ci * Therefore each none-empty command will consume o->max_cmd_len. 36348c2ecf20Sopenharmony_ci */ 36358c2ecf20Sopenharmony_ci if (p->mcast_list_len) 36368c2ecf20Sopenharmony_ci o->total_pending_num += o->max_cmd_len; 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci return 0; 36398c2ecf20Sopenharmony_ci} 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_cistatic void bnx2x_mcast_revert_e1(struct bnx2x *bp, 36428c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 36438c2ecf20Sopenharmony_ci int old_num_macs, 36448c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 36458c2ecf20Sopenharmony_ci{ 36468c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci o->set_registry_size(o, old_num_macs); 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci /* If current command hasn't been handled yet and we are 36518c2ecf20Sopenharmony_ci * here means that it's meant to be dropped and we have to 36528c2ecf20Sopenharmony_ci * update the number of outstanding MACs accordingly. 36538c2ecf20Sopenharmony_ci */ 36548c2ecf20Sopenharmony_ci if (p->mcast_list_len) 36558c2ecf20Sopenharmony_ci o->total_pending_num -= o->max_cmd_len; 36568c2ecf20Sopenharmony_ci} 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_cistatic void bnx2x_mcast_set_one_rule_e1(struct bnx2x *bp, 36598c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o, int idx, 36608c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data *cfg_data, 36618c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 36628c2ecf20Sopenharmony_ci{ 36638c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 36648c2ecf20Sopenharmony_ci struct mac_configuration_cmd *data = 36658c2ecf20Sopenharmony_ci (struct mac_configuration_cmd *)(r->rdata); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci /* copy mac */ 36688c2ecf20Sopenharmony_ci if ((cmd == BNX2X_MCAST_CMD_ADD) || (cmd == BNX2X_MCAST_CMD_RESTORE)) { 36698c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&data->config_table[idx].msb_mac_addr, 36708c2ecf20Sopenharmony_ci &data->config_table[idx].middle_mac_addr, 36718c2ecf20Sopenharmony_ci &data->config_table[idx].lsb_mac_addr, 36728c2ecf20Sopenharmony_ci cfg_data->mac); 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci data->config_table[idx].vlan_id = 0; 36758c2ecf20Sopenharmony_ci data->config_table[idx].pf_id = r->func_id; 36768c2ecf20Sopenharmony_ci data->config_table[idx].clients_bit_vector = 36778c2ecf20Sopenharmony_ci cpu_to_le32(1 << r->cl_id); 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci SET_FLAG(data->config_table[idx].flags, 36808c2ecf20Sopenharmony_ci MAC_CONFIGURATION_ENTRY_ACTION_TYPE, 36818c2ecf20Sopenharmony_ci T_ETH_MAC_COMMAND_SET); 36828c2ecf20Sopenharmony_ci } 36838c2ecf20Sopenharmony_ci} 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci/** 36868c2ecf20Sopenharmony_ci * bnx2x_mcast_set_rdata_hdr_e1 - set header values in mac_configuration_cmd 36878c2ecf20Sopenharmony_ci * 36888c2ecf20Sopenharmony_ci * @bp: device handle 36898c2ecf20Sopenharmony_ci * @p: ramrod parameters 36908c2ecf20Sopenharmony_ci * @len: number of rules to handle 36918c2ecf20Sopenharmony_ci */ 36928c2ecf20Sopenharmony_cistatic inline void bnx2x_mcast_set_rdata_hdr_e1(struct bnx2x *bp, 36938c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 36948c2ecf20Sopenharmony_ci u8 len) 36958c2ecf20Sopenharmony_ci{ 36968c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &p->mcast_obj->raw; 36978c2ecf20Sopenharmony_ci struct mac_configuration_cmd *data = 36988c2ecf20Sopenharmony_ci (struct mac_configuration_cmd *)(r->rdata); 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci u8 offset = (CHIP_REV_IS_SLOW(bp) ? 37018c2ecf20Sopenharmony_ci BNX2X_MAX_EMUL_MULTI*(1 + r->func_id) : 37028c2ecf20Sopenharmony_ci BNX2X_MAX_MULTICAST*(1 + r->func_id)); 37038c2ecf20Sopenharmony_ci 37048c2ecf20Sopenharmony_ci data->hdr.offset = offset; 37058c2ecf20Sopenharmony_ci data->hdr.client_id = cpu_to_le16(0xff); 37068c2ecf20Sopenharmony_ci data->hdr.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) | 37078c2ecf20Sopenharmony_ci (BNX2X_FILTER_MCAST_PENDING << 37088c2ecf20Sopenharmony_ci BNX2X_SWCID_SHIFT)); 37098c2ecf20Sopenharmony_ci data->hdr.length = len; 37108c2ecf20Sopenharmony_ci} 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci/** 37138c2ecf20Sopenharmony_ci * bnx2x_mcast_handle_restore_cmd_e1 - restore command for 57710 37148c2ecf20Sopenharmony_ci * 37158c2ecf20Sopenharmony_ci * @bp: device handle 37168c2ecf20Sopenharmony_ci * @o: multicast info 37178c2ecf20Sopenharmony_ci * @start_idx: index in the registry to start from 37188c2ecf20Sopenharmony_ci * @rdata_idx: index in the ramrod data to start from 37198c2ecf20Sopenharmony_ci * 37208c2ecf20Sopenharmony_ci * restore command for 57710 is like all other commands - always a stand alone 37218c2ecf20Sopenharmony_ci * command - start_idx and rdata_idx will always be 0. This function will always 37228c2ecf20Sopenharmony_ci * succeed. 37238c2ecf20Sopenharmony_ci * returns -1 to comply with 57712 variant. 37248c2ecf20Sopenharmony_ci */ 37258c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_handle_restore_cmd_e1( 37268c2ecf20Sopenharmony_ci struct bnx2x *bp, struct bnx2x_mcast_obj *o , int start_idx, 37278c2ecf20Sopenharmony_ci int *rdata_idx) 37288c2ecf20Sopenharmony_ci{ 37298c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem *elem; 37308c2ecf20Sopenharmony_ci int i = 0; 37318c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data cfg_data = {NULL}; 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci /* go through the registry and configure the MACs from it. */ 37348c2ecf20Sopenharmony_ci list_for_each_entry(elem, &o->registry.exact_match.macs, link) { 37358c2ecf20Sopenharmony_ci cfg_data.mac = &elem->mac[0]; 37368c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, i, &cfg_data, BNX2X_MCAST_CMD_RESTORE); 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci i++; 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n", 37418c2ecf20Sopenharmony_ci cfg_data.mac); 37428c2ecf20Sopenharmony_ci } 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci *rdata_idx = i; 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci return -1; 37478c2ecf20Sopenharmony_ci} 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_handle_pending_cmds_e1( 37508c2ecf20Sopenharmony_ci struct bnx2x *bp, struct bnx2x_mcast_ramrod_params *p) 37518c2ecf20Sopenharmony_ci{ 37528c2ecf20Sopenharmony_ci struct bnx2x_pending_mcast_cmd *cmd_pos; 37538c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem *pmac_pos; 37548c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 37558c2ecf20Sopenharmony_ci union bnx2x_mcast_config_data cfg_data = {NULL}; 37568c2ecf20Sopenharmony_ci int cnt = 0; 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci /* If nothing to be done - return */ 37598c2ecf20Sopenharmony_ci if (list_empty(&o->pending_cmds_head)) 37608c2ecf20Sopenharmony_ci return 0; 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_ci /* Handle the first command */ 37638c2ecf20Sopenharmony_ci cmd_pos = list_first_entry(&o->pending_cmds_head, 37648c2ecf20Sopenharmony_ci struct bnx2x_pending_mcast_cmd, link); 37658c2ecf20Sopenharmony_ci 37668c2ecf20Sopenharmony_ci switch (cmd_pos->type) { 37678c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_ADD: 37688c2ecf20Sopenharmony_ci list_for_each_entry(pmac_pos, &cmd_pos->data.macs_head, link) { 37698c2ecf20Sopenharmony_ci cfg_data.mac = &pmac_pos->mac[0]; 37708c2ecf20Sopenharmony_ci o->set_one_rule(bp, o, cnt, &cfg_data, cmd_pos->type); 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci cnt++; 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n", 37758c2ecf20Sopenharmony_ci pmac_pos->mac); 37768c2ecf20Sopenharmony_ci } 37778c2ecf20Sopenharmony_ci break; 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_DEL: 37808c2ecf20Sopenharmony_ci cnt = cmd_pos->data.macs_num; 37818c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "About to delete %d multicast MACs\n", cnt); 37828c2ecf20Sopenharmony_ci break; 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci case BNX2X_MCAST_CMD_RESTORE: 37858c2ecf20Sopenharmony_ci o->hdl_restore(bp, o, 0, &cnt); 37868c2ecf20Sopenharmony_ci break; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci default: 37898c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", cmd_pos->type); 37908c2ecf20Sopenharmony_ci return -EINVAL; 37918c2ecf20Sopenharmony_ci } 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci list_del(&cmd_pos->link); 37948c2ecf20Sopenharmony_ci bnx2x_free_groups(&cmd_pos->group_head); 37958c2ecf20Sopenharmony_ci kfree(cmd_pos); 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ci return cnt; 37988c2ecf20Sopenharmony_ci} 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci/** 38018c2ecf20Sopenharmony_ci * bnx2x_get_fw_mac_addr - revert the bnx2x_set_fw_mac_addr(). 38028c2ecf20Sopenharmony_ci * 38038c2ecf20Sopenharmony_ci * @fw_hi: address 38048c2ecf20Sopenharmony_ci * @fw_mid: address 38058c2ecf20Sopenharmony_ci * @fw_lo: address 38068c2ecf20Sopenharmony_ci * @mac: mac address 38078c2ecf20Sopenharmony_ci */ 38088c2ecf20Sopenharmony_cistatic inline void bnx2x_get_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid, 38098c2ecf20Sopenharmony_ci __le16 *fw_lo, u8 *mac) 38108c2ecf20Sopenharmony_ci{ 38118c2ecf20Sopenharmony_ci mac[1] = ((u8 *)fw_hi)[0]; 38128c2ecf20Sopenharmony_ci mac[0] = ((u8 *)fw_hi)[1]; 38138c2ecf20Sopenharmony_ci mac[3] = ((u8 *)fw_mid)[0]; 38148c2ecf20Sopenharmony_ci mac[2] = ((u8 *)fw_mid)[1]; 38158c2ecf20Sopenharmony_ci mac[5] = ((u8 *)fw_lo)[0]; 38168c2ecf20Sopenharmony_ci mac[4] = ((u8 *)fw_lo)[1]; 38178c2ecf20Sopenharmony_ci} 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci/** 38208c2ecf20Sopenharmony_ci * bnx2x_mcast_refresh_registry_e1 - 38218c2ecf20Sopenharmony_ci * 38228c2ecf20Sopenharmony_ci * @bp: device handle 38238c2ecf20Sopenharmony_ci * @o: multicast info 38248c2ecf20Sopenharmony_ci * 38258c2ecf20Sopenharmony_ci * Check the ramrod data first entry flag to see if it's a DELETE or ADD command 38268c2ecf20Sopenharmony_ci * and update the registry correspondingly: if ADD - allocate a memory and add 38278c2ecf20Sopenharmony_ci * the entries to the registry (list), if DELETE - clear the registry and free 38288c2ecf20Sopenharmony_ci * the memory. 38298c2ecf20Sopenharmony_ci */ 38308c2ecf20Sopenharmony_cistatic inline int bnx2x_mcast_refresh_registry_e1(struct bnx2x *bp, 38318c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o) 38328c2ecf20Sopenharmony_ci{ 38338c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 38348c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem *elem; 38358c2ecf20Sopenharmony_ci struct mac_configuration_cmd *data = 38368c2ecf20Sopenharmony_ci (struct mac_configuration_cmd *)(raw->rdata); 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci /* If first entry contains a SET bit - the command was ADD, 38398c2ecf20Sopenharmony_ci * otherwise - DEL_ALL 38408c2ecf20Sopenharmony_ci */ 38418c2ecf20Sopenharmony_ci if (GET_FLAG(data->config_table[0].flags, 38428c2ecf20Sopenharmony_ci MAC_CONFIGURATION_ENTRY_ACTION_TYPE)) { 38438c2ecf20Sopenharmony_ci int i, len = data->hdr.length; 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci /* Break if it was a RESTORE command */ 38468c2ecf20Sopenharmony_ci if (!list_empty(&o->registry.exact_match.macs)) 38478c2ecf20Sopenharmony_ci return 0; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci elem = kcalloc(len, sizeof(*elem), GFP_ATOMIC); 38508c2ecf20Sopenharmony_ci if (!elem) { 38518c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to allocate registry memory\n"); 38528c2ecf20Sopenharmony_ci return -ENOMEM; 38538c2ecf20Sopenharmony_ci } 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci for (i = 0; i < len; i++, elem++) { 38568c2ecf20Sopenharmony_ci bnx2x_get_fw_mac_addr( 38578c2ecf20Sopenharmony_ci &data->config_table[i].msb_mac_addr, 38588c2ecf20Sopenharmony_ci &data->config_table[i].middle_mac_addr, 38598c2ecf20Sopenharmony_ci &data->config_table[i].lsb_mac_addr, 38608c2ecf20Sopenharmony_ci elem->mac); 38618c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Adding registry entry for [%pM]\n", 38628c2ecf20Sopenharmony_ci elem->mac); 38638c2ecf20Sopenharmony_ci list_add_tail(&elem->link, 38648c2ecf20Sopenharmony_ci &o->registry.exact_match.macs); 38658c2ecf20Sopenharmony_ci } 38668c2ecf20Sopenharmony_ci } else { 38678c2ecf20Sopenharmony_ci elem = list_first_entry(&o->registry.exact_match.macs, 38688c2ecf20Sopenharmony_ci struct bnx2x_mcast_mac_elem, link); 38698c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Deleting a registry\n"); 38708c2ecf20Sopenharmony_ci kfree(elem); 38718c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&o->registry.exact_match.macs); 38728c2ecf20Sopenharmony_ci } 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci return 0; 38758c2ecf20Sopenharmony_ci} 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_cistatic int bnx2x_mcast_setup_e1(struct bnx2x *bp, 38788c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 38798c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 38808c2ecf20Sopenharmony_ci{ 38818c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 38828c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *raw = &o->raw; 38838c2ecf20Sopenharmony_ci struct mac_configuration_cmd *data = 38848c2ecf20Sopenharmony_ci (struct mac_configuration_cmd *)(raw->rdata); 38858c2ecf20Sopenharmony_ci int cnt = 0, i, rc; 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci /* Reset the ramrod data buffer */ 38888c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci /* First set all entries as invalid */ 38918c2ecf20Sopenharmony_ci for (i = 0; i < o->max_cmd_len ; i++) 38928c2ecf20Sopenharmony_ci SET_FLAG(data->config_table[i].flags, 38938c2ecf20Sopenharmony_ci MAC_CONFIGURATION_ENTRY_ACTION_TYPE, 38948c2ecf20Sopenharmony_ci T_ETH_MAC_COMMAND_INVALIDATE); 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci /* Handle pending commands first */ 38978c2ecf20Sopenharmony_ci cnt = bnx2x_mcast_handle_pending_cmds_e1(bp, p); 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ci /* If there are no more pending commands - clear SCHEDULED state */ 39008c2ecf20Sopenharmony_ci if (list_empty(&o->pending_cmds_head)) 39018c2ecf20Sopenharmony_ci o->clear_sched(o); 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci /* The below may be true iff there were no pending commands */ 39048c2ecf20Sopenharmony_ci if (!cnt) 39058c2ecf20Sopenharmony_ci cnt = bnx2x_mcast_handle_current_cmd(bp, p, cmd, 0); 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci /* For 57710 every command has o->max_cmd_len length to ensure that 39088c2ecf20Sopenharmony_ci * commands are done one at a time. 39098c2ecf20Sopenharmony_ci */ 39108c2ecf20Sopenharmony_ci o->total_pending_num -= o->max_cmd_len; 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci /* send a ramrod */ 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci WARN_ON(cnt > o->max_cmd_len); 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci /* Set ramrod header (in particular, a number of entries to update) */ 39178c2ecf20Sopenharmony_ci bnx2x_mcast_set_rdata_hdr_e1(bp, p, (u8)cnt); 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci /* update a registry: we need the registry contents to be always up 39208c2ecf20Sopenharmony_ci * to date in order to be able to execute a RESTORE opcode. Here 39218c2ecf20Sopenharmony_ci * we use the fact that for 57710 we sent one command at a time 39228c2ecf20Sopenharmony_ci * hence we may take the registry update out of the command handling 39238c2ecf20Sopenharmony_ci * and do it in a simpler way here. 39248c2ecf20Sopenharmony_ci */ 39258c2ecf20Sopenharmony_ci rc = bnx2x_mcast_refresh_registry_e1(bp, o); 39268c2ecf20Sopenharmony_ci if (rc) 39278c2ecf20Sopenharmony_ci return rc; 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci /* If CLEAR_ONLY was requested - don't send a ramrod and clear 39308c2ecf20Sopenharmony_ci * RAMROD_PENDING status immediately. 39318c2ecf20Sopenharmony_ci */ 39328c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) { 39338c2ecf20Sopenharmony_ci raw->clear_pending(raw); 39348c2ecf20Sopenharmony_ci return 0; 39358c2ecf20Sopenharmony_ci } else { 39368c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 39378c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 39388c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 39398c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 39408c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 39418c2ecf20Sopenharmony_ci */ 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci /* Send a ramrod */ 39448c2ecf20Sopenharmony_ci rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, raw->cid, 39458c2ecf20Sopenharmony_ci U64_HI(raw->rdata_mapping), 39468c2ecf20Sopenharmony_ci U64_LO(raw->rdata_mapping), 39478c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 39488c2ecf20Sopenharmony_ci if (rc) 39498c2ecf20Sopenharmony_ci return rc; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci /* Ramrod completion is pending */ 39528c2ecf20Sopenharmony_ci return 1; 39538c2ecf20Sopenharmony_ci } 39548c2ecf20Sopenharmony_ci} 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_cistatic int bnx2x_mcast_get_registry_size_exact(struct bnx2x_mcast_obj *o) 39578c2ecf20Sopenharmony_ci{ 39588c2ecf20Sopenharmony_ci return o->registry.exact_match.num_macs_set; 39598c2ecf20Sopenharmony_ci} 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_cistatic int bnx2x_mcast_get_registry_size_aprox(struct bnx2x_mcast_obj *o) 39628c2ecf20Sopenharmony_ci{ 39638c2ecf20Sopenharmony_ci return o->registry.aprox_match.num_bins_set; 39648c2ecf20Sopenharmony_ci} 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_cistatic void bnx2x_mcast_set_registry_size_exact(struct bnx2x_mcast_obj *o, 39678c2ecf20Sopenharmony_ci int n) 39688c2ecf20Sopenharmony_ci{ 39698c2ecf20Sopenharmony_ci o->registry.exact_match.num_macs_set = n; 39708c2ecf20Sopenharmony_ci} 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_cistatic void bnx2x_mcast_set_registry_size_aprox(struct bnx2x_mcast_obj *o, 39738c2ecf20Sopenharmony_ci int n) 39748c2ecf20Sopenharmony_ci{ 39758c2ecf20Sopenharmony_ci o->registry.aprox_match.num_bins_set = n; 39768c2ecf20Sopenharmony_ci} 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ciint bnx2x_config_mcast(struct bnx2x *bp, 39798c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params *p, 39808c2ecf20Sopenharmony_ci enum bnx2x_mcast_cmd cmd) 39818c2ecf20Sopenharmony_ci{ 39828c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *o = p->mcast_obj; 39838c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 39848c2ecf20Sopenharmony_ci int rc = 0, old_reg_size; 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci /* This is needed to recover number of currently configured mcast macs 39878c2ecf20Sopenharmony_ci * in case of failure. 39888c2ecf20Sopenharmony_ci */ 39898c2ecf20Sopenharmony_ci old_reg_size = o->get_registry_size(o); 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci /* Do some calculations and checks */ 39928c2ecf20Sopenharmony_ci rc = o->validate(bp, p, cmd); 39938c2ecf20Sopenharmony_ci if (rc) 39948c2ecf20Sopenharmony_ci return rc; 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci /* Return if there is no work to do */ 39978c2ecf20Sopenharmony_ci if ((!p->mcast_list_len) && (!o->check_sched(o))) 39988c2ecf20Sopenharmony_ci return 0; 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "o->total_pending_num=%d p->mcast_list_len=%d o->max_cmd_len=%d\n", 40018c2ecf20Sopenharmony_ci o->total_pending_num, p->mcast_list_len, o->max_cmd_len); 40028c2ecf20Sopenharmony_ci 40038c2ecf20Sopenharmony_ci /* Enqueue the current command to the pending list if we can't complete 40048c2ecf20Sopenharmony_ci * it in the current iteration 40058c2ecf20Sopenharmony_ci */ 40068c2ecf20Sopenharmony_ci if (r->check_pending(r) || 40078c2ecf20Sopenharmony_ci ((o->max_cmd_len > 0) && (o->total_pending_num > o->max_cmd_len))) { 40088c2ecf20Sopenharmony_ci rc = o->enqueue_cmd(bp, p->mcast_obj, p, cmd); 40098c2ecf20Sopenharmony_ci if (rc < 0) 40108c2ecf20Sopenharmony_ci goto error_exit1; 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci /* As long as the current command is in a command list we 40138c2ecf20Sopenharmony_ci * don't need to handle it separately. 40148c2ecf20Sopenharmony_ci */ 40158c2ecf20Sopenharmony_ci p->mcast_list_len = 0; 40168c2ecf20Sopenharmony_ci } 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci if (!r->check_pending(r)) { 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci /* Set 'pending' state */ 40218c2ecf20Sopenharmony_ci r->set_pending(r); 40228c2ecf20Sopenharmony_ci 40238c2ecf20Sopenharmony_ci /* Configure the new classification in the chip */ 40248c2ecf20Sopenharmony_ci rc = o->config_mcast(bp, p, cmd); 40258c2ecf20Sopenharmony_ci if (rc < 0) 40268c2ecf20Sopenharmony_ci goto error_exit2; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci /* Wait for a ramrod completion if was requested */ 40298c2ecf20Sopenharmony_ci if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) 40308c2ecf20Sopenharmony_ci rc = o->wait_comp(bp, o); 40318c2ecf20Sopenharmony_ci } 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci return rc; 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_cierror_exit2: 40368c2ecf20Sopenharmony_ci r->clear_pending(r); 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_cierror_exit1: 40398c2ecf20Sopenharmony_ci o->revert(bp, p, old_reg_size, cmd); 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci return rc; 40428c2ecf20Sopenharmony_ci} 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_cistatic void bnx2x_mcast_clear_sched(struct bnx2x_mcast_obj *o) 40458c2ecf20Sopenharmony_ci{ 40468c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 40478c2ecf20Sopenharmony_ci clear_bit(o->sched_state, o->raw.pstate); 40488c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 40498c2ecf20Sopenharmony_ci} 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_cistatic void bnx2x_mcast_set_sched(struct bnx2x_mcast_obj *o) 40528c2ecf20Sopenharmony_ci{ 40538c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 40548c2ecf20Sopenharmony_ci set_bit(o->sched_state, o->raw.pstate); 40558c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 40568c2ecf20Sopenharmony_ci} 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_cistatic bool bnx2x_mcast_check_sched(struct bnx2x_mcast_obj *o) 40598c2ecf20Sopenharmony_ci{ 40608c2ecf20Sopenharmony_ci return !!test_bit(o->sched_state, o->raw.pstate); 40618c2ecf20Sopenharmony_ci} 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_cistatic bool bnx2x_mcast_check_pending(struct bnx2x_mcast_obj *o) 40648c2ecf20Sopenharmony_ci{ 40658c2ecf20Sopenharmony_ci return o->raw.check_pending(&o->raw) || o->check_sched(o); 40668c2ecf20Sopenharmony_ci} 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_civoid bnx2x_init_mcast_obj(struct bnx2x *bp, 40698c2ecf20Sopenharmony_ci struct bnx2x_mcast_obj *mcast_obj, 40708c2ecf20Sopenharmony_ci u8 mcast_cl_id, u32 mcast_cid, u8 func_id, 40718c2ecf20Sopenharmony_ci u8 engine_id, void *rdata, dma_addr_t rdata_mapping, 40728c2ecf20Sopenharmony_ci int state, unsigned long *pstate, bnx2x_obj_type type) 40738c2ecf20Sopenharmony_ci{ 40748c2ecf20Sopenharmony_ci memset(mcast_obj, 0, sizeof(*mcast_obj)); 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci bnx2x_init_raw_obj(&mcast_obj->raw, mcast_cl_id, mcast_cid, func_id, 40778c2ecf20Sopenharmony_ci rdata, rdata_mapping, state, pstate, type); 40788c2ecf20Sopenharmony_ci 40798c2ecf20Sopenharmony_ci mcast_obj->engine_id = engine_id; 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mcast_obj->pending_cmds_head); 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci mcast_obj->sched_state = BNX2X_FILTER_MCAST_SCHED; 40848c2ecf20Sopenharmony_ci mcast_obj->check_sched = bnx2x_mcast_check_sched; 40858c2ecf20Sopenharmony_ci mcast_obj->set_sched = bnx2x_mcast_set_sched; 40868c2ecf20Sopenharmony_ci mcast_obj->clear_sched = bnx2x_mcast_clear_sched; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) { 40898c2ecf20Sopenharmony_ci mcast_obj->config_mcast = bnx2x_mcast_setup_e1; 40908c2ecf20Sopenharmony_ci mcast_obj->enqueue_cmd = bnx2x_mcast_enqueue_cmd; 40918c2ecf20Sopenharmony_ci mcast_obj->hdl_restore = 40928c2ecf20Sopenharmony_ci bnx2x_mcast_handle_restore_cmd_e1; 40938c2ecf20Sopenharmony_ci mcast_obj->check_pending = bnx2x_mcast_check_pending; 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci if (CHIP_REV_IS_SLOW(bp)) 40968c2ecf20Sopenharmony_ci mcast_obj->max_cmd_len = BNX2X_MAX_EMUL_MULTI; 40978c2ecf20Sopenharmony_ci else 40988c2ecf20Sopenharmony_ci mcast_obj->max_cmd_len = BNX2X_MAX_MULTICAST; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci mcast_obj->wait_comp = bnx2x_mcast_wait; 41018c2ecf20Sopenharmony_ci mcast_obj->set_one_rule = bnx2x_mcast_set_one_rule_e1; 41028c2ecf20Sopenharmony_ci mcast_obj->validate = bnx2x_mcast_validate_e1; 41038c2ecf20Sopenharmony_ci mcast_obj->revert = bnx2x_mcast_revert_e1; 41048c2ecf20Sopenharmony_ci mcast_obj->get_registry_size = 41058c2ecf20Sopenharmony_ci bnx2x_mcast_get_registry_size_exact; 41068c2ecf20Sopenharmony_ci mcast_obj->set_registry_size = 41078c2ecf20Sopenharmony_ci bnx2x_mcast_set_registry_size_exact; 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_ci /* 57710 is the only chip that uses the exact match for mcast 41108c2ecf20Sopenharmony_ci * at the moment. 41118c2ecf20Sopenharmony_ci */ 41128c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mcast_obj->registry.exact_match.macs); 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci } else if (CHIP_IS_E1H(bp)) { 41158c2ecf20Sopenharmony_ci mcast_obj->config_mcast = bnx2x_mcast_setup_e1h; 41168c2ecf20Sopenharmony_ci mcast_obj->enqueue_cmd = NULL; 41178c2ecf20Sopenharmony_ci mcast_obj->hdl_restore = NULL; 41188c2ecf20Sopenharmony_ci mcast_obj->check_pending = bnx2x_mcast_check_pending; 41198c2ecf20Sopenharmony_ci 41208c2ecf20Sopenharmony_ci /* 57711 doesn't send a ramrod, so it has unlimited credit 41218c2ecf20Sopenharmony_ci * for one command. 41228c2ecf20Sopenharmony_ci */ 41238c2ecf20Sopenharmony_ci mcast_obj->max_cmd_len = -1; 41248c2ecf20Sopenharmony_ci mcast_obj->wait_comp = bnx2x_mcast_wait; 41258c2ecf20Sopenharmony_ci mcast_obj->set_one_rule = NULL; 41268c2ecf20Sopenharmony_ci mcast_obj->validate = bnx2x_mcast_validate_e1h; 41278c2ecf20Sopenharmony_ci mcast_obj->revert = bnx2x_mcast_revert_e1h; 41288c2ecf20Sopenharmony_ci mcast_obj->get_registry_size = 41298c2ecf20Sopenharmony_ci bnx2x_mcast_get_registry_size_aprox; 41308c2ecf20Sopenharmony_ci mcast_obj->set_registry_size = 41318c2ecf20Sopenharmony_ci bnx2x_mcast_set_registry_size_aprox; 41328c2ecf20Sopenharmony_ci } else { 41338c2ecf20Sopenharmony_ci mcast_obj->config_mcast = bnx2x_mcast_setup_e2; 41348c2ecf20Sopenharmony_ci mcast_obj->enqueue_cmd = bnx2x_mcast_enqueue_cmd; 41358c2ecf20Sopenharmony_ci mcast_obj->hdl_restore = 41368c2ecf20Sopenharmony_ci bnx2x_mcast_handle_restore_cmd_e2; 41378c2ecf20Sopenharmony_ci mcast_obj->check_pending = bnx2x_mcast_check_pending; 41388c2ecf20Sopenharmony_ci /* TODO: There should be a proper HSI define for this number!!! 41398c2ecf20Sopenharmony_ci */ 41408c2ecf20Sopenharmony_ci mcast_obj->max_cmd_len = 16; 41418c2ecf20Sopenharmony_ci mcast_obj->wait_comp = bnx2x_mcast_wait; 41428c2ecf20Sopenharmony_ci mcast_obj->set_one_rule = bnx2x_mcast_set_one_rule_e2; 41438c2ecf20Sopenharmony_ci mcast_obj->validate = bnx2x_mcast_validate_e2; 41448c2ecf20Sopenharmony_ci mcast_obj->revert = bnx2x_mcast_revert_e2; 41458c2ecf20Sopenharmony_ci mcast_obj->get_registry_size = 41468c2ecf20Sopenharmony_ci bnx2x_mcast_get_registry_size_aprox; 41478c2ecf20Sopenharmony_ci mcast_obj->set_registry_size = 41488c2ecf20Sopenharmony_ci bnx2x_mcast_set_registry_size_aprox; 41498c2ecf20Sopenharmony_ci } 41508c2ecf20Sopenharmony_ci} 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci/*************************** Credit handling **********************************/ 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_ci/** 41558c2ecf20Sopenharmony_ci * atomic_add_ifless - add if the result is less than a given value. 41568c2ecf20Sopenharmony_ci * 41578c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 41588c2ecf20Sopenharmony_ci * @a: the amount to add to v... 41598c2ecf20Sopenharmony_ci * @u: ...if (v + a) is less than u. 41608c2ecf20Sopenharmony_ci * 41618c2ecf20Sopenharmony_ci * returns true if (v + a) was less than u, and false otherwise. 41628c2ecf20Sopenharmony_ci * 41638c2ecf20Sopenharmony_ci */ 41648c2ecf20Sopenharmony_cistatic inline bool __atomic_add_ifless(atomic_t *v, int a, int u) 41658c2ecf20Sopenharmony_ci{ 41668c2ecf20Sopenharmony_ci int c, old; 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci c = atomic_read(v); 41698c2ecf20Sopenharmony_ci for (;;) { 41708c2ecf20Sopenharmony_ci if (unlikely(c + a >= u)) 41718c2ecf20Sopenharmony_ci return false; 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_ci old = atomic_cmpxchg((v), c, c + a); 41748c2ecf20Sopenharmony_ci if (likely(old == c)) 41758c2ecf20Sopenharmony_ci break; 41768c2ecf20Sopenharmony_ci c = old; 41778c2ecf20Sopenharmony_ci } 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci return true; 41808c2ecf20Sopenharmony_ci} 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci/** 41838c2ecf20Sopenharmony_ci * atomic_dec_ifmoe - dec if the result is more or equal than a given value. 41848c2ecf20Sopenharmony_ci * 41858c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 41868c2ecf20Sopenharmony_ci * @a: the amount to dec from v... 41878c2ecf20Sopenharmony_ci * @u: ...if (v - a) is more or equal than u. 41888c2ecf20Sopenharmony_ci * 41898c2ecf20Sopenharmony_ci * returns true if (v - a) was more or equal than u, and false 41908c2ecf20Sopenharmony_ci * otherwise. 41918c2ecf20Sopenharmony_ci */ 41928c2ecf20Sopenharmony_cistatic inline bool __atomic_dec_ifmoe(atomic_t *v, int a, int u) 41938c2ecf20Sopenharmony_ci{ 41948c2ecf20Sopenharmony_ci int c, old; 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_ci c = atomic_read(v); 41978c2ecf20Sopenharmony_ci for (;;) { 41988c2ecf20Sopenharmony_ci if (unlikely(c - a < u)) 41998c2ecf20Sopenharmony_ci return false; 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci old = atomic_cmpxchg((v), c, c - a); 42028c2ecf20Sopenharmony_ci if (likely(old == c)) 42038c2ecf20Sopenharmony_ci break; 42048c2ecf20Sopenharmony_ci c = old; 42058c2ecf20Sopenharmony_ci } 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci return true; 42088c2ecf20Sopenharmony_ci} 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_get(struct bnx2x_credit_pool_obj *o, int cnt) 42118c2ecf20Sopenharmony_ci{ 42128c2ecf20Sopenharmony_ci bool rc; 42138c2ecf20Sopenharmony_ci 42148c2ecf20Sopenharmony_ci smp_mb(); 42158c2ecf20Sopenharmony_ci rc = __atomic_dec_ifmoe(&o->credit, cnt, 0); 42168c2ecf20Sopenharmony_ci smp_mb(); 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_ci return rc; 42198c2ecf20Sopenharmony_ci} 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_put(struct bnx2x_credit_pool_obj *o, int cnt) 42228c2ecf20Sopenharmony_ci{ 42238c2ecf20Sopenharmony_ci bool rc; 42248c2ecf20Sopenharmony_ci 42258c2ecf20Sopenharmony_ci smp_mb(); 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci /* Don't let to refill if credit + cnt > pool_sz */ 42288c2ecf20Sopenharmony_ci rc = __atomic_add_ifless(&o->credit, cnt, o->pool_sz + 1); 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_ci smp_mb(); 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci return rc; 42338c2ecf20Sopenharmony_ci} 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_cistatic int bnx2x_credit_pool_check(struct bnx2x_credit_pool_obj *o) 42368c2ecf20Sopenharmony_ci{ 42378c2ecf20Sopenharmony_ci int cur_credit; 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci smp_mb(); 42408c2ecf20Sopenharmony_ci cur_credit = atomic_read(&o->credit); 42418c2ecf20Sopenharmony_ci 42428c2ecf20Sopenharmony_ci return cur_credit; 42438c2ecf20Sopenharmony_ci} 42448c2ecf20Sopenharmony_ci 42458c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_always_true(struct bnx2x_credit_pool_obj *o, 42468c2ecf20Sopenharmony_ci int cnt) 42478c2ecf20Sopenharmony_ci{ 42488c2ecf20Sopenharmony_ci return true; 42498c2ecf20Sopenharmony_ci} 42508c2ecf20Sopenharmony_ci 42518c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_get_entry( 42528c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *o, 42538c2ecf20Sopenharmony_ci int *offset) 42548c2ecf20Sopenharmony_ci{ 42558c2ecf20Sopenharmony_ci int idx, vec, i; 42568c2ecf20Sopenharmony_ci 42578c2ecf20Sopenharmony_ci *offset = -1; 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci /* Find "internal cam-offset" then add to base for this object... */ 42608c2ecf20Sopenharmony_ci for (vec = 0; vec < BNX2X_POOL_VEC_SIZE; vec++) { 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_ci /* Skip the current vector if there are no free entries in it */ 42638c2ecf20Sopenharmony_ci if (!o->pool_mirror[vec]) 42648c2ecf20Sopenharmony_ci continue; 42658c2ecf20Sopenharmony_ci 42668c2ecf20Sopenharmony_ci /* If we've got here we are going to find a free entry */ 42678c2ecf20Sopenharmony_ci for (idx = vec * BIT_VEC64_ELEM_SZ, i = 0; 42688c2ecf20Sopenharmony_ci i < BIT_VEC64_ELEM_SZ; idx++, i++) 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ci if (BIT_VEC64_TEST_BIT(o->pool_mirror, idx)) { 42718c2ecf20Sopenharmony_ci /* Got one!! */ 42728c2ecf20Sopenharmony_ci BIT_VEC64_CLEAR_BIT(o->pool_mirror, idx); 42738c2ecf20Sopenharmony_ci *offset = o->base_pool_offset + idx; 42748c2ecf20Sopenharmony_ci return true; 42758c2ecf20Sopenharmony_ci } 42768c2ecf20Sopenharmony_ci } 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci return false; 42798c2ecf20Sopenharmony_ci} 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_put_entry( 42828c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *o, 42838c2ecf20Sopenharmony_ci int offset) 42848c2ecf20Sopenharmony_ci{ 42858c2ecf20Sopenharmony_ci if (offset < o->base_pool_offset) 42868c2ecf20Sopenharmony_ci return false; 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_ci offset -= o->base_pool_offset; 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci if (offset >= o->pool_sz) 42918c2ecf20Sopenharmony_ci return false; 42928c2ecf20Sopenharmony_ci 42938c2ecf20Sopenharmony_ci /* Return the entry to the pool */ 42948c2ecf20Sopenharmony_ci BIT_VEC64_SET_BIT(o->pool_mirror, offset); 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci return true; 42978c2ecf20Sopenharmony_ci} 42988c2ecf20Sopenharmony_ci 42998c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_put_entry_always_true( 43008c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *o, 43018c2ecf20Sopenharmony_ci int offset) 43028c2ecf20Sopenharmony_ci{ 43038c2ecf20Sopenharmony_ci return true; 43048c2ecf20Sopenharmony_ci} 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_cistatic bool bnx2x_credit_pool_get_entry_always_true( 43078c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *o, 43088c2ecf20Sopenharmony_ci int *offset) 43098c2ecf20Sopenharmony_ci{ 43108c2ecf20Sopenharmony_ci *offset = -1; 43118c2ecf20Sopenharmony_ci return true; 43128c2ecf20Sopenharmony_ci} 43138c2ecf20Sopenharmony_ci/** 43148c2ecf20Sopenharmony_ci * bnx2x_init_credit_pool - initialize credit pool internals. 43158c2ecf20Sopenharmony_ci * 43168c2ecf20Sopenharmony_ci * @p: credit pool 43178c2ecf20Sopenharmony_ci * @base: Base entry in the CAM to use. 43188c2ecf20Sopenharmony_ci * @credit: pool size. 43198c2ecf20Sopenharmony_ci * 43208c2ecf20Sopenharmony_ci * If base is negative no CAM entries handling will be performed. 43218c2ecf20Sopenharmony_ci * If credit is negative pool operations will always succeed (unlimited pool). 43228c2ecf20Sopenharmony_ci * 43238c2ecf20Sopenharmony_ci */ 43248c2ecf20Sopenharmony_civoid bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p, 43258c2ecf20Sopenharmony_ci int base, int credit) 43268c2ecf20Sopenharmony_ci{ 43278c2ecf20Sopenharmony_ci /* Zero the object first */ 43288c2ecf20Sopenharmony_ci memset(p, 0, sizeof(*p)); 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci /* Set the table to all 1s */ 43318c2ecf20Sopenharmony_ci memset(&p->pool_mirror, 0xff, sizeof(p->pool_mirror)); 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ci /* Init a pool as full */ 43348c2ecf20Sopenharmony_ci atomic_set(&p->credit, credit); 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci /* The total poll size */ 43378c2ecf20Sopenharmony_ci p->pool_sz = credit; 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci p->base_pool_offset = base; 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_ci /* Commit the change */ 43428c2ecf20Sopenharmony_ci smp_mb(); 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci p->check = bnx2x_credit_pool_check; 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci /* if pool credit is negative - disable the checks */ 43478c2ecf20Sopenharmony_ci if (credit >= 0) { 43488c2ecf20Sopenharmony_ci p->put = bnx2x_credit_pool_put; 43498c2ecf20Sopenharmony_ci p->get = bnx2x_credit_pool_get; 43508c2ecf20Sopenharmony_ci p->put_entry = bnx2x_credit_pool_put_entry; 43518c2ecf20Sopenharmony_ci p->get_entry = bnx2x_credit_pool_get_entry; 43528c2ecf20Sopenharmony_ci } else { 43538c2ecf20Sopenharmony_ci p->put = bnx2x_credit_pool_always_true; 43548c2ecf20Sopenharmony_ci p->get = bnx2x_credit_pool_always_true; 43558c2ecf20Sopenharmony_ci p->put_entry = bnx2x_credit_pool_put_entry_always_true; 43568c2ecf20Sopenharmony_ci p->get_entry = bnx2x_credit_pool_get_entry_always_true; 43578c2ecf20Sopenharmony_ci } 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci /* If base is negative - disable entries handling */ 43608c2ecf20Sopenharmony_ci if (base < 0) { 43618c2ecf20Sopenharmony_ci p->put_entry = bnx2x_credit_pool_put_entry_always_true; 43628c2ecf20Sopenharmony_ci p->get_entry = bnx2x_credit_pool_get_entry_always_true; 43638c2ecf20Sopenharmony_ci } 43648c2ecf20Sopenharmony_ci} 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_civoid bnx2x_init_mac_credit_pool(struct bnx2x *bp, 43678c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *p, u8 func_id, 43688c2ecf20Sopenharmony_ci u8 func_num) 43698c2ecf20Sopenharmony_ci{ 43708c2ecf20Sopenharmony_ci/* TODO: this will be defined in consts as well... */ 43718c2ecf20Sopenharmony_ci#define BNX2X_CAM_SIZE_EMUL 5 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci int cam_sz; 43748c2ecf20Sopenharmony_ci 43758c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) { 43768c2ecf20Sopenharmony_ci /* In E1, Multicast is saved in cam... */ 43778c2ecf20Sopenharmony_ci if (!CHIP_REV_IS_SLOW(bp)) 43788c2ecf20Sopenharmony_ci cam_sz = (MAX_MAC_CREDIT_E1 / 2) - BNX2X_MAX_MULTICAST; 43798c2ecf20Sopenharmony_ci else 43808c2ecf20Sopenharmony_ci cam_sz = BNX2X_CAM_SIZE_EMUL - BNX2X_MAX_EMUL_MULTI; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, func_id * cam_sz, cam_sz); 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci } else if (CHIP_IS_E1H(bp)) { 43858c2ecf20Sopenharmony_ci /* CAM credit is equaly divided between all active functions 43868c2ecf20Sopenharmony_ci * on the PORT!. 43878c2ecf20Sopenharmony_ci */ 43888c2ecf20Sopenharmony_ci if ((func_num > 0)) { 43898c2ecf20Sopenharmony_ci if (!CHIP_REV_IS_SLOW(bp)) 43908c2ecf20Sopenharmony_ci cam_sz = (MAX_MAC_CREDIT_E1H / (2*func_num)); 43918c2ecf20Sopenharmony_ci else 43928c2ecf20Sopenharmony_ci cam_sz = BNX2X_CAM_SIZE_EMUL; 43938c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, func_id * cam_sz, cam_sz); 43948c2ecf20Sopenharmony_ci } else { 43958c2ecf20Sopenharmony_ci /* this should never happen! Block MAC operations. */ 43968c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, 0, 0); 43978c2ecf20Sopenharmony_ci } 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ci } else { 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci /* CAM credit is equaly divided between all active functions 44028c2ecf20Sopenharmony_ci * on the PATH. 44038c2ecf20Sopenharmony_ci */ 44048c2ecf20Sopenharmony_ci if (func_num > 0) { 44058c2ecf20Sopenharmony_ci if (!CHIP_REV_IS_SLOW(bp)) 44068c2ecf20Sopenharmony_ci cam_sz = PF_MAC_CREDIT_E2(bp, func_num); 44078c2ecf20Sopenharmony_ci else 44088c2ecf20Sopenharmony_ci cam_sz = BNX2X_CAM_SIZE_EMUL; 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci /* No need for CAM entries handling for 57712 and 44118c2ecf20Sopenharmony_ci * newer. 44128c2ecf20Sopenharmony_ci */ 44138c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, -1, cam_sz); 44148c2ecf20Sopenharmony_ci } else { 44158c2ecf20Sopenharmony_ci /* this should never happen! Block MAC operations. */ 44168c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, 0, 0); 44178c2ecf20Sopenharmony_ci } 44188c2ecf20Sopenharmony_ci } 44198c2ecf20Sopenharmony_ci} 44208c2ecf20Sopenharmony_ci 44218c2ecf20Sopenharmony_civoid bnx2x_init_vlan_credit_pool(struct bnx2x *bp, 44228c2ecf20Sopenharmony_ci struct bnx2x_credit_pool_obj *p, 44238c2ecf20Sopenharmony_ci u8 func_id, 44248c2ecf20Sopenharmony_ci u8 func_num) 44258c2ecf20Sopenharmony_ci{ 44268c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp)) { 44278c2ecf20Sopenharmony_ci /* There is no VLAN credit in HW on 57710 and 57711 only 44288c2ecf20Sopenharmony_ci * MAC / MAC-VLAN can be set 44298c2ecf20Sopenharmony_ci */ 44308c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, 0, -1); 44318c2ecf20Sopenharmony_ci } else { 44328c2ecf20Sopenharmony_ci /* CAM credit is equally divided between all active functions 44338c2ecf20Sopenharmony_ci * on the PATH. 44348c2ecf20Sopenharmony_ci */ 44358c2ecf20Sopenharmony_ci if (func_num > 0) { 44368c2ecf20Sopenharmony_ci int credit = PF_VLAN_CREDIT_E2(bp, func_num); 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, -1/*unused for E2*/, credit); 44398c2ecf20Sopenharmony_ci } else 44408c2ecf20Sopenharmony_ci /* this should never happen! Block VLAN operations. */ 44418c2ecf20Sopenharmony_ci bnx2x_init_credit_pool(p, 0, 0); 44428c2ecf20Sopenharmony_ci } 44438c2ecf20Sopenharmony_ci} 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci/****************** RSS Configuration ******************/ 44468c2ecf20Sopenharmony_ci/** 44478c2ecf20Sopenharmony_ci * bnx2x_debug_print_ind_table - prints the indirection table configuration. 44488c2ecf20Sopenharmony_ci * 44498c2ecf20Sopenharmony_ci * @bp: driver handle 44508c2ecf20Sopenharmony_ci * @p: pointer to rss configuration 44518c2ecf20Sopenharmony_ci * 44528c2ecf20Sopenharmony_ci * Prints it when NETIF_MSG_IFUP debug level is configured. 44538c2ecf20Sopenharmony_ci */ 44548c2ecf20Sopenharmony_cistatic inline void bnx2x_debug_print_ind_table(struct bnx2x *bp, 44558c2ecf20Sopenharmony_ci struct bnx2x_config_rss_params *p) 44568c2ecf20Sopenharmony_ci{ 44578c2ecf20Sopenharmony_ci int i; 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Setting indirection table to:\n"); 44608c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "0x0000: "); 44618c2ecf20Sopenharmony_ci for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { 44628c2ecf20Sopenharmony_ci DP_CONT(BNX2X_MSG_SP, "0x%02x ", p->ind_table[i]); 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci /* Print 4 bytes in a line */ 44658c2ecf20Sopenharmony_ci if ((i + 1 < T_ETH_INDIRECTION_TABLE_SIZE) && 44668c2ecf20Sopenharmony_ci (((i + 1) & 0x3) == 0)) { 44678c2ecf20Sopenharmony_ci DP_CONT(BNX2X_MSG_SP, "\n"); 44688c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "0x%04x: ", i + 1); 44698c2ecf20Sopenharmony_ci } 44708c2ecf20Sopenharmony_ci } 44718c2ecf20Sopenharmony_ci 44728c2ecf20Sopenharmony_ci DP_CONT(BNX2X_MSG_SP, "\n"); 44738c2ecf20Sopenharmony_ci} 44748c2ecf20Sopenharmony_ci 44758c2ecf20Sopenharmony_ci/** 44768c2ecf20Sopenharmony_ci * bnx2x_setup_rss - configure RSS 44778c2ecf20Sopenharmony_ci * 44788c2ecf20Sopenharmony_ci * @bp: device handle 44798c2ecf20Sopenharmony_ci * @p: rss configuration 44808c2ecf20Sopenharmony_ci * 44818c2ecf20Sopenharmony_ci * sends on UPDATE ramrod for that matter. 44828c2ecf20Sopenharmony_ci */ 44838c2ecf20Sopenharmony_cistatic int bnx2x_setup_rss(struct bnx2x *bp, 44848c2ecf20Sopenharmony_ci struct bnx2x_config_rss_params *p) 44858c2ecf20Sopenharmony_ci{ 44868c2ecf20Sopenharmony_ci struct bnx2x_rss_config_obj *o = p->rss_obj; 44878c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 44888c2ecf20Sopenharmony_ci struct eth_rss_update_ramrod_data *data = 44898c2ecf20Sopenharmony_ci (struct eth_rss_update_ramrod_data *)(r->rdata); 44908c2ecf20Sopenharmony_ci u16 caps = 0; 44918c2ecf20Sopenharmony_ci u8 rss_mode = 0; 44928c2ecf20Sopenharmony_ci int rc; 44938c2ecf20Sopenharmony_ci 44948c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Configuring RSS\n"); 44978c2ecf20Sopenharmony_ci 44988c2ecf20Sopenharmony_ci /* Set an echo field */ 44998c2ecf20Sopenharmony_ci data->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) | 45008c2ecf20Sopenharmony_ci (r->state << BNX2X_SWCID_SHIFT)); 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci /* RSS mode */ 45038c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_MODE_DISABLED, &p->rss_flags)) 45048c2ecf20Sopenharmony_ci rss_mode = ETH_RSS_MODE_DISABLED; 45058c2ecf20Sopenharmony_ci else if (test_bit(BNX2X_RSS_MODE_REGULAR, &p->rss_flags)) 45068c2ecf20Sopenharmony_ci rss_mode = ETH_RSS_MODE_REGULAR; 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci data->rss_mode = rss_mode; 45098c2ecf20Sopenharmony_ci 45108c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "rss_mode=%d\n", rss_mode); 45118c2ecf20Sopenharmony_ci 45128c2ecf20Sopenharmony_ci /* RSS capabilities */ 45138c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV4, &p->rss_flags)) 45148c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY; 45158c2ecf20Sopenharmony_ci 45168c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV4_TCP, &p->rss_flags)) 45178c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY; 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags)) 45208c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY; 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags)) 45238c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY; 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV6_TCP, &p->rss_flags)) 45268c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY; 45278c2ecf20Sopenharmony_ci 45288c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags)) 45298c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY; 45308c2ecf20Sopenharmony_ci 45318c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV4_VXLAN, &p->rss_flags)) 45328c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY; 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_IPV6_VXLAN, &p->rss_flags)) 45358c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY; 45368c2ecf20Sopenharmony_ci 45378c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_TUNN_INNER_HDRS, &p->rss_flags)) 45388c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY; 45398c2ecf20Sopenharmony_ci 45408c2ecf20Sopenharmony_ci /* RSS keys */ 45418c2ecf20Sopenharmony_ci if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) { 45428c2ecf20Sopenharmony_ci u8 *dst = (u8 *)(data->rss_key) + sizeof(data->rss_key); 45438c2ecf20Sopenharmony_ci const u8 *src = (const u8 *)p->rss_key; 45448c2ecf20Sopenharmony_ci int i; 45458c2ecf20Sopenharmony_ci 45468c2ecf20Sopenharmony_ci /* Apparently, bnx2x reads this array in reverse order 45478c2ecf20Sopenharmony_ci * We need to byte swap rss_key to comply with Toeplitz specs. 45488c2ecf20Sopenharmony_ci */ 45498c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(data->rss_key); i++) 45508c2ecf20Sopenharmony_ci *--dst = *src++; 45518c2ecf20Sopenharmony_ci 45528c2ecf20Sopenharmony_ci caps |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY; 45538c2ecf20Sopenharmony_ci } 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci data->capabilities = cpu_to_le16(caps); 45568c2ecf20Sopenharmony_ci 45578c2ecf20Sopenharmony_ci /* Hashing mask */ 45588c2ecf20Sopenharmony_ci data->rss_result_mask = p->rss_result_mask; 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci /* RSS engine ID */ 45618c2ecf20Sopenharmony_ci data->rss_engine_id = o->engine_id; 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "rss_engine_id=%d\n", data->rss_engine_id); 45648c2ecf20Sopenharmony_ci 45658c2ecf20Sopenharmony_ci /* Indirection table */ 45668c2ecf20Sopenharmony_ci memcpy(data->indirection_table, p->ind_table, 45678c2ecf20Sopenharmony_ci T_ETH_INDIRECTION_TABLE_SIZE); 45688c2ecf20Sopenharmony_ci 45698c2ecf20Sopenharmony_ci /* Remember the last configuration */ 45708c2ecf20Sopenharmony_ci memcpy(o->ind_table, p->ind_table, T_ETH_INDIRECTION_TABLE_SIZE); 45718c2ecf20Sopenharmony_ci 45728c2ecf20Sopenharmony_ci /* Print the indirection table */ 45738c2ecf20Sopenharmony_ci if (netif_msg_ifup(bp)) 45748c2ecf20Sopenharmony_ci bnx2x_debug_print_ind_table(bp, p); 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 45778c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 45788c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 45798c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 45808c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 45818c2ecf20Sopenharmony_ci */ 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_ci /* Send a ramrod */ 45848c2ecf20Sopenharmony_ci rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_RSS_UPDATE, r->cid, 45858c2ecf20Sopenharmony_ci U64_HI(r->rdata_mapping), 45868c2ecf20Sopenharmony_ci U64_LO(r->rdata_mapping), 45878c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_ci if (rc < 0) 45908c2ecf20Sopenharmony_ci return rc; 45918c2ecf20Sopenharmony_ci 45928c2ecf20Sopenharmony_ci return 1; 45938c2ecf20Sopenharmony_ci} 45948c2ecf20Sopenharmony_ci 45958c2ecf20Sopenharmony_civoid bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj, 45968c2ecf20Sopenharmony_ci u8 *ind_table) 45978c2ecf20Sopenharmony_ci{ 45988c2ecf20Sopenharmony_ci memcpy(ind_table, rss_obj->ind_table, sizeof(rss_obj->ind_table)); 45998c2ecf20Sopenharmony_ci} 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_ciint bnx2x_config_rss(struct bnx2x *bp, 46028c2ecf20Sopenharmony_ci struct bnx2x_config_rss_params *p) 46038c2ecf20Sopenharmony_ci{ 46048c2ecf20Sopenharmony_ci int rc; 46058c2ecf20Sopenharmony_ci struct bnx2x_rss_config_obj *o = p->rss_obj; 46068c2ecf20Sopenharmony_ci struct bnx2x_raw_obj *r = &o->raw; 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_ci /* Do nothing if only driver cleanup was requested */ 46098c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) { 46108c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Not configuring RSS ramrod_flags=%lx\n", 46118c2ecf20Sopenharmony_ci p->ramrod_flags); 46128c2ecf20Sopenharmony_ci return 0; 46138c2ecf20Sopenharmony_ci } 46148c2ecf20Sopenharmony_ci 46158c2ecf20Sopenharmony_ci r->set_pending(r); 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ci rc = o->config_rss(bp, p); 46188c2ecf20Sopenharmony_ci if (rc < 0) { 46198c2ecf20Sopenharmony_ci r->clear_pending(r); 46208c2ecf20Sopenharmony_ci return rc; 46218c2ecf20Sopenharmony_ci } 46228c2ecf20Sopenharmony_ci 46238c2ecf20Sopenharmony_ci if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) 46248c2ecf20Sopenharmony_ci rc = r->wait_comp(bp, r); 46258c2ecf20Sopenharmony_ci 46268c2ecf20Sopenharmony_ci return rc; 46278c2ecf20Sopenharmony_ci} 46288c2ecf20Sopenharmony_ci 46298c2ecf20Sopenharmony_civoid bnx2x_init_rss_config_obj(struct bnx2x *bp, 46308c2ecf20Sopenharmony_ci struct bnx2x_rss_config_obj *rss_obj, 46318c2ecf20Sopenharmony_ci u8 cl_id, u32 cid, u8 func_id, u8 engine_id, 46328c2ecf20Sopenharmony_ci void *rdata, dma_addr_t rdata_mapping, 46338c2ecf20Sopenharmony_ci int state, unsigned long *pstate, 46348c2ecf20Sopenharmony_ci bnx2x_obj_type type) 46358c2ecf20Sopenharmony_ci{ 46368c2ecf20Sopenharmony_ci bnx2x_init_raw_obj(&rss_obj->raw, cl_id, cid, func_id, rdata, 46378c2ecf20Sopenharmony_ci rdata_mapping, state, pstate, type); 46388c2ecf20Sopenharmony_ci 46398c2ecf20Sopenharmony_ci rss_obj->engine_id = engine_id; 46408c2ecf20Sopenharmony_ci rss_obj->config_rss = bnx2x_setup_rss; 46418c2ecf20Sopenharmony_ci} 46428c2ecf20Sopenharmony_ci 46438c2ecf20Sopenharmony_ci/********************** Queue state object ***********************************/ 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_ci/** 46468c2ecf20Sopenharmony_ci * bnx2x_queue_state_change - perform Queue state change transition 46478c2ecf20Sopenharmony_ci * 46488c2ecf20Sopenharmony_ci * @bp: device handle 46498c2ecf20Sopenharmony_ci * @params: parameters to perform the transition 46508c2ecf20Sopenharmony_ci * 46518c2ecf20Sopenharmony_ci * returns 0 in case of successfully completed transition, negative error 46528c2ecf20Sopenharmony_ci * code in case of failure, positive (EBUSY) value if there is a completion 46538c2ecf20Sopenharmony_ci * to that is still pending (possible only if RAMROD_COMP_WAIT is 46548c2ecf20Sopenharmony_ci * not set in params->ramrod_flags for asynchronous commands). 46558c2ecf20Sopenharmony_ci * 46568c2ecf20Sopenharmony_ci */ 46578c2ecf20Sopenharmony_ciint bnx2x_queue_state_change(struct bnx2x *bp, 46588c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 46598c2ecf20Sopenharmony_ci{ 46608c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 46618c2ecf20Sopenharmony_ci int rc, pending_bit; 46628c2ecf20Sopenharmony_ci unsigned long *pending = &o->pending; 46638c2ecf20Sopenharmony_ci 46648c2ecf20Sopenharmony_ci /* Check that the requested transition is legal */ 46658c2ecf20Sopenharmony_ci rc = o->check_transition(bp, o, params); 46668c2ecf20Sopenharmony_ci if (rc) { 46678c2ecf20Sopenharmony_ci BNX2X_ERR("check transition returned an error. rc %d\n", rc); 46688c2ecf20Sopenharmony_ci return -EINVAL; 46698c2ecf20Sopenharmony_ci } 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci /* Set "pending" bit */ 46728c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "pending bit was=%lx\n", o->pending); 46738c2ecf20Sopenharmony_ci pending_bit = o->set_pending(o, params); 46748c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "pending bit now=%lx\n", o->pending); 46758c2ecf20Sopenharmony_ci 46768c2ecf20Sopenharmony_ci /* Don't send a command if only driver cleanup was requested */ 46778c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) 46788c2ecf20Sopenharmony_ci o->complete_cmd(bp, o, pending_bit); 46798c2ecf20Sopenharmony_ci else { 46808c2ecf20Sopenharmony_ci /* Send a ramrod */ 46818c2ecf20Sopenharmony_ci rc = o->send_cmd(bp, params); 46828c2ecf20Sopenharmony_ci if (rc) { 46838c2ecf20Sopenharmony_ci o->next_state = BNX2X_Q_STATE_MAX; 46848c2ecf20Sopenharmony_ci clear_bit(pending_bit, pending); 46858c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 46868c2ecf20Sopenharmony_ci return rc; 46878c2ecf20Sopenharmony_ci } 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci if (test_bit(RAMROD_COMP_WAIT, ¶ms->ramrod_flags)) { 46908c2ecf20Sopenharmony_ci rc = o->wait_comp(bp, o, pending_bit); 46918c2ecf20Sopenharmony_ci if (rc) 46928c2ecf20Sopenharmony_ci return rc; 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci return 0; 46958c2ecf20Sopenharmony_ci } 46968c2ecf20Sopenharmony_ci } 46978c2ecf20Sopenharmony_ci 46988c2ecf20Sopenharmony_ci return !!test_bit(pending_bit, pending); 46998c2ecf20Sopenharmony_ci} 47008c2ecf20Sopenharmony_ci 47018c2ecf20Sopenharmony_cistatic int bnx2x_queue_set_pending(struct bnx2x_queue_sp_obj *obj, 47028c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 47038c2ecf20Sopenharmony_ci{ 47048c2ecf20Sopenharmony_ci enum bnx2x_queue_cmd cmd = params->cmd, bit; 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci /* ACTIVATE and DEACTIVATE commands are implemented on top of 47078c2ecf20Sopenharmony_ci * UPDATE command. 47088c2ecf20Sopenharmony_ci */ 47098c2ecf20Sopenharmony_ci if ((cmd == BNX2X_Q_CMD_ACTIVATE) || 47108c2ecf20Sopenharmony_ci (cmd == BNX2X_Q_CMD_DEACTIVATE)) 47118c2ecf20Sopenharmony_ci bit = BNX2X_Q_CMD_UPDATE; 47128c2ecf20Sopenharmony_ci else 47138c2ecf20Sopenharmony_ci bit = cmd; 47148c2ecf20Sopenharmony_ci 47158c2ecf20Sopenharmony_ci set_bit(bit, &obj->pending); 47168c2ecf20Sopenharmony_ci return bit; 47178c2ecf20Sopenharmony_ci} 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_cistatic int bnx2x_queue_wait_comp(struct bnx2x *bp, 47208c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o, 47218c2ecf20Sopenharmony_ci enum bnx2x_queue_cmd cmd) 47228c2ecf20Sopenharmony_ci{ 47238c2ecf20Sopenharmony_ci return bnx2x_state_wait(bp, cmd, &o->pending); 47248c2ecf20Sopenharmony_ci} 47258c2ecf20Sopenharmony_ci 47268c2ecf20Sopenharmony_ci/** 47278c2ecf20Sopenharmony_ci * bnx2x_queue_comp_cmd - complete the state change command. 47288c2ecf20Sopenharmony_ci * 47298c2ecf20Sopenharmony_ci * @bp: device handle 47308c2ecf20Sopenharmony_ci * @o: queue info 47318c2ecf20Sopenharmony_ci * @cmd: command to exec 47328c2ecf20Sopenharmony_ci * 47338c2ecf20Sopenharmony_ci * Checks that the arrived completion is expected. 47348c2ecf20Sopenharmony_ci */ 47358c2ecf20Sopenharmony_cistatic int bnx2x_queue_comp_cmd(struct bnx2x *bp, 47368c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o, 47378c2ecf20Sopenharmony_ci enum bnx2x_queue_cmd cmd) 47388c2ecf20Sopenharmony_ci{ 47398c2ecf20Sopenharmony_ci unsigned long cur_pending = o->pending; 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci if (!test_and_clear_bit(cmd, &cur_pending)) { 47428c2ecf20Sopenharmony_ci BNX2X_ERR("Bad MC reply %d for queue %d in state %d pending 0x%lx, next_state %d\n", 47438c2ecf20Sopenharmony_ci cmd, o->cids[BNX2X_PRIMARY_CID_INDEX], 47448c2ecf20Sopenharmony_ci o->state, cur_pending, o->next_state); 47458c2ecf20Sopenharmony_ci return -EINVAL; 47468c2ecf20Sopenharmony_ci } 47478c2ecf20Sopenharmony_ci 47488c2ecf20Sopenharmony_ci if (o->next_tx_only >= o->max_cos) 47498c2ecf20Sopenharmony_ci /* >= because tx only must always be smaller than cos since the 47508c2ecf20Sopenharmony_ci * primary connection supports COS 0 47518c2ecf20Sopenharmony_ci */ 47528c2ecf20Sopenharmony_ci BNX2X_ERR("illegal value for next tx_only: %d. max cos was %d", 47538c2ecf20Sopenharmony_ci o->next_tx_only, o->max_cos); 47548c2ecf20Sopenharmony_ci 47558c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, 47568c2ecf20Sopenharmony_ci "Completing command %d for queue %d, setting state to %d\n", 47578c2ecf20Sopenharmony_ci cmd, o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_state); 47588c2ecf20Sopenharmony_ci 47598c2ecf20Sopenharmony_ci if (o->next_tx_only) /* print num tx-only if any exist */ 47608c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "primary cid %d: num tx-only cons %d\n", 47618c2ecf20Sopenharmony_ci o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_tx_only); 47628c2ecf20Sopenharmony_ci 47638c2ecf20Sopenharmony_ci o->state = o->next_state; 47648c2ecf20Sopenharmony_ci o->num_tx_only = o->next_tx_only; 47658c2ecf20Sopenharmony_ci o->next_state = BNX2X_Q_STATE_MAX; 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci /* It's important that o->state and o->next_state are 47688c2ecf20Sopenharmony_ci * updated before o->pending. 47698c2ecf20Sopenharmony_ci */ 47708c2ecf20Sopenharmony_ci wmb(); 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_ci clear_bit(cmd, &o->pending); 47738c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ci return 0; 47768c2ecf20Sopenharmony_ci} 47778c2ecf20Sopenharmony_ci 47788c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_setup_data_e2(struct bnx2x *bp, 47798c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *cmd_params, 47808c2ecf20Sopenharmony_ci struct client_init_ramrod_data *data) 47818c2ecf20Sopenharmony_ci{ 47828c2ecf20Sopenharmony_ci struct bnx2x_queue_setup_params *params = &cmd_params->params.setup; 47838c2ecf20Sopenharmony_ci 47848c2ecf20Sopenharmony_ci /* Rx data */ 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci /* IPv6 TPA supported for E2 and above only */ 47878c2ecf20Sopenharmony_ci data->rx.tpa_en |= test_bit(BNX2X_Q_FLG_TPA_IPV6, ¶ms->flags) * 47888c2ecf20Sopenharmony_ci CLIENT_INIT_RX_DATA_TPA_EN_IPV6; 47898c2ecf20Sopenharmony_ci} 47908c2ecf20Sopenharmony_ci 47918c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_init_general_data(struct bnx2x *bp, 47928c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o, 47938c2ecf20Sopenharmony_ci struct bnx2x_general_setup_params *params, 47948c2ecf20Sopenharmony_ci struct client_init_general_data *gen_data, 47958c2ecf20Sopenharmony_ci unsigned long *flags) 47968c2ecf20Sopenharmony_ci{ 47978c2ecf20Sopenharmony_ci gen_data->client_id = o->cl_id; 47988c2ecf20Sopenharmony_ci 47998c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_FLG_STATS, flags)) { 48008c2ecf20Sopenharmony_ci gen_data->statistics_counter_id = 48018c2ecf20Sopenharmony_ci params->stat_id; 48028c2ecf20Sopenharmony_ci gen_data->statistics_en_flg = 1; 48038c2ecf20Sopenharmony_ci gen_data->statistics_zero_flg = 48048c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_ZERO_STATS, flags); 48058c2ecf20Sopenharmony_ci } else 48068c2ecf20Sopenharmony_ci gen_data->statistics_counter_id = 48078c2ecf20Sopenharmony_ci DISABLE_STATISTIC_COUNTER_ID_VALUE; 48088c2ecf20Sopenharmony_ci 48098c2ecf20Sopenharmony_ci gen_data->is_fcoe_flg = test_bit(BNX2X_Q_FLG_FCOE, flags); 48108c2ecf20Sopenharmony_ci gen_data->activate_flg = test_bit(BNX2X_Q_FLG_ACTIVE, flags); 48118c2ecf20Sopenharmony_ci gen_data->sp_client_id = params->spcl_id; 48128c2ecf20Sopenharmony_ci gen_data->mtu = cpu_to_le16(params->mtu); 48138c2ecf20Sopenharmony_ci gen_data->func_id = o->func_id; 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci gen_data->cos = params->cos; 48168c2ecf20Sopenharmony_ci 48178c2ecf20Sopenharmony_ci gen_data->traffic_type = 48188c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_FCOE, flags) ? 48198c2ecf20Sopenharmony_ci LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW; 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci gen_data->fp_hsi_ver = params->fp_hsi; 48228c2ecf20Sopenharmony_ci 48238c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d\n", 48248c2ecf20Sopenharmony_ci gen_data->activate_flg, gen_data->cos, gen_data->statistics_en_flg); 48258c2ecf20Sopenharmony_ci} 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_init_tx_data(struct bnx2x_queue_sp_obj *o, 48288c2ecf20Sopenharmony_ci struct bnx2x_txq_setup_params *params, 48298c2ecf20Sopenharmony_ci struct client_init_tx_data *tx_data, 48308c2ecf20Sopenharmony_ci unsigned long *flags) 48318c2ecf20Sopenharmony_ci{ 48328c2ecf20Sopenharmony_ci tx_data->enforce_security_flg = 48338c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_TX_SEC, flags); 48348c2ecf20Sopenharmony_ci tx_data->default_vlan = 48358c2ecf20Sopenharmony_ci cpu_to_le16(params->default_vlan); 48368c2ecf20Sopenharmony_ci tx_data->default_vlan_flg = 48378c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_DEF_VLAN, flags); 48388c2ecf20Sopenharmony_ci tx_data->tx_switching_flg = 48398c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_TX_SWITCH, flags); 48408c2ecf20Sopenharmony_ci tx_data->anti_spoofing_flg = 48418c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_ANTI_SPOOF, flags); 48428c2ecf20Sopenharmony_ci tx_data->force_default_pri_flg = 48438c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_FORCE_DEFAULT_PRI, flags); 48448c2ecf20Sopenharmony_ci tx_data->refuse_outband_vlan_flg = 48458c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_REFUSE_OUTBAND_VLAN, flags); 48468c2ecf20Sopenharmony_ci tx_data->tunnel_lso_inc_ip_id = 48478c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, flags); 48488c2ecf20Sopenharmony_ci tx_data->tunnel_non_lso_pcsum_location = 48498c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? CSUM_ON_PKT : 48508c2ecf20Sopenharmony_ci CSUM_ON_BD; 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci tx_data->tx_status_block_id = params->fw_sb_id; 48538c2ecf20Sopenharmony_ci tx_data->tx_sb_index_number = params->sb_cq_index; 48548c2ecf20Sopenharmony_ci tx_data->tss_leading_client_id = params->tss_leading_cl_id; 48558c2ecf20Sopenharmony_ci 48568c2ecf20Sopenharmony_ci tx_data->tx_bd_page_base.lo = 48578c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(params->dscr_map)); 48588c2ecf20Sopenharmony_ci tx_data->tx_bd_page_base.hi = 48598c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(params->dscr_map)); 48608c2ecf20Sopenharmony_ci 48618c2ecf20Sopenharmony_ci /* Don't configure any Tx switching mode during queue SETUP */ 48628c2ecf20Sopenharmony_ci tx_data->state = 0; 48638c2ecf20Sopenharmony_ci} 48648c2ecf20Sopenharmony_ci 48658c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_init_pause_data(struct bnx2x_queue_sp_obj *o, 48668c2ecf20Sopenharmony_ci struct rxq_pause_params *params, 48678c2ecf20Sopenharmony_ci struct client_init_rx_data *rx_data) 48688c2ecf20Sopenharmony_ci{ 48698c2ecf20Sopenharmony_ci /* flow control data */ 48708c2ecf20Sopenharmony_ci rx_data->cqe_pause_thr_low = cpu_to_le16(params->rcq_th_lo); 48718c2ecf20Sopenharmony_ci rx_data->cqe_pause_thr_high = cpu_to_le16(params->rcq_th_hi); 48728c2ecf20Sopenharmony_ci rx_data->bd_pause_thr_low = cpu_to_le16(params->bd_th_lo); 48738c2ecf20Sopenharmony_ci rx_data->bd_pause_thr_high = cpu_to_le16(params->bd_th_hi); 48748c2ecf20Sopenharmony_ci rx_data->sge_pause_thr_low = cpu_to_le16(params->sge_th_lo); 48758c2ecf20Sopenharmony_ci rx_data->sge_pause_thr_high = cpu_to_le16(params->sge_th_hi); 48768c2ecf20Sopenharmony_ci rx_data->rx_cos_mask = cpu_to_le16(params->pri_map); 48778c2ecf20Sopenharmony_ci} 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_init_rx_data(struct bnx2x_queue_sp_obj *o, 48808c2ecf20Sopenharmony_ci struct bnx2x_rxq_setup_params *params, 48818c2ecf20Sopenharmony_ci struct client_init_rx_data *rx_data, 48828c2ecf20Sopenharmony_ci unsigned long *flags) 48838c2ecf20Sopenharmony_ci{ 48848c2ecf20Sopenharmony_ci rx_data->tpa_en = test_bit(BNX2X_Q_FLG_TPA, flags) * 48858c2ecf20Sopenharmony_ci CLIENT_INIT_RX_DATA_TPA_EN_IPV4; 48868c2ecf20Sopenharmony_ci rx_data->tpa_en |= test_bit(BNX2X_Q_FLG_TPA_GRO, flags) * 48878c2ecf20Sopenharmony_ci CLIENT_INIT_RX_DATA_TPA_MODE; 48888c2ecf20Sopenharmony_ci rx_data->vmqueue_mode_en_flg = 0; 48898c2ecf20Sopenharmony_ci 48908c2ecf20Sopenharmony_ci rx_data->cache_line_alignment_log_size = 48918c2ecf20Sopenharmony_ci params->cache_line_log; 48928c2ecf20Sopenharmony_ci rx_data->enable_dynamic_hc = 48938c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_DHC, flags); 48948c2ecf20Sopenharmony_ci rx_data->max_sges_for_packet = params->max_sges_pkt; 48958c2ecf20Sopenharmony_ci rx_data->client_qzone_id = params->cl_qzone_id; 48968c2ecf20Sopenharmony_ci rx_data->max_agg_size = cpu_to_le16(params->tpa_agg_sz); 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci /* Always start in DROP_ALL mode */ 48998c2ecf20Sopenharmony_ci rx_data->state = cpu_to_le16(CLIENT_INIT_RX_DATA_UCAST_DROP_ALL | 49008c2ecf20Sopenharmony_ci CLIENT_INIT_RX_DATA_MCAST_DROP_ALL); 49018c2ecf20Sopenharmony_ci 49028c2ecf20Sopenharmony_ci /* We don't set drop flags */ 49038c2ecf20Sopenharmony_ci rx_data->drop_ip_cs_err_flg = 0; 49048c2ecf20Sopenharmony_ci rx_data->drop_tcp_cs_err_flg = 0; 49058c2ecf20Sopenharmony_ci rx_data->drop_ttl0_flg = 0; 49068c2ecf20Sopenharmony_ci rx_data->drop_udp_cs_err_flg = 0; 49078c2ecf20Sopenharmony_ci rx_data->inner_vlan_removal_enable_flg = 49088c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_VLAN, flags); 49098c2ecf20Sopenharmony_ci rx_data->outer_vlan_removal_enable_flg = 49108c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_OV, flags); 49118c2ecf20Sopenharmony_ci rx_data->status_block_id = params->fw_sb_id; 49128c2ecf20Sopenharmony_ci rx_data->rx_sb_index_number = params->sb_cq_index; 49138c2ecf20Sopenharmony_ci rx_data->max_tpa_queues = params->max_tpa_queues; 49148c2ecf20Sopenharmony_ci rx_data->max_bytes_on_bd = cpu_to_le16(params->buf_sz); 49158c2ecf20Sopenharmony_ci rx_data->sge_buff_size = cpu_to_le16(params->sge_buf_sz); 49168c2ecf20Sopenharmony_ci rx_data->bd_page_base.lo = 49178c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(params->dscr_map)); 49188c2ecf20Sopenharmony_ci rx_data->bd_page_base.hi = 49198c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(params->dscr_map)); 49208c2ecf20Sopenharmony_ci rx_data->sge_page_base.lo = 49218c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(params->sge_map)); 49228c2ecf20Sopenharmony_ci rx_data->sge_page_base.hi = 49238c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(params->sge_map)); 49248c2ecf20Sopenharmony_ci rx_data->cqe_page_base.lo = 49258c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(params->rcq_map)); 49268c2ecf20Sopenharmony_ci rx_data->cqe_page_base.hi = 49278c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(params->rcq_map)); 49288c2ecf20Sopenharmony_ci rx_data->is_leading_rss = test_bit(BNX2X_Q_FLG_LEADING_RSS, flags); 49298c2ecf20Sopenharmony_ci 49308c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_FLG_MCAST, flags)) { 49318c2ecf20Sopenharmony_ci rx_data->approx_mcast_engine_id = params->mcast_engine_id; 49328c2ecf20Sopenharmony_ci rx_data->is_approx_mcast = 1; 49338c2ecf20Sopenharmony_ci } 49348c2ecf20Sopenharmony_ci 49358c2ecf20Sopenharmony_ci rx_data->rss_engine_id = params->rss_engine_id; 49368c2ecf20Sopenharmony_ci 49378c2ecf20Sopenharmony_ci /* silent vlan removal */ 49388c2ecf20Sopenharmony_ci rx_data->silent_vlan_removal_flg = 49398c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_SILENT_VLAN_REM, flags); 49408c2ecf20Sopenharmony_ci rx_data->silent_vlan_value = 49418c2ecf20Sopenharmony_ci cpu_to_le16(params->silent_removal_value); 49428c2ecf20Sopenharmony_ci rx_data->silent_vlan_mask = 49438c2ecf20Sopenharmony_ci cpu_to_le16(params->silent_removal_mask); 49448c2ecf20Sopenharmony_ci} 49458c2ecf20Sopenharmony_ci 49468c2ecf20Sopenharmony_ci/* initialize the general, tx and rx parts of a queue object */ 49478c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_setup_data_cmn(struct bnx2x *bp, 49488c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *cmd_params, 49498c2ecf20Sopenharmony_ci struct client_init_ramrod_data *data) 49508c2ecf20Sopenharmony_ci{ 49518c2ecf20Sopenharmony_ci bnx2x_q_fill_init_general_data(bp, cmd_params->q_obj, 49528c2ecf20Sopenharmony_ci &cmd_params->params.setup.gen_params, 49538c2ecf20Sopenharmony_ci &data->general, 49548c2ecf20Sopenharmony_ci &cmd_params->params.setup.flags); 49558c2ecf20Sopenharmony_ci 49568c2ecf20Sopenharmony_ci bnx2x_q_fill_init_tx_data(cmd_params->q_obj, 49578c2ecf20Sopenharmony_ci &cmd_params->params.setup.txq_params, 49588c2ecf20Sopenharmony_ci &data->tx, 49598c2ecf20Sopenharmony_ci &cmd_params->params.setup.flags); 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci bnx2x_q_fill_init_rx_data(cmd_params->q_obj, 49628c2ecf20Sopenharmony_ci &cmd_params->params.setup.rxq_params, 49638c2ecf20Sopenharmony_ci &data->rx, 49648c2ecf20Sopenharmony_ci &cmd_params->params.setup.flags); 49658c2ecf20Sopenharmony_ci 49668c2ecf20Sopenharmony_ci bnx2x_q_fill_init_pause_data(cmd_params->q_obj, 49678c2ecf20Sopenharmony_ci &cmd_params->params.setup.pause_params, 49688c2ecf20Sopenharmony_ci &data->rx); 49698c2ecf20Sopenharmony_ci} 49708c2ecf20Sopenharmony_ci 49718c2ecf20Sopenharmony_ci/* initialize the general and tx parts of a tx-only queue object */ 49728c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_setup_tx_only(struct bnx2x *bp, 49738c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *cmd_params, 49748c2ecf20Sopenharmony_ci struct tx_queue_init_ramrod_data *data) 49758c2ecf20Sopenharmony_ci{ 49768c2ecf20Sopenharmony_ci bnx2x_q_fill_init_general_data(bp, cmd_params->q_obj, 49778c2ecf20Sopenharmony_ci &cmd_params->params.tx_only.gen_params, 49788c2ecf20Sopenharmony_ci &data->general, 49798c2ecf20Sopenharmony_ci &cmd_params->params.tx_only.flags); 49808c2ecf20Sopenharmony_ci 49818c2ecf20Sopenharmony_ci bnx2x_q_fill_init_tx_data(cmd_params->q_obj, 49828c2ecf20Sopenharmony_ci &cmd_params->params.tx_only.txq_params, 49838c2ecf20Sopenharmony_ci &data->tx, 49848c2ecf20Sopenharmony_ci &cmd_params->params.tx_only.flags); 49858c2ecf20Sopenharmony_ci 49868c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "cid %d, tx bd page lo %x hi %x", 49878c2ecf20Sopenharmony_ci cmd_params->q_obj->cids[0], 49888c2ecf20Sopenharmony_ci data->tx.tx_bd_page_base.lo, 49898c2ecf20Sopenharmony_ci data->tx.tx_bd_page_base.hi); 49908c2ecf20Sopenharmony_ci} 49918c2ecf20Sopenharmony_ci 49928c2ecf20Sopenharmony_ci/** 49938c2ecf20Sopenharmony_ci * bnx2x_q_init - init HW/FW queue 49948c2ecf20Sopenharmony_ci * 49958c2ecf20Sopenharmony_ci * @bp: device handle 49968c2ecf20Sopenharmony_ci * @params: 49978c2ecf20Sopenharmony_ci * 49988c2ecf20Sopenharmony_ci * HW/FW initial Queue configuration: 49998c2ecf20Sopenharmony_ci * - HC: Rx and Tx 50008c2ecf20Sopenharmony_ci * - CDU context validation 50018c2ecf20Sopenharmony_ci * 50028c2ecf20Sopenharmony_ci */ 50038c2ecf20Sopenharmony_cistatic inline int bnx2x_q_init(struct bnx2x *bp, 50048c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 50058c2ecf20Sopenharmony_ci{ 50068c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 50078c2ecf20Sopenharmony_ci struct bnx2x_queue_init_params *init = ¶ms->params.init; 50088c2ecf20Sopenharmony_ci u16 hc_usec; 50098c2ecf20Sopenharmony_ci u8 cos; 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci /* Tx HC configuration */ 50128c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_TYPE_HAS_TX, &o->type) && 50138c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_HC, &init->tx.flags)) { 50148c2ecf20Sopenharmony_ci hc_usec = init->tx.hc_rate ? 1000000 / init->tx.hc_rate : 0; 50158c2ecf20Sopenharmony_ci 50168c2ecf20Sopenharmony_ci bnx2x_update_coalesce_sb_index(bp, init->tx.fw_sb_id, 50178c2ecf20Sopenharmony_ci init->tx.sb_cq_index, 50188c2ecf20Sopenharmony_ci !test_bit(BNX2X_Q_FLG_HC_EN, &init->tx.flags), 50198c2ecf20Sopenharmony_ci hc_usec); 50208c2ecf20Sopenharmony_ci } 50218c2ecf20Sopenharmony_ci 50228c2ecf20Sopenharmony_ci /* Rx HC configuration */ 50238c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_TYPE_HAS_RX, &o->type) && 50248c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_FLG_HC, &init->rx.flags)) { 50258c2ecf20Sopenharmony_ci hc_usec = init->rx.hc_rate ? 1000000 / init->rx.hc_rate : 0; 50268c2ecf20Sopenharmony_ci 50278c2ecf20Sopenharmony_ci bnx2x_update_coalesce_sb_index(bp, init->rx.fw_sb_id, 50288c2ecf20Sopenharmony_ci init->rx.sb_cq_index, 50298c2ecf20Sopenharmony_ci !test_bit(BNX2X_Q_FLG_HC_EN, &init->rx.flags), 50308c2ecf20Sopenharmony_ci hc_usec); 50318c2ecf20Sopenharmony_ci } 50328c2ecf20Sopenharmony_ci 50338c2ecf20Sopenharmony_ci /* Set CDU context validation values */ 50348c2ecf20Sopenharmony_ci for (cos = 0; cos < o->max_cos; cos++) { 50358c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "setting context validation. cid %d, cos %d\n", 50368c2ecf20Sopenharmony_ci o->cids[cos], cos); 50378c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "context pointer %p\n", init->cxts[cos]); 50388c2ecf20Sopenharmony_ci bnx2x_set_ctx_validation(bp, init->cxts[cos], o->cids[cos]); 50398c2ecf20Sopenharmony_ci } 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci /* As no ramrod is sent, complete the command immediately */ 50428c2ecf20Sopenharmony_ci o->complete_cmd(bp, o, BNX2X_Q_CMD_INIT); 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci smp_mb(); 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci return 0; 50478c2ecf20Sopenharmony_ci} 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp, 50508c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 50518c2ecf20Sopenharmony_ci{ 50528c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 50538c2ecf20Sopenharmony_ci struct client_init_ramrod_data *rdata = 50548c2ecf20Sopenharmony_ci (struct client_init_ramrod_data *)o->rdata; 50558c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 50568c2ecf20Sopenharmony_ci int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP; 50578c2ecf20Sopenharmony_ci 50588c2ecf20Sopenharmony_ci /* Clear the ramrod data */ 50598c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 50608c2ecf20Sopenharmony_ci 50618c2ecf20Sopenharmony_ci /* Fill the ramrod data */ 50628c2ecf20Sopenharmony_ci bnx2x_q_fill_setup_data_cmn(bp, params, rdata); 50638c2ecf20Sopenharmony_ci 50648c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 50658c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 50668c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 50678c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 50688c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 50698c2ecf20Sopenharmony_ci */ 50708c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX], 50718c2ecf20Sopenharmony_ci U64_HI(data_mapping), 50728c2ecf20Sopenharmony_ci U64_LO(data_mapping), ETH_CONNECTION_TYPE); 50738c2ecf20Sopenharmony_ci} 50748c2ecf20Sopenharmony_ci 50758c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_setup_e2(struct bnx2x *bp, 50768c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 50778c2ecf20Sopenharmony_ci{ 50788c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 50798c2ecf20Sopenharmony_ci struct client_init_ramrod_data *rdata = 50808c2ecf20Sopenharmony_ci (struct client_init_ramrod_data *)o->rdata; 50818c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 50828c2ecf20Sopenharmony_ci int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP; 50838c2ecf20Sopenharmony_ci 50848c2ecf20Sopenharmony_ci /* Clear the ramrod data */ 50858c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 50868c2ecf20Sopenharmony_ci 50878c2ecf20Sopenharmony_ci /* Fill the ramrod data */ 50888c2ecf20Sopenharmony_ci bnx2x_q_fill_setup_data_cmn(bp, params, rdata); 50898c2ecf20Sopenharmony_ci bnx2x_q_fill_setup_data_e2(bp, params, rdata); 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 50928c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 50938c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 50948c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 50958c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 50968c2ecf20Sopenharmony_ci */ 50978c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX], 50988c2ecf20Sopenharmony_ci U64_HI(data_mapping), 50998c2ecf20Sopenharmony_ci U64_LO(data_mapping), ETH_CONNECTION_TYPE); 51008c2ecf20Sopenharmony_ci} 51018c2ecf20Sopenharmony_ci 51028c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp, 51038c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 51048c2ecf20Sopenharmony_ci{ 51058c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 51068c2ecf20Sopenharmony_ci struct tx_queue_init_ramrod_data *rdata = 51078c2ecf20Sopenharmony_ci (struct tx_queue_init_ramrod_data *)o->rdata; 51088c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 51098c2ecf20Sopenharmony_ci int ramrod = RAMROD_CMD_ID_ETH_TX_QUEUE_SETUP; 51108c2ecf20Sopenharmony_ci struct bnx2x_queue_setup_tx_only_params *tx_only_params = 51118c2ecf20Sopenharmony_ci ¶ms->params.tx_only; 51128c2ecf20Sopenharmony_ci u8 cid_index = tx_only_params->cid_index; 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ci if (cid_index >= o->max_cos) { 51158c2ecf20Sopenharmony_ci BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", 51168c2ecf20Sopenharmony_ci o->cl_id, cid_index); 51178c2ecf20Sopenharmony_ci return -EINVAL; 51188c2ecf20Sopenharmony_ci } 51198c2ecf20Sopenharmony_ci 51208c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "parameters received: cos: %d sp-id: %d\n", 51218c2ecf20Sopenharmony_ci tx_only_params->gen_params.cos, 51228c2ecf20Sopenharmony_ci tx_only_params->gen_params.spcl_id); 51238c2ecf20Sopenharmony_ci 51248c2ecf20Sopenharmony_ci /* Clear the ramrod data */ 51258c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci /* Fill the ramrod data */ 51288c2ecf20Sopenharmony_ci bnx2x_q_fill_setup_tx_only(bp, params, rdata); 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "sending tx-only ramrod: cid %d, client-id %d, sp-client id %d, cos %d\n", 51318c2ecf20Sopenharmony_ci o->cids[cid_index], rdata->general.client_id, 51328c2ecf20Sopenharmony_ci rdata->general.sp_client_id, rdata->general.cos); 51338c2ecf20Sopenharmony_ci 51348c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 51358c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 51368c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 51378c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 51388c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 51398c2ecf20Sopenharmony_ci */ 51408c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, ramrod, o->cids[cid_index], 51418c2ecf20Sopenharmony_ci U64_HI(data_mapping), 51428c2ecf20Sopenharmony_ci U64_LO(data_mapping), ETH_CONNECTION_TYPE); 51438c2ecf20Sopenharmony_ci} 51448c2ecf20Sopenharmony_ci 51458c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_update_data(struct bnx2x *bp, 51468c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *obj, 51478c2ecf20Sopenharmony_ci struct bnx2x_queue_update_params *params, 51488c2ecf20Sopenharmony_ci struct client_update_ramrod_data *data) 51498c2ecf20Sopenharmony_ci{ 51508c2ecf20Sopenharmony_ci /* Client ID of the client to update */ 51518c2ecf20Sopenharmony_ci data->client_id = obj->cl_id; 51528c2ecf20Sopenharmony_ci 51538c2ecf20Sopenharmony_ci /* Function ID of the client to update */ 51548c2ecf20Sopenharmony_ci data->func_id = obj->func_id; 51558c2ecf20Sopenharmony_ci 51568c2ecf20Sopenharmony_ci /* Default VLAN value */ 51578c2ecf20Sopenharmony_ci data->default_vlan = cpu_to_le16(params->def_vlan); 51588c2ecf20Sopenharmony_ci 51598c2ecf20Sopenharmony_ci /* Inner VLAN stripping */ 51608c2ecf20Sopenharmony_ci data->inner_vlan_removal_enable_flg = 51618c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM, ¶ms->update_flags); 51628c2ecf20Sopenharmony_ci data->inner_vlan_removal_change_flg = 51638c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM_CHNG, 51648c2ecf20Sopenharmony_ci ¶ms->update_flags); 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci /* Outer VLAN stripping */ 51678c2ecf20Sopenharmony_ci data->outer_vlan_removal_enable_flg = 51688c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM, ¶ms->update_flags); 51698c2ecf20Sopenharmony_ci data->outer_vlan_removal_change_flg = 51708c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM_CHNG, 51718c2ecf20Sopenharmony_ci ¶ms->update_flags); 51728c2ecf20Sopenharmony_ci 51738c2ecf20Sopenharmony_ci /* Drop packets that have source MAC that doesn't belong to this 51748c2ecf20Sopenharmony_ci * Queue. 51758c2ecf20Sopenharmony_ci */ 51768c2ecf20Sopenharmony_ci data->anti_spoofing_enable_flg = 51778c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF, ¶ms->update_flags); 51788c2ecf20Sopenharmony_ci data->anti_spoofing_change_flg = 51798c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG, ¶ms->update_flags); 51808c2ecf20Sopenharmony_ci 51818c2ecf20Sopenharmony_ci /* Activate/Deactivate */ 51828c2ecf20Sopenharmony_ci data->activate_flg = 51838c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ACTIVATE, ¶ms->update_flags); 51848c2ecf20Sopenharmony_ci data->activate_change_flg = 51858c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, ¶ms->update_flags); 51868c2ecf20Sopenharmony_ci 51878c2ecf20Sopenharmony_ci /* Enable default VLAN */ 51888c2ecf20Sopenharmony_ci data->default_vlan_enable_flg = 51898c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, ¶ms->update_flags); 51908c2ecf20Sopenharmony_ci data->default_vlan_change_flg = 51918c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, 51928c2ecf20Sopenharmony_ci ¶ms->update_flags); 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci /* silent vlan removal */ 51958c2ecf20Sopenharmony_ci data->silent_vlan_change_flg = 51968c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, 51978c2ecf20Sopenharmony_ci ¶ms->update_flags); 51988c2ecf20Sopenharmony_ci data->silent_vlan_removal_flg = 51998c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, ¶ms->update_flags); 52008c2ecf20Sopenharmony_ci data->silent_vlan_value = cpu_to_le16(params->silent_removal_value); 52018c2ecf20Sopenharmony_ci data->silent_vlan_mask = cpu_to_le16(params->silent_removal_mask); 52028c2ecf20Sopenharmony_ci 52038c2ecf20Sopenharmony_ci /* tx switching */ 52048c2ecf20Sopenharmony_ci data->tx_switching_flg = 52058c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_TX_SWITCHING, ¶ms->update_flags); 52068c2ecf20Sopenharmony_ci data->tx_switching_change_flg = 52078c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG, 52088c2ecf20Sopenharmony_ci ¶ms->update_flags); 52098c2ecf20Sopenharmony_ci 52108c2ecf20Sopenharmony_ci /* PTP */ 52118c2ecf20Sopenharmony_ci data->handle_ptp_pkts_flg = 52128c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_PTP_PKTS, ¶ms->update_flags); 52138c2ecf20Sopenharmony_ci data->handle_ptp_pkts_change_flg = 52148c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG, ¶ms->update_flags); 52158c2ecf20Sopenharmony_ci} 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_update(struct bnx2x *bp, 52188c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 52198c2ecf20Sopenharmony_ci{ 52208c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 52218c2ecf20Sopenharmony_ci struct client_update_ramrod_data *rdata = 52228c2ecf20Sopenharmony_ci (struct client_update_ramrod_data *)o->rdata; 52238c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 52248c2ecf20Sopenharmony_ci struct bnx2x_queue_update_params *update_params = 52258c2ecf20Sopenharmony_ci ¶ms->params.update; 52268c2ecf20Sopenharmony_ci u8 cid_index = update_params->cid_index; 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci if (cid_index >= o->max_cos) { 52298c2ecf20Sopenharmony_ci BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", 52308c2ecf20Sopenharmony_ci o->cl_id, cid_index); 52318c2ecf20Sopenharmony_ci return -EINVAL; 52328c2ecf20Sopenharmony_ci } 52338c2ecf20Sopenharmony_ci 52348c2ecf20Sopenharmony_ci /* Clear the ramrod data */ 52358c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 52368c2ecf20Sopenharmony_ci 52378c2ecf20Sopenharmony_ci /* Fill the ramrod data */ 52388c2ecf20Sopenharmony_ci bnx2x_q_fill_update_data(bp, o, update_params, rdata); 52398c2ecf20Sopenharmony_ci 52408c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 52418c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 52428c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 52438c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 52448c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 52458c2ecf20Sopenharmony_ci */ 52468c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE, 52478c2ecf20Sopenharmony_ci o->cids[cid_index], U64_HI(data_mapping), 52488c2ecf20Sopenharmony_ci U64_LO(data_mapping), ETH_CONNECTION_TYPE); 52498c2ecf20Sopenharmony_ci} 52508c2ecf20Sopenharmony_ci 52518c2ecf20Sopenharmony_ci/** 52528c2ecf20Sopenharmony_ci * bnx2x_q_send_deactivate - send DEACTIVATE command 52538c2ecf20Sopenharmony_ci * 52548c2ecf20Sopenharmony_ci * @bp: device handle 52558c2ecf20Sopenharmony_ci * @params: 52568c2ecf20Sopenharmony_ci * 52578c2ecf20Sopenharmony_ci * implemented using the UPDATE command. 52588c2ecf20Sopenharmony_ci */ 52598c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_deactivate(struct bnx2x *bp, 52608c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 52618c2ecf20Sopenharmony_ci{ 52628c2ecf20Sopenharmony_ci struct bnx2x_queue_update_params *update = ¶ms->params.update; 52638c2ecf20Sopenharmony_ci 52648c2ecf20Sopenharmony_ci memset(update, 0, sizeof(*update)); 52658c2ecf20Sopenharmony_ci 52668c2ecf20Sopenharmony_ci __set_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &update->update_flags); 52678c2ecf20Sopenharmony_ci 52688c2ecf20Sopenharmony_ci return bnx2x_q_send_update(bp, params); 52698c2ecf20Sopenharmony_ci} 52708c2ecf20Sopenharmony_ci 52718c2ecf20Sopenharmony_ci/** 52728c2ecf20Sopenharmony_ci * bnx2x_q_send_activate - send ACTIVATE command 52738c2ecf20Sopenharmony_ci * 52748c2ecf20Sopenharmony_ci * @bp: device handle 52758c2ecf20Sopenharmony_ci * @params: 52768c2ecf20Sopenharmony_ci * 52778c2ecf20Sopenharmony_ci * implemented using the UPDATE command. 52788c2ecf20Sopenharmony_ci */ 52798c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_activate(struct bnx2x *bp, 52808c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 52818c2ecf20Sopenharmony_ci{ 52828c2ecf20Sopenharmony_ci struct bnx2x_queue_update_params *update = ¶ms->params.update; 52838c2ecf20Sopenharmony_ci 52848c2ecf20Sopenharmony_ci memset(update, 0, sizeof(*update)); 52858c2ecf20Sopenharmony_ci 52868c2ecf20Sopenharmony_ci __set_bit(BNX2X_Q_UPDATE_ACTIVATE, &update->update_flags); 52878c2ecf20Sopenharmony_ci __set_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &update->update_flags); 52888c2ecf20Sopenharmony_ci 52898c2ecf20Sopenharmony_ci return bnx2x_q_send_update(bp, params); 52908c2ecf20Sopenharmony_ci} 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_cistatic void bnx2x_q_fill_update_tpa_data(struct bnx2x *bp, 52938c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *obj, 52948c2ecf20Sopenharmony_ci struct bnx2x_queue_update_tpa_params *params, 52958c2ecf20Sopenharmony_ci struct tpa_update_ramrod_data *data) 52968c2ecf20Sopenharmony_ci{ 52978c2ecf20Sopenharmony_ci data->client_id = obj->cl_id; 52988c2ecf20Sopenharmony_ci data->complete_on_both_clients = params->complete_on_both_clients; 52998c2ecf20Sopenharmony_ci data->dont_verify_rings_pause_thr_flg = 53008c2ecf20Sopenharmony_ci params->dont_verify_thr; 53018c2ecf20Sopenharmony_ci data->max_agg_size = cpu_to_le16(params->max_agg_sz); 53028c2ecf20Sopenharmony_ci data->max_sges_for_packet = params->max_sges_pkt; 53038c2ecf20Sopenharmony_ci data->max_tpa_queues = params->max_tpa_queues; 53048c2ecf20Sopenharmony_ci data->sge_buff_size = cpu_to_le16(params->sge_buff_sz); 53058c2ecf20Sopenharmony_ci data->sge_page_base_hi = cpu_to_le32(U64_HI(params->sge_map)); 53068c2ecf20Sopenharmony_ci data->sge_page_base_lo = cpu_to_le32(U64_LO(params->sge_map)); 53078c2ecf20Sopenharmony_ci data->sge_pause_thr_high = cpu_to_le16(params->sge_pause_thr_high); 53088c2ecf20Sopenharmony_ci data->sge_pause_thr_low = cpu_to_le16(params->sge_pause_thr_low); 53098c2ecf20Sopenharmony_ci data->tpa_mode = params->tpa_mode; 53108c2ecf20Sopenharmony_ci data->update_ipv4 = params->update_ipv4; 53118c2ecf20Sopenharmony_ci data->update_ipv6 = params->update_ipv6; 53128c2ecf20Sopenharmony_ci} 53138c2ecf20Sopenharmony_ci 53148c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_update_tpa(struct bnx2x *bp, 53158c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 53168c2ecf20Sopenharmony_ci{ 53178c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 53188c2ecf20Sopenharmony_ci struct tpa_update_ramrod_data *rdata = 53198c2ecf20Sopenharmony_ci (struct tpa_update_ramrod_data *)o->rdata; 53208c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 53218c2ecf20Sopenharmony_ci struct bnx2x_queue_update_tpa_params *update_tpa_params = 53228c2ecf20Sopenharmony_ci ¶ms->params.update_tpa; 53238c2ecf20Sopenharmony_ci u16 type; 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci /* Clear the ramrod data */ 53268c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 53278c2ecf20Sopenharmony_ci 53288c2ecf20Sopenharmony_ci /* Fill the ramrod data */ 53298c2ecf20Sopenharmony_ci bnx2x_q_fill_update_tpa_data(bp, o, update_tpa_params, rdata); 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci /* Add the function id inside the type, so that sp post function 53328c2ecf20Sopenharmony_ci * doesn't automatically add the PF func-id, this is required 53338c2ecf20Sopenharmony_ci * for operations done by PFs on behalf of their VFs 53348c2ecf20Sopenharmony_ci */ 53358c2ecf20Sopenharmony_ci type = ETH_CONNECTION_TYPE | 53368c2ecf20Sopenharmony_ci ((o->func_id) << SPE_HDR_FUNCTION_ID_SHIFT); 53378c2ecf20Sopenharmony_ci 53388c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 53398c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 53408c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 53418c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 53428c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 53438c2ecf20Sopenharmony_ci */ 53448c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TPA_UPDATE, 53458c2ecf20Sopenharmony_ci o->cids[BNX2X_PRIMARY_CID_INDEX], 53468c2ecf20Sopenharmony_ci U64_HI(data_mapping), 53478c2ecf20Sopenharmony_ci U64_LO(data_mapping), type); 53488c2ecf20Sopenharmony_ci} 53498c2ecf20Sopenharmony_ci 53508c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_halt(struct bnx2x *bp, 53518c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 53528c2ecf20Sopenharmony_ci{ 53538c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 53568c2ecf20Sopenharmony_ci o->cids[BNX2X_PRIMARY_CID_INDEX], 0, o->cl_id, 53578c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 53588c2ecf20Sopenharmony_ci} 53598c2ecf20Sopenharmony_ci 53608c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_cfc_del(struct bnx2x *bp, 53618c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 53628c2ecf20Sopenharmony_ci{ 53638c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 53648c2ecf20Sopenharmony_ci u8 cid_idx = params->params.cfc_del.cid_index; 53658c2ecf20Sopenharmony_ci 53668c2ecf20Sopenharmony_ci if (cid_idx >= o->max_cos) { 53678c2ecf20Sopenharmony_ci BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", 53688c2ecf20Sopenharmony_ci o->cl_id, cid_idx); 53698c2ecf20Sopenharmony_ci return -EINVAL; 53708c2ecf20Sopenharmony_ci } 53718c2ecf20Sopenharmony_ci 53728c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_CFC_DEL, 53738c2ecf20Sopenharmony_ci o->cids[cid_idx], 0, 0, NONE_CONNECTION_TYPE); 53748c2ecf20Sopenharmony_ci} 53758c2ecf20Sopenharmony_ci 53768c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_terminate(struct bnx2x *bp, 53778c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 53788c2ecf20Sopenharmony_ci{ 53798c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 53808c2ecf20Sopenharmony_ci u8 cid_index = params->params.terminate.cid_index; 53818c2ecf20Sopenharmony_ci 53828c2ecf20Sopenharmony_ci if (cid_index >= o->max_cos) { 53838c2ecf20Sopenharmony_ci BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", 53848c2ecf20Sopenharmony_ci o->cl_id, cid_index); 53858c2ecf20Sopenharmony_ci return -EINVAL; 53868c2ecf20Sopenharmony_ci } 53878c2ecf20Sopenharmony_ci 53888c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TERMINATE, 53898c2ecf20Sopenharmony_ci o->cids[cid_index], 0, 0, ETH_CONNECTION_TYPE); 53908c2ecf20Sopenharmony_ci} 53918c2ecf20Sopenharmony_ci 53928c2ecf20Sopenharmony_cistatic inline int bnx2x_q_send_empty(struct bnx2x *bp, 53938c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 53948c2ecf20Sopenharmony_ci{ 53958c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o = params->q_obj; 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_EMPTY, 53988c2ecf20Sopenharmony_ci o->cids[BNX2X_PRIMARY_CID_INDEX], 0, 0, 53998c2ecf20Sopenharmony_ci ETH_CONNECTION_TYPE); 54008c2ecf20Sopenharmony_ci} 54018c2ecf20Sopenharmony_ci 54028c2ecf20Sopenharmony_cistatic inline int bnx2x_queue_send_cmd_cmn(struct bnx2x *bp, 54038c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 54048c2ecf20Sopenharmony_ci{ 54058c2ecf20Sopenharmony_ci switch (params->cmd) { 54068c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_INIT: 54078c2ecf20Sopenharmony_ci return bnx2x_q_init(bp, params); 54088c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_SETUP_TX_ONLY: 54098c2ecf20Sopenharmony_ci return bnx2x_q_send_setup_tx_only(bp, params); 54108c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_DEACTIVATE: 54118c2ecf20Sopenharmony_ci return bnx2x_q_send_deactivate(bp, params); 54128c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_ACTIVATE: 54138c2ecf20Sopenharmony_ci return bnx2x_q_send_activate(bp, params); 54148c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_UPDATE: 54158c2ecf20Sopenharmony_ci return bnx2x_q_send_update(bp, params); 54168c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_UPDATE_TPA: 54178c2ecf20Sopenharmony_ci return bnx2x_q_send_update_tpa(bp, params); 54188c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_HALT: 54198c2ecf20Sopenharmony_ci return bnx2x_q_send_halt(bp, params); 54208c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_CFC_DEL: 54218c2ecf20Sopenharmony_ci return bnx2x_q_send_cfc_del(bp, params); 54228c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_TERMINATE: 54238c2ecf20Sopenharmony_ci return bnx2x_q_send_terminate(bp, params); 54248c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_EMPTY: 54258c2ecf20Sopenharmony_ci return bnx2x_q_send_empty(bp, params); 54268c2ecf20Sopenharmony_ci default: 54278c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", params->cmd); 54288c2ecf20Sopenharmony_ci return -EINVAL; 54298c2ecf20Sopenharmony_ci } 54308c2ecf20Sopenharmony_ci} 54318c2ecf20Sopenharmony_ci 54328c2ecf20Sopenharmony_cistatic int bnx2x_queue_send_cmd_e1x(struct bnx2x *bp, 54338c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 54348c2ecf20Sopenharmony_ci{ 54358c2ecf20Sopenharmony_ci switch (params->cmd) { 54368c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_SETUP: 54378c2ecf20Sopenharmony_ci return bnx2x_q_send_setup_e1x(bp, params); 54388c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_INIT: 54398c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_SETUP_TX_ONLY: 54408c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_DEACTIVATE: 54418c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_ACTIVATE: 54428c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_UPDATE: 54438c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_UPDATE_TPA: 54448c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_HALT: 54458c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_CFC_DEL: 54468c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_TERMINATE: 54478c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_EMPTY: 54488c2ecf20Sopenharmony_ci return bnx2x_queue_send_cmd_cmn(bp, params); 54498c2ecf20Sopenharmony_ci default: 54508c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", params->cmd); 54518c2ecf20Sopenharmony_ci return -EINVAL; 54528c2ecf20Sopenharmony_ci } 54538c2ecf20Sopenharmony_ci} 54548c2ecf20Sopenharmony_ci 54558c2ecf20Sopenharmony_cistatic int bnx2x_queue_send_cmd_e2(struct bnx2x *bp, 54568c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 54578c2ecf20Sopenharmony_ci{ 54588c2ecf20Sopenharmony_ci switch (params->cmd) { 54598c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_SETUP: 54608c2ecf20Sopenharmony_ci return bnx2x_q_send_setup_e2(bp, params); 54618c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_INIT: 54628c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_SETUP_TX_ONLY: 54638c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_DEACTIVATE: 54648c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_ACTIVATE: 54658c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_UPDATE: 54668c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_UPDATE_TPA: 54678c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_HALT: 54688c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_CFC_DEL: 54698c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_TERMINATE: 54708c2ecf20Sopenharmony_ci case BNX2X_Q_CMD_EMPTY: 54718c2ecf20Sopenharmony_ci return bnx2x_queue_send_cmd_cmn(bp, params); 54728c2ecf20Sopenharmony_ci default: 54738c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", params->cmd); 54748c2ecf20Sopenharmony_ci return -EINVAL; 54758c2ecf20Sopenharmony_ci } 54768c2ecf20Sopenharmony_ci} 54778c2ecf20Sopenharmony_ci 54788c2ecf20Sopenharmony_ci/** 54798c2ecf20Sopenharmony_ci * bnx2x_queue_chk_transition - check state machine of a regular Queue 54808c2ecf20Sopenharmony_ci * 54818c2ecf20Sopenharmony_ci * @bp: device handle 54828c2ecf20Sopenharmony_ci * @o: queue info 54838c2ecf20Sopenharmony_ci * @params: queue state 54848c2ecf20Sopenharmony_ci * 54858c2ecf20Sopenharmony_ci * (not Forwarding) 54868c2ecf20Sopenharmony_ci * It both checks if the requested command is legal in a current 54878c2ecf20Sopenharmony_ci * state and, if it's legal, sets a `next_state' in the object 54888c2ecf20Sopenharmony_ci * that will be used in the completion flow to set the `state' 54898c2ecf20Sopenharmony_ci * of the object. 54908c2ecf20Sopenharmony_ci * 54918c2ecf20Sopenharmony_ci * returns 0 if a requested command is a legal transition, 54928c2ecf20Sopenharmony_ci * -EINVAL otherwise. 54938c2ecf20Sopenharmony_ci */ 54948c2ecf20Sopenharmony_cistatic int bnx2x_queue_chk_transition(struct bnx2x *bp, 54958c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *o, 54968c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params *params) 54978c2ecf20Sopenharmony_ci{ 54988c2ecf20Sopenharmony_ci enum bnx2x_q_state state = o->state, next_state = BNX2X_Q_STATE_MAX; 54998c2ecf20Sopenharmony_ci enum bnx2x_queue_cmd cmd = params->cmd; 55008c2ecf20Sopenharmony_ci struct bnx2x_queue_update_params *update_params = 55018c2ecf20Sopenharmony_ci ¶ms->params.update; 55028c2ecf20Sopenharmony_ci u8 next_tx_only = o->num_tx_only; 55038c2ecf20Sopenharmony_ci 55048c2ecf20Sopenharmony_ci /* Forget all pending for completion commands if a driver only state 55058c2ecf20Sopenharmony_ci * transition has been requested. 55068c2ecf20Sopenharmony_ci */ 55078c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) { 55088c2ecf20Sopenharmony_ci o->pending = 0; 55098c2ecf20Sopenharmony_ci o->next_state = BNX2X_Q_STATE_MAX; 55108c2ecf20Sopenharmony_ci } 55118c2ecf20Sopenharmony_ci 55128c2ecf20Sopenharmony_ci /* Don't allow a next state transition if we are in the middle of 55138c2ecf20Sopenharmony_ci * the previous one. 55148c2ecf20Sopenharmony_ci */ 55158c2ecf20Sopenharmony_ci if (o->pending) { 55168c2ecf20Sopenharmony_ci BNX2X_ERR("Blocking transition since pending was %lx\n", 55178c2ecf20Sopenharmony_ci o->pending); 55188c2ecf20Sopenharmony_ci return -EBUSY; 55198c2ecf20Sopenharmony_ci } 55208c2ecf20Sopenharmony_ci 55218c2ecf20Sopenharmony_ci switch (state) { 55228c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_RESET: 55238c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_INIT) 55248c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INITIALIZED; 55258c2ecf20Sopenharmony_ci 55268c2ecf20Sopenharmony_ci break; 55278c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_INITIALIZED: 55288c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_SETUP) { 55298c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_FLG_ACTIVE, 55308c2ecf20Sopenharmony_ci ¶ms->params.setup.flags)) 55318c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_ACTIVE; 55328c2ecf20Sopenharmony_ci else 55338c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INACTIVE; 55348c2ecf20Sopenharmony_ci } 55358c2ecf20Sopenharmony_ci 55368c2ecf20Sopenharmony_ci break; 55378c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_ACTIVE: 55388c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_DEACTIVATE) 55398c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INACTIVE; 55408c2ecf20Sopenharmony_ci 55418c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_Q_CMD_EMPTY) || 55428c2ecf20Sopenharmony_ci (cmd == BNX2X_Q_CMD_UPDATE_TPA)) 55438c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_ACTIVE; 55448c2ecf20Sopenharmony_ci 55458c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_SETUP_TX_ONLY) { 55468c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MULTI_COS; 55478c2ecf20Sopenharmony_ci next_tx_only = 1; 55488c2ecf20Sopenharmony_ci } 55498c2ecf20Sopenharmony_ci 55508c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_HALT) 55518c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_STOPPED; 55528c2ecf20Sopenharmony_ci 55538c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_UPDATE) { 55548c2ecf20Sopenharmony_ci /* If "active" state change is requested, update the 55558c2ecf20Sopenharmony_ci * state accordingly. 55568c2ecf20Sopenharmony_ci */ 55578c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, 55588c2ecf20Sopenharmony_ci &update_params->update_flags) && 55598c2ecf20Sopenharmony_ci !test_bit(BNX2X_Q_UPDATE_ACTIVATE, 55608c2ecf20Sopenharmony_ci &update_params->update_flags)) 55618c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INACTIVE; 55628c2ecf20Sopenharmony_ci else 55638c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_ACTIVE; 55648c2ecf20Sopenharmony_ci } 55658c2ecf20Sopenharmony_ci 55668c2ecf20Sopenharmony_ci break; 55678c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_MULTI_COS: 55688c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_TERMINATE) 55698c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MCOS_TERMINATED; 55708c2ecf20Sopenharmony_ci 55718c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_SETUP_TX_ONLY) { 55728c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MULTI_COS; 55738c2ecf20Sopenharmony_ci next_tx_only = o->num_tx_only + 1; 55748c2ecf20Sopenharmony_ci } 55758c2ecf20Sopenharmony_ci 55768c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_Q_CMD_EMPTY) || 55778c2ecf20Sopenharmony_ci (cmd == BNX2X_Q_CMD_UPDATE_TPA)) 55788c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MULTI_COS; 55798c2ecf20Sopenharmony_ci 55808c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_UPDATE) { 55818c2ecf20Sopenharmony_ci /* If "active" state change is requested, update the 55828c2ecf20Sopenharmony_ci * state accordingly. 55838c2ecf20Sopenharmony_ci */ 55848c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, 55858c2ecf20Sopenharmony_ci &update_params->update_flags) && 55868c2ecf20Sopenharmony_ci !test_bit(BNX2X_Q_UPDATE_ACTIVATE, 55878c2ecf20Sopenharmony_ci &update_params->update_flags)) 55888c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INACTIVE; 55898c2ecf20Sopenharmony_ci else 55908c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MULTI_COS; 55918c2ecf20Sopenharmony_ci } 55928c2ecf20Sopenharmony_ci 55938c2ecf20Sopenharmony_ci break; 55948c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_MCOS_TERMINATED: 55958c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_CFC_DEL) { 55968c2ecf20Sopenharmony_ci next_tx_only = o->num_tx_only - 1; 55978c2ecf20Sopenharmony_ci if (next_tx_only == 0) 55988c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_ACTIVE; 55998c2ecf20Sopenharmony_ci else 56008c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MULTI_COS; 56018c2ecf20Sopenharmony_ci } 56028c2ecf20Sopenharmony_ci 56038c2ecf20Sopenharmony_ci break; 56048c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_INACTIVE: 56058c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_ACTIVATE) 56068c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_ACTIVE; 56078c2ecf20Sopenharmony_ci 56088c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_Q_CMD_EMPTY) || 56098c2ecf20Sopenharmony_ci (cmd == BNX2X_Q_CMD_UPDATE_TPA)) 56108c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INACTIVE; 56118c2ecf20Sopenharmony_ci 56128c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_HALT) 56138c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_STOPPED; 56148c2ecf20Sopenharmony_ci 56158c2ecf20Sopenharmony_ci else if (cmd == BNX2X_Q_CMD_UPDATE) { 56168c2ecf20Sopenharmony_ci /* If "active" state change is requested, update the 56178c2ecf20Sopenharmony_ci * state accordingly. 56188c2ecf20Sopenharmony_ci */ 56198c2ecf20Sopenharmony_ci if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, 56208c2ecf20Sopenharmony_ci &update_params->update_flags) && 56218c2ecf20Sopenharmony_ci test_bit(BNX2X_Q_UPDATE_ACTIVATE, 56228c2ecf20Sopenharmony_ci &update_params->update_flags)){ 56238c2ecf20Sopenharmony_ci if (o->num_tx_only == 0) 56248c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_ACTIVE; 56258c2ecf20Sopenharmony_ci else /* tx only queues exist for this queue */ 56268c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_MULTI_COS; 56278c2ecf20Sopenharmony_ci } else 56288c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_INACTIVE; 56298c2ecf20Sopenharmony_ci } 56308c2ecf20Sopenharmony_ci 56318c2ecf20Sopenharmony_ci break; 56328c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_STOPPED: 56338c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_TERMINATE) 56348c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_TERMINATED; 56358c2ecf20Sopenharmony_ci 56368c2ecf20Sopenharmony_ci break; 56378c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_TERMINATED: 56388c2ecf20Sopenharmony_ci if (cmd == BNX2X_Q_CMD_CFC_DEL) 56398c2ecf20Sopenharmony_ci next_state = BNX2X_Q_STATE_RESET; 56408c2ecf20Sopenharmony_ci 56418c2ecf20Sopenharmony_ci break; 56428c2ecf20Sopenharmony_ci default: 56438c2ecf20Sopenharmony_ci BNX2X_ERR("Illegal state: %d\n", state); 56448c2ecf20Sopenharmony_ci } 56458c2ecf20Sopenharmony_ci 56468c2ecf20Sopenharmony_ci /* Transition is assured */ 56478c2ecf20Sopenharmony_ci if (next_state != BNX2X_Q_STATE_MAX) { 56488c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Good state transition: %d(%d)->%d\n", 56498c2ecf20Sopenharmony_ci state, cmd, next_state); 56508c2ecf20Sopenharmony_ci o->next_state = next_state; 56518c2ecf20Sopenharmony_ci o->next_tx_only = next_tx_only; 56528c2ecf20Sopenharmony_ci return 0; 56538c2ecf20Sopenharmony_ci } 56548c2ecf20Sopenharmony_ci 56558c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Bad state transition request: %d %d\n", state, cmd); 56568c2ecf20Sopenharmony_ci 56578c2ecf20Sopenharmony_ci return -EINVAL; 56588c2ecf20Sopenharmony_ci} 56598c2ecf20Sopenharmony_ci 56608c2ecf20Sopenharmony_civoid bnx2x_init_queue_obj(struct bnx2x *bp, 56618c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *obj, 56628c2ecf20Sopenharmony_ci u8 cl_id, u32 *cids, u8 cid_cnt, u8 func_id, 56638c2ecf20Sopenharmony_ci void *rdata, 56648c2ecf20Sopenharmony_ci dma_addr_t rdata_mapping, unsigned long type) 56658c2ecf20Sopenharmony_ci{ 56668c2ecf20Sopenharmony_ci memset(obj, 0, sizeof(*obj)); 56678c2ecf20Sopenharmony_ci 56688c2ecf20Sopenharmony_ci /* We support only BNX2X_MULTI_TX_COS Tx CoS at the moment */ 56698c2ecf20Sopenharmony_ci BUG_ON(BNX2X_MULTI_TX_COS < cid_cnt); 56708c2ecf20Sopenharmony_ci 56718c2ecf20Sopenharmony_ci memcpy(obj->cids, cids, sizeof(obj->cids[0]) * cid_cnt); 56728c2ecf20Sopenharmony_ci obj->max_cos = cid_cnt; 56738c2ecf20Sopenharmony_ci obj->cl_id = cl_id; 56748c2ecf20Sopenharmony_ci obj->func_id = func_id; 56758c2ecf20Sopenharmony_ci obj->rdata = rdata; 56768c2ecf20Sopenharmony_ci obj->rdata_mapping = rdata_mapping; 56778c2ecf20Sopenharmony_ci obj->type = type; 56788c2ecf20Sopenharmony_ci obj->next_state = BNX2X_Q_STATE_MAX; 56798c2ecf20Sopenharmony_ci 56808c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp)) 56818c2ecf20Sopenharmony_ci obj->send_cmd = bnx2x_queue_send_cmd_e1x; 56828c2ecf20Sopenharmony_ci else 56838c2ecf20Sopenharmony_ci obj->send_cmd = bnx2x_queue_send_cmd_e2; 56848c2ecf20Sopenharmony_ci 56858c2ecf20Sopenharmony_ci obj->check_transition = bnx2x_queue_chk_transition; 56868c2ecf20Sopenharmony_ci 56878c2ecf20Sopenharmony_ci obj->complete_cmd = bnx2x_queue_comp_cmd; 56888c2ecf20Sopenharmony_ci obj->wait_comp = bnx2x_queue_wait_comp; 56898c2ecf20Sopenharmony_ci obj->set_pending = bnx2x_queue_set_pending; 56908c2ecf20Sopenharmony_ci} 56918c2ecf20Sopenharmony_ci 56928c2ecf20Sopenharmony_ci/* return a queue object's logical state*/ 56938c2ecf20Sopenharmony_ciint bnx2x_get_q_logical_state(struct bnx2x *bp, 56948c2ecf20Sopenharmony_ci struct bnx2x_queue_sp_obj *obj) 56958c2ecf20Sopenharmony_ci{ 56968c2ecf20Sopenharmony_ci switch (obj->state) { 56978c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_ACTIVE: 56988c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_MULTI_COS: 56998c2ecf20Sopenharmony_ci return BNX2X_Q_LOGICAL_STATE_ACTIVE; 57008c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_RESET: 57018c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_INITIALIZED: 57028c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_MCOS_TERMINATED: 57038c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_INACTIVE: 57048c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_STOPPED: 57058c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_TERMINATED: 57068c2ecf20Sopenharmony_ci case BNX2X_Q_STATE_FLRED: 57078c2ecf20Sopenharmony_ci return BNX2X_Q_LOGICAL_STATE_STOPPED; 57088c2ecf20Sopenharmony_ci default: 57098c2ecf20Sopenharmony_ci return -EINVAL; 57108c2ecf20Sopenharmony_ci } 57118c2ecf20Sopenharmony_ci} 57128c2ecf20Sopenharmony_ci 57138c2ecf20Sopenharmony_ci/********************** Function state object *********************************/ 57148c2ecf20Sopenharmony_cienum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp, 57158c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o) 57168c2ecf20Sopenharmony_ci{ 57178c2ecf20Sopenharmony_ci /* in the middle of transaction - return INVALID state */ 57188c2ecf20Sopenharmony_ci if (o->pending) 57198c2ecf20Sopenharmony_ci return BNX2X_F_STATE_MAX; 57208c2ecf20Sopenharmony_ci 57218c2ecf20Sopenharmony_ci /* unsure the order of reading of o->pending and o->state 57228c2ecf20Sopenharmony_ci * o->pending should be read first 57238c2ecf20Sopenharmony_ci */ 57248c2ecf20Sopenharmony_ci rmb(); 57258c2ecf20Sopenharmony_ci 57268c2ecf20Sopenharmony_ci return o->state; 57278c2ecf20Sopenharmony_ci} 57288c2ecf20Sopenharmony_ci 57298c2ecf20Sopenharmony_cistatic int bnx2x_func_wait_comp(struct bnx2x *bp, 57308c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o, 57318c2ecf20Sopenharmony_ci enum bnx2x_func_cmd cmd) 57328c2ecf20Sopenharmony_ci{ 57338c2ecf20Sopenharmony_ci return bnx2x_state_wait(bp, cmd, &o->pending); 57348c2ecf20Sopenharmony_ci} 57358c2ecf20Sopenharmony_ci 57368c2ecf20Sopenharmony_ci/** 57378c2ecf20Sopenharmony_ci * bnx2x_func_state_change_comp - complete the state machine transition 57388c2ecf20Sopenharmony_ci * 57398c2ecf20Sopenharmony_ci * @bp: device handle 57408c2ecf20Sopenharmony_ci * @o: function info 57418c2ecf20Sopenharmony_ci * @cmd: more info 57428c2ecf20Sopenharmony_ci * 57438c2ecf20Sopenharmony_ci * Called on state change transition. Completes the state 57448c2ecf20Sopenharmony_ci * machine transition only - no HW interaction. 57458c2ecf20Sopenharmony_ci */ 57468c2ecf20Sopenharmony_cistatic inline int bnx2x_func_state_change_comp(struct bnx2x *bp, 57478c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o, 57488c2ecf20Sopenharmony_ci enum bnx2x_func_cmd cmd) 57498c2ecf20Sopenharmony_ci{ 57508c2ecf20Sopenharmony_ci unsigned long cur_pending = o->pending; 57518c2ecf20Sopenharmony_ci 57528c2ecf20Sopenharmony_ci if (!test_and_clear_bit(cmd, &cur_pending)) { 57538c2ecf20Sopenharmony_ci BNX2X_ERR("Bad MC reply %d for func %d in state %d pending 0x%lx, next_state %d\n", 57548c2ecf20Sopenharmony_ci cmd, BP_FUNC(bp), o->state, 57558c2ecf20Sopenharmony_ci cur_pending, o->next_state); 57568c2ecf20Sopenharmony_ci return -EINVAL; 57578c2ecf20Sopenharmony_ci } 57588c2ecf20Sopenharmony_ci 57598c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, 57608c2ecf20Sopenharmony_ci "Completing command %d for func %d, setting state to %d\n", 57618c2ecf20Sopenharmony_ci cmd, BP_FUNC(bp), o->next_state); 57628c2ecf20Sopenharmony_ci 57638c2ecf20Sopenharmony_ci o->state = o->next_state; 57648c2ecf20Sopenharmony_ci o->next_state = BNX2X_F_STATE_MAX; 57658c2ecf20Sopenharmony_ci 57668c2ecf20Sopenharmony_ci /* It's important that o->state and o->next_state are 57678c2ecf20Sopenharmony_ci * updated before o->pending. 57688c2ecf20Sopenharmony_ci */ 57698c2ecf20Sopenharmony_ci wmb(); 57708c2ecf20Sopenharmony_ci 57718c2ecf20Sopenharmony_ci clear_bit(cmd, &o->pending); 57728c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 57738c2ecf20Sopenharmony_ci 57748c2ecf20Sopenharmony_ci return 0; 57758c2ecf20Sopenharmony_ci} 57768c2ecf20Sopenharmony_ci 57778c2ecf20Sopenharmony_ci/** 57788c2ecf20Sopenharmony_ci * bnx2x_func_comp_cmd - complete the state change command 57798c2ecf20Sopenharmony_ci * 57808c2ecf20Sopenharmony_ci * @bp: device handle 57818c2ecf20Sopenharmony_ci * @o: function info 57828c2ecf20Sopenharmony_ci * @cmd: more info 57838c2ecf20Sopenharmony_ci * 57848c2ecf20Sopenharmony_ci * Checks that the arrived completion is expected. 57858c2ecf20Sopenharmony_ci */ 57868c2ecf20Sopenharmony_cistatic int bnx2x_func_comp_cmd(struct bnx2x *bp, 57878c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o, 57888c2ecf20Sopenharmony_ci enum bnx2x_func_cmd cmd) 57898c2ecf20Sopenharmony_ci{ 57908c2ecf20Sopenharmony_ci /* Complete the state machine part first, check if it's a 57918c2ecf20Sopenharmony_ci * legal completion. 57928c2ecf20Sopenharmony_ci */ 57938c2ecf20Sopenharmony_ci int rc = bnx2x_func_state_change_comp(bp, o, cmd); 57948c2ecf20Sopenharmony_ci return rc; 57958c2ecf20Sopenharmony_ci} 57968c2ecf20Sopenharmony_ci 57978c2ecf20Sopenharmony_ci/** 57988c2ecf20Sopenharmony_ci * bnx2x_func_chk_transition - perform function state machine transition 57998c2ecf20Sopenharmony_ci * 58008c2ecf20Sopenharmony_ci * @bp: device handle 58018c2ecf20Sopenharmony_ci * @o: function info 58028c2ecf20Sopenharmony_ci * @params: state parameters 58038c2ecf20Sopenharmony_ci * 58048c2ecf20Sopenharmony_ci * It both checks if the requested command is legal in a current 58058c2ecf20Sopenharmony_ci * state and, if it's legal, sets a `next_state' in the object 58068c2ecf20Sopenharmony_ci * that will be used in the completion flow to set the `state' 58078c2ecf20Sopenharmony_ci * of the object. 58088c2ecf20Sopenharmony_ci * 58098c2ecf20Sopenharmony_ci * returns 0 if a requested command is a legal transition, 58108c2ecf20Sopenharmony_ci * -EINVAL otherwise. 58118c2ecf20Sopenharmony_ci */ 58128c2ecf20Sopenharmony_cistatic int bnx2x_func_chk_transition(struct bnx2x *bp, 58138c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o, 58148c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 58158c2ecf20Sopenharmony_ci{ 58168c2ecf20Sopenharmony_ci enum bnx2x_func_state state = o->state, next_state = BNX2X_F_STATE_MAX; 58178c2ecf20Sopenharmony_ci enum bnx2x_func_cmd cmd = params->cmd; 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci /* Forget all pending for completion commands if a driver only state 58208c2ecf20Sopenharmony_ci * transition has been requested. 58218c2ecf20Sopenharmony_ci */ 58228c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) { 58238c2ecf20Sopenharmony_ci o->pending = 0; 58248c2ecf20Sopenharmony_ci o->next_state = BNX2X_F_STATE_MAX; 58258c2ecf20Sopenharmony_ci } 58268c2ecf20Sopenharmony_ci 58278c2ecf20Sopenharmony_ci /* Don't allow a next state transition if we are in the middle of 58288c2ecf20Sopenharmony_ci * the previous one. 58298c2ecf20Sopenharmony_ci */ 58308c2ecf20Sopenharmony_ci if (o->pending) 58318c2ecf20Sopenharmony_ci return -EBUSY; 58328c2ecf20Sopenharmony_ci 58338c2ecf20Sopenharmony_ci switch (state) { 58348c2ecf20Sopenharmony_ci case BNX2X_F_STATE_RESET: 58358c2ecf20Sopenharmony_ci if (cmd == BNX2X_F_CMD_HW_INIT) 58368c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_INITIALIZED; 58378c2ecf20Sopenharmony_ci 58388c2ecf20Sopenharmony_ci break; 58398c2ecf20Sopenharmony_ci case BNX2X_F_STATE_INITIALIZED: 58408c2ecf20Sopenharmony_ci if (cmd == BNX2X_F_CMD_START) 58418c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_STARTED; 58428c2ecf20Sopenharmony_ci 58438c2ecf20Sopenharmony_ci else if (cmd == BNX2X_F_CMD_HW_RESET) 58448c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_RESET; 58458c2ecf20Sopenharmony_ci 58468c2ecf20Sopenharmony_ci break; 58478c2ecf20Sopenharmony_ci case BNX2X_F_STATE_STARTED: 58488c2ecf20Sopenharmony_ci if (cmd == BNX2X_F_CMD_STOP) 58498c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_INITIALIZED; 58508c2ecf20Sopenharmony_ci /* afex ramrods can be sent only in started mode, and only 58518c2ecf20Sopenharmony_ci * if not pending for function_stop ramrod completion 58528c2ecf20Sopenharmony_ci * for these events - next state remained STARTED. 58538c2ecf20Sopenharmony_ci */ 58548c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_F_CMD_AFEX_UPDATE) && 58558c2ecf20Sopenharmony_ci (!test_bit(BNX2X_F_CMD_STOP, &o->pending))) 58568c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_STARTED; 58578c2ecf20Sopenharmony_ci 58588c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_F_CMD_AFEX_VIFLISTS) && 58598c2ecf20Sopenharmony_ci (!test_bit(BNX2X_F_CMD_STOP, &o->pending))) 58608c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_STARTED; 58618c2ecf20Sopenharmony_ci 58628c2ecf20Sopenharmony_ci /* Switch_update ramrod can be sent in either started or 58638c2ecf20Sopenharmony_ci * tx_stopped state, and it doesn't change the state. 58648c2ecf20Sopenharmony_ci */ 58658c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_F_CMD_SWITCH_UPDATE) && 58668c2ecf20Sopenharmony_ci (!test_bit(BNX2X_F_CMD_STOP, &o->pending))) 58678c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_STARTED; 58688c2ecf20Sopenharmony_ci 58698c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) && 58708c2ecf20Sopenharmony_ci (!test_bit(BNX2X_F_CMD_STOP, &o->pending))) 58718c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_STARTED; 58728c2ecf20Sopenharmony_ci 58738c2ecf20Sopenharmony_ci else if (cmd == BNX2X_F_CMD_TX_STOP) 58748c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_TX_STOPPED; 58758c2ecf20Sopenharmony_ci 58768c2ecf20Sopenharmony_ci break; 58778c2ecf20Sopenharmony_ci case BNX2X_F_STATE_TX_STOPPED: 58788c2ecf20Sopenharmony_ci if ((cmd == BNX2X_F_CMD_SWITCH_UPDATE) && 58798c2ecf20Sopenharmony_ci (!test_bit(BNX2X_F_CMD_STOP, &o->pending))) 58808c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_TX_STOPPED; 58818c2ecf20Sopenharmony_ci 58828c2ecf20Sopenharmony_ci else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) && 58838c2ecf20Sopenharmony_ci (!test_bit(BNX2X_F_CMD_STOP, &o->pending))) 58848c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_TX_STOPPED; 58858c2ecf20Sopenharmony_ci 58868c2ecf20Sopenharmony_ci else if (cmd == BNX2X_F_CMD_TX_START) 58878c2ecf20Sopenharmony_ci next_state = BNX2X_F_STATE_STARTED; 58888c2ecf20Sopenharmony_ci 58898c2ecf20Sopenharmony_ci break; 58908c2ecf20Sopenharmony_ci default: 58918c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown state: %d\n", state); 58928c2ecf20Sopenharmony_ci } 58938c2ecf20Sopenharmony_ci 58948c2ecf20Sopenharmony_ci /* Transition is assured */ 58958c2ecf20Sopenharmony_ci if (next_state != BNX2X_F_STATE_MAX) { 58968c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Good function state transition: %d(%d)->%d\n", 58978c2ecf20Sopenharmony_ci state, cmd, next_state); 58988c2ecf20Sopenharmony_ci o->next_state = next_state; 58998c2ecf20Sopenharmony_ci return 0; 59008c2ecf20Sopenharmony_ci } 59018c2ecf20Sopenharmony_ci 59028c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "Bad function state transition request: %d %d\n", 59038c2ecf20Sopenharmony_ci state, cmd); 59048c2ecf20Sopenharmony_ci 59058c2ecf20Sopenharmony_ci return -EINVAL; 59068c2ecf20Sopenharmony_ci} 59078c2ecf20Sopenharmony_ci 59088c2ecf20Sopenharmony_ci/** 59098c2ecf20Sopenharmony_ci * bnx2x_func_init_func - performs HW init at function stage 59108c2ecf20Sopenharmony_ci * 59118c2ecf20Sopenharmony_ci * @bp: device handle 59128c2ecf20Sopenharmony_ci * @drv: 59138c2ecf20Sopenharmony_ci * 59148c2ecf20Sopenharmony_ci * Init HW when the current phase is 59158c2ecf20Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_FUNCTION: initialize only FUNCTION-only 59168c2ecf20Sopenharmony_ci * HW blocks. 59178c2ecf20Sopenharmony_ci */ 59188c2ecf20Sopenharmony_cistatic inline int bnx2x_func_init_func(struct bnx2x *bp, 59198c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 59208c2ecf20Sopenharmony_ci{ 59218c2ecf20Sopenharmony_ci return drv->init_hw_func(bp); 59228c2ecf20Sopenharmony_ci} 59238c2ecf20Sopenharmony_ci 59248c2ecf20Sopenharmony_ci/** 59258c2ecf20Sopenharmony_ci * bnx2x_func_init_port - performs HW init at port stage 59268c2ecf20Sopenharmony_ci * 59278c2ecf20Sopenharmony_ci * @bp: device handle 59288c2ecf20Sopenharmony_ci * @drv: 59298c2ecf20Sopenharmony_ci * 59308c2ecf20Sopenharmony_ci * Init HW when the current phase is 59318c2ecf20Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_PORT: initialize PORT-only and 59328c2ecf20Sopenharmony_ci * FUNCTION-only HW blocks. 59338c2ecf20Sopenharmony_ci * 59348c2ecf20Sopenharmony_ci */ 59358c2ecf20Sopenharmony_cistatic inline int bnx2x_func_init_port(struct bnx2x *bp, 59368c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 59378c2ecf20Sopenharmony_ci{ 59388c2ecf20Sopenharmony_ci int rc = drv->init_hw_port(bp); 59398c2ecf20Sopenharmony_ci if (rc) 59408c2ecf20Sopenharmony_ci return rc; 59418c2ecf20Sopenharmony_ci 59428c2ecf20Sopenharmony_ci return bnx2x_func_init_func(bp, drv); 59438c2ecf20Sopenharmony_ci} 59448c2ecf20Sopenharmony_ci 59458c2ecf20Sopenharmony_ci/** 59468c2ecf20Sopenharmony_ci * bnx2x_func_init_cmn_chip - performs HW init at chip-common stage 59478c2ecf20Sopenharmony_ci * 59488c2ecf20Sopenharmony_ci * @bp: device handle 59498c2ecf20Sopenharmony_ci * @drv: 59508c2ecf20Sopenharmony_ci * 59518c2ecf20Sopenharmony_ci * Init HW when the current phase is 59528c2ecf20Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: initialize COMMON_CHIP, 59538c2ecf20Sopenharmony_ci * PORT-only and FUNCTION-only HW blocks. 59548c2ecf20Sopenharmony_ci */ 59558c2ecf20Sopenharmony_cistatic inline int bnx2x_func_init_cmn_chip(struct bnx2x *bp, 59568c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 59578c2ecf20Sopenharmony_ci{ 59588c2ecf20Sopenharmony_ci int rc = drv->init_hw_cmn_chip(bp); 59598c2ecf20Sopenharmony_ci if (rc) 59608c2ecf20Sopenharmony_ci return rc; 59618c2ecf20Sopenharmony_ci 59628c2ecf20Sopenharmony_ci return bnx2x_func_init_port(bp, drv); 59638c2ecf20Sopenharmony_ci} 59648c2ecf20Sopenharmony_ci 59658c2ecf20Sopenharmony_ci/** 59668c2ecf20Sopenharmony_ci * bnx2x_func_init_cmn - performs HW init at common stage 59678c2ecf20Sopenharmony_ci * 59688c2ecf20Sopenharmony_ci * @bp: device handle 59698c2ecf20Sopenharmony_ci * @drv: 59708c2ecf20Sopenharmony_ci * 59718c2ecf20Sopenharmony_ci * Init HW when the current phase is 59728c2ecf20Sopenharmony_ci * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: initialize COMMON, 59738c2ecf20Sopenharmony_ci * PORT-only and FUNCTION-only HW blocks. 59748c2ecf20Sopenharmony_ci */ 59758c2ecf20Sopenharmony_cistatic inline int bnx2x_func_init_cmn(struct bnx2x *bp, 59768c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 59778c2ecf20Sopenharmony_ci{ 59788c2ecf20Sopenharmony_ci int rc = drv->init_hw_cmn(bp); 59798c2ecf20Sopenharmony_ci if (rc) 59808c2ecf20Sopenharmony_ci return rc; 59818c2ecf20Sopenharmony_ci 59828c2ecf20Sopenharmony_ci return bnx2x_func_init_port(bp, drv); 59838c2ecf20Sopenharmony_ci} 59848c2ecf20Sopenharmony_ci 59858c2ecf20Sopenharmony_cistatic int bnx2x_func_hw_init(struct bnx2x *bp, 59868c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 59878c2ecf20Sopenharmony_ci{ 59888c2ecf20Sopenharmony_ci u32 load_code = params->params.hw_init.load_phase; 59898c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 59908c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv = o->drv; 59918c2ecf20Sopenharmony_ci int rc = 0; 59928c2ecf20Sopenharmony_ci 59938c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "function %d load_code %x\n", 59948c2ecf20Sopenharmony_ci BP_ABS_FUNC(bp), load_code); 59958c2ecf20Sopenharmony_ci 59968c2ecf20Sopenharmony_ci /* Prepare buffers for unzipping the FW */ 59978c2ecf20Sopenharmony_ci rc = drv->gunzip_init(bp); 59988c2ecf20Sopenharmony_ci if (rc) 59998c2ecf20Sopenharmony_ci return rc; 60008c2ecf20Sopenharmony_ci 60018c2ecf20Sopenharmony_ci /* Prepare FW */ 60028c2ecf20Sopenharmony_ci rc = drv->init_fw(bp); 60038c2ecf20Sopenharmony_ci if (rc) { 60048c2ecf20Sopenharmony_ci BNX2X_ERR("Error loading firmware\n"); 60058c2ecf20Sopenharmony_ci goto init_err; 60068c2ecf20Sopenharmony_ci } 60078c2ecf20Sopenharmony_ci 60088c2ecf20Sopenharmony_ci /* Handle the beginning of COMMON_XXX pases separately... */ 60098c2ecf20Sopenharmony_ci switch (load_code) { 60108c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: 60118c2ecf20Sopenharmony_ci rc = bnx2x_func_init_cmn_chip(bp, drv); 60128c2ecf20Sopenharmony_ci if (rc) 60138c2ecf20Sopenharmony_ci goto init_err; 60148c2ecf20Sopenharmony_ci 60158c2ecf20Sopenharmony_ci break; 60168c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_COMMON: 60178c2ecf20Sopenharmony_ci rc = bnx2x_func_init_cmn(bp, drv); 60188c2ecf20Sopenharmony_ci if (rc) 60198c2ecf20Sopenharmony_ci goto init_err; 60208c2ecf20Sopenharmony_ci 60218c2ecf20Sopenharmony_ci break; 60228c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_PORT: 60238c2ecf20Sopenharmony_ci rc = bnx2x_func_init_port(bp, drv); 60248c2ecf20Sopenharmony_ci if (rc) 60258c2ecf20Sopenharmony_ci goto init_err; 60268c2ecf20Sopenharmony_ci 60278c2ecf20Sopenharmony_ci break; 60288c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_FUNCTION: 60298c2ecf20Sopenharmony_ci rc = bnx2x_func_init_func(bp, drv); 60308c2ecf20Sopenharmony_ci if (rc) 60318c2ecf20Sopenharmony_ci goto init_err; 60328c2ecf20Sopenharmony_ci 60338c2ecf20Sopenharmony_ci break; 60348c2ecf20Sopenharmony_ci default: 60358c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code); 60368c2ecf20Sopenharmony_ci rc = -EINVAL; 60378c2ecf20Sopenharmony_ci } 60388c2ecf20Sopenharmony_ci 60398c2ecf20Sopenharmony_ciinit_err: 60408c2ecf20Sopenharmony_ci drv->gunzip_end(bp); 60418c2ecf20Sopenharmony_ci 60428c2ecf20Sopenharmony_ci /* In case of success, complete the command immediately: no ramrods 60438c2ecf20Sopenharmony_ci * have been sent. 60448c2ecf20Sopenharmony_ci */ 60458c2ecf20Sopenharmony_ci if (!rc) 60468c2ecf20Sopenharmony_ci o->complete_cmd(bp, o, BNX2X_F_CMD_HW_INIT); 60478c2ecf20Sopenharmony_ci 60488c2ecf20Sopenharmony_ci return rc; 60498c2ecf20Sopenharmony_ci} 60508c2ecf20Sopenharmony_ci 60518c2ecf20Sopenharmony_ci/** 60528c2ecf20Sopenharmony_ci * bnx2x_func_reset_func - reset HW at function stage 60538c2ecf20Sopenharmony_ci * 60548c2ecf20Sopenharmony_ci * @bp: device handle 60558c2ecf20Sopenharmony_ci * @drv: 60568c2ecf20Sopenharmony_ci * 60578c2ecf20Sopenharmony_ci * Reset HW at FW_MSG_CODE_DRV_UNLOAD_FUNCTION stage: reset only 60588c2ecf20Sopenharmony_ci * FUNCTION-only HW blocks. 60598c2ecf20Sopenharmony_ci */ 60608c2ecf20Sopenharmony_cistatic inline void bnx2x_func_reset_func(struct bnx2x *bp, 60618c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 60628c2ecf20Sopenharmony_ci{ 60638c2ecf20Sopenharmony_ci drv->reset_hw_func(bp); 60648c2ecf20Sopenharmony_ci} 60658c2ecf20Sopenharmony_ci 60668c2ecf20Sopenharmony_ci/** 60678c2ecf20Sopenharmony_ci * bnx2x_func_reset_port - reset HW at port stage 60688c2ecf20Sopenharmony_ci * 60698c2ecf20Sopenharmony_ci * @bp: device handle 60708c2ecf20Sopenharmony_ci * @drv: 60718c2ecf20Sopenharmony_ci * 60728c2ecf20Sopenharmony_ci * Reset HW at FW_MSG_CODE_DRV_UNLOAD_PORT stage: reset 60738c2ecf20Sopenharmony_ci * FUNCTION-only and PORT-only HW blocks. 60748c2ecf20Sopenharmony_ci * 60758c2ecf20Sopenharmony_ci * !!!IMPORTANT!!! 60768c2ecf20Sopenharmony_ci * 60778c2ecf20Sopenharmony_ci * It's important to call reset_port before reset_func() as the last thing 60788c2ecf20Sopenharmony_ci * reset_func does is pf_disable() thus disabling PGLUE_B, which 60798c2ecf20Sopenharmony_ci * makes impossible any DMAE transactions. 60808c2ecf20Sopenharmony_ci */ 60818c2ecf20Sopenharmony_cistatic inline void bnx2x_func_reset_port(struct bnx2x *bp, 60828c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 60838c2ecf20Sopenharmony_ci{ 60848c2ecf20Sopenharmony_ci drv->reset_hw_port(bp); 60858c2ecf20Sopenharmony_ci bnx2x_func_reset_func(bp, drv); 60868c2ecf20Sopenharmony_ci} 60878c2ecf20Sopenharmony_ci 60888c2ecf20Sopenharmony_ci/** 60898c2ecf20Sopenharmony_ci * bnx2x_func_reset_cmn - reset HW at common stage 60908c2ecf20Sopenharmony_ci * 60918c2ecf20Sopenharmony_ci * @bp: device handle 60928c2ecf20Sopenharmony_ci * @drv: 60938c2ecf20Sopenharmony_ci * 60948c2ecf20Sopenharmony_ci * Reset HW at FW_MSG_CODE_DRV_UNLOAD_COMMON and 60958c2ecf20Sopenharmony_ci * FW_MSG_CODE_DRV_UNLOAD_COMMON_CHIP stages: reset COMMON, 60968c2ecf20Sopenharmony_ci * COMMON_CHIP, FUNCTION-only and PORT-only HW blocks. 60978c2ecf20Sopenharmony_ci */ 60988c2ecf20Sopenharmony_cistatic inline void bnx2x_func_reset_cmn(struct bnx2x *bp, 60998c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv) 61008c2ecf20Sopenharmony_ci{ 61018c2ecf20Sopenharmony_ci bnx2x_func_reset_port(bp, drv); 61028c2ecf20Sopenharmony_ci drv->reset_hw_cmn(bp); 61038c2ecf20Sopenharmony_ci} 61048c2ecf20Sopenharmony_ci 61058c2ecf20Sopenharmony_cistatic inline int bnx2x_func_hw_reset(struct bnx2x *bp, 61068c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 61078c2ecf20Sopenharmony_ci{ 61088c2ecf20Sopenharmony_ci u32 reset_phase = params->params.hw_reset.reset_phase; 61098c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 61108c2ecf20Sopenharmony_ci const struct bnx2x_func_sp_drv_ops *drv = o->drv; 61118c2ecf20Sopenharmony_ci 61128c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "function %d reset_phase %x\n", BP_ABS_FUNC(bp), 61138c2ecf20Sopenharmony_ci reset_phase); 61148c2ecf20Sopenharmony_ci 61158c2ecf20Sopenharmony_ci switch (reset_phase) { 61168c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_UNLOAD_COMMON: 61178c2ecf20Sopenharmony_ci bnx2x_func_reset_cmn(bp, drv); 61188c2ecf20Sopenharmony_ci break; 61198c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_UNLOAD_PORT: 61208c2ecf20Sopenharmony_ci bnx2x_func_reset_port(bp, drv); 61218c2ecf20Sopenharmony_ci break; 61228c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_UNLOAD_FUNCTION: 61238c2ecf20Sopenharmony_ci bnx2x_func_reset_func(bp, drv); 61248c2ecf20Sopenharmony_ci break; 61258c2ecf20Sopenharmony_ci default: 61268c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown reset_phase (0x%x) from MCP\n", 61278c2ecf20Sopenharmony_ci reset_phase); 61288c2ecf20Sopenharmony_ci break; 61298c2ecf20Sopenharmony_ci } 61308c2ecf20Sopenharmony_ci 61318c2ecf20Sopenharmony_ci /* Complete the command immediately: no ramrods have been sent. */ 61328c2ecf20Sopenharmony_ci o->complete_cmd(bp, o, BNX2X_F_CMD_HW_RESET); 61338c2ecf20Sopenharmony_ci 61348c2ecf20Sopenharmony_ci return 0; 61358c2ecf20Sopenharmony_ci} 61368c2ecf20Sopenharmony_ci 61378c2ecf20Sopenharmony_cistatic inline int bnx2x_func_send_start(struct bnx2x *bp, 61388c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 61398c2ecf20Sopenharmony_ci{ 61408c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 61418c2ecf20Sopenharmony_ci struct function_start_data *rdata = 61428c2ecf20Sopenharmony_ci (struct function_start_data *)o->rdata; 61438c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 61448c2ecf20Sopenharmony_ci struct bnx2x_func_start_params *start_params = ¶ms->params.start; 61458c2ecf20Sopenharmony_ci 61468c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 61478c2ecf20Sopenharmony_ci 61488c2ecf20Sopenharmony_ci /* Fill the ramrod data with provided parameters */ 61498c2ecf20Sopenharmony_ci rdata->function_mode = (u8)start_params->mf_mode; 61508c2ecf20Sopenharmony_ci rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag); 61518c2ecf20Sopenharmony_ci rdata->path_id = BP_PATH(bp); 61528c2ecf20Sopenharmony_ci rdata->network_cos_mode = start_params->network_cos_mode; 61538c2ecf20Sopenharmony_ci rdata->dmae_cmd_id = BNX2X_FW_DMAE_C; 61548c2ecf20Sopenharmony_ci 61558c2ecf20Sopenharmony_ci rdata->vxlan_dst_port = cpu_to_le16(start_params->vxlan_dst_port); 61568c2ecf20Sopenharmony_ci rdata->geneve_dst_port = cpu_to_le16(start_params->geneve_dst_port); 61578c2ecf20Sopenharmony_ci rdata->inner_clss_l2gre = start_params->inner_clss_l2gre; 61588c2ecf20Sopenharmony_ci rdata->inner_clss_l2geneve = start_params->inner_clss_l2geneve; 61598c2ecf20Sopenharmony_ci rdata->inner_clss_vxlan = start_params->inner_clss_vxlan; 61608c2ecf20Sopenharmony_ci rdata->inner_rss = start_params->inner_rss; 61618c2ecf20Sopenharmony_ci 61628c2ecf20Sopenharmony_ci rdata->sd_accept_mf_clss_fail = start_params->class_fail; 61638c2ecf20Sopenharmony_ci if (start_params->class_fail_ethtype) { 61648c2ecf20Sopenharmony_ci rdata->sd_accept_mf_clss_fail_match_ethtype = 1; 61658c2ecf20Sopenharmony_ci rdata->sd_accept_mf_clss_fail_ethtype = 61668c2ecf20Sopenharmony_ci cpu_to_le16(start_params->class_fail_ethtype); 61678c2ecf20Sopenharmony_ci } 61688c2ecf20Sopenharmony_ci 61698c2ecf20Sopenharmony_ci rdata->sd_vlan_force_pri_flg = start_params->sd_vlan_force_pri; 61708c2ecf20Sopenharmony_ci rdata->sd_vlan_force_pri_val = start_params->sd_vlan_force_pri_val; 61718c2ecf20Sopenharmony_ci if (start_params->sd_vlan_eth_type) 61728c2ecf20Sopenharmony_ci rdata->sd_vlan_eth_type = 61738c2ecf20Sopenharmony_ci cpu_to_le16(start_params->sd_vlan_eth_type); 61748c2ecf20Sopenharmony_ci else 61758c2ecf20Sopenharmony_ci rdata->sd_vlan_eth_type = 61768c2ecf20Sopenharmony_ci cpu_to_le16(0x8100); 61778c2ecf20Sopenharmony_ci 61788c2ecf20Sopenharmony_ci rdata->no_added_tags = start_params->no_added_tags; 61798c2ecf20Sopenharmony_ci 61808c2ecf20Sopenharmony_ci rdata->c2s_pri_tt_valid = start_params->c2s_pri_valid; 61818c2ecf20Sopenharmony_ci if (rdata->c2s_pri_tt_valid) { 61828c2ecf20Sopenharmony_ci memcpy(rdata->c2s_pri_trans_table.val, 61838c2ecf20Sopenharmony_ci start_params->c2s_pri, 61848c2ecf20Sopenharmony_ci MAX_VLAN_PRIORITIES); 61858c2ecf20Sopenharmony_ci rdata->c2s_pri_default = start_params->c2s_pri_default; 61868c2ecf20Sopenharmony_ci } 61878c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long we would 61888c2ecf20Sopenharmony_ci * need to ensure the ordering of writing to the SPQ element 61898c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 61908c2ecf20Sopenharmony_ci * read and we will have to put a full memory barrier there 61918c2ecf20Sopenharmony_ci * (inside bnx2x_sp_post()). 61928c2ecf20Sopenharmony_ci */ 61938c2ecf20Sopenharmony_ci 61948c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_START, 0, 61958c2ecf20Sopenharmony_ci U64_HI(data_mapping), 61968c2ecf20Sopenharmony_ci U64_LO(data_mapping), NONE_CONNECTION_TYPE); 61978c2ecf20Sopenharmony_ci} 61988c2ecf20Sopenharmony_ci 61998c2ecf20Sopenharmony_cistatic inline int bnx2x_func_send_switch_update(struct bnx2x *bp, 62008c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 62018c2ecf20Sopenharmony_ci{ 62028c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 62038c2ecf20Sopenharmony_ci struct function_update_data *rdata = 62048c2ecf20Sopenharmony_ci (struct function_update_data *)o->rdata; 62058c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 62068c2ecf20Sopenharmony_ci struct bnx2x_func_switch_update_params *switch_update_params = 62078c2ecf20Sopenharmony_ci ¶ms->params.switch_update; 62088c2ecf20Sopenharmony_ci 62098c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 62108c2ecf20Sopenharmony_ci 62118c2ecf20Sopenharmony_ci /* Fill the ramrod data with provided parameters */ 62128c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG, 62138c2ecf20Sopenharmony_ci &switch_update_params->changes)) { 62148c2ecf20Sopenharmony_ci rdata->tx_switch_suspend_change_flg = 1; 62158c2ecf20Sopenharmony_ci rdata->tx_switch_suspend = 62168c2ecf20Sopenharmony_ci test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND, 62178c2ecf20Sopenharmony_ci &switch_update_params->changes); 62188c2ecf20Sopenharmony_ci } 62198c2ecf20Sopenharmony_ci 62208c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_SD_VLAN_TAG_CHNG, 62218c2ecf20Sopenharmony_ci &switch_update_params->changes)) { 62228c2ecf20Sopenharmony_ci rdata->sd_vlan_tag_change_flg = 1; 62238c2ecf20Sopenharmony_ci rdata->sd_vlan_tag = 62248c2ecf20Sopenharmony_ci cpu_to_le16(switch_update_params->vlan); 62258c2ecf20Sopenharmony_ci } 62268c2ecf20Sopenharmony_ci 62278c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_SD_VLAN_ETH_TYPE_CHNG, 62288c2ecf20Sopenharmony_ci &switch_update_params->changes)) { 62298c2ecf20Sopenharmony_ci rdata->sd_vlan_eth_type_change_flg = 1; 62308c2ecf20Sopenharmony_ci rdata->sd_vlan_eth_type = 62318c2ecf20Sopenharmony_ci cpu_to_le16(switch_update_params->vlan_eth_type); 62328c2ecf20Sopenharmony_ci } 62338c2ecf20Sopenharmony_ci 62348c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_VLAN_FORCE_PRIO_CHNG, 62358c2ecf20Sopenharmony_ci &switch_update_params->changes)) { 62368c2ecf20Sopenharmony_ci rdata->sd_vlan_force_pri_change_flg = 1; 62378c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_VLAN_FORCE_PRIO_FLAG, 62388c2ecf20Sopenharmony_ci &switch_update_params->changes)) 62398c2ecf20Sopenharmony_ci rdata->sd_vlan_force_pri_flg = 1; 62408c2ecf20Sopenharmony_ci rdata->sd_vlan_force_pri_flg = 62418c2ecf20Sopenharmony_ci switch_update_params->vlan_force_prio; 62428c2ecf20Sopenharmony_ci } 62438c2ecf20Sopenharmony_ci 62448c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG, 62458c2ecf20Sopenharmony_ci &switch_update_params->changes)) { 62468c2ecf20Sopenharmony_ci rdata->update_tunn_cfg_flg = 1; 62478c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GRE, 62488c2ecf20Sopenharmony_ci &switch_update_params->changes)) 62498c2ecf20Sopenharmony_ci rdata->inner_clss_l2gre = 1; 62508c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_VXLAN, 62518c2ecf20Sopenharmony_ci &switch_update_params->changes)) 62528c2ecf20Sopenharmony_ci rdata->inner_clss_vxlan = 1; 62538c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GENEVE, 62548c2ecf20Sopenharmony_ci &switch_update_params->changes)) 62558c2ecf20Sopenharmony_ci rdata->inner_clss_l2geneve = 1; 62568c2ecf20Sopenharmony_ci if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_RSS, 62578c2ecf20Sopenharmony_ci &switch_update_params->changes)) 62588c2ecf20Sopenharmony_ci rdata->inner_rss = 1; 62598c2ecf20Sopenharmony_ci rdata->vxlan_dst_port = 62608c2ecf20Sopenharmony_ci cpu_to_le16(switch_update_params->vxlan_dst_port); 62618c2ecf20Sopenharmony_ci rdata->geneve_dst_port = 62628c2ecf20Sopenharmony_ci cpu_to_le16(switch_update_params->geneve_dst_port); 62638c2ecf20Sopenharmony_ci } 62648c2ecf20Sopenharmony_ci 62658c2ecf20Sopenharmony_ci rdata->echo = SWITCH_UPDATE; 62668c2ecf20Sopenharmony_ci 62678c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 62688c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 62698c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 62708c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 62718c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 62728c2ecf20Sopenharmony_ci */ 62738c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0, 62748c2ecf20Sopenharmony_ci U64_HI(data_mapping), 62758c2ecf20Sopenharmony_ci U64_LO(data_mapping), NONE_CONNECTION_TYPE); 62768c2ecf20Sopenharmony_ci} 62778c2ecf20Sopenharmony_ci 62788c2ecf20Sopenharmony_cistatic inline int bnx2x_func_send_afex_update(struct bnx2x *bp, 62798c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 62808c2ecf20Sopenharmony_ci{ 62818c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 62828c2ecf20Sopenharmony_ci struct function_update_data *rdata = 62838c2ecf20Sopenharmony_ci (struct function_update_data *)o->afex_rdata; 62848c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->afex_rdata_mapping; 62858c2ecf20Sopenharmony_ci struct bnx2x_func_afex_update_params *afex_update_params = 62868c2ecf20Sopenharmony_ci ¶ms->params.afex_update; 62878c2ecf20Sopenharmony_ci 62888c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 62898c2ecf20Sopenharmony_ci 62908c2ecf20Sopenharmony_ci /* Fill the ramrod data with provided parameters */ 62918c2ecf20Sopenharmony_ci rdata->vif_id_change_flg = 1; 62928c2ecf20Sopenharmony_ci rdata->vif_id = cpu_to_le16(afex_update_params->vif_id); 62938c2ecf20Sopenharmony_ci rdata->afex_default_vlan_change_flg = 1; 62948c2ecf20Sopenharmony_ci rdata->afex_default_vlan = 62958c2ecf20Sopenharmony_ci cpu_to_le16(afex_update_params->afex_default_vlan); 62968c2ecf20Sopenharmony_ci rdata->allowed_priorities_change_flg = 1; 62978c2ecf20Sopenharmony_ci rdata->allowed_priorities = afex_update_params->allowed_priorities; 62988c2ecf20Sopenharmony_ci rdata->echo = AFEX_UPDATE; 62998c2ecf20Sopenharmony_ci 63008c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 63018c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 63028c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 63038c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 63048c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 63058c2ecf20Sopenharmony_ci */ 63068c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, 63078c2ecf20Sopenharmony_ci "afex: sending func_update vif_id 0x%x dvlan 0x%x prio 0x%x\n", 63088c2ecf20Sopenharmony_ci rdata->vif_id, 63098c2ecf20Sopenharmony_ci rdata->afex_default_vlan, rdata->allowed_priorities); 63108c2ecf20Sopenharmony_ci 63118c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0, 63128c2ecf20Sopenharmony_ci U64_HI(data_mapping), 63138c2ecf20Sopenharmony_ci U64_LO(data_mapping), NONE_CONNECTION_TYPE); 63148c2ecf20Sopenharmony_ci} 63158c2ecf20Sopenharmony_ci 63168c2ecf20Sopenharmony_cistatic 63178c2ecf20Sopenharmony_ciinline int bnx2x_func_send_afex_viflists(struct bnx2x *bp, 63188c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 63198c2ecf20Sopenharmony_ci{ 63208c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 63218c2ecf20Sopenharmony_ci struct afex_vif_list_ramrod_data *rdata = 63228c2ecf20Sopenharmony_ci (struct afex_vif_list_ramrod_data *)o->afex_rdata; 63238c2ecf20Sopenharmony_ci struct bnx2x_func_afex_viflists_params *afex_vif_params = 63248c2ecf20Sopenharmony_ci ¶ms->params.afex_viflists; 63258c2ecf20Sopenharmony_ci u64 *p_rdata = (u64 *)rdata; 63268c2ecf20Sopenharmony_ci 63278c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 63288c2ecf20Sopenharmony_ci 63298c2ecf20Sopenharmony_ci /* Fill the ramrod data with provided parameters */ 63308c2ecf20Sopenharmony_ci rdata->vif_list_index = cpu_to_le16(afex_vif_params->vif_list_index); 63318c2ecf20Sopenharmony_ci rdata->func_bit_map = afex_vif_params->func_bit_map; 63328c2ecf20Sopenharmony_ci rdata->afex_vif_list_command = afex_vif_params->afex_vif_list_command; 63338c2ecf20Sopenharmony_ci rdata->func_to_clear = afex_vif_params->func_to_clear; 63348c2ecf20Sopenharmony_ci 63358c2ecf20Sopenharmony_ci /* send in echo type of sub command */ 63368c2ecf20Sopenharmony_ci rdata->echo = afex_vif_params->afex_vif_list_command; 63378c2ecf20Sopenharmony_ci 63388c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long we would 63398c2ecf20Sopenharmony_ci * need to ensure the ordering of writing to the SPQ element 63408c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 63418c2ecf20Sopenharmony_ci * read and we will have to put a full memory barrier there 63428c2ecf20Sopenharmony_ci * (inside bnx2x_sp_post()). 63438c2ecf20Sopenharmony_ci */ 63448c2ecf20Sopenharmony_ci 63458c2ecf20Sopenharmony_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", 63468c2ecf20Sopenharmony_ci rdata->afex_vif_list_command, rdata->vif_list_index, 63478c2ecf20Sopenharmony_ci rdata->func_bit_map, rdata->func_to_clear); 63488c2ecf20Sopenharmony_ci 63498c2ecf20Sopenharmony_ci /* this ramrod sends data directly and not through DMA mapping */ 63508c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_AFEX_VIF_LISTS, 0, 63518c2ecf20Sopenharmony_ci U64_HI(*p_rdata), U64_LO(*p_rdata), 63528c2ecf20Sopenharmony_ci NONE_CONNECTION_TYPE); 63538c2ecf20Sopenharmony_ci} 63548c2ecf20Sopenharmony_ci 63558c2ecf20Sopenharmony_cistatic inline int bnx2x_func_send_stop(struct bnx2x *bp, 63568c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 63578c2ecf20Sopenharmony_ci{ 63588c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_STOP, 0, 0, 0, 63598c2ecf20Sopenharmony_ci NONE_CONNECTION_TYPE); 63608c2ecf20Sopenharmony_ci} 63618c2ecf20Sopenharmony_ci 63628c2ecf20Sopenharmony_cistatic inline int bnx2x_func_send_tx_stop(struct bnx2x *bp, 63638c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 63648c2ecf20Sopenharmony_ci{ 63658c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC, 0, 0, 0, 63668c2ecf20Sopenharmony_ci NONE_CONNECTION_TYPE); 63678c2ecf20Sopenharmony_ci} 63688c2ecf20Sopenharmony_cistatic inline int bnx2x_func_send_tx_start(struct bnx2x *bp, 63698c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 63708c2ecf20Sopenharmony_ci{ 63718c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 63728c2ecf20Sopenharmony_ci struct flow_control_configuration *rdata = 63738c2ecf20Sopenharmony_ci (struct flow_control_configuration *)o->rdata; 63748c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 63758c2ecf20Sopenharmony_ci struct bnx2x_func_tx_start_params *tx_start_params = 63768c2ecf20Sopenharmony_ci ¶ms->params.tx_start; 63778c2ecf20Sopenharmony_ci int i; 63788c2ecf20Sopenharmony_ci 63798c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 63808c2ecf20Sopenharmony_ci 63818c2ecf20Sopenharmony_ci rdata->dcb_enabled = tx_start_params->dcb_enabled; 63828c2ecf20Sopenharmony_ci rdata->dcb_version = tx_start_params->dcb_version; 63838c2ecf20Sopenharmony_ci rdata->dont_add_pri_0_en = tx_start_params->dont_add_pri_0_en; 63848c2ecf20Sopenharmony_ci 63858c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rdata->traffic_type_to_priority_cos); i++) 63868c2ecf20Sopenharmony_ci rdata->traffic_type_to_priority_cos[i] = 63878c2ecf20Sopenharmony_ci tx_start_params->traffic_type_to_priority_cos[i]; 63888c2ecf20Sopenharmony_ci 63898c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TRAFFIC_TYPES; i++) 63908c2ecf20Sopenharmony_ci rdata->dcb_outer_pri[i] = tx_start_params->dcb_outer_pri[i]; 63918c2ecf20Sopenharmony_ci /* No need for an explicit memory barrier here as long as we 63928c2ecf20Sopenharmony_ci * ensure the ordering of writing to the SPQ element 63938c2ecf20Sopenharmony_ci * and updating of the SPQ producer which involves a memory 63948c2ecf20Sopenharmony_ci * read. If the memory read is removed we will have to put a 63958c2ecf20Sopenharmony_ci * full memory barrier there (inside bnx2x_sp_post()). 63968c2ecf20Sopenharmony_ci */ 63978c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0, 63988c2ecf20Sopenharmony_ci U64_HI(data_mapping), 63998c2ecf20Sopenharmony_ci U64_LO(data_mapping), NONE_CONNECTION_TYPE); 64008c2ecf20Sopenharmony_ci} 64018c2ecf20Sopenharmony_ci 64028c2ecf20Sopenharmony_cistatic inline 64038c2ecf20Sopenharmony_ciint bnx2x_func_send_set_timesync(struct bnx2x *bp, 64048c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 64058c2ecf20Sopenharmony_ci{ 64068c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 64078c2ecf20Sopenharmony_ci struct set_timesync_ramrod_data *rdata = 64088c2ecf20Sopenharmony_ci (struct set_timesync_ramrod_data *)o->rdata; 64098c2ecf20Sopenharmony_ci dma_addr_t data_mapping = o->rdata_mapping; 64108c2ecf20Sopenharmony_ci struct bnx2x_func_set_timesync_params *set_timesync_params = 64118c2ecf20Sopenharmony_ci ¶ms->params.set_timesync; 64128c2ecf20Sopenharmony_ci 64138c2ecf20Sopenharmony_ci memset(rdata, 0, sizeof(*rdata)); 64148c2ecf20Sopenharmony_ci 64158c2ecf20Sopenharmony_ci /* Fill the ramrod data with provided parameters */ 64168c2ecf20Sopenharmony_ci rdata->drift_adjust_cmd = set_timesync_params->drift_adjust_cmd; 64178c2ecf20Sopenharmony_ci rdata->offset_cmd = set_timesync_params->offset_cmd; 64188c2ecf20Sopenharmony_ci rdata->add_sub_drift_adjust_value = 64198c2ecf20Sopenharmony_ci set_timesync_params->add_sub_drift_adjust_value; 64208c2ecf20Sopenharmony_ci rdata->drift_adjust_value = set_timesync_params->drift_adjust_value; 64218c2ecf20Sopenharmony_ci rdata->drift_adjust_period = set_timesync_params->drift_adjust_period; 64228c2ecf20Sopenharmony_ci rdata->offset_delta.lo = 64238c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(set_timesync_params->offset_delta)); 64248c2ecf20Sopenharmony_ci rdata->offset_delta.hi = 64258c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(set_timesync_params->offset_delta)); 64268c2ecf20Sopenharmony_ci 64278c2ecf20Sopenharmony_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", 64288c2ecf20Sopenharmony_ci rdata->drift_adjust_cmd, rdata->offset_cmd, 64298c2ecf20Sopenharmony_ci rdata->add_sub_drift_adjust_value, rdata->drift_adjust_value, 64308c2ecf20Sopenharmony_ci rdata->drift_adjust_period, rdata->offset_delta.lo, 64318c2ecf20Sopenharmony_ci rdata->offset_delta.hi); 64328c2ecf20Sopenharmony_ci 64338c2ecf20Sopenharmony_ci return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_TIMESYNC, 0, 64348c2ecf20Sopenharmony_ci U64_HI(data_mapping), 64358c2ecf20Sopenharmony_ci U64_LO(data_mapping), NONE_CONNECTION_TYPE); 64368c2ecf20Sopenharmony_ci} 64378c2ecf20Sopenharmony_ci 64388c2ecf20Sopenharmony_cistatic int bnx2x_func_send_cmd(struct bnx2x *bp, 64398c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 64408c2ecf20Sopenharmony_ci{ 64418c2ecf20Sopenharmony_ci switch (params->cmd) { 64428c2ecf20Sopenharmony_ci case BNX2X_F_CMD_HW_INIT: 64438c2ecf20Sopenharmony_ci return bnx2x_func_hw_init(bp, params); 64448c2ecf20Sopenharmony_ci case BNX2X_F_CMD_START: 64458c2ecf20Sopenharmony_ci return bnx2x_func_send_start(bp, params); 64468c2ecf20Sopenharmony_ci case BNX2X_F_CMD_STOP: 64478c2ecf20Sopenharmony_ci return bnx2x_func_send_stop(bp, params); 64488c2ecf20Sopenharmony_ci case BNX2X_F_CMD_HW_RESET: 64498c2ecf20Sopenharmony_ci return bnx2x_func_hw_reset(bp, params); 64508c2ecf20Sopenharmony_ci case BNX2X_F_CMD_AFEX_UPDATE: 64518c2ecf20Sopenharmony_ci return bnx2x_func_send_afex_update(bp, params); 64528c2ecf20Sopenharmony_ci case BNX2X_F_CMD_AFEX_VIFLISTS: 64538c2ecf20Sopenharmony_ci return bnx2x_func_send_afex_viflists(bp, params); 64548c2ecf20Sopenharmony_ci case BNX2X_F_CMD_TX_STOP: 64558c2ecf20Sopenharmony_ci return bnx2x_func_send_tx_stop(bp, params); 64568c2ecf20Sopenharmony_ci case BNX2X_F_CMD_TX_START: 64578c2ecf20Sopenharmony_ci return bnx2x_func_send_tx_start(bp, params); 64588c2ecf20Sopenharmony_ci case BNX2X_F_CMD_SWITCH_UPDATE: 64598c2ecf20Sopenharmony_ci return bnx2x_func_send_switch_update(bp, params); 64608c2ecf20Sopenharmony_ci case BNX2X_F_CMD_SET_TIMESYNC: 64618c2ecf20Sopenharmony_ci return bnx2x_func_send_set_timesync(bp, params); 64628c2ecf20Sopenharmony_ci default: 64638c2ecf20Sopenharmony_ci BNX2X_ERR("Unknown command: %d\n", params->cmd); 64648c2ecf20Sopenharmony_ci return -EINVAL; 64658c2ecf20Sopenharmony_ci } 64668c2ecf20Sopenharmony_ci} 64678c2ecf20Sopenharmony_ci 64688c2ecf20Sopenharmony_civoid bnx2x_init_func_obj(struct bnx2x *bp, 64698c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *obj, 64708c2ecf20Sopenharmony_ci void *rdata, dma_addr_t rdata_mapping, 64718c2ecf20Sopenharmony_ci void *afex_rdata, dma_addr_t afex_rdata_mapping, 64728c2ecf20Sopenharmony_ci struct bnx2x_func_sp_drv_ops *drv_iface) 64738c2ecf20Sopenharmony_ci{ 64748c2ecf20Sopenharmony_ci memset(obj, 0, sizeof(*obj)); 64758c2ecf20Sopenharmony_ci 64768c2ecf20Sopenharmony_ci mutex_init(&obj->one_pending_mutex); 64778c2ecf20Sopenharmony_ci 64788c2ecf20Sopenharmony_ci obj->rdata = rdata; 64798c2ecf20Sopenharmony_ci obj->rdata_mapping = rdata_mapping; 64808c2ecf20Sopenharmony_ci obj->afex_rdata = afex_rdata; 64818c2ecf20Sopenharmony_ci obj->afex_rdata_mapping = afex_rdata_mapping; 64828c2ecf20Sopenharmony_ci obj->send_cmd = bnx2x_func_send_cmd; 64838c2ecf20Sopenharmony_ci obj->check_transition = bnx2x_func_chk_transition; 64848c2ecf20Sopenharmony_ci obj->complete_cmd = bnx2x_func_comp_cmd; 64858c2ecf20Sopenharmony_ci obj->wait_comp = bnx2x_func_wait_comp; 64868c2ecf20Sopenharmony_ci 64878c2ecf20Sopenharmony_ci obj->drv = drv_iface; 64888c2ecf20Sopenharmony_ci} 64898c2ecf20Sopenharmony_ci 64908c2ecf20Sopenharmony_ci/** 64918c2ecf20Sopenharmony_ci * bnx2x_func_state_change - perform Function state change transition 64928c2ecf20Sopenharmony_ci * 64938c2ecf20Sopenharmony_ci * @bp: device handle 64948c2ecf20Sopenharmony_ci * @params: parameters to perform the transaction 64958c2ecf20Sopenharmony_ci * 64968c2ecf20Sopenharmony_ci * returns 0 in case of successfully completed transition, 64978c2ecf20Sopenharmony_ci * negative error code in case of failure, positive 64988c2ecf20Sopenharmony_ci * (EBUSY) value if there is a completion to that is 64998c2ecf20Sopenharmony_ci * still pending (possible only if RAMROD_COMP_WAIT is 65008c2ecf20Sopenharmony_ci * not set in params->ramrod_flags for asynchronous 65018c2ecf20Sopenharmony_ci * commands). 65028c2ecf20Sopenharmony_ci */ 65038c2ecf20Sopenharmony_ciint bnx2x_func_state_change(struct bnx2x *bp, 65048c2ecf20Sopenharmony_ci struct bnx2x_func_state_params *params) 65058c2ecf20Sopenharmony_ci{ 65068c2ecf20Sopenharmony_ci struct bnx2x_func_sp_obj *o = params->f_obj; 65078c2ecf20Sopenharmony_ci int rc, cnt = 300; 65088c2ecf20Sopenharmony_ci enum bnx2x_func_cmd cmd = params->cmd; 65098c2ecf20Sopenharmony_ci unsigned long *pending = &o->pending; 65108c2ecf20Sopenharmony_ci 65118c2ecf20Sopenharmony_ci mutex_lock(&o->one_pending_mutex); 65128c2ecf20Sopenharmony_ci 65138c2ecf20Sopenharmony_ci /* Check that the requested transition is legal */ 65148c2ecf20Sopenharmony_ci rc = o->check_transition(bp, o, params); 65158c2ecf20Sopenharmony_ci if ((rc == -EBUSY) && 65168c2ecf20Sopenharmony_ci (test_bit(RAMROD_RETRY, ¶ms->ramrod_flags))) { 65178c2ecf20Sopenharmony_ci while ((rc == -EBUSY) && (--cnt > 0)) { 65188c2ecf20Sopenharmony_ci mutex_unlock(&o->one_pending_mutex); 65198c2ecf20Sopenharmony_ci msleep(10); 65208c2ecf20Sopenharmony_ci mutex_lock(&o->one_pending_mutex); 65218c2ecf20Sopenharmony_ci rc = o->check_transition(bp, o, params); 65228c2ecf20Sopenharmony_ci } 65238c2ecf20Sopenharmony_ci if (rc == -EBUSY) { 65248c2ecf20Sopenharmony_ci mutex_unlock(&o->one_pending_mutex); 65258c2ecf20Sopenharmony_ci BNX2X_ERR("timeout waiting for previous ramrod completion\n"); 65268c2ecf20Sopenharmony_ci return rc; 65278c2ecf20Sopenharmony_ci } 65288c2ecf20Sopenharmony_ci } else if (rc) { 65298c2ecf20Sopenharmony_ci mutex_unlock(&o->one_pending_mutex); 65308c2ecf20Sopenharmony_ci return rc; 65318c2ecf20Sopenharmony_ci } 65328c2ecf20Sopenharmony_ci 65338c2ecf20Sopenharmony_ci /* Set "pending" bit */ 65348c2ecf20Sopenharmony_ci set_bit(cmd, pending); 65358c2ecf20Sopenharmony_ci 65368c2ecf20Sopenharmony_ci /* Don't send a command if only driver cleanup was requested */ 65378c2ecf20Sopenharmony_ci if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) { 65388c2ecf20Sopenharmony_ci bnx2x_func_state_change_comp(bp, o, cmd); 65398c2ecf20Sopenharmony_ci mutex_unlock(&o->one_pending_mutex); 65408c2ecf20Sopenharmony_ci } else { 65418c2ecf20Sopenharmony_ci /* Send a ramrod */ 65428c2ecf20Sopenharmony_ci rc = o->send_cmd(bp, params); 65438c2ecf20Sopenharmony_ci 65448c2ecf20Sopenharmony_ci mutex_unlock(&o->one_pending_mutex); 65458c2ecf20Sopenharmony_ci 65468c2ecf20Sopenharmony_ci if (rc) { 65478c2ecf20Sopenharmony_ci o->next_state = BNX2X_F_STATE_MAX; 65488c2ecf20Sopenharmony_ci clear_bit(cmd, pending); 65498c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 65508c2ecf20Sopenharmony_ci return rc; 65518c2ecf20Sopenharmony_ci } 65528c2ecf20Sopenharmony_ci 65538c2ecf20Sopenharmony_ci if (test_bit(RAMROD_COMP_WAIT, ¶ms->ramrod_flags)) { 65548c2ecf20Sopenharmony_ci rc = o->wait_comp(bp, o, cmd); 65558c2ecf20Sopenharmony_ci if (rc) 65568c2ecf20Sopenharmony_ci return rc; 65578c2ecf20Sopenharmony_ci 65588c2ecf20Sopenharmony_ci return 0; 65598c2ecf20Sopenharmony_ci } 65608c2ecf20Sopenharmony_ci } 65618c2ecf20Sopenharmony_ci 65628c2ecf20Sopenharmony_ci return !!test_bit(cmd, pending); 65638c2ecf20Sopenharmony_ci} 6564