162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. 462306a36Sopenharmony_ci * All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This software is available to you under a choice of one of two 862306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 962306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1062306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1162306a36Sopenharmony_ci * OpenIB.org BSD license below: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1462306a36Sopenharmony_ci * without modification, are permitted provided that the following 1562306a36Sopenharmony_ci * conditions are met: 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1862306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1962306a36Sopenharmony_ci * disclaimer. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2262306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2362306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2462306a36Sopenharmony_ci * provided with the distribution. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2762306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2862306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2962306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 3062306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3162306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3262306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3362306a36Sopenharmony_ci * SOFTWARE. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/sched.h> 3762306a36Sopenharmony_ci#include <linux/pci.h> 3862306a36Sopenharmony_ci#include <linux/errno.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/io.h> 4162306a36Sopenharmony_ci#include <linux/slab.h> 4262306a36Sopenharmony_ci#include <linux/mlx4/cmd.h> 4362306a36Sopenharmony_ci#include <linux/mlx4/qp.h> 4462306a36Sopenharmony_ci#include <linux/if_ether.h> 4562306a36Sopenharmony_ci#include <linux/etherdevice.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include "mlx4.h" 4862306a36Sopenharmony_ci#include "fw.h" 4962306a36Sopenharmony_ci#include "mlx4_stats.h" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define MLX4_MAC_VALID (1ull << 63) 5262306a36Sopenharmony_ci#define MLX4_PF_COUNTERS_PER_PORT 2 5362306a36Sopenharmony_ci#define MLX4_VF_COUNTERS_PER_PORT 1 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct mac_res { 5662306a36Sopenharmony_ci struct list_head list; 5762306a36Sopenharmony_ci u64 mac; 5862306a36Sopenharmony_ci int ref_count; 5962306a36Sopenharmony_ci u8 smac_index; 6062306a36Sopenharmony_ci u8 port; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct vlan_res { 6462306a36Sopenharmony_ci struct list_head list; 6562306a36Sopenharmony_ci u16 vlan; 6662306a36Sopenharmony_ci int ref_count; 6762306a36Sopenharmony_ci int vlan_index; 6862306a36Sopenharmony_ci u8 port; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct res_common { 7262306a36Sopenharmony_ci struct list_head list; 7362306a36Sopenharmony_ci struct rb_node node; 7462306a36Sopenharmony_ci u64 res_id; 7562306a36Sopenharmony_ci int owner; 7662306a36Sopenharmony_ci int state; 7762306a36Sopenharmony_ci int from_state; 7862306a36Sopenharmony_ci int to_state; 7962306a36Sopenharmony_ci int removing; 8062306a36Sopenharmony_ci const char *func_name; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cienum { 8462306a36Sopenharmony_ci RES_ANY_BUSY = 1 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct res_gid { 8862306a36Sopenharmony_ci struct list_head list; 8962306a36Sopenharmony_ci u8 gid[16]; 9062306a36Sopenharmony_ci enum mlx4_protocol prot; 9162306a36Sopenharmony_ci enum mlx4_steer_type steer; 9262306a36Sopenharmony_ci u64 reg_id; 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cienum res_qp_states { 9662306a36Sopenharmony_ci RES_QP_BUSY = RES_ANY_BUSY, 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* QP number was allocated */ 9962306a36Sopenharmony_ci RES_QP_RESERVED, 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* ICM memory for QP context was mapped */ 10262306a36Sopenharmony_ci RES_QP_MAPPED, 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* QP is in hw ownership */ 10562306a36Sopenharmony_ci RES_QP_HW 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct res_qp { 10962306a36Sopenharmony_ci struct res_common com; 11062306a36Sopenharmony_ci struct res_mtt *mtt; 11162306a36Sopenharmony_ci struct res_cq *rcq; 11262306a36Sopenharmony_ci struct res_cq *scq; 11362306a36Sopenharmony_ci struct res_srq *srq; 11462306a36Sopenharmony_ci struct list_head mcg_list; 11562306a36Sopenharmony_ci spinlock_t mcg_spl; 11662306a36Sopenharmony_ci int local_qpn; 11762306a36Sopenharmony_ci atomic_t ref_count; 11862306a36Sopenharmony_ci u32 qpc_flags; 11962306a36Sopenharmony_ci /* saved qp params before VST enforcement in order to restore on VGT */ 12062306a36Sopenharmony_ci u8 sched_queue; 12162306a36Sopenharmony_ci __be32 param3; 12262306a36Sopenharmony_ci u8 vlan_control; 12362306a36Sopenharmony_ci u8 fvl_rx; 12462306a36Sopenharmony_ci u8 pri_path_fl; 12562306a36Sopenharmony_ci u8 vlan_index; 12662306a36Sopenharmony_ci u8 feup; 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cienum res_mtt_states { 13062306a36Sopenharmony_ci RES_MTT_BUSY = RES_ANY_BUSY, 13162306a36Sopenharmony_ci RES_MTT_ALLOCATED, 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic inline const char *mtt_states_str(enum res_mtt_states state) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci switch (state) { 13762306a36Sopenharmony_ci case RES_MTT_BUSY: return "RES_MTT_BUSY"; 13862306a36Sopenharmony_ci case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED"; 13962306a36Sopenharmony_ci default: return "Unknown"; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistruct res_mtt { 14462306a36Sopenharmony_ci struct res_common com; 14562306a36Sopenharmony_ci int order; 14662306a36Sopenharmony_ci atomic_t ref_count; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cienum res_mpt_states { 15062306a36Sopenharmony_ci RES_MPT_BUSY = RES_ANY_BUSY, 15162306a36Sopenharmony_ci RES_MPT_RESERVED, 15262306a36Sopenharmony_ci RES_MPT_MAPPED, 15362306a36Sopenharmony_ci RES_MPT_HW, 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistruct res_mpt { 15762306a36Sopenharmony_ci struct res_common com; 15862306a36Sopenharmony_ci struct res_mtt *mtt; 15962306a36Sopenharmony_ci int key; 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cienum res_eq_states { 16362306a36Sopenharmony_ci RES_EQ_BUSY = RES_ANY_BUSY, 16462306a36Sopenharmony_ci RES_EQ_RESERVED, 16562306a36Sopenharmony_ci RES_EQ_HW, 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistruct res_eq { 16962306a36Sopenharmony_ci struct res_common com; 17062306a36Sopenharmony_ci struct res_mtt *mtt; 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cienum res_cq_states { 17462306a36Sopenharmony_ci RES_CQ_BUSY = RES_ANY_BUSY, 17562306a36Sopenharmony_ci RES_CQ_ALLOCATED, 17662306a36Sopenharmony_ci RES_CQ_HW, 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistruct res_cq { 18062306a36Sopenharmony_ci struct res_common com; 18162306a36Sopenharmony_ci struct res_mtt *mtt; 18262306a36Sopenharmony_ci atomic_t ref_count; 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cienum res_srq_states { 18662306a36Sopenharmony_ci RES_SRQ_BUSY = RES_ANY_BUSY, 18762306a36Sopenharmony_ci RES_SRQ_ALLOCATED, 18862306a36Sopenharmony_ci RES_SRQ_HW, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistruct res_srq { 19262306a36Sopenharmony_ci struct res_common com; 19362306a36Sopenharmony_ci struct res_mtt *mtt; 19462306a36Sopenharmony_ci struct res_cq *cq; 19562306a36Sopenharmony_ci atomic_t ref_count; 19662306a36Sopenharmony_ci}; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cienum res_counter_states { 19962306a36Sopenharmony_ci RES_COUNTER_BUSY = RES_ANY_BUSY, 20062306a36Sopenharmony_ci RES_COUNTER_ALLOCATED, 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistruct res_counter { 20462306a36Sopenharmony_ci struct res_common com; 20562306a36Sopenharmony_ci int port; 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cienum res_xrcdn_states { 20962306a36Sopenharmony_ci RES_XRCD_BUSY = RES_ANY_BUSY, 21062306a36Sopenharmony_ci RES_XRCD_ALLOCATED, 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistruct res_xrcdn { 21462306a36Sopenharmony_ci struct res_common com; 21562306a36Sopenharmony_ci int port; 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cienum res_fs_rule_states { 21962306a36Sopenharmony_ci RES_FS_RULE_BUSY = RES_ANY_BUSY, 22062306a36Sopenharmony_ci RES_FS_RULE_ALLOCATED, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistruct res_fs_rule { 22462306a36Sopenharmony_ci struct res_common com; 22562306a36Sopenharmony_ci int qpn; 22662306a36Sopenharmony_ci /* VF DMFS mbox with port flipped */ 22762306a36Sopenharmony_ci void *mirr_mbox; 22862306a36Sopenharmony_ci /* > 0 --> apply mirror when getting into HA mode */ 22962306a36Sopenharmony_ci /* = 0 --> un-apply mirror when getting out of HA mode */ 23062306a36Sopenharmony_ci u32 mirr_mbox_size; 23162306a36Sopenharmony_ci struct list_head mirr_list; 23262306a36Sopenharmony_ci u64 mirr_rule_id; 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void *res_tracker_lookup(struct rb_root *root, u64 res_id) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct rb_node *node = root->rb_node; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci while (node) { 24062306a36Sopenharmony_ci struct res_common *res = rb_entry(node, struct res_common, 24162306a36Sopenharmony_ci node); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (res_id < res->res_id) 24462306a36Sopenharmony_ci node = node->rb_left; 24562306a36Sopenharmony_ci else if (res_id > res->res_id) 24662306a36Sopenharmony_ci node = node->rb_right; 24762306a36Sopenharmony_ci else 24862306a36Sopenharmony_ci return res; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return NULL; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int res_tracker_insert(struct rb_root *root, struct res_common *res) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct rb_node **new = &(root->rb_node), *parent = NULL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Figure out where to put new node */ 25862306a36Sopenharmony_ci while (*new) { 25962306a36Sopenharmony_ci struct res_common *this = rb_entry(*new, struct res_common, 26062306a36Sopenharmony_ci node); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci parent = *new; 26362306a36Sopenharmony_ci if (res->res_id < this->res_id) 26462306a36Sopenharmony_ci new = &((*new)->rb_left); 26562306a36Sopenharmony_ci else if (res->res_id > this->res_id) 26662306a36Sopenharmony_ci new = &((*new)->rb_right); 26762306a36Sopenharmony_ci else 26862306a36Sopenharmony_ci return -EEXIST; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Add new node and rebalance tree. */ 27262306a36Sopenharmony_ci rb_link_node(&res->node, parent, new); 27362306a36Sopenharmony_ci rb_insert_color(&res->node, root); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cienum qp_transition { 27962306a36Sopenharmony_ci QP_TRANS_INIT2RTR, 28062306a36Sopenharmony_ci QP_TRANS_RTR2RTS, 28162306a36Sopenharmony_ci QP_TRANS_RTS2RTS, 28262306a36Sopenharmony_ci QP_TRANS_SQERR2RTS, 28362306a36Sopenharmony_ci QP_TRANS_SQD2SQD, 28462306a36Sopenharmony_ci QP_TRANS_SQD2RTS 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* For Debug uses */ 28862306a36Sopenharmony_cistatic const char *resource_str(enum mlx4_resource rt) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci switch (rt) { 29162306a36Sopenharmony_ci case RES_QP: return "RES_QP"; 29262306a36Sopenharmony_ci case RES_CQ: return "RES_CQ"; 29362306a36Sopenharmony_ci case RES_SRQ: return "RES_SRQ"; 29462306a36Sopenharmony_ci case RES_MPT: return "RES_MPT"; 29562306a36Sopenharmony_ci case RES_MTT: return "RES_MTT"; 29662306a36Sopenharmony_ci case RES_MAC: return "RES_MAC"; 29762306a36Sopenharmony_ci case RES_VLAN: return "RES_VLAN"; 29862306a36Sopenharmony_ci case RES_EQ: return "RES_EQ"; 29962306a36Sopenharmony_ci case RES_COUNTER: return "RES_COUNTER"; 30062306a36Sopenharmony_ci case RES_FS_RULE: return "RES_FS_RULE"; 30162306a36Sopenharmony_ci case RES_XRCD: return "RES_XRCD"; 30262306a36Sopenharmony_ci default: return "Unknown resource type !!!"; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void rem_slave_vlans(struct mlx4_dev *dev, int slave); 30762306a36Sopenharmony_cistatic inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, 30862306a36Sopenharmony_ci enum mlx4_resource res_type, int count, 30962306a36Sopenharmony_ci int port) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 31262306a36Sopenharmony_ci struct resource_allocator *res_alloc = 31362306a36Sopenharmony_ci &priv->mfunc.master.res_tracker.res_alloc[res_type]; 31462306a36Sopenharmony_ci int err = -EDQUOT; 31562306a36Sopenharmony_ci int allocated, free, reserved, guaranteed, from_free; 31662306a36Sopenharmony_ci int from_rsvd; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (slave > dev->persist->num_vfs) 31962306a36Sopenharmony_ci return -EINVAL; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci spin_lock(&res_alloc->alloc_lock); 32262306a36Sopenharmony_ci allocated = (port > 0) ? 32362306a36Sopenharmony_ci res_alloc->allocated[(port - 1) * 32462306a36Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] : 32562306a36Sopenharmony_ci res_alloc->allocated[slave]; 32662306a36Sopenharmony_ci free = (port > 0) ? res_alloc->res_port_free[port - 1] : 32762306a36Sopenharmony_ci res_alloc->res_free; 32862306a36Sopenharmony_ci reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] : 32962306a36Sopenharmony_ci res_alloc->res_reserved; 33062306a36Sopenharmony_ci guaranteed = res_alloc->guaranteed[slave]; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (allocated + count > res_alloc->quota[slave]) { 33362306a36Sopenharmony_ci mlx4_warn(dev, "VF %d port %d res %s: quota exceeded, count %d alloc %d quota %d\n", 33462306a36Sopenharmony_ci slave, port, resource_str(res_type), count, 33562306a36Sopenharmony_ci allocated, res_alloc->quota[slave]); 33662306a36Sopenharmony_ci goto out; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (allocated + count <= guaranteed) { 34062306a36Sopenharmony_ci err = 0; 34162306a36Sopenharmony_ci from_rsvd = count; 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci /* portion may need to be obtained from free area */ 34462306a36Sopenharmony_ci if (guaranteed - allocated > 0) 34562306a36Sopenharmony_ci from_free = count - (guaranteed - allocated); 34662306a36Sopenharmony_ci else 34762306a36Sopenharmony_ci from_free = count; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci from_rsvd = count - from_free; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (free - from_free >= reserved) 35262306a36Sopenharmony_ci err = 0; 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci mlx4_warn(dev, "VF %d port %d res %s: free pool empty, free %d from_free %d rsvd %d\n", 35562306a36Sopenharmony_ci slave, port, resource_str(res_type), free, 35662306a36Sopenharmony_ci from_free, reserved); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (!err) { 36062306a36Sopenharmony_ci /* grant the request */ 36162306a36Sopenharmony_ci if (port > 0) { 36262306a36Sopenharmony_ci res_alloc->allocated[(port - 1) * 36362306a36Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] += count; 36462306a36Sopenharmony_ci res_alloc->res_port_free[port - 1] -= count; 36562306a36Sopenharmony_ci res_alloc->res_port_rsvd[port - 1] -= from_rsvd; 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci res_alloc->allocated[slave] += count; 36862306a36Sopenharmony_ci res_alloc->res_free -= count; 36962306a36Sopenharmony_ci res_alloc->res_reserved -= from_rsvd; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ciout: 37462306a36Sopenharmony_ci spin_unlock(&res_alloc->alloc_lock); 37562306a36Sopenharmony_ci return err; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, 37962306a36Sopenharmony_ci enum mlx4_resource res_type, int count, 38062306a36Sopenharmony_ci int port) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 38362306a36Sopenharmony_ci struct resource_allocator *res_alloc = 38462306a36Sopenharmony_ci &priv->mfunc.master.res_tracker.res_alloc[res_type]; 38562306a36Sopenharmony_ci int allocated, guaranteed, from_rsvd; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (slave > dev->persist->num_vfs) 38862306a36Sopenharmony_ci return; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci spin_lock(&res_alloc->alloc_lock); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci allocated = (port > 0) ? 39362306a36Sopenharmony_ci res_alloc->allocated[(port - 1) * 39462306a36Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] : 39562306a36Sopenharmony_ci res_alloc->allocated[slave]; 39662306a36Sopenharmony_ci guaranteed = res_alloc->guaranteed[slave]; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (allocated - count >= guaranteed) { 39962306a36Sopenharmony_ci from_rsvd = 0; 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci /* portion may need to be returned to reserved area */ 40262306a36Sopenharmony_ci if (allocated - guaranteed > 0) 40362306a36Sopenharmony_ci from_rsvd = count - (allocated - guaranteed); 40462306a36Sopenharmony_ci else 40562306a36Sopenharmony_ci from_rsvd = count; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (port > 0) { 40962306a36Sopenharmony_ci res_alloc->allocated[(port - 1) * 41062306a36Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] -= count; 41162306a36Sopenharmony_ci res_alloc->res_port_free[port - 1] += count; 41262306a36Sopenharmony_ci res_alloc->res_port_rsvd[port - 1] += from_rsvd; 41362306a36Sopenharmony_ci } else { 41462306a36Sopenharmony_ci res_alloc->allocated[slave] -= count; 41562306a36Sopenharmony_ci res_alloc->res_free += count; 41662306a36Sopenharmony_ci res_alloc->res_reserved += from_rsvd; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci spin_unlock(&res_alloc->alloc_lock); 42062306a36Sopenharmony_ci return; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic inline void initialize_res_quotas(struct mlx4_dev *dev, 42462306a36Sopenharmony_ci struct resource_allocator *res_alloc, 42562306a36Sopenharmony_ci enum mlx4_resource res_type, 42662306a36Sopenharmony_ci int vf, int num_instances) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci res_alloc->guaranteed[vf] = num_instances / 42962306a36Sopenharmony_ci (2 * (dev->persist->num_vfs + 1)); 43062306a36Sopenharmony_ci res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; 43162306a36Sopenharmony_ci if (vf == mlx4_master_func_num(dev)) { 43262306a36Sopenharmony_ci res_alloc->res_free = num_instances; 43362306a36Sopenharmony_ci if (res_type == RES_MTT) { 43462306a36Sopenharmony_ci /* reserved mtts will be taken out of the PF allocation */ 43562306a36Sopenharmony_ci res_alloc->res_free += dev->caps.reserved_mtts; 43662306a36Sopenharmony_ci res_alloc->guaranteed[vf] += dev->caps.reserved_mtts; 43762306a36Sopenharmony_ci res_alloc->quota[vf] += dev->caps.reserved_mtts; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_civoid mlx4_init_quotas(struct mlx4_dev *dev) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 44562306a36Sopenharmony_ci int pf; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* quotas for VFs are initialized in mlx4_slave_cap */ 44862306a36Sopenharmony_ci if (mlx4_is_slave(dev)) 44962306a36Sopenharmony_ci return; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!mlx4_is_mfunc(dev)) { 45262306a36Sopenharmony_ci dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps - 45362306a36Sopenharmony_ci mlx4_num_reserved_sqps(dev); 45462306a36Sopenharmony_ci dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs; 45562306a36Sopenharmony_ci dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs; 45662306a36Sopenharmony_ci dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts; 45762306a36Sopenharmony_ci dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws; 45862306a36Sopenharmony_ci return; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci pf = mlx4_master_func_num(dev); 46262306a36Sopenharmony_ci dev->quotas.qp = 46362306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf]; 46462306a36Sopenharmony_ci dev->quotas.cq = 46562306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf]; 46662306a36Sopenharmony_ci dev->quotas.srq = 46762306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf]; 46862306a36Sopenharmony_ci dev->quotas.mtt = 46962306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf]; 47062306a36Sopenharmony_ci dev->quotas.mpt = 47162306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int 47562306a36Sopenharmony_cimlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev, 47662306a36Sopenharmony_ci struct resource_allocator *res_alloc, 47762306a36Sopenharmony_ci int vf) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct mlx4_active_ports actv_ports; 48062306a36Sopenharmony_ci int ports, counters_guaranteed; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* For master, only allocate according to the number of phys ports */ 48362306a36Sopenharmony_ci if (vf == mlx4_master_func_num(dev)) 48462306a36Sopenharmony_ci return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* calculate real number of ports for the VF */ 48762306a36Sopenharmony_ci actv_ports = mlx4_get_active_ports(dev, vf); 48862306a36Sopenharmony_ci ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports); 48962306a36Sopenharmony_ci counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* If we do not have enough counters for this VF, do not 49262306a36Sopenharmony_ci * allocate any for it. '-1' to reduce the sink counter. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci if ((res_alloc->res_reserved + counters_guaranteed) > 49562306a36Sopenharmony_ci (dev->caps.max_counters - 1)) 49662306a36Sopenharmony_ci return 0; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return counters_guaranteed; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ciint mlx4_init_resource_tracker(struct mlx4_dev *dev) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 50462306a36Sopenharmony_ci int i, j; 50562306a36Sopenharmony_ci int t; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci priv->mfunc.master.res_tracker.slave_list = 50862306a36Sopenharmony_ci kcalloc(dev->num_slaves, sizeof(struct slave_list), 50962306a36Sopenharmony_ci GFP_KERNEL); 51062306a36Sopenharmony_ci if (!priv->mfunc.master.res_tracker.slave_list) 51162306a36Sopenharmony_ci return -ENOMEM; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci for (i = 0 ; i < dev->num_slaves; i++) { 51462306a36Sopenharmony_ci for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t) 51562306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->mfunc.master.res_tracker. 51662306a36Sopenharmony_ci slave_list[i].res_list[t]); 51762306a36Sopenharmony_ci mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n", 52162306a36Sopenharmony_ci dev->num_slaves); 52262306a36Sopenharmony_ci for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) 52362306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 52662306a36Sopenharmony_ci struct resource_allocator *res_alloc = 52762306a36Sopenharmony_ci &priv->mfunc.master.res_tracker.res_alloc[i]; 52862306a36Sopenharmony_ci res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1, 52962306a36Sopenharmony_ci sizeof(int), 53062306a36Sopenharmony_ci GFP_KERNEL); 53162306a36Sopenharmony_ci res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1, 53262306a36Sopenharmony_ci sizeof(int), 53362306a36Sopenharmony_ci GFP_KERNEL); 53462306a36Sopenharmony_ci if (i == RES_MAC || i == RES_VLAN) 53562306a36Sopenharmony_ci res_alloc->allocated = 53662306a36Sopenharmony_ci kcalloc(MLX4_MAX_PORTS * 53762306a36Sopenharmony_ci (dev->persist->num_vfs + 1), 53862306a36Sopenharmony_ci sizeof(int), GFP_KERNEL); 53962306a36Sopenharmony_ci else 54062306a36Sopenharmony_ci res_alloc->allocated = 54162306a36Sopenharmony_ci kcalloc(dev->persist->num_vfs + 1, 54262306a36Sopenharmony_ci sizeof(int), GFP_KERNEL); 54362306a36Sopenharmony_ci /* Reduce the sink counter */ 54462306a36Sopenharmony_ci if (i == RES_COUNTER) 54562306a36Sopenharmony_ci res_alloc->res_free = dev->caps.max_counters - 1; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!res_alloc->quota || !res_alloc->guaranteed || 54862306a36Sopenharmony_ci !res_alloc->allocated) 54962306a36Sopenharmony_ci goto no_mem_err; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci spin_lock_init(&res_alloc->alloc_lock); 55262306a36Sopenharmony_ci for (t = 0; t < dev->persist->num_vfs + 1; t++) { 55362306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = 55462306a36Sopenharmony_ci mlx4_get_active_ports(dev, t); 55562306a36Sopenharmony_ci switch (i) { 55662306a36Sopenharmony_ci case RES_QP: 55762306a36Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_QP, 55862306a36Sopenharmony_ci t, dev->caps.num_qps - 55962306a36Sopenharmony_ci dev->caps.reserved_qps - 56062306a36Sopenharmony_ci mlx4_num_reserved_sqps(dev)); 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci case RES_CQ: 56362306a36Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_CQ, 56462306a36Sopenharmony_ci t, dev->caps.num_cqs - 56562306a36Sopenharmony_ci dev->caps.reserved_cqs); 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci case RES_SRQ: 56862306a36Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_SRQ, 56962306a36Sopenharmony_ci t, dev->caps.num_srqs - 57062306a36Sopenharmony_ci dev->caps.reserved_srqs); 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci case RES_MPT: 57362306a36Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_MPT, 57462306a36Sopenharmony_ci t, dev->caps.num_mpts - 57562306a36Sopenharmony_ci dev->caps.reserved_mrws); 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci case RES_MTT: 57862306a36Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_MTT, 57962306a36Sopenharmony_ci t, dev->caps.num_mtts - 58062306a36Sopenharmony_ci dev->caps.reserved_mtts); 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case RES_MAC: 58362306a36Sopenharmony_ci if (t == mlx4_master_func_num(dev)) { 58462306a36Sopenharmony_ci int max_vfs_pport = 0; 58562306a36Sopenharmony_ci /* Calculate the max vfs per port for */ 58662306a36Sopenharmony_ci /* both ports. */ 58762306a36Sopenharmony_ci for (j = 0; j < dev->caps.num_ports; 58862306a36Sopenharmony_ci j++) { 58962306a36Sopenharmony_ci struct mlx4_slaves_pport slaves_pport = 59062306a36Sopenharmony_ci mlx4_phys_to_slaves_pport(dev, j + 1); 59162306a36Sopenharmony_ci unsigned current_slaves = 59262306a36Sopenharmony_ci bitmap_weight(slaves_pport.slaves, 59362306a36Sopenharmony_ci dev->caps.num_ports) - 1; 59462306a36Sopenharmony_ci if (max_vfs_pport < current_slaves) 59562306a36Sopenharmony_ci max_vfs_pport = 59662306a36Sopenharmony_ci current_slaves; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci res_alloc->quota[t] = 59962306a36Sopenharmony_ci MLX4_MAX_MAC_NUM - 60062306a36Sopenharmony_ci 2 * max_vfs_pport; 60162306a36Sopenharmony_ci res_alloc->guaranteed[t] = 2; 60262306a36Sopenharmony_ci for (j = 0; j < MLX4_MAX_PORTS; j++) 60362306a36Sopenharmony_ci res_alloc->res_port_free[j] = 60462306a36Sopenharmony_ci MLX4_MAX_MAC_NUM; 60562306a36Sopenharmony_ci } else { 60662306a36Sopenharmony_ci res_alloc->quota[t] = MLX4_MAX_MAC_NUM; 60762306a36Sopenharmony_ci res_alloc->guaranteed[t] = 2; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case RES_VLAN: 61162306a36Sopenharmony_ci if (t == mlx4_master_func_num(dev)) { 61262306a36Sopenharmony_ci res_alloc->quota[t] = MLX4_MAX_VLAN_NUM; 61362306a36Sopenharmony_ci res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2; 61462306a36Sopenharmony_ci for (j = 0; j < MLX4_MAX_PORTS; j++) 61562306a36Sopenharmony_ci res_alloc->res_port_free[j] = 61662306a36Sopenharmony_ci res_alloc->quota[t]; 61762306a36Sopenharmony_ci } else { 61862306a36Sopenharmony_ci res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2; 61962306a36Sopenharmony_ci res_alloc->guaranteed[t] = 0; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci case RES_COUNTER: 62362306a36Sopenharmony_ci res_alloc->quota[t] = dev->caps.max_counters; 62462306a36Sopenharmony_ci res_alloc->guaranteed[t] = 62562306a36Sopenharmony_ci mlx4_calc_res_counter_guaranteed(dev, res_alloc, t); 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci default: 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci if (i == RES_MAC || i == RES_VLAN) { 63162306a36Sopenharmony_ci for (j = 0; j < dev->caps.num_ports; j++) 63262306a36Sopenharmony_ci if (test_bit(j, actv_ports.ports)) 63362306a36Sopenharmony_ci res_alloc->res_port_rsvd[j] += 63462306a36Sopenharmony_ci res_alloc->guaranteed[t]; 63562306a36Sopenharmony_ci } else { 63662306a36Sopenharmony_ci res_alloc->res_reserved += res_alloc->guaranteed[t]; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci spin_lock_init(&priv->mfunc.master.res_tracker.lock); 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cino_mem_err: 64462306a36Sopenharmony_ci for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 64562306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 64662306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 64762306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 64862306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 64962306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 65062306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci return -ENOMEM; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_civoid mlx4_free_resource_tracker(struct mlx4_dev *dev, 65662306a36Sopenharmony_ci enum mlx4_res_tracker_free_type type) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 65962306a36Sopenharmony_ci int i; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (priv->mfunc.master.res_tracker.slave_list) { 66262306a36Sopenharmony_ci if (type != RES_TR_FREE_STRUCTS_ONLY) { 66362306a36Sopenharmony_ci for (i = 0; i < dev->num_slaves; i++) { 66462306a36Sopenharmony_ci if (type == RES_TR_FREE_ALL || 66562306a36Sopenharmony_ci dev->caps.function != i) 66662306a36Sopenharmony_ci mlx4_delete_all_resources_for_slave(dev, i); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci /* free master's vlans */ 66962306a36Sopenharmony_ci i = dev->caps.function; 67062306a36Sopenharmony_ci mlx4_reset_roce_gids(dev, i); 67162306a36Sopenharmony_ci mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 67262306a36Sopenharmony_ci rem_slave_vlans(dev, i); 67362306a36Sopenharmony_ci mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (type != RES_TR_FREE_SLAVES_ONLY) { 67762306a36Sopenharmony_ci for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 67862306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 67962306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 68062306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 68162306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 68262306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 68362306a36Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.slave_list); 68662306a36Sopenharmony_ci priv->mfunc.master.res_tracker.slave_list = NULL; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic void update_pkey_index(struct mlx4_dev *dev, int slave, 69262306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci u8 sched = *(u8 *)(inbox->buf + 64); 69562306a36Sopenharmony_ci u8 orig_index = *(u8 *)(inbox->buf + 35); 69662306a36Sopenharmony_ci u8 new_index; 69762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 69862306a36Sopenharmony_ci int port; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci port = (sched >> 6 & 1) + 1; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci new_index = priv->virt2phys_pkey[slave][port - 1][orig_index]; 70362306a36Sopenharmony_ci *(u8 *)(inbox->buf + 35) = new_index; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, 70762306a36Sopenharmony_ci u8 slave) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct mlx4_qp_context *qp_ctx = inbox->buf + 8; 71062306a36Sopenharmony_ci enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); 71162306a36Sopenharmony_ci u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 71262306a36Sopenharmony_ci int port; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (MLX4_QP_ST_UD == ts) { 71562306a36Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 71662306a36Sopenharmony_ci if (mlx4_is_eth(dev, port)) 71762306a36Sopenharmony_ci qp_ctx->pri_path.mgid_index = 71862306a36Sopenharmony_ci mlx4_get_base_gid_ix(dev, slave, port) | 0x80; 71962306a36Sopenharmony_ci else 72062306a36Sopenharmony_ci qp_ctx->pri_path.mgid_index = slave | 0x80; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) { 72362306a36Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 72462306a36Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 72562306a36Sopenharmony_ci if (mlx4_is_eth(dev, port)) { 72662306a36Sopenharmony_ci qp_ctx->pri_path.mgid_index += 72762306a36Sopenharmony_ci mlx4_get_base_gid_ix(dev, slave, port); 72862306a36Sopenharmony_ci qp_ctx->pri_path.mgid_index &= 0x7f; 72962306a36Sopenharmony_ci } else { 73062306a36Sopenharmony_ci qp_ctx->pri_path.mgid_index = slave & 0x7F; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 73462306a36Sopenharmony_ci port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 73562306a36Sopenharmony_ci if (mlx4_is_eth(dev, port)) { 73662306a36Sopenharmony_ci qp_ctx->alt_path.mgid_index += 73762306a36Sopenharmony_ci mlx4_get_base_gid_ix(dev, slave, port); 73862306a36Sopenharmony_ci qp_ctx->alt_path.mgid_index &= 0x7f; 73962306a36Sopenharmony_ci } else { 74062306a36Sopenharmony_ci qp_ctx->alt_path.mgid_index = slave & 0x7F; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc, 74762306a36Sopenharmony_ci u8 slave, int port); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int update_vport_qp_param(struct mlx4_dev *dev, 75062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 75162306a36Sopenharmony_ci u8 slave, u32 qpn) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct mlx4_qp_context *qpc = inbox->buf + 8; 75462306a36Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 75562306a36Sopenharmony_ci struct mlx4_priv *priv; 75662306a36Sopenharmony_ci u32 qp_type; 75762306a36Sopenharmony_ci int port, err = 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; 76062306a36Sopenharmony_ci priv = mlx4_priv(dev); 76162306a36Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 76262306a36Sopenharmony_ci qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci err = handle_counter(dev, qpc, slave, port); 76562306a36Sopenharmony_ci if (err) 76662306a36Sopenharmony_ci goto out; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (MLX4_VGT != vp_oper->state.default_vlan) { 76962306a36Sopenharmony_ci /* the reserved QPs (special, proxy, tunnel) 77062306a36Sopenharmony_ci * do not operate over vlans 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci if (mlx4_is_qp_reserved(dev, qpn)) 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* force strip vlan by clear vsd, MLX QP refers to Raw Ethernet */ 77662306a36Sopenharmony_ci if (qp_type == MLX4_QP_ST_UD || 77762306a36Sopenharmony_ci (qp_type == MLX4_QP_ST_MLX && mlx4_is_eth(dev, port))) { 77862306a36Sopenharmony_ci if (dev->caps.bmme_flags & MLX4_BMME_FLAG_VSD_INIT2RTR) { 77962306a36Sopenharmony_ci *(__be32 *)inbox->buf = 78062306a36Sopenharmony_ci cpu_to_be32(be32_to_cpu(*(__be32 *)inbox->buf) | 78162306a36Sopenharmony_ci MLX4_QP_OPTPAR_VLAN_STRIPPING); 78262306a36Sopenharmony_ci qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); 78362306a36Sopenharmony_ci } else { 78462306a36Sopenharmony_ci struct mlx4_update_qp_params params = {.flags = 0}; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, ¶ms); 78762306a36Sopenharmony_ci if (err) 78862306a36Sopenharmony_ci goto out; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* preserve IF_COUNTER flag */ 79362306a36Sopenharmony_ci qpc->pri_path.vlan_control &= 79462306a36Sopenharmony_ci MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER; 79562306a36Sopenharmony_ci if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE && 79662306a36Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) { 79762306a36Sopenharmony_ci qpc->pri_path.vlan_control |= 79862306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 79962306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 80062306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED | 80162306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 80262306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED | 80362306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 80462306a36Sopenharmony_ci } else if (0 != vp_oper->state.default_vlan) { 80562306a36Sopenharmony_ci if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) { 80662306a36Sopenharmony_ci /* vst QinQ should block untagged on TX, 80762306a36Sopenharmony_ci * but cvlan is in payload and phv is set so 80862306a36Sopenharmony_ci * hw see it as untagged. Block tagged instead. 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_ci qpc->pri_path.vlan_control |= 81162306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 81262306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 81362306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 81462306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 81562306a36Sopenharmony_ci } else { /* vst 802.1Q */ 81662306a36Sopenharmony_ci qpc->pri_path.vlan_control |= 81762306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 81862306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 81962306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci } else { /* priority tagged */ 82262306a36Sopenharmony_ci qpc->pri_path.vlan_control |= 82362306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 82462306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN; 82862306a36Sopenharmony_ci qpc->pri_path.vlan_index = vp_oper->vlan_idx; 82962306a36Sopenharmony_ci qpc->pri_path.fl |= MLX4_FL_ETH_HIDE_CQE_VLAN; 83062306a36Sopenharmony_ci if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) 83162306a36Sopenharmony_ci qpc->pri_path.fl |= MLX4_FL_SV; 83262306a36Sopenharmony_ci else 83362306a36Sopenharmony_ci qpc->pri_path.fl |= MLX4_FL_CV; 83462306a36Sopenharmony_ci qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 83562306a36Sopenharmony_ci qpc->pri_path.sched_queue &= 0xC7; 83662306a36Sopenharmony_ci qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; 83762306a36Sopenharmony_ci qpc->qos_vport = vp_oper->state.qos_vport; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci if (vp_oper->state.spoofchk) { 84062306a36Sopenharmony_ci qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC; 84162306a36Sopenharmony_ci qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ciout: 84462306a36Sopenharmony_ci return err; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int mpt_mask(struct mlx4_dev *dev) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci return dev->caps.num_mpts - 1; 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic const char *mlx4_resource_type_to_str(enum mlx4_resource t) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci switch (t) { 85562306a36Sopenharmony_ci case RES_QP: 85662306a36Sopenharmony_ci return "QP"; 85762306a36Sopenharmony_ci case RES_CQ: 85862306a36Sopenharmony_ci return "CQ"; 85962306a36Sopenharmony_ci case RES_SRQ: 86062306a36Sopenharmony_ci return "SRQ"; 86162306a36Sopenharmony_ci case RES_XRCD: 86262306a36Sopenharmony_ci return "XRCD"; 86362306a36Sopenharmony_ci case RES_MPT: 86462306a36Sopenharmony_ci return "MPT"; 86562306a36Sopenharmony_ci case RES_MTT: 86662306a36Sopenharmony_ci return "MTT"; 86762306a36Sopenharmony_ci case RES_MAC: 86862306a36Sopenharmony_ci return "MAC"; 86962306a36Sopenharmony_ci case RES_VLAN: 87062306a36Sopenharmony_ci return "VLAN"; 87162306a36Sopenharmony_ci case RES_COUNTER: 87262306a36Sopenharmony_ci return "COUNTER"; 87362306a36Sopenharmony_ci case RES_FS_RULE: 87462306a36Sopenharmony_ci return "FS_RULE"; 87562306a36Sopenharmony_ci case RES_EQ: 87662306a36Sopenharmony_ci return "EQ"; 87762306a36Sopenharmony_ci default: 87862306a36Sopenharmony_ci return "INVALID RESOURCE"; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic void *find_res(struct mlx4_dev *dev, u64 res_id, 88362306a36Sopenharmony_ci enum mlx4_resource type) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type], 88862306a36Sopenharmony_ci res_id); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int _get_res(struct mlx4_dev *dev, int slave, u64 res_id, 89262306a36Sopenharmony_ci enum mlx4_resource type, 89362306a36Sopenharmony_ci void *res, const char *func_name) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct res_common *r; 89662306a36Sopenharmony_ci int err = 0; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 89962306a36Sopenharmony_ci r = find_res(dev, res_id, type); 90062306a36Sopenharmony_ci if (!r) { 90162306a36Sopenharmony_ci err = -ENONET; 90262306a36Sopenharmony_ci goto exit; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (r->state == RES_ANY_BUSY) { 90662306a36Sopenharmony_ci mlx4_warn(dev, 90762306a36Sopenharmony_ci "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n", 90862306a36Sopenharmony_ci func_name, slave, res_id, mlx4_resource_type_to_str(type), 90962306a36Sopenharmony_ci r->func_name); 91062306a36Sopenharmony_ci err = -EBUSY; 91162306a36Sopenharmony_ci goto exit; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (r->owner != slave) { 91562306a36Sopenharmony_ci err = -EPERM; 91662306a36Sopenharmony_ci goto exit; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci r->from_state = r->state; 92062306a36Sopenharmony_ci r->state = RES_ANY_BUSY; 92162306a36Sopenharmony_ci r->func_name = func_name; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (res) 92462306a36Sopenharmony_ci *((struct res_common **)res) = r; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ciexit: 92762306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 92862306a36Sopenharmony_ci return err; 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci#define get_res(dev, slave, res_id, type, res) \ 93262306a36Sopenharmony_ci _get_res((dev), (slave), (res_id), (type), (res), __func__) 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ciint mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, 93562306a36Sopenharmony_ci enum mlx4_resource type, 93662306a36Sopenharmony_ci u64 res_id, int *slave) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci struct res_common *r; 94062306a36Sopenharmony_ci int err = -ENOENT; 94162306a36Sopenharmony_ci int id = res_id; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (type == RES_QP) 94462306a36Sopenharmony_ci id &= 0x7fffff; 94562306a36Sopenharmony_ci spin_lock(mlx4_tlock(dev)); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci r = find_res(dev, id, type); 94862306a36Sopenharmony_ci if (r) { 94962306a36Sopenharmony_ci *slave = r->owner; 95062306a36Sopenharmony_ci err = 0; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci spin_unlock(mlx4_tlock(dev)); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return err; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic void put_res(struct mlx4_dev *dev, int slave, u64 res_id, 95862306a36Sopenharmony_ci enum mlx4_resource type) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct res_common *r; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 96362306a36Sopenharmony_ci r = find_res(dev, res_id, type); 96462306a36Sopenharmony_ci if (r) { 96562306a36Sopenharmony_ci r->state = r->from_state; 96662306a36Sopenharmony_ci r->func_name = ""; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 97262306a36Sopenharmony_ci u64 in_param, u64 *out_param, int port); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port, 97562306a36Sopenharmony_ci int counter_index) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct res_common *r; 97862306a36Sopenharmony_ci struct res_counter *counter; 97962306a36Sopenharmony_ci int ret = 0; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (counter_index == MLX4_SINK_COUNTER_INDEX(dev)) 98262306a36Sopenharmony_ci return ret; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 98562306a36Sopenharmony_ci r = find_res(dev, counter_index, RES_COUNTER); 98662306a36Sopenharmony_ci if (!r || r->owner != slave) { 98762306a36Sopenharmony_ci ret = -EINVAL; 98862306a36Sopenharmony_ci } else { 98962306a36Sopenharmony_ci counter = container_of(r, struct res_counter, com); 99062306a36Sopenharmony_ci if (!counter->port) 99162306a36Sopenharmony_ci counter->port = port; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 99562306a36Sopenharmony_ci return ret; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int handle_unexisting_counter(struct mlx4_dev *dev, 99962306a36Sopenharmony_ci struct mlx4_qp_context *qpc, u8 slave, 100062306a36Sopenharmony_ci int port) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 100362306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 100462306a36Sopenharmony_ci struct res_common *tmp; 100562306a36Sopenharmony_ci struct res_counter *counter; 100662306a36Sopenharmony_ci u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev); 100762306a36Sopenharmony_ci int err = 0; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 101062306a36Sopenharmony_ci list_for_each_entry(tmp, 101162306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_COUNTER], 101262306a36Sopenharmony_ci list) { 101362306a36Sopenharmony_ci counter = container_of(tmp, struct res_counter, com); 101462306a36Sopenharmony_ci if (port == counter->port) { 101562306a36Sopenharmony_ci qpc->pri_path.counter_index = counter->com.res_id; 101662306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 101762306a36Sopenharmony_ci return 0; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* No existing counter, need to allocate a new counter */ 102362306a36Sopenharmony_ci err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx, 102462306a36Sopenharmony_ci port); 102562306a36Sopenharmony_ci if (err == -ENOENT) { 102662306a36Sopenharmony_ci err = 0; 102762306a36Sopenharmony_ci } else if (err && err != -ENOSPC) { 102862306a36Sopenharmony_ci mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n", 102962306a36Sopenharmony_ci __func__, slave, err); 103062306a36Sopenharmony_ci } else { 103162306a36Sopenharmony_ci qpc->pri_path.counter_index = counter_idx; 103262306a36Sopenharmony_ci mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n", 103362306a36Sopenharmony_ci __func__, slave, qpc->pri_path.counter_index); 103462306a36Sopenharmony_ci err = 0; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci return err; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc, 104162306a36Sopenharmony_ci u8 slave, int port) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev)) 104462306a36Sopenharmony_ci return handle_existing_counter(dev, slave, port, 104562306a36Sopenharmony_ci qpc->pri_path.counter_index); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci return handle_unexisting_counter(dev, qpc, slave, port); 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic struct res_common *alloc_qp_tr(int id) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct res_qp *ret; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 105562306a36Sopenharmony_ci if (!ret) 105662306a36Sopenharmony_ci return NULL; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci ret->com.res_id = id; 105962306a36Sopenharmony_ci ret->com.state = RES_QP_RESERVED; 106062306a36Sopenharmony_ci ret->local_qpn = id; 106162306a36Sopenharmony_ci INIT_LIST_HEAD(&ret->mcg_list); 106262306a36Sopenharmony_ci spin_lock_init(&ret->mcg_spl); 106362306a36Sopenharmony_ci atomic_set(&ret->ref_count, 0); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci return &ret->com; 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic struct res_common *alloc_mtt_tr(int id, int order) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct res_mtt *ret; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 107362306a36Sopenharmony_ci if (!ret) 107462306a36Sopenharmony_ci return NULL; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci ret->com.res_id = id; 107762306a36Sopenharmony_ci ret->order = order; 107862306a36Sopenharmony_ci ret->com.state = RES_MTT_ALLOCATED; 107962306a36Sopenharmony_ci atomic_set(&ret->ref_count, 0); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci return &ret->com; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic struct res_common *alloc_mpt_tr(int id, int key) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct res_mpt *ret; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 108962306a36Sopenharmony_ci if (!ret) 109062306a36Sopenharmony_ci return NULL; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci ret->com.res_id = id; 109362306a36Sopenharmony_ci ret->com.state = RES_MPT_RESERVED; 109462306a36Sopenharmony_ci ret->key = key; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci return &ret->com; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic struct res_common *alloc_eq_tr(int id) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct res_eq *ret; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 110462306a36Sopenharmony_ci if (!ret) 110562306a36Sopenharmony_ci return NULL; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ret->com.res_id = id; 110862306a36Sopenharmony_ci ret->com.state = RES_EQ_RESERVED; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return &ret->com; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic struct res_common *alloc_cq_tr(int id) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct res_cq *ret; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 111862306a36Sopenharmony_ci if (!ret) 111962306a36Sopenharmony_ci return NULL; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci ret->com.res_id = id; 112262306a36Sopenharmony_ci ret->com.state = RES_CQ_ALLOCATED; 112362306a36Sopenharmony_ci atomic_set(&ret->ref_count, 0); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci return &ret->com; 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic struct res_common *alloc_srq_tr(int id) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci struct res_srq *ret; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 113362306a36Sopenharmony_ci if (!ret) 113462306a36Sopenharmony_ci return NULL; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci ret->com.res_id = id; 113762306a36Sopenharmony_ci ret->com.state = RES_SRQ_ALLOCATED; 113862306a36Sopenharmony_ci atomic_set(&ret->ref_count, 0); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci return &ret->com; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic struct res_common *alloc_counter_tr(int id, int port) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci struct res_counter *ret; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 114862306a36Sopenharmony_ci if (!ret) 114962306a36Sopenharmony_ci return NULL; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci ret->com.res_id = id; 115262306a36Sopenharmony_ci ret->com.state = RES_COUNTER_ALLOCATED; 115362306a36Sopenharmony_ci ret->port = port; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci return &ret->com; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic struct res_common *alloc_xrcdn_tr(int id) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct res_xrcdn *ret; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 116362306a36Sopenharmony_ci if (!ret) 116462306a36Sopenharmony_ci return NULL; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci ret->com.res_id = id; 116762306a36Sopenharmony_ci ret->com.state = RES_XRCD_ALLOCATED; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci return &ret->com; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic struct res_common *alloc_fs_rule_tr(u64 id, int qpn) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci struct res_fs_rule *ret; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 117762306a36Sopenharmony_ci if (!ret) 117862306a36Sopenharmony_ci return NULL; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci ret->com.res_id = id; 118162306a36Sopenharmony_ci ret->com.state = RES_FS_RULE_ALLOCATED; 118262306a36Sopenharmony_ci ret->qpn = qpn; 118362306a36Sopenharmony_ci return &ret->com; 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, 118762306a36Sopenharmony_ci int extra) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci struct res_common *ret; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci switch (type) { 119262306a36Sopenharmony_ci case RES_QP: 119362306a36Sopenharmony_ci ret = alloc_qp_tr(id); 119462306a36Sopenharmony_ci break; 119562306a36Sopenharmony_ci case RES_MPT: 119662306a36Sopenharmony_ci ret = alloc_mpt_tr(id, extra); 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci case RES_MTT: 119962306a36Sopenharmony_ci ret = alloc_mtt_tr(id, extra); 120062306a36Sopenharmony_ci break; 120162306a36Sopenharmony_ci case RES_EQ: 120262306a36Sopenharmony_ci ret = alloc_eq_tr(id); 120362306a36Sopenharmony_ci break; 120462306a36Sopenharmony_ci case RES_CQ: 120562306a36Sopenharmony_ci ret = alloc_cq_tr(id); 120662306a36Sopenharmony_ci break; 120762306a36Sopenharmony_ci case RES_SRQ: 120862306a36Sopenharmony_ci ret = alloc_srq_tr(id); 120962306a36Sopenharmony_ci break; 121062306a36Sopenharmony_ci case RES_MAC: 121162306a36Sopenharmony_ci pr_err("implementation missing\n"); 121262306a36Sopenharmony_ci return NULL; 121362306a36Sopenharmony_ci case RES_COUNTER: 121462306a36Sopenharmony_ci ret = alloc_counter_tr(id, extra); 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci case RES_XRCD: 121762306a36Sopenharmony_ci ret = alloc_xrcdn_tr(id); 121862306a36Sopenharmony_ci break; 121962306a36Sopenharmony_ci case RES_FS_RULE: 122062306a36Sopenharmony_ci ret = alloc_fs_rule_tr(id, extra); 122162306a36Sopenharmony_ci break; 122262306a36Sopenharmony_ci default: 122362306a36Sopenharmony_ci return NULL; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci if (ret) 122662306a36Sopenharmony_ci ret->owner = slave; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci return ret; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ciint mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port, 123262306a36Sopenharmony_ci struct mlx4_counter *data) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 123562306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 123662306a36Sopenharmony_ci struct res_common *tmp; 123762306a36Sopenharmony_ci struct res_counter *counter; 123862306a36Sopenharmony_ci int *counters_arr; 123962306a36Sopenharmony_ci int i = 0, err = 0; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci memset(data, 0, sizeof(*data)); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci counters_arr = kmalloc_array(dev->caps.max_counters, 124462306a36Sopenharmony_ci sizeof(*counters_arr), GFP_KERNEL); 124562306a36Sopenharmony_ci if (!counters_arr) 124662306a36Sopenharmony_ci return -ENOMEM; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 124962306a36Sopenharmony_ci list_for_each_entry(tmp, 125062306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_COUNTER], 125162306a36Sopenharmony_ci list) { 125262306a36Sopenharmony_ci counter = container_of(tmp, struct res_counter, com); 125362306a36Sopenharmony_ci if (counter->port == port) { 125462306a36Sopenharmony_ci counters_arr[i] = (int)tmp->res_id; 125562306a36Sopenharmony_ci i++; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 125962306a36Sopenharmony_ci counters_arr[i] = -1; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci i = 0; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci while (counters_arr[i] != -1) { 126462306a36Sopenharmony_ci err = mlx4_get_counter_stats(dev, counters_arr[i], data, 126562306a36Sopenharmony_ci 0); 126662306a36Sopenharmony_ci if (err) { 126762306a36Sopenharmony_ci memset(data, 0, sizeof(*data)); 126862306a36Sopenharmony_ci goto table_changed; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci i++; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_citable_changed: 127462306a36Sopenharmony_ci kfree(counters_arr); 127562306a36Sopenharmony_ci return 0; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 127962306a36Sopenharmony_ci enum mlx4_resource type, int extra) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci int i; 128262306a36Sopenharmony_ci int err; 128362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 128462306a36Sopenharmony_ci struct res_common **res_arr; 128562306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 128662306a36Sopenharmony_ci struct rb_root *root = &tracker->res_tree[type]; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci res_arr = kcalloc(count, sizeof(*res_arr), GFP_KERNEL); 128962306a36Sopenharmony_ci if (!res_arr) 129062306a36Sopenharmony_ci return -ENOMEM; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 129362306a36Sopenharmony_ci res_arr[i] = alloc_tr(base + i, type, slave, extra); 129462306a36Sopenharmony_ci if (!res_arr[i]) { 129562306a36Sopenharmony_ci for (--i; i >= 0; --i) 129662306a36Sopenharmony_ci kfree(res_arr[i]); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci kfree(res_arr); 129962306a36Sopenharmony_ci return -ENOMEM; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 130462306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 130562306a36Sopenharmony_ci if (find_res(dev, base + i, type)) { 130662306a36Sopenharmony_ci err = -EEXIST; 130762306a36Sopenharmony_ci goto undo; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci err = res_tracker_insert(root, res_arr[i]); 131062306a36Sopenharmony_ci if (err) 131162306a36Sopenharmony_ci goto undo; 131262306a36Sopenharmony_ci list_add_tail(&res_arr[i]->list, 131362306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[type]); 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 131662306a36Sopenharmony_ci kfree(res_arr); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci return 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ciundo: 132162306a36Sopenharmony_ci for (--i; i >= 0; --i) { 132262306a36Sopenharmony_ci rb_erase(&res_arr[i]->node, root); 132362306a36Sopenharmony_ci list_del_init(&res_arr[i]->list); 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci for (i = 0; i < count; ++i) 132962306a36Sopenharmony_ci kfree(res_arr[i]); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci kfree(res_arr); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci return err; 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic int remove_qp_ok(struct res_qp *res) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || 133962306a36Sopenharmony_ci !list_empty(&res->mcg_list)) { 134062306a36Sopenharmony_ci pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", 134162306a36Sopenharmony_ci res->com.state, atomic_read(&res->ref_count)); 134262306a36Sopenharmony_ci return -EBUSY; 134362306a36Sopenharmony_ci } else if (res->com.state != RES_QP_RESERVED) { 134462306a36Sopenharmony_ci return -EPERM; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci return 0; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int remove_mtt_ok(struct res_mtt *res, int order) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci if (res->com.state == RES_MTT_BUSY || 135362306a36Sopenharmony_ci atomic_read(&res->ref_count)) { 135462306a36Sopenharmony_ci pr_devel("%s-%d: state %s, ref_count %d\n", 135562306a36Sopenharmony_ci __func__, __LINE__, 135662306a36Sopenharmony_ci mtt_states_str(res->com.state), 135762306a36Sopenharmony_ci atomic_read(&res->ref_count)); 135862306a36Sopenharmony_ci return -EBUSY; 135962306a36Sopenharmony_ci } else if (res->com.state != RES_MTT_ALLOCATED) 136062306a36Sopenharmony_ci return -EPERM; 136162306a36Sopenharmony_ci else if (res->order != order) 136262306a36Sopenharmony_ci return -EINVAL; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci return 0; 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic int remove_mpt_ok(struct res_mpt *res) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci if (res->com.state == RES_MPT_BUSY) 137062306a36Sopenharmony_ci return -EBUSY; 137162306a36Sopenharmony_ci else if (res->com.state != RES_MPT_RESERVED) 137262306a36Sopenharmony_ci return -EPERM; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci return 0; 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic int remove_eq_ok(struct res_eq *res) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci if (res->com.state == RES_MPT_BUSY) 138062306a36Sopenharmony_ci return -EBUSY; 138162306a36Sopenharmony_ci else if (res->com.state != RES_MPT_RESERVED) 138262306a36Sopenharmony_ci return -EPERM; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return 0; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic int remove_counter_ok(struct res_counter *res) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci if (res->com.state == RES_COUNTER_BUSY) 139062306a36Sopenharmony_ci return -EBUSY; 139162306a36Sopenharmony_ci else if (res->com.state != RES_COUNTER_ALLOCATED) 139262306a36Sopenharmony_ci return -EPERM; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci return 0; 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic int remove_xrcdn_ok(struct res_xrcdn *res) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci if (res->com.state == RES_XRCD_BUSY) 140062306a36Sopenharmony_ci return -EBUSY; 140162306a36Sopenharmony_ci else if (res->com.state != RES_XRCD_ALLOCATED) 140262306a36Sopenharmony_ci return -EPERM; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return 0; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic int remove_fs_rule_ok(struct res_fs_rule *res) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci if (res->com.state == RES_FS_RULE_BUSY) 141062306a36Sopenharmony_ci return -EBUSY; 141162306a36Sopenharmony_ci else if (res->com.state != RES_FS_RULE_ALLOCATED) 141262306a36Sopenharmony_ci return -EPERM; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci return 0; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_cistatic int remove_cq_ok(struct res_cq *res) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci if (res->com.state == RES_CQ_BUSY) 142062306a36Sopenharmony_ci return -EBUSY; 142162306a36Sopenharmony_ci else if (res->com.state != RES_CQ_ALLOCATED) 142262306a36Sopenharmony_ci return -EPERM; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return 0; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_cistatic int remove_srq_ok(struct res_srq *res) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci if (res->com.state == RES_SRQ_BUSY) 143062306a36Sopenharmony_ci return -EBUSY; 143162306a36Sopenharmony_ci else if (res->com.state != RES_SRQ_ALLOCATED) 143262306a36Sopenharmony_ci return -EPERM; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci return 0; 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci switch (type) { 144062306a36Sopenharmony_ci case RES_QP: 144162306a36Sopenharmony_ci return remove_qp_ok((struct res_qp *)res); 144262306a36Sopenharmony_ci case RES_CQ: 144362306a36Sopenharmony_ci return remove_cq_ok((struct res_cq *)res); 144462306a36Sopenharmony_ci case RES_SRQ: 144562306a36Sopenharmony_ci return remove_srq_ok((struct res_srq *)res); 144662306a36Sopenharmony_ci case RES_MPT: 144762306a36Sopenharmony_ci return remove_mpt_ok((struct res_mpt *)res); 144862306a36Sopenharmony_ci case RES_MTT: 144962306a36Sopenharmony_ci return remove_mtt_ok((struct res_mtt *)res, extra); 145062306a36Sopenharmony_ci case RES_MAC: 145162306a36Sopenharmony_ci return -EOPNOTSUPP; 145262306a36Sopenharmony_ci case RES_EQ: 145362306a36Sopenharmony_ci return remove_eq_ok((struct res_eq *)res); 145462306a36Sopenharmony_ci case RES_COUNTER: 145562306a36Sopenharmony_ci return remove_counter_ok((struct res_counter *)res); 145662306a36Sopenharmony_ci case RES_XRCD: 145762306a36Sopenharmony_ci return remove_xrcdn_ok((struct res_xrcdn *)res); 145862306a36Sopenharmony_ci case RES_FS_RULE: 145962306a36Sopenharmony_ci return remove_fs_rule_ok((struct res_fs_rule *)res); 146062306a36Sopenharmony_ci default: 146162306a36Sopenharmony_ci return -EINVAL; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 146662306a36Sopenharmony_ci enum mlx4_resource type, int extra) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci u64 i; 146962306a36Sopenharmony_ci int err; 147062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 147162306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 147262306a36Sopenharmony_ci struct res_common *r; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 147562306a36Sopenharmony_ci for (i = base; i < base + count; ++i) { 147662306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], i); 147762306a36Sopenharmony_ci if (!r) { 147862306a36Sopenharmony_ci err = -ENOENT; 147962306a36Sopenharmony_ci goto out; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci if (r->owner != slave) { 148262306a36Sopenharmony_ci err = -EPERM; 148362306a36Sopenharmony_ci goto out; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci err = remove_ok(r, type, extra); 148662306a36Sopenharmony_ci if (err) 148762306a36Sopenharmony_ci goto out; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci for (i = base; i < base + count; ++i) { 149162306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], i); 149262306a36Sopenharmony_ci rb_erase(&r->node, &tracker->res_tree[type]); 149362306a36Sopenharmony_ci list_del(&r->list); 149462306a36Sopenharmony_ci kfree(r); 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci err = 0; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ciout: 149962306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return err; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn, 150562306a36Sopenharmony_ci enum res_qp_states state, struct res_qp **qp, 150662306a36Sopenharmony_ci int alloc) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 150962306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 151062306a36Sopenharmony_ci struct res_qp *r; 151162306a36Sopenharmony_ci int err = 0; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 151462306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn); 151562306a36Sopenharmony_ci if (!r) 151662306a36Sopenharmony_ci err = -ENOENT; 151762306a36Sopenharmony_ci else if (r->com.owner != slave) 151862306a36Sopenharmony_ci err = -EPERM; 151962306a36Sopenharmony_ci else { 152062306a36Sopenharmony_ci switch (state) { 152162306a36Sopenharmony_ci case RES_QP_BUSY: 152262306a36Sopenharmony_ci mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n", 152362306a36Sopenharmony_ci __func__, r->com.res_id); 152462306a36Sopenharmony_ci err = -EBUSY; 152562306a36Sopenharmony_ci break; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci case RES_QP_RESERVED: 152862306a36Sopenharmony_ci if (r->com.state == RES_QP_MAPPED && !alloc) 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id); 153262306a36Sopenharmony_ci err = -EINVAL; 153362306a36Sopenharmony_ci break; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci case RES_QP_MAPPED: 153662306a36Sopenharmony_ci if ((r->com.state == RES_QP_RESERVED && alloc) || 153762306a36Sopenharmony_ci r->com.state == RES_QP_HW) 153862306a36Sopenharmony_ci break; 153962306a36Sopenharmony_ci else { 154062306a36Sopenharmony_ci mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", 154162306a36Sopenharmony_ci r->com.res_id); 154262306a36Sopenharmony_ci err = -EINVAL; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci break; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci case RES_QP_HW: 154862306a36Sopenharmony_ci if (r->com.state != RES_QP_MAPPED) 154962306a36Sopenharmony_ci err = -EINVAL; 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci default: 155262306a36Sopenharmony_ci err = -EINVAL; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (!err) { 155662306a36Sopenharmony_ci r->com.from_state = r->com.state; 155762306a36Sopenharmony_ci r->com.to_state = state; 155862306a36Sopenharmony_ci r->com.state = RES_QP_BUSY; 155962306a36Sopenharmony_ci if (qp) 156062306a36Sopenharmony_ci *qp = r; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci return err; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 157062306a36Sopenharmony_ci enum res_mpt_states state, struct res_mpt **mpt) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 157362306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 157462306a36Sopenharmony_ci struct res_mpt *r; 157562306a36Sopenharmony_ci int err = 0; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 157862306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index); 157962306a36Sopenharmony_ci if (!r) 158062306a36Sopenharmony_ci err = -ENOENT; 158162306a36Sopenharmony_ci else if (r->com.owner != slave) 158262306a36Sopenharmony_ci err = -EPERM; 158362306a36Sopenharmony_ci else { 158462306a36Sopenharmony_ci switch (state) { 158562306a36Sopenharmony_ci case RES_MPT_BUSY: 158662306a36Sopenharmony_ci err = -EINVAL; 158762306a36Sopenharmony_ci break; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci case RES_MPT_RESERVED: 159062306a36Sopenharmony_ci if (r->com.state != RES_MPT_MAPPED) 159162306a36Sopenharmony_ci err = -EINVAL; 159262306a36Sopenharmony_ci break; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci case RES_MPT_MAPPED: 159562306a36Sopenharmony_ci if (r->com.state != RES_MPT_RESERVED && 159662306a36Sopenharmony_ci r->com.state != RES_MPT_HW) 159762306a36Sopenharmony_ci err = -EINVAL; 159862306a36Sopenharmony_ci break; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci case RES_MPT_HW: 160162306a36Sopenharmony_ci if (r->com.state != RES_MPT_MAPPED) 160262306a36Sopenharmony_ci err = -EINVAL; 160362306a36Sopenharmony_ci break; 160462306a36Sopenharmony_ci default: 160562306a36Sopenharmony_ci err = -EINVAL; 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci if (!err) { 160962306a36Sopenharmony_ci r->com.from_state = r->com.state; 161062306a36Sopenharmony_ci r->com.to_state = state; 161162306a36Sopenharmony_ci r->com.state = RES_MPT_BUSY; 161262306a36Sopenharmony_ci if (mpt) 161362306a36Sopenharmony_ci *mpt = r; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci return err; 162062306a36Sopenharmony_ci} 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_cistatic int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 162362306a36Sopenharmony_ci enum res_eq_states state, struct res_eq **eq) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 162662306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 162762306a36Sopenharmony_ci struct res_eq *r; 162862306a36Sopenharmony_ci int err = 0; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 163162306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index); 163262306a36Sopenharmony_ci if (!r) 163362306a36Sopenharmony_ci err = -ENOENT; 163462306a36Sopenharmony_ci else if (r->com.owner != slave) 163562306a36Sopenharmony_ci err = -EPERM; 163662306a36Sopenharmony_ci else { 163762306a36Sopenharmony_ci switch (state) { 163862306a36Sopenharmony_ci case RES_EQ_BUSY: 163962306a36Sopenharmony_ci err = -EINVAL; 164062306a36Sopenharmony_ci break; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci case RES_EQ_RESERVED: 164362306a36Sopenharmony_ci if (r->com.state != RES_EQ_HW) 164462306a36Sopenharmony_ci err = -EINVAL; 164562306a36Sopenharmony_ci break; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci case RES_EQ_HW: 164862306a36Sopenharmony_ci if (r->com.state != RES_EQ_RESERVED) 164962306a36Sopenharmony_ci err = -EINVAL; 165062306a36Sopenharmony_ci break; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci default: 165362306a36Sopenharmony_ci err = -EINVAL; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci if (!err) { 165762306a36Sopenharmony_ci r->com.from_state = r->com.state; 165862306a36Sopenharmony_ci r->com.to_state = state; 165962306a36Sopenharmony_ci r->com.state = RES_EQ_BUSY; 166062306a36Sopenharmony_ci } 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (!err && eq) 166662306a36Sopenharmony_ci *eq = r; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci return err; 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn, 167262306a36Sopenharmony_ci enum res_cq_states state, struct res_cq **cq) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 167562306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 167662306a36Sopenharmony_ci struct res_cq *r; 167762306a36Sopenharmony_ci int err; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 168062306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn); 168162306a36Sopenharmony_ci if (!r) { 168262306a36Sopenharmony_ci err = -ENOENT; 168362306a36Sopenharmony_ci } else if (r->com.owner != slave) { 168462306a36Sopenharmony_ci err = -EPERM; 168562306a36Sopenharmony_ci } else if (state == RES_CQ_ALLOCATED) { 168662306a36Sopenharmony_ci if (r->com.state != RES_CQ_HW) 168762306a36Sopenharmony_ci err = -EINVAL; 168862306a36Sopenharmony_ci else if (atomic_read(&r->ref_count)) 168962306a36Sopenharmony_ci err = -EBUSY; 169062306a36Sopenharmony_ci else 169162306a36Sopenharmony_ci err = 0; 169262306a36Sopenharmony_ci } else if (state != RES_CQ_HW || r->com.state != RES_CQ_ALLOCATED) { 169362306a36Sopenharmony_ci err = -EINVAL; 169462306a36Sopenharmony_ci } else { 169562306a36Sopenharmony_ci err = 0; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci if (!err) { 169962306a36Sopenharmony_ci r->com.from_state = r->com.state; 170062306a36Sopenharmony_ci r->com.to_state = state; 170162306a36Sopenharmony_ci r->com.state = RES_CQ_BUSY; 170262306a36Sopenharmony_ci if (cq) 170362306a36Sopenharmony_ci *cq = r; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci return err; 170962306a36Sopenharmony_ci} 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 171262306a36Sopenharmony_ci enum res_srq_states state, struct res_srq **srq) 171362306a36Sopenharmony_ci{ 171462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 171562306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 171662306a36Sopenharmony_ci struct res_srq *r; 171762306a36Sopenharmony_ci int err = 0; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 172062306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index); 172162306a36Sopenharmony_ci if (!r) { 172262306a36Sopenharmony_ci err = -ENOENT; 172362306a36Sopenharmony_ci } else if (r->com.owner != slave) { 172462306a36Sopenharmony_ci err = -EPERM; 172562306a36Sopenharmony_ci } else if (state == RES_SRQ_ALLOCATED) { 172662306a36Sopenharmony_ci if (r->com.state != RES_SRQ_HW) 172762306a36Sopenharmony_ci err = -EINVAL; 172862306a36Sopenharmony_ci else if (atomic_read(&r->ref_count)) 172962306a36Sopenharmony_ci err = -EBUSY; 173062306a36Sopenharmony_ci } else if (state != RES_SRQ_HW || r->com.state != RES_SRQ_ALLOCATED) { 173162306a36Sopenharmony_ci err = -EINVAL; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (!err) { 173562306a36Sopenharmony_ci r->com.from_state = r->com.state; 173662306a36Sopenharmony_ci r->com.to_state = state; 173762306a36Sopenharmony_ci r->com.state = RES_SRQ_BUSY; 173862306a36Sopenharmony_ci if (srq) 173962306a36Sopenharmony_ci *srq = r; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci return err; 174562306a36Sopenharmony_ci} 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_cistatic void res_abort_move(struct mlx4_dev *dev, int slave, 174862306a36Sopenharmony_ci enum mlx4_resource type, int id) 174962306a36Sopenharmony_ci{ 175062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 175162306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 175262306a36Sopenharmony_ci struct res_common *r; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 175562306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], id); 175662306a36Sopenharmony_ci if (r && (r->owner == slave)) 175762306a36Sopenharmony_ci r->state = r->from_state; 175862306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 175962306a36Sopenharmony_ci} 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_cistatic void res_end_move(struct mlx4_dev *dev, int slave, 176262306a36Sopenharmony_ci enum mlx4_resource type, int id) 176362306a36Sopenharmony_ci{ 176462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 176562306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 176662306a36Sopenharmony_ci struct res_common *r; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 176962306a36Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], id); 177062306a36Sopenharmony_ci if (r && (r->owner == slave)) 177162306a36Sopenharmony_ci r->state = r->to_state; 177262306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 177362306a36Sopenharmony_ci} 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_cistatic int valid_reserved(struct mlx4_dev *dev, int slave, int qpn) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci return mlx4_is_qp_reserved(dev, qpn) && 177862306a36Sopenharmony_ci (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn)); 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic int fw_reserved(struct mlx4_dev *dev, int qpn) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; 178462306a36Sopenharmony_ci} 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_cistatic int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 178762306a36Sopenharmony_ci u64 in_param, u64 *out_param) 178862306a36Sopenharmony_ci{ 178962306a36Sopenharmony_ci int err; 179062306a36Sopenharmony_ci int count; 179162306a36Sopenharmony_ci int align; 179262306a36Sopenharmony_ci int base; 179362306a36Sopenharmony_ci int qpn; 179462306a36Sopenharmony_ci u8 flags; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci switch (op) { 179762306a36Sopenharmony_ci case RES_OP_RESERVE: 179862306a36Sopenharmony_ci count = get_param_l(&in_param) & 0xffffff; 179962306a36Sopenharmony_ci /* Turn off all unsupported QP allocation flags that the 180062306a36Sopenharmony_ci * slave tries to set. 180162306a36Sopenharmony_ci */ 180262306a36Sopenharmony_ci flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask; 180362306a36Sopenharmony_ci align = get_param_h(&in_param); 180462306a36Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); 180562306a36Sopenharmony_ci if (err) 180662306a36Sopenharmony_ci return err; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci err = __mlx4_qp_reserve_range(dev, count, align, &base, flags); 180962306a36Sopenharmony_ci if (err) { 181062306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_QP, count, 0); 181162306a36Sopenharmony_ci return err; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci err = add_res_range(dev, slave, base, count, RES_QP, 0); 181562306a36Sopenharmony_ci if (err) { 181662306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_QP, count, 0); 181762306a36Sopenharmony_ci __mlx4_qp_release_range(dev, base, count); 181862306a36Sopenharmony_ci return err; 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci set_param_l(out_param, base); 182162306a36Sopenharmony_ci break; 182262306a36Sopenharmony_ci case RES_OP_MAP_ICM: 182362306a36Sopenharmony_ci qpn = get_param_l(&in_param) & 0x7fffff; 182462306a36Sopenharmony_ci if (valid_reserved(dev, slave, qpn)) { 182562306a36Sopenharmony_ci err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); 182662306a36Sopenharmony_ci if (err) 182762306a36Sopenharmony_ci return err; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, 183162306a36Sopenharmony_ci NULL, 1); 183262306a36Sopenharmony_ci if (err) 183362306a36Sopenharmony_ci return err; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (!fw_reserved(dev, qpn)) { 183662306a36Sopenharmony_ci err = __mlx4_qp_alloc_icm(dev, qpn); 183762306a36Sopenharmony_ci if (err) { 183862306a36Sopenharmony_ci res_abort_move(dev, slave, RES_QP, qpn); 183962306a36Sopenharmony_ci return err; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 184462306a36Sopenharmony_ci break; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci default: 184762306a36Sopenharmony_ci err = -EINVAL; 184862306a36Sopenharmony_ci break; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci return err; 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_cistatic int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 185462306a36Sopenharmony_ci u64 in_param, u64 *out_param) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci int err = -EINVAL; 185762306a36Sopenharmony_ci int base; 185862306a36Sopenharmony_ci int order; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (op != RES_OP_RESERVE_AND_MAP) 186162306a36Sopenharmony_ci return err; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci order = get_param_l(&in_param); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); 186662306a36Sopenharmony_ci if (err) 186762306a36Sopenharmony_ci return err; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci base = __mlx4_alloc_mtt_range(dev, order); 187062306a36Sopenharmony_ci if (base == -1) { 187162306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 187262306a36Sopenharmony_ci return -ENOMEM; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci err = add_res_range(dev, slave, base, 1, RES_MTT, order); 187662306a36Sopenharmony_ci if (err) { 187762306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 187862306a36Sopenharmony_ci __mlx4_free_mtt_range(dev, base, order); 187962306a36Sopenharmony_ci } else { 188062306a36Sopenharmony_ci set_param_l(out_param, base); 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci return err; 188462306a36Sopenharmony_ci} 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_cistatic int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 188762306a36Sopenharmony_ci u64 in_param, u64 *out_param) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci int err = -EINVAL; 189062306a36Sopenharmony_ci int index; 189162306a36Sopenharmony_ci int id; 189262306a36Sopenharmony_ci struct res_mpt *mpt; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci switch (op) { 189562306a36Sopenharmony_ci case RES_OP_RESERVE: 189662306a36Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); 189762306a36Sopenharmony_ci if (err) 189862306a36Sopenharmony_ci break; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci index = __mlx4_mpt_reserve(dev); 190162306a36Sopenharmony_ci if (index == -1) { 190262306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 190362306a36Sopenharmony_ci break; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci id = index & mpt_mask(dev); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci err = add_res_range(dev, slave, id, 1, RES_MPT, index); 190862306a36Sopenharmony_ci if (err) { 190962306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 191062306a36Sopenharmony_ci __mlx4_mpt_release(dev, index); 191162306a36Sopenharmony_ci break; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci set_param_l(out_param, index); 191462306a36Sopenharmony_ci break; 191562306a36Sopenharmony_ci case RES_OP_MAP_ICM: 191662306a36Sopenharmony_ci index = get_param_l(&in_param); 191762306a36Sopenharmony_ci id = index & mpt_mask(dev); 191862306a36Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, 191962306a36Sopenharmony_ci RES_MPT_MAPPED, &mpt); 192062306a36Sopenharmony_ci if (err) 192162306a36Sopenharmony_ci return err; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci err = __mlx4_mpt_alloc_icm(dev, mpt->key); 192462306a36Sopenharmony_ci if (err) { 192562306a36Sopenharmony_ci res_abort_move(dev, slave, RES_MPT, id); 192662306a36Sopenharmony_ci return err; 192762306a36Sopenharmony_ci } 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 193062306a36Sopenharmony_ci break; 193162306a36Sopenharmony_ci } 193262306a36Sopenharmony_ci return err; 193362306a36Sopenharmony_ci} 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_cistatic int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 193662306a36Sopenharmony_ci u64 in_param, u64 *out_param) 193762306a36Sopenharmony_ci{ 193862306a36Sopenharmony_ci int cqn; 193962306a36Sopenharmony_ci int err; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci switch (op) { 194262306a36Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 194362306a36Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); 194462306a36Sopenharmony_ci if (err) 194562306a36Sopenharmony_ci break; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci err = __mlx4_cq_alloc_icm(dev, &cqn); 194862306a36Sopenharmony_ci if (err) { 194962306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 195062306a36Sopenharmony_ci break; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); 195462306a36Sopenharmony_ci if (err) { 195562306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 195662306a36Sopenharmony_ci __mlx4_cq_free_icm(dev, cqn); 195762306a36Sopenharmony_ci break; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci set_param_l(out_param, cqn); 196162306a36Sopenharmony_ci break; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci default: 196462306a36Sopenharmony_ci err = -EINVAL; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci return err; 196862306a36Sopenharmony_ci} 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_cistatic int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 197162306a36Sopenharmony_ci u64 in_param, u64 *out_param) 197262306a36Sopenharmony_ci{ 197362306a36Sopenharmony_ci int srqn; 197462306a36Sopenharmony_ci int err; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci switch (op) { 197762306a36Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 197862306a36Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); 197962306a36Sopenharmony_ci if (err) 198062306a36Sopenharmony_ci break; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci err = __mlx4_srq_alloc_icm(dev, &srqn); 198362306a36Sopenharmony_ci if (err) { 198462306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 198562306a36Sopenharmony_ci break; 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 198962306a36Sopenharmony_ci if (err) { 199062306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 199162306a36Sopenharmony_ci __mlx4_srq_free_icm(dev, srqn); 199262306a36Sopenharmony_ci break; 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci set_param_l(out_param, srqn); 199662306a36Sopenharmony_ci break; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci default: 199962306a36Sopenharmony_ci err = -EINVAL; 200062306a36Sopenharmony_ci } 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci return err; 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, 200662306a36Sopenharmony_ci u8 smac_index, u64 *mac) 200762306a36Sopenharmony_ci{ 200862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 200962306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 201062306a36Sopenharmony_ci struct list_head *mac_list = 201162306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 201262306a36Sopenharmony_ci struct mac_res *res, *tmp; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 201562306a36Sopenharmony_ci if (res->smac_index == smac_index && res->port == (u8) port) { 201662306a36Sopenharmony_ci *mac = res->mac; 201762306a36Sopenharmony_ci return 0; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci return -ENOENT; 202162306a36Sopenharmony_ci} 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_cistatic int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) 202462306a36Sopenharmony_ci{ 202562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 202662306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 202762306a36Sopenharmony_ci struct list_head *mac_list = 202862306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 202962306a36Sopenharmony_ci struct mac_res *res, *tmp; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 203262306a36Sopenharmony_ci if (res->mac == mac && res->port == (u8) port) { 203362306a36Sopenharmony_ci /* mac found. update ref count */ 203462306a36Sopenharmony_ci ++res->ref_count; 203562306a36Sopenharmony_ci return 0; 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) 204062306a36Sopenharmony_ci return -EINVAL; 204162306a36Sopenharmony_ci res = kzalloc(sizeof(*res), GFP_KERNEL); 204262306a36Sopenharmony_ci if (!res) { 204362306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MAC, 1, port); 204462306a36Sopenharmony_ci return -ENOMEM; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci res->mac = mac; 204762306a36Sopenharmony_ci res->port = (u8) port; 204862306a36Sopenharmony_ci res->smac_index = smac_index; 204962306a36Sopenharmony_ci res->ref_count = 1; 205062306a36Sopenharmony_ci list_add_tail(&res->list, 205162306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]); 205262306a36Sopenharmony_ci return 0; 205362306a36Sopenharmony_ci} 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_cistatic void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, 205662306a36Sopenharmony_ci int port) 205762306a36Sopenharmony_ci{ 205862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 205962306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 206062306a36Sopenharmony_ci struct list_head *mac_list = 206162306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 206262306a36Sopenharmony_ci struct mac_res *res, *tmp; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 206562306a36Sopenharmony_ci if (res->mac == mac && res->port == (u8) port) { 206662306a36Sopenharmony_ci if (!--res->ref_count) { 206762306a36Sopenharmony_ci list_del(&res->list); 206862306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MAC, 1, port); 206962306a36Sopenharmony_ci kfree(res); 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci break; 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci} 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_cistatic void rem_slave_macs(struct mlx4_dev *dev, int slave) 207762306a36Sopenharmony_ci{ 207862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 207962306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 208062306a36Sopenharmony_ci struct list_head *mac_list = 208162306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 208262306a36Sopenharmony_ci struct mac_res *res, *tmp; 208362306a36Sopenharmony_ci int i; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 208662306a36Sopenharmony_ci list_del(&res->list); 208762306a36Sopenharmony_ci /* dereference the mac the num times the slave referenced it */ 208862306a36Sopenharmony_ci for (i = 0; i < res->ref_count; i++) 208962306a36Sopenharmony_ci __mlx4_unregister_mac(dev, res->port, res->mac); 209062306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); 209162306a36Sopenharmony_ci kfree(res); 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_cistatic int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 209662306a36Sopenharmony_ci u64 in_param, u64 *out_param, int in_port) 209762306a36Sopenharmony_ci{ 209862306a36Sopenharmony_ci int err = -EINVAL; 209962306a36Sopenharmony_ci int port; 210062306a36Sopenharmony_ci u64 mac; 210162306a36Sopenharmony_ci u8 smac_index; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci if (op != RES_OP_RESERVE_AND_MAP) 210462306a36Sopenharmony_ci return err; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci port = !in_port ? get_param_l(out_param) : in_port; 210762306a36Sopenharmony_ci port = mlx4_slave_convert_port( 210862306a36Sopenharmony_ci dev, slave, port); 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci if (port < 0) 211162306a36Sopenharmony_ci return -EINVAL; 211262306a36Sopenharmony_ci mac = in_param; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci err = __mlx4_register_mac(dev, port, mac); 211562306a36Sopenharmony_ci if (err >= 0) { 211662306a36Sopenharmony_ci smac_index = err; 211762306a36Sopenharmony_ci set_param_l(out_param, err); 211862306a36Sopenharmony_ci err = 0; 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci if (!err) { 212262306a36Sopenharmony_ci err = mac_add_to_slave(dev, slave, mac, port, smac_index); 212362306a36Sopenharmony_ci if (err) 212462306a36Sopenharmony_ci __mlx4_unregister_mac(dev, port, mac); 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci return err; 212762306a36Sopenharmony_ci} 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_cistatic int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, 213062306a36Sopenharmony_ci int port, int vlan_index) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 213362306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 213462306a36Sopenharmony_ci struct list_head *vlan_list = 213562306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]; 213662306a36Sopenharmony_ci struct vlan_res *res, *tmp; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, vlan_list, list) { 213962306a36Sopenharmony_ci if (res->vlan == vlan && res->port == (u8) port) { 214062306a36Sopenharmony_ci /* vlan found. update ref count */ 214162306a36Sopenharmony_ci ++res->ref_count; 214262306a36Sopenharmony_ci return 0; 214362306a36Sopenharmony_ci } 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) 214762306a36Sopenharmony_ci return -EINVAL; 214862306a36Sopenharmony_ci res = kzalloc(sizeof(*res), GFP_KERNEL); 214962306a36Sopenharmony_ci if (!res) { 215062306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_VLAN, 1, port); 215162306a36Sopenharmony_ci return -ENOMEM; 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci res->vlan = vlan; 215462306a36Sopenharmony_ci res->port = (u8) port; 215562306a36Sopenharmony_ci res->vlan_index = vlan_index; 215662306a36Sopenharmony_ci res->ref_count = 1; 215762306a36Sopenharmony_ci list_add_tail(&res->list, 215862306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]); 215962306a36Sopenharmony_ci return 0; 216062306a36Sopenharmony_ci} 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_cistatic void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, 216462306a36Sopenharmony_ci int port) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 216762306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 216862306a36Sopenharmony_ci struct list_head *vlan_list = 216962306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]; 217062306a36Sopenharmony_ci struct vlan_res *res, *tmp; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, vlan_list, list) { 217362306a36Sopenharmony_ci if (res->vlan == vlan && res->port == (u8) port) { 217462306a36Sopenharmony_ci if (!--res->ref_count) { 217562306a36Sopenharmony_ci list_del(&res->list); 217662306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_VLAN, 217762306a36Sopenharmony_ci 1, port); 217862306a36Sopenharmony_ci kfree(res); 217962306a36Sopenharmony_ci } 218062306a36Sopenharmony_ci break; 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci} 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_cistatic void rem_slave_vlans(struct mlx4_dev *dev, int slave) 218662306a36Sopenharmony_ci{ 218762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 218862306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 218962306a36Sopenharmony_ci struct list_head *vlan_list = 219062306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]; 219162306a36Sopenharmony_ci struct vlan_res *res, *tmp; 219262306a36Sopenharmony_ci int i; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, vlan_list, list) { 219562306a36Sopenharmony_ci list_del(&res->list); 219662306a36Sopenharmony_ci /* dereference the vlan the num times the slave referenced it */ 219762306a36Sopenharmony_ci for (i = 0; i < res->ref_count; i++) 219862306a36Sopenharmony_ci __mlx4_unregister_vlan(dev, res->port, res->vlan); 219962306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); 220062306a36Sopenharmony_ci kfree(res); 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci} 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_cistatic int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 220562306a36Sopenharmony_ci u64 in_param, u64 *out_param, int in_port) 220662306a36Sopenharmony_ci{ 220762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 220862306a36Sopenharmony_ci struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 220962306a36Sopenharmony_ci int err; 221062306a36Sopenharmony_ci u16 vlan; 221162306a36Sopenharmony_ci int vlan_index; 221262306a36Sopenharmony_ci int port; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci port = !in_port ? get_param_l(out_param) : in_port; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci if (!port || op != RES_OP_RESERVE_AND_MAP) 221762306a36Sopenharmony_ci return -EINVAL; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci port = mlx4_slave_convert_port( 222062306a36Sopenharmony_ci dev, slave, port); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (port < 0) 222362306a36Sopenharmony_ci return -EINVAL; 222462306a36Sopenharmony_ci /* upstream kernels had NOP for reg/unreg vlan. Continue this. */ 222562306a36Sopenharmony_ci if (!in_port && port > 0 && port <= dev->caps.num_ports) { 222662306a36Sopenharmony_ci slave_state[slave].old_vlan_api = true; 222762306a36Sopenharmony_ci return 0; 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci vlan = (u16) in_param; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); 223362306a36Sopenharmony_ci if (!err) { 223462306a36Sopenharmony_ci set_param_l(out_param, (u32) vlan_index); 223562306a36Sopenharmony_ci err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); 223662306a36Sopenharmony_ci if (err) 223762306a36Sopenharmony_ci __mlx4_unregister_vlan(dev, port, vlan); 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci return err; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_cistatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 224362306a36Sopenharmony_ci u64 in_param, u64 *out_param, int port) 224462306a36Sopenharmony_ci{ 224562306a36Sopenharmony_ci u32 index; 224662306a36Sopenharmony_ci int err; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci if (op != RES_OP_RESERVE) 224962306a36Sopenharmony_ci return -EINVAL; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0); 225262306a36Sopenharmony_ci if (err) 225362306a36Sopenharmony_ci return err; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci err = __mlx4_counter_alloc(dev, &index); 225662306a36Sopenharmony_ci if (err) { 225762306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 225862306a36Sopenharmony_ci return err; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci err = add_res_range(dev, slave, index, 1, RES_COUNTER, port); 226262306a36Sopenharmony_ci if (err) { 226362306a36Sopenharmony_ci __mlx4_counter_free(dev, index); 226462306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 226562306a36Sopenharmony_ci } else { 226662306a36Sopenharmony_ci set_param_l(out_param, index); 226762306a36Sopenharmony_ci } 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci return err; 227062306a36Sopenharmony_ci} 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_cistatic int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 227362306a36Sopenharmony_ci u64 in_param, u64 *out_param) 227462306a36Sopenharmony_ci{ 227562306a36Sopenharmony_ci u32 xrcdn; 227662306a36Sopenharmony_ci int err; 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci if (op != RES_OP_RESERVE) 227962306a36Sopenharmony_ci return -EINVAL; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci err = __mlx4_xrcd_alloc(dev, &xrcdn); 228262306a36Sopenharmony_ci if (err) 228362306a36Sopenharmony_ci return err; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 228662306a36Sopenharmony_ci if (err) 228762306a36Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 228862306a36Sopenharmony_ci else 228962306a36Sopenharmony_ci set_param_l(out_param, xrcdn); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci return err; 229262306a36Sopenharmony_ci} 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ciint mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, 229562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 229662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 229762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 229862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 229962306a36Sopenharmony_ci{ 230062306a36Sopenharmony_ci int err; 230162306a36Sopenharmony_ci int alop = vhcr->op_modifier; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci switch (vhcr->in_modifier & 0xFF) { 230462306a36Sopenharmony_ci case RES_QP: 230562306a36Sopenharmony_ci err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, 230662306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 230762306a36Sopenharmony_ci break; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci case RES_MTT: 231062306a36Sopenharmony_ci err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, 231162306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 231262306a36Sopenharmony_ci break; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci case RES_MPT: 231562306a36Sopenharmony_ci err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, 231662306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 231762306a36Sopenharmony_ci break; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci case RES_CQ: 232062306a36Sopenharmony_ci err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, 232162306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 232262306a36Sopenharmony_ci break; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci case RES_SRQ: 232562306a36Sopenharmony_ci err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, 232662306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 232762306a36Sopenharmony_ci break; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci case RES_MAC: 233062306a36Sopenharmony_ci err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, 233162306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 233262306a36Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 233362306a36Sopenharmony_ci break; 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci case RES_VLAN: 233662306a36Sopenharmony_ci err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, 233762306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 233862306a36Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 233962306a36Sopenharmony_ci break; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci case RES_COUNTER: 234262306a36Sopenharmony_ci err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, 234362306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 0); 234462306a36Sopenharmony_ci break; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci case RES_XRCD: 234762306a36Sopenharmony_ci err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, 234862306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 234962306a36Sopenharmony_ci break; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci default: 235262306a36Sopenharmony_ci err = -EINVAL; 235362306a36Sopenharmony_ci break; 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci return err; 235762306a36Sopenharmony_ci} 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_cistatic int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 236062306a36Sopenharmony_ci u64 in_param) 236162306a36Sopenharmony_ci{ 236262306a36Sopenharmony_ci int err; 236362306a36Sopenharmony_ci int count; 236462306a36Sopenharmony_ci int base; 236562306a36Sopenharmony_ci int qpn; 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci switch (op) { 236862306a36Sopenharmony_ci case RES_OP_RESERVE: 236962306a36Sopenharmony_ci base = get_param_l(&in_param) & 0x7fffff; 237062306a36Sopenharmony_ci count = get_param_h(&in_param); 237162306a36Sopenharmony_ci err = rem_res_range(dev, slave, base, count, RES_QP, 0); 237262306a36Sopenharmony_ci if (err) 237362306a36Sopenharmony_ci break; 237462306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_QP, count, 0); 237562306a36Sopenharmony_ci __mlx4_qp_release_range(dev, base, count); 237662306a36Sopenharmony_ci break; 237762306a36Sopenharmony_ci case RES_OP_MAP_ICM: 237862306a36Sopenharmony_ci qpn = get_param_l(&in_param) & 0x7fffff; 237962306a36Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, 238062306a36Sopenharmony_ci NULL, 0); 238162306a36Sopenharmony_ci if (err) 238262306a36Sopenharmony_ci return err; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci if (!fw_reserved(dev, qpn)) 238562306a36Sopenharmony_ci __mlx4_qp_free_icm(dev, qpn); 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (valid_reserved(dev, slave, qpn)) 239062306a36Sopenharmony_ci err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); 239162306a36Sopenharmony_ci break; 239262306a36Sopenharmony_ci default: 239362306a36Sopenharmony_ci err = -EINVAL; 239462306a36Sopenharmony_ci break; 239562306a36Sopenharmony_ci } 239662306a36Sopenharmony_ci return err; 239762306a36Sopenharmony_ci} 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_cistatic int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 240062306a36Sopenharmony_ci u64 in_param, u64 *out_param) 240162306a36Sopenharmony_ci{ 240262306a36Sopenharmony_ci int err = -EINVAL; 240362306a36Sopenharmony_ci int base; 240462306a36Sopenharmony_ci int order; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci if (op != RES_OP_RESERVE_AND_MAP) 240762306a36Sopenharmony_ci return err; 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci base = get_param_l(&in_param); 241062306a36Sopenharmony_ci order = get_param_h(&in_param); 241162306a36Sopenharmony_ci err = rem_res_range(dev, slave, base, 1, RES_MTT, order); 241262306a36Sopenharmony_ci if (!err) { 241362306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 241462306a36Sopenharmony_ci __mlx4_free_mtt_range(dev, base, order); 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci return err; 241762306a36Sopenharmony_ci} 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cistatic int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 242062306a36Sopenharmony_ci u64 in_param) 242162306a36Sopenharmony_ci{ 242262306a36Sopenharmony_ci int err = -EINVAL; 242362306a36Sopenharmony_ci int index; 242462306a36Sopenharmony_ci int id; 242562306a36Sopenharmony_ci struct res_mpt *mpt; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci switch (op) { 242862306a36Sopenharmony_ci case RES_OP_RESERVE: 242962306a36Sopenharmony_ci index = get_param_l(&in_param); 243062306a36Sopenharmony_ci id = index & mpt_mask(dev); 243162306a36Sopenharmony_ci err = get_res(dev, slave, id, RES_MPT, &mpt); 243262306a36Sopenharmony_ci if (err) 243362306a36Sopenharmony_ci break; 243462306a36Sopenharmony_ci index = mpt->key; 243562306a36Sopenharmony_ci put_res(dev, slave, id, RES_MPT); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); 243862306a36Sopenharmony_ci if (err) 243962306a36Sopenharmony_ci break; 244062306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 244162306a36Sopenharmony_ci __mlx4_mpt_release(dev, index); 244262306a36Sopenharmony_ci break; 244362306a36Sopenharmony_ci case RES_OP_MAP_ICM: 244462306a36Sopenharmony_ci index = get_param_l(&in_param); 244562306a36Sopenharmony_ci id = index & mpt_mask(dev); 244662306a36Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, 244762306a36Sopenharmony_ci RES_MPT_RESERVED, &mpt); 244862306a36Sopenharmony_ci if (err) 244962306a36Sopenharmony_ci return err; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci __mlx4_mpt_free_icm(dev, mpt->key); 245262306a36Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 245362306a36Sopenharmony_ci break; 245462306a36Sopenharmony_ci default: 245562306a36Sopenharmony_ci err = -EINVAL; 245662306a36Sopenharmony_ci break; 245762306a36Sopenharmony_ci } 245862306a36Sopenharmony_ci return err; 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_cistatic int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 246262306a36Sopenharmony_ci u64 in_param, u64 *out_param) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci int cqn; 246562306a36Sopenharmony_ci int err; 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci switch (op) { 246862306a36Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 246962306a36Sopenharmony_ci cqn = get_param_l(&in_param); 247062306a36Sopenharmony_ci err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); 247162306a36Sopenharmony_ci if (err) 247262306a36Sopenharmony_ci break; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 247562306a36Sopenharmony_ci __mlx4_cq_free_icm(dev, cqn); 247662306a36Sopenharmony_ci break; 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci default: 247962306a36Sopenharmony_ci err = -EINVAL; 248062306a36Sopenharmony_ci break; 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci return err; 248462306a36Sopenharmony_ci} 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_cistatic int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 248762306a36Sopenharmony_ci u64 in_param, u64 *out_param) 248862306a36Sopenharmony_ci{ 248962306a36Sopenharmony_ci int srqn; 249062306a36Sopenharmony_ci int err; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci switch (op) { 249362306a36Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 249462306a36Sopenharmony_ci srqn = get_param_l(&in_param); 249562306a36Sopenharmony_ci err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 249662306a36Sopenharmony_ci if (err) 249762306a36Sopenharmony_ci break; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 250062306a36Sopenharmony_ci __mlx4_srq_free_icm(dev, srqn); 250162306a36Sopenharmony_ci break; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci default: 250462306a36Sopenharmony_ci err = -EINVAL; 250562306a36Sopenharmony_ci break; 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci return err; 250962306a36Sopenharmony_ci} 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_cistatic int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 251262306a36Sopenharmony_ci u64 in_param, u64 *out_param, int in_port) 251362306a36Sopenharmony_ci{ 251462306a36Sopenharmony_ci int port; 251562306a36Sopenharmony_ci int err = 0; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci switch (op) { 251862306a36Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 251962306a36Sopenharmony_ci port = !in_port ? get_param_l(out_param) : in_port; 252062306a36Sopenharmony_ci port = mlx4_slave_convert_port( 252162306a36Sopenharmony_ci dev, slave, port); 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (port < 0) 252462306a36Sopenharmony_ci return -EINVAL; 252562306a36Sopenharmony_ci mac_del_from_slave(dev, slave, in_param, port); 252662306a36Sopenharmony_ci __mlx4_unregister_mac(dev, port, in_param); 252762306a36Sopenharmony_ci break; 252862306a36Sopenharmony_ci default: 252962306a36Sopenharmony_ci err = -EINVAL; 253062306a36Sopenharmony_ci break; 253162306a36Sopenharmony_ci } 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci return err; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci} 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_cistatic int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 253862306a36Sopenharmony_ci u64 in_param, u64 *out_param, int port) 253962306a36Sopenharmony_ci{ 254062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 254162306a36Sopenharmony_ci struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 254262306a36Sopenharmony_ci int err = 0; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci port = mlx4_slave_convert_port( 254562306a36Sopenharmony_ci dev, slave, port); 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci if (port < 0) 254862306a36Sopenharmony_ci return -EINVAL; 254962306a36Sopenharmony_ci switch (op) { 255062306a36Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 255162306a36Sopenharmony_ci if (slave_state[slave].old_vlan_api) 255262306a36Sopenharmony_ci return 0; 255362306a36Sopenharmony_ci if (!port) 255462306a36Sopenharmony_ci return -EINVAL; 255562306a36Sopenharmony_ci vlan_del_from_slave(dev, slave, in_param, port); 255662306a36Sopenharmony_ci __mlx4_unregister_vlan(dev, port, in_param); 255762306a36Sopenharmony_ci break; 255862306a36Sopenharmony_ci default: 255962306a36Sopenharmony_ci err = -EINVAL; 256062306a36Sopenharmony_ci break; 256162306a36Sopenharmony_ci } 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci return err; 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 256762306a36Sopenharmony_ci u64 in_param, u64 *out_param) 256862306a36Sopenharmony_ci{ 256962306a36Sopenharmony_ci int index; 257062306a36Sopenharmony_ci int err; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci if (op != RES_OP_RESERVE) 257362306a36Sopenharmony_ci return -EINVAL; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci index = get_param_l(&in_param); 257662306a36Sopenharmony_ci if (index == MLX4_SINK_COUNTER_INDEX(dev)) 257762306a36Sopenharmony_ci return 0; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0); 258062306a36Sopenharmony_ci if (err) 258162306a36Sopenharmony_ci return err; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci __mlx4_counter_free(dev, index); 258462306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci return err; 258762306a36Sopenharmony_ci} 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_cistatic int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 259062306a36Sopenharmony_ci u64 in_param, u64 *out_param) 259162306a36Sopenharmony_ci{ 259262306a36Sopenharmony_ci int xrcdn; 259362306a36Sopenharmony_ci int err; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci if (op != RES_OP_RESERVE) 259662306a36Sopenharmony_ci return -EINVAL; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci xrcdn = get_param_l(&in_param); 259962306a36Sopenharmony_ci err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 260062306a36Sopenharmony_ci if (err) 260162306a36Sopenharmony_ci return err; 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci return err; 260662306a36Sopenharmony_ci} 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ciint mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, 260962306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 261062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 261162306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 261262306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 261362306a36Sopenharmony_ci{ 261462306a36Sopenharmony_ci int err = -EINVAL; 261562306a36Sopenharmony_ci int alop = vhcr->op_modifier; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci switch (vhcr->in_modifier & 0xFF) { 261862306a36Sopenharmony_ci case RES_QP: 261962306a36Sopenharmony_ci err = qp_free_res(dev, slave, vhcr->op_modifier, alop, 262062306a36Sopenharmony_ci vhcr->in_param); 262162306a36Sopenharmony_ci break; 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci case RES_MTT: 262462306a36Sopenharmony_ci err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, 262562306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 262662306a36Sopenharmony_ci break; 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci case RES_MPT: 262962306a36Sopenharmony_ci err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, 263062306a36Sopenharmony_ci vhcr->in_param); 263162306a36Sopenharmony_ci break; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci case RES_CQ: 263462306a36Sopenharmony_ci err = cq_free_res(dev, slave, vhcr->op_modifier, alop, 263562306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 263662306a36Sopenharmony_ci break; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci case RES_SRQ: 263962306a36Sopenharmony_ci err = srq_free_res(dev, slave, vhcr->op_modifier, alop, 264062306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 264162306a36Sopenharmony_ci break; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci case RES_MAC: 264462306a36Sopenharmony_ci err = mac_free_res(dev, slave, vhcr->op_modifier, alop, 264562306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 264662306a36Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 264762306a36Sopenharmony_ci break; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci case RES_VLAN: 265062306a36Sopenharmony_ci err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, 265162306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 265262306a36Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 265362306a36Sopenharmony_ci break; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci case RES_COUNTER: 265662306a36Sopenharmony_ci err = counter_free_res(dev, slave, vhcr->op_modifier, alop, 265762306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 265862306a36Sopenharmony_ci break; 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci case RES_XRCD: 266162306a36Sopenharmony_ci err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, 266262306a36Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 266362306a36Sopenharmony_ci break; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci default: 266662306a36Sopenharmony_ci break; 266762306a36Sopenharmony_ci } 266862306a36Sopenharmony_ci return err; 266962306a36Sopenharmony_ci} 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci/* ugly but other choices are uglier */ 267262306a36Sopenharmony_cistatic int mr_phys_mpt(struct mlx4_mpt_entry *mpt) 267362306a36Sopenharmony_ci{ 267462306a36Sopenharmony_ci return (be32_to_cpu(mpt->flags) >> 9) & 1; 267562306a36Sopenharmony_ci} 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_cistatic int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; 268062306a36Sopenharmony_ci} 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_cistatic int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) 268362306a36Sopenharmony_ci{ 268462306a36Sopenharmony_ci return be32_to_cpu(mpt->mtt_sz); 268562306a36Sopenharmony_ci} 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_cistatic u32 mr_get_pd(struct mlx4_mpt_entry *mpt) 268862306a36Sopenharmony_ci{ 268962306a36Sopenharmony_ci return be32_to_cpu(mpt->pd_flags) & 0x00ffffff; 269062306a36Sopenharmony_ci} 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_cistatic int mr_is_fmr(struct mlx4_mpt_entry *mpt) 269362306a36Sopenharmony_ci{ 269462306a36Sopenharmony_ci return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG; 269562306a36Sopenharmony_ci} 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_cistatic int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt) 269862306a36Sopenharmony_ci{ 269962306a36Sopenharmony_ci return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE; 270062306a36Sopenharmony_ci} 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_cistatic int mr_is_region(struct mlx4_mpt_entry *mpt) 270362306a36Sopenharmony_ci{ 270462306a36Sopenharmony_ci return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION; 270562306a36Sopenharmony_ci} 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_cistatic int qp_get_mtt_addr(struct mlx4_qp_context *qpc) 270862306a36Sopenharmony_ci{ 270962306a36Sopenharmony_ci return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; 271062306a36Sopenharmony_ci} 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_cistatic int srq_get_mtt_addr(struct mlx4_srq_context *srqc) 271362306a36Sopenharmony_ci{ 271462306a36Sopenharmony_ci return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; 271562306a36Sopenharmony_ci} 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_cistatic int qp_get_mtt_size(struct mlx4_qp_context *qpc) 271862306a36Sopenharmony_ci{ 271962306a36Sopenharmony_ci int page_shift = (qpc->log_page_size & 0x3f) + 12; 272062306a36Sopenharmony_ci int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; 272162306a36Sopenharmony_ci int log_sq_sride = qpc->sq_size_stride & 7; 272262306a36Sopenharmony_ci int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; 272362306a36Sopenharmony_ci int log_rq_stride = qpc->rq_size_stride & 7; 272462306a36Sopenharmony_ci int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; 272562306a36Sopenharmony_ci int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; 272662306a36Sopenharmony_ci u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 272762306a36Sopenharmony_ci int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0; 272862306a36Sopenharmony_ci int sq_size; 272962306a36Sopenharmony_ci int rq_size; 273062306a36Sopenharmony_ci int total_pages; 273162306a36Sopenharmony_ci int total_mem; 273262306a36Sopenharmony_ci int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; 273362306a36Sopenharmony_ci int tot; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci sq_size = 1 << (log_sq_size + log_sq_sride + 4); 273662306a36Sopenharmony_ci rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); 273762306a36Sopenharmony_ci total_mem = sq_size + rq_size; 273862306a36Sopenharmony_ci tot = (total_mem + (page_offset << 6)) >> page_shift; 273962306a36Sopenharmony_ci total_pages = !tot ? 1 : roundup_pow_of_two(tot); 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci return total_pages; 274262306a36Sopenharmony_ci} 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_cistatic int check_mtt_range(struct mlx4_dev *dev, int slave, int start, 274562306a36Sopenharmony_ci int size, struct res_mtt *mtt) 274662306a36Sopenharmony_ci{ 274762306a36Sopenharmony_ci int res_start = mtt->com.res_id; 274862306a36Sopenharmony_ci int res_size = (1 << mtt->order); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci if (start < res_start || start + size > res_start + res_size) 275162306a36Sopenharmony_ci return -EPERM; 275262306a36Sopenharmony_ci return 0; 275362306a36Sopenharmony_ci} 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ciint mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, 275662306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 275762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 275862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 275962306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 276062306a36Sopenharmony_ci{ 276162306a36Sopenharmony_ci int err; 276262306a36Sopenharmony_ci int index = vhcr->in_modifier; 276362306a36Sopenharmony_ci struct res_mtt *mtt; 276462306a36Sopenharmony_ci struct res_mpt *mpt = NULL; 276562306a36Sopenharmony_ci int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; 276662306a36Sopenharmony_ci int phys; 276762306a36Sopenharmony_ci int id; 276862306a36Sopenharmony_ci u32 pd; 276962306a36Sopenharmony_ci int pd_slave; 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci id = index & mpt_mask(dev); 277262306a36Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); 277362306a36Sopenharmony_ci if (err) 277462306a36Sopenharmony_ci return err; 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci /* Disable memory windows for VFs. */ 277762306a36Sopenharmony_ci if (!mr_is_region(inbox->buf)) { 277862306a36Sopenharmony_ci err = -EPERM; 277962306a36Sopenharmony_ci goto ex_abort; 278062306a36Sopenharmony_ci } 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci /* Make sure that the PD bits related to the slave id are zeros. */ 278362306a36Sopenharmony_ci pd = mr_get_pd(inbox->buf); 278462306a36Sopenharmony_ci pd_slave = (pd >> 17) & 0x7f; 278562306a36Sopenharmony_ci if (pd_slave != 0 && --pd_slave != slave) { 278662306a36Sopenharmony_ci err = -EPERM; 278762306a36Sopenharmony_ci goto ex_abort; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci if (mr_is_fmr(inbox->buf)) { 279162306a36Sopenharmony_ci /* FMR and Bind Enable are forbidden in slave devices. */ 279262306a36Sopenharmony_ci if (mr_is_bind_enabled(inbox->buf)) { 279362306a36Sopenharmony_ci err = -EPERM; 279462306a36Sopenharmony_ci goto ex_abort; 279562306a36Sopenharmony_ci } 279662306a36Sopenharmony_ci /* FMR and Memory Windows are also forbidden. */ 279762306a36Sopenharmony_ci if (!mr_is_region(inbox->buf)) { 279862306a36Sopenharmony_ci err = -EPERM; 279962306a36Sopenharmony_ci goto ex_abort; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci phys = mr_phys_mpt(inbox->buf); 280462306a36Sopenharmony_ci if (!phys) { 280562306a36Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 280662306a36Sopenharmony_ci if (err) 280762306a36Sopenharmony_ci goto ex_abort; 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, 281062306a36Sopenharmony_ci mr_get_mtt_size(inbox->buf), mtt); 281162306a36Sopenharmony_ci if (err) 281262306a36Sopenharmony_ci goto ex_put; 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci mpt->mtt = mtt; 281562306a36Sopenharmony_ci } 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 281862306a36Sopenharmony_ci if (err) 281962306a36Sopenharmony_ci goto ex_put; 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci if (!phys) { 282262306a36Sopenharmony_ci atomic_inc(&mtt->ref_count); 282362306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 282462306a36Sopenharmony_ci } 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 282762306a36Sopenharmony_ci return 0; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ciex_put: 283062306a36Sopenharmony_ci if (!phys) 283162306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 283262306a36Sopenharmony_ciex_abort: 283362306a36Sopenharmony_ci res_abort_move(dev, slave, RES_MPT, id); 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci return err; 283662306a36Sopenharmony_ci} 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ciint mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, 283962306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 284062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 284162306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 284262306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 284362306a36Sopenharmony_ci{ 284462306a36Sopenharmony_ci int err; 284562306a36Sopenharmony_ci int index = vhcr->in_modifier; 284662306a36Sopenharmony_ci struct res_mpt *mpt; 284762306a36Sopenharmony_ci int id; 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci id = index & mpt_mask(dev); 285062306a36Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); 285162306a36Sopenharmony_ci if (err) 285262306a36Sopenharmony_ci return err; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 285562306a36Sopenharmony_ci if (err) 285662306a36Sopenharmony_ci goto ex_abort; 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci if (mpt->mtt) 285962306a36Sopenharmony_ci atomic_dec(&mpt->mtt->ref_count); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 286262306a36Sopenharmony_ci return 0; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ciex_abort: 286562306a36Sopenharmony_ci res_abort_move(dev, slave, RES_MPT, id); 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci return err; 286862306a36Sopenharmony_ci} 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ciint mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, 287162306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 287262306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 287362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 287462306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 287562306a36Sopenharmony_ci{ 287662306a36Sopenharmony_ci int err; 287762306a36Sopenharmony_ci int index = vhcr->in_modifier; 287862306a36Sopenharmony_ci struct res_mpt *mpt; 287962306a36Sopenharmony_ci int id; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci id = index & mpt_mask(dev); 288262306a36Sopenharmony_ci err = get_res(dev, slave, id, RES_MPT, &mpt); 288362306a36Sopenharmony_ci if (err) 288462306a36Sopenharmony_ci return err; 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci if (mpt->com.from_state == RES_MPT_MAPPED) { 288762306a36Sopenharmony_ci /* In order to allow rereg in SRIOV, we need to alter the MPT entry. To do 288862306a36Sopenharmony_ci * that, the VF must read the MPT. But since the MPT entry memory is not 288962306a36Sopenharmony_ci * in the VF's virtual memory space, it must use QUERY_MPT to obtain the 289062306a36Sopenharmony_ci * entry contents. To guarantee that the MPT cannot be changed, the driver 289162306a36Sopenharmony_ci * must perform HW2SW_MPT before this query and return the MPT entry to HW 289262306a36Sopenharmony_ci * ownership fofollowing the change. The change here allows the VF to 289362306a36Sopenharmony_ci * perform QUERY_MPT also when the entry is in SW ownership. 289462306a36Sopenharmony_ci */ 289562306a36Sopenharmony_ci struct mlx4_mpt_entry *mpt_entry = mlx4_table_find( 289662306a36Sopenharmony_ci &mlx4_priv(dev)->mr_table.dmpt_table, 289762306a36Sopenharmony_ci mpt->key, NULL); 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci if (NULL == mpt_entry || NULL == outbox->buf) { 290062306a36Sopenharmony_ci err = -EINVAL; 290162306a36Sopenharmony_ci goto out; 290262306a36Sopenharmony_ci } 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci memcpy(outbox->buf, mpt_entry, sizeof(*mpt_entry)); 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci err = 0; 290762306a36Sopenharmony_ci } else if (mpt->com.from_state == RES_MPT_HW) { 290862306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 290962306a36Sopenharmony_ci } else { 291062306a36Sopenharmony_ci err = -EBUSY; 291162306a36Sopenharmony_ci goto out; 291262306a36Sopenharmony_ci } 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ciout: 291662306a36Sopenharmony_ci put_res(dev, slave, id, RES_MPT); 291762306a36Sopenharmony_ci return err; 291862306a36Sopenharmony_ci} 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_cistatic int qp_get_rcqn(struct mlx4_qp_context *qpc) 292162306a36Sopenharmony_ci{ 292262306a36Sopenharmony_ci return be32_to_cpu(qpc->cqn_recv) & 0xffffff; 292362306a36Sopenharmony_ci} 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_cistatic int qp_get_scqn(struct mlx4_qp_context *qpc) 292662306a36Sopenharmony_ci{ 292762306a36Sopenharmony_ci return be32_to_cpu(qpc->cqn_send) & 0xffffff; 292862306a36Sopenharmony_ci} 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_cistatic u32 qp_get_srqn(struct mlx4_qp_context *qpc) 293162306a36Sopenharmony_ci{ 293262306a36Sopenharmony_ci return be32_to_cpu(qpc->srqn) & 0x1ffffff; 293362306a36Sopenharmony_ci} 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_cistatic void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, 293662306a36Sopenharmony_ci struct mlx4_qp_context *context) 293762306a36Sopenharmony_ci{ 293862306a36Sopenharmony_ci u32 qpn = vhcr->in_modifier & 0xffffff; 293962306a36Sopenharmony_ci u32 qkey = 0; 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci if (mlx4_get_parav_qkey(dev, qpn, &qkey)) 294262306a36Sopenharmony_ci return; 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci /* adjust qkey in qp context */ 294562306a36Sopenharmony_ci context->qkey = cpu_to_be32(qkey); 294662306a36Sopenharmony_ci} 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_cistatic int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave, 294962306a36Sopenharmony_ci struct mlx4_qp_context *qpc, 295062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox); 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ciint mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 295362306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 295462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 295562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 295662306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 295762306a36Sopenharmony_ci{ 295862306a36Sopenharmony_ci int err; 295962306a36Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 296062306a36Sopenharmony_ci struct res_mtt *mtt; 296162306a36Sopenharmony_ci struct res_qp *qp; 296262306a36Sopenharmony_ci struct mlx4_qp_context *qpc = inbox->buf + 8; 296362306a36Sopenharmony_ci int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; 296462306a36Sopenharmony_ci int mtt_size = qp_get_mtt_size(qpc); 296562306a36Sopenharmony_ci struct res_cq *rcq; 296662306a36Sopenharmony_ci struct res_cq *scq; 296762306a36Sopenharmony_ci int rcqn = qp_get_rcqn(qpc); 296862306a36Sopenharmony_ci int scqn = qp_get_scqn(qpc); 296962306a36Sopenharmony_ci u32 srqn = qp_get_srqn(qpc) & 0xffffff; 297062306a36Sopenharmony_ci int use_srq = (qp_get_srqn(qpc) >> 24) & 1; 297162306a36Sopenharmony_ci struct res_srq *srq; 297262306a36Sopenharmony_ci int local_qpn = vhcr->in_modifier & 0xffffff; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, qpc, inbox); 297562306a36Sopenharmony_ci if (err) 297662306a36Sopenharmony_ci return err; 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); 297962306a36Sopenharmony_ci if (err) 298062306a36Sopenharmony_ci return err; 298162306a36Sopenharmony_ci qp->local_qpn = local_qpn; 298262306a36Sopenharmony_ci qp->sched_queue = 0; 298362306a36Sopenharmony_ci qp->param3 = 0; 298462306a36Sopenharmony_ci qp->vlan_control = 0; 298562306a36Sopenharmony_ci qp->fvl_rx = 0; 298662306a36Sopenharmony_ci qp->pri_path_fl = 0; 298762306a36Sopenharmony_ci qp->vlan_index = 0; 298862306a36Sopenharmony_ci qp->feup = 0; 298962306a36Sopenharmony_ci qp->qpc_flags = be32_to_cpu(qpc->flags); 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 299262306a36Sopenharmony_ci if (err) 299362306a36Sopenharmony_ci goto ex_abort; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 299662306a36Sopenharmony_ci if (err) 299762306a36Sopenharmony_ci goto ex_put_mtt; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci err = get_res(dev, slave, rcqn, RES_CQ, &rcq); 300062306a36Sopenharmony_ci if (err) 300162306a36Sopenharmony_ci goto ex_put_mtt; 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci if (scqn != rcqn) { 300462306a36Sopenharmony_ci err = get_res(dev, slave, scqn, RES_CQ, &scq); 300562306a36Sopenharmony_ci if (err) 300662306a36Sopenharmony_ci goto ex_put_rcq; 300762306a36Sopenharmony_ci } else 300862306a36Sopenharmony_ci scq = rcq; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci if (use_srq) { 301162306a36Sopenharmony_ci err = get_res(dev, slave, srqn, RES_SRQ, &srq); 301262306a36Sopenharmony_ci if (err) 301362306a36Sopenharmony_ci goto ex_put_scq; 301462306a36Sopenharmony_ci } 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, qpc); 301762306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 301862306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 301962306a36Sopenharmony_ci if (err) 302062306a36Sopenharmony_ci goto ex_put_srq; 302162306a36Sopenharmony_ci atomic_inc(&mtt->ref_count); 302262306a36Sopenharmony_ci qp->mtt = mtt; 302362306a36Sopenharmony_ci atomic_inc(&rcq->ref_count); 302462306a36Sopenharmony_ci qp->rcq = rcq; 302562306a36Sopenharmony_ci atomic_inc(&scq->ref_count); 302662306a36Sopenharmony_ci qp->scq = scq; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci if (scqn != rcqn) 302962306a36Sopenharmony_ci put_res(dev, slave, scqn, RES_CQ); 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci if (use_srq) { 303262306a36Sopenharmony_ci atomic_inc(&srq->ref_count); 303362306a36Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 303462306a36Sopenharmony_ci qp->srq = srq; 303562306a36Sopenharmony_ci } 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci /* Save param3 for dynamic changes from VST back to VGT */ 303862306a36Sopenharmony_ci qp->param3 = qpc->param3; 303962306a36Sopenharmony_ci put_res(dev, slave, rcqn, RES_CQ); 304062306a36Sopenharmony_ci put_res(dev, slave, mtt_base, RES_MTT); 304162306a36Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci return 0; 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ciex_put_srq: 304662306a36Sopenharmony_ci if (use_srq) 304762306a36Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 304862306a36Sopenharmony_ciex_put_scq: 304962306a36Sopenharmony_ci if (scqn != rcqn) 305062306a36Sopenharmony_ci put_res(dev, slave, scqn, RES_CQ); 305162306a36Sopenharmony_ciex_put_rcq: 305262306a36Sopenharmony_ci put_res(dev, slave, rcqn, RES_CQ); 305362306a36Sopenharmony_ciex_put_mtt: 305462306a36Sopenharmony_ci put_res(dev, slave, mtt_base, RES_MTT); 305562306a36Sopenharmony_ciex_abort: 305662306a36Sopenharmony_ci res_abort_move(dev, slave, RES_QP, qpn); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci return err; 305962306a36Sopenharmony_ci} 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_cistatic int eq_get_mtt_addr(struct mlx4_eq_context *eqc) 306262306a36Sopenharmony_ci{ 306362306a36Sopenharmony_ci return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; 306462306a36Sopenharmony_ci} 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_cistatic int eq_get_mtt_size(struct mlx4_eq_context *eqc) 306762306a36Sopenharmony_ci{ 306862306a36Sopenharmony_ci int log_eq_size = eqc->log_eq_size & 0x1f; 306962306a36Sopenharmony_ci int page_shift = (eqc->log_page_size & 0x3f) + 12; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci if (log_eq_size + 5 < page_shift) 307262306a36Sopenharmony_ci return 1; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci return 1 << (log_eq_size + 5 - page_shift); 307562306a36Sopenharmony_ci} 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_cistatic int cq_get_mtt_addr(struct mlx4_cq_context *cqc) 307862306a36Sopenharmony_ci{ 307962306a36Sopenharmony_ci return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; 308062306a36Sopenharmony_ci} 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_cistatic int cq_get_mtt_size(struct mlx4_cq_context *cqc) 308362306a36Sopenharmony_ci{ 308462306a36Sopenharmony_ci int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; 308562306a36Sopenharmony_ci int page_shift = (cqc->log_page_size & 0x3f) + 12; 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci if (log_cq_size + 5 < page_shift) 308862306a36Sopenharmony_ci return 1; 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci return 1 << (log_cq_size + 5 - page_shift); 309162306a36Sopenharmony_ci} 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ciint mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, 309462306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 309562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 309662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 309762306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 309862306a36Sopenharmony_ci{ 309962306a36Sopenharmony_ci int err; 310062306a36Sopenharmony_ci int eqn = vhcr->in_modifier; 310162306a36Sopenharmony_ci int res_id = (slave << 10) | eqn; 310262306a36Sopenharmony_ci struct mlx4_eq_context *eqc = inbox->buf; 310362306a36Sopenharmony_ci int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; 310462306a36Sopenharmony_ci int mtt_size = eq_get_mtt_size(eqc); 310562306a36Sopenharmony_ci struct res_eq *eq; 310662306a36Sopenharmony_ci struct res_mtt *mtt; 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); 310962306a36Sopenharmony_ci if (err) 311062306a36Sopenharmony_ci return err; 311162306a36Sopenharmony_ci err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); 311262306a36Sopenharmony_ci if (err) 311362306a36Sopenharmony_ci goto out_add; 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 311662306a36Sopenharmony_ci if (err) 311762306a36Sopenharmony_ci goto out_move; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 312062306a36Sopenharmony_ci if (err) 312162306a36Sopenharmony_ci goto out_put; 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 312462306a36Sopenharmony_ci if (err) 312562306a36Sopenharmony_ci goto out_put; 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci atomic_inc(&mtt->ref_count); 312862306a36Sopenharmony_ci eq->mtt = mtt; 312962306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 313062306a36Sopenharmony_ci res_end_move(dev, slave, RES_EQ, res_id); 313162306a36Sopenharmony_ci return 0; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ciout_put: 313462306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 313562306a36Sopenharmony_ciout_move: 313662306a36Sopenharmony_ci res_abort_move(dev, slave, RES_EQ, res_id); 313762306a36Sopenharmony_ciout_add: 313862306a36Sopenharmony_ci rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 313962306a36Sopenharmony_ci return err; 314062306a36Sopenharmony_ci} 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ciint mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave, 314362306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 314462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 314562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 314662306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 314762306a36Sopenharmony_ci{ 314862306a36Sopenharmony_ci int err; 314962306a36Sopenharmony_ci u8 get = vhcr->op_modifier; 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci if (get != 1) 315262306a36Sopenharmony_ci return -EPERM; 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci return err; 315762306a36Sopenharmony_ci} 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_cistatic int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, 316062306a36Sopenharmony_ci int len, struct res_mtt **res) 316162306a36Sopenharmony_ci{ 316262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 316362306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 316462306a36Sopenharmony_ci struct res_mtt *mtt; 316562306a36Sopenharmony_ci int err = -EINVAL; 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 316862306a36Sopenharmony_ci list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], 316962306a36Sopenharmony_ci com.list) { 317062306a36Sopenharmony_ci if (!check_mtt_range(dev, slave, start, len, mtt)) { 317162306a36Sopenharmony_ci *res = mtt; 317262306a36Sopenharmony_ci mtt->com.from_state = mtt->com.state; 317362306a36Sopenharmony_ci mtt->com.state = RES_MTT_BUSY; 317462306a36Sopenharmony_ci err = 0; 317562306a36Sopenharmony_ci break; 317662306a36Sopenharmony_ci } 317762306a36Sopenharmony_ci } 317862306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci return err; 318162306a36Sopenharmony_ci} 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_cistatic int verify_qp_parameters(struct mlx4_dev *dev, 318462306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 318562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 318662306a36Sopenharmony_ci enum qp_transition transition, u8 slave) 318762306a36Sopenharmony_ci{ 318862306a36Sopenharmony_ci u32 qp_type; 318962306a36Sopenharmony_ci u32 qpn; 319062306a36Sopenharmony_ci struct mlx4_qp_context *qp_ctx; 319162306a36Sopenharmony_ci enum mlx4_qp_optpar optpar; 319262306a36Sopenharmony_ci int port; 319362306a36Sopenharmony_ci int num_gids; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci qp_ctx = inbox->buf + 8; 319662306a36Sopenharmony_ci qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 319762306a36Sopenharmony_ci optpar = be32_to_cpu(*(__be32 *) inbox->buf); 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci if (slave != mlx4_master_func_num(dev)) { 320062306a36Sopenharmony_ci qp_ctx->params2 &= ~cpu_to_be32(MLX4_QP_BIT_FPP); 320162306a36Sopenharmony_ci /* setting QP rate-limit is disallowed for VFs */ 320262306a36Sopenharmony_ci if (qp_ctx->rate_limit_params) 320362306a36Sopenharmony_ci return -EPERM; 320462306a36Sopenharmony_ci } 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci switch (qp_type) { 320762306a36Sopenharmony_ci case MLX4_QP_ST_RC: 320862306a36Sopenharmony_ci case MLX4_QP_ST_XRC: 320962306a36Sopenharmony_ci case MLX4_QP_ST_UC: 321062306a36Sopenharmony_ci switch (transition) { 321162306a36Sopenharmony_ci case QP_TRANS_INIT2RTR: 321262306a36Sopenharmony_ci case QP_TRANS_RTR2RTS: 321362306a36Sopenharmony_ci case QP_TRANS_RTS2RTS: 321462306a36Sopenharmony_ci case QP_TRANS_SQD2SQD: 321562306a36Sopenharmony_ci case QP_TRANS_SQD2RTS: 321662306a36Sopenharmony_ci if (slave != mlx4_master_func_num(dev)) { 321762306a36Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 321862306a36Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 321962306a36Sopenharmony_ci if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 322062306a36Sopenharmony_ci num_gids = mlx4_get_slave_num_gids(dev, slave, port); 322162306a36Sopenharmony_ci else 322262306a36Sopenharmony_ci num_gids = 1; 322362306a36Sopenharmony_ci if (qp_ctx->pri_path.mgid_index >= num_gids) 322462306a36Sopenharmony_ci return -EINVAL; 322562306a36Sopenharmony_ci } 322662306a36Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 322762306a36Sopenharmony_ci port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 322862306a36Sopenharmony_ci if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 322962306a36Sopenharmony_ci num_gids = mlx4_get_slave_num_gids(dev, slave, port); 323062306a36Sopenharmony_ci else 323162306a36Sopenharmony_ci num_gids = 1; 323262306a36Sopenharmony_ci if (qp_ctx->alt_path.mgid_index >= num_gids) 323362306a36Sopenharmony_ci return -EINVAL; 323462306a36Sopenharmony_ci } 323562306a36Sopenharmony_ci } 323662306a36Sopenharmony_ci break; 323762306a36Sopenharmony_ci default: 323862306a36Sopenharmony_ci break; 323962306a36Sopenharmony_ci } 324062306a36Sopenharmony_ci break; 324162306a36Sopenharmony_ci 324262306a36Sopenharmony_ci case MLX4_QP_ST_MLX: 324362306a36Sopenharmony_ci qpn = vhcr->in_modifier & 0x7fffff; 324462306a36Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 324562306a36Sopenharmony_ci if (transition == QP_TRANS_INIT2RTR && 324662306a36Sopenharmony_ci slave != mlx4_master_func_num(dev) && 324762306a36Sopenharmony_ci mlx4_is_qp_reserved(dev, qpn) && 324862306a36Sopenharmony_ci !mlx4_vf_smi_enabled(dev, slave, port)) { 324962306a36Sopenharmony_ci /* only enabled VFs may create MLX proxy QPs */ 325062306a36Sopenharmony_ci mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n", 325162306a36Sopenharmony_ci __func__, slave, port); 325262306a36Sopenharmony_ci return -EPERM; 325362306a36Sopenharmony_ci } 325462306a36Sopenharmony_ci break; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci default: 325762306a36Sopenharmony_ci break; 325862306a36Sopenharmony_ci } 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci return 0; 326162306a36Sopenharmony_ci} 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ciint mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, 326462306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 326562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 326662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 326762306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 326862306a36Sopenharmony_ci{ 326962306a36Sopenharmony_ci struct mlx4_mtt mtt; 327062306a36Sopenharmony_ci __be64 *page_list = inbox->buf; 327162306a36Sopenharmony_ci u64 *pg_list = (u64 *)page_list; 327262306a36Sopenharmony_ci int i; 327362306a36Sopenharmony_ci struct res_mtt *rmtt = NULL; 327462306a36Sopenharmony_ci int start = be64_to_cpu(page_list[0]); 327562306a36Sopenharmony_ci int npages = vhcr->in_modifier; 327662306a36Sopenharmony_ci int err; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci err = get_containing_mtt(dev, slave, start, npages, &rmtt); 327962306a36Sopenharmony_ci if (err) 328062306a36Sopenharmony_ci return err; 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci /* Call the SW implementation of write_mtt: 328362306a36Sopenharmony_ci * - Prepare a dummy mtt struct 328462306a36Sopenharmony_ci * - Translate inbox contents to simple addresses in host endianness */ 328562306a36Sopenharmony_ci mtt.offset = 0; /* TBD this is broken but I don't handle it since 328662306a36Sopenharmony_ci we don't really use it */ 328762306a36Sopenharmony_ci mtt.order = 0; 328862306a36Sopenharmony_ci mtt.page_shift = 0; 328962306a36Sopenharmony_ci for (i = 0; i < npages; ++i) 329062306a36Sopenharmony_ci pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, 329362306a36Sopenharmony_ci ((u64 *)page_list + 2)); 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci if (rmtt) 329662306a36Sopenharmony_ci put_res(dev, slave, rmtt->com.res_id, RES_MTT); 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci return err; 329962306a36Sopenharmony_ci} 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ciint mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, 330262306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 330362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 330462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 330562306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 330662306a36Sopenharmony_ci{ 330762306a36Sopenharmony_ci int eqn = vhcr->in_modifier; 330862306a36Sopenharmony_ci int res_id = eqn | (slave << 10); 330962306a36Sopenharmony_ci struct res_eq *eq; 331062306a36Sopenharmony_ci int err; 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); 331362306a36Sopenharmony_ci if (err) 331462306a36Sopenharmony_ci return err; 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); 331762306a36Sopenharmony_ci if (err) 331862306a36Sopenharmony_ci goto ex_abort; 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 332162306a36Sopenharmony_ci if (err) 332262306a36Sopenharmony_ci goto ex_put; 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci atomic_dec(&eq->mtt->ref_count); 332562306a36Sopenharmony_ci put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 332662306a36Sopenharmony_ci res_end_move(dev, slave, RES_EQ, res_id); 332762306a36Sopenharmony_ci rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci return 0; 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ciex_put: 333262306a36Sopenharmony_ci put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 333362306a36Sopenharmony_ciex_abort: 333462306a36Sopenharmony_ci res_abort_move(dev, slave, RES_EQ, res_id); 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci return err; 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ciint mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) 334062306a36Sopenharmony_ci{ 334162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 334262306a36Sopenharmony_ci struct mlx4_slave_event_eq_info *event_eq; 334362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 334462306a36Sopenharmony_ci u32 in_modifier = 0; 334562306a36Sopenharmony_ci int err; 334662306a36Sopenharmony_ci int res_id; 334762306a36Sopenharmony_ci struct res_eq *req; 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci if (!priv->mfunc.master.slave_state) 335062306a36Sopenharmony_ci return -EINVAL; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci /* check for slave valid, slave not PF, and slave active */ 335362306a36Sopenharmony_ci if (slave < 0 || slave > dev->persist->num_vfs || 335462306a36Sopenharmony_ci slave == dev->caps.function || 335562306a36Sopenharmony_ci !priv->mfunc.master.slave_state[slave].active) 335662306a36Sopenharmony_ci return 0; 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci /* Create the event only if the slave is registered */ 336162306a36Sopenharmony_ci if (event_eq->eqn < 0) 336262306a36Sopenharmony_ci return 0; 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); 336562306a36Sopenharmony_ci res_id = (slave << 10) | event_eq->eqn; 336662306a36Sopenharmony_ci err = get_res(dev, slave, res_id, RES_EQ, &req); 336762306a36Sopenharmony_ci if (err) 336862306a36Sopenharmony_ci goto unlock; 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci if (req->com.from_state != RES_EQ_HW) { 337162306a36Sopenharmony_ci err = -EINVAL; 337262306a36Sopenharmony_ci goto put; 337362306a36Sopenharmony_ci } 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 337662306a36Sopenharmony_ci if (IS_ERR(mailbox)) { 337762306a36Sopenharmony_ci err = PTR_ERR(mailbox); 337862306a36Sopenharmony_ci goto put; 337962306a36Sopenharmony_ci } 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci if (eqe->type == MLX4_EVENT_TYPE_CMD) { 338262306a36Sopenharmony_ci ++event_eq->token; 338362306a36Sopenharmony_ci eqe->event.cmd.token = cpu_to_be16(event_eq->token); 338462306a36Sopenharmony_ci } 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci memcpy(mailbox->buf, (u8 *) eqe, 28); 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16); 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, 339162306a36Sopenharmony_ci MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, 339262306a36Sopenharmony_ci MLX4_CMD_NATIVE); 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci put_res(dev, slave, res_id, RES_EQ); 339562306a36Sopenharmony_ci mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 339662306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 339762306a36Sopenharmony_ci return err; 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ciput: 340062306a36Sopenharmony_ci put_res(dev, slave, res_id, RES_EQ); 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ciunlock: 340362306a36Sopenharmony_ci mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 340462306a36Sopenharmony_ci return err; 340562306a36Sopenharmony_ci} 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ciint mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, 340862306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 340962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 341062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 341162306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 341262306a36Sopenharmony_ci{ 341362306a36Sopenharmony_ci int eqn = vhcr->in_modifier; 341462306a36Sopenharmony_ci int res_id = eqn | (slave << 10); 341562306a36Sopenharmony_ci struct res_eq *eq; 341662306a36Sopenharmony_ci int err; 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci err = get_res(dev, slave, res_id, RES_EQ, &eq); 341962306a36Sopenharmony_ci if (err) 342062306a36Sopenharmony_ci return err; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci if (eq->com.from_state != RES_EQ_HW) { 342362306a36Sopenharmony_ci err = -EINVAL; 342462306a36Sopenharmony_ci goto ex_put; 342562306a36Sopenharmony_ci } 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ciex_put: 343062306a36Sopenharmony_ci put_res(dev, slave, res_id, RES_EQ); 343162306a36Sopenharmony_ci return err; 343262306a36Sopenharmony_ci} 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ciint mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, 343562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 343662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 343762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 343862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 343962306a36Sopenharmony_ci{ 344062306a36Sopenharmony_ci int err; 344162306a36Sopenharmony_ci int cqn = vhcr->in_modifier; 344262306a36Sopenharmony_ci struct mlx4_cq_context *cqc = inbox->buf; 344362306a36Sopenharmony_ci int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 344462306a36Sopenharmony_ci struct res_cq *cq = NULL; 344562306a36Sopenharmony_ci struct res_mtt *mtt; 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); 344862306a36Sopenharmony_ci if (err) 344962306a36Sopenharmony_ci return err; 345062306a36Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 345162306a36Sopenharmony_ci if (err) 345262306a36Sopenharmony_ci goto out_move; 345362306a36Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 345462306a36Sopenharmony_ci if (err) 345562306a36Sopenharmony_ci goto out_put; 345662306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 345762306a36Sopenharmony_ci if (err) 345862306a36Sopenharmony_ci goto out_put; 345962306a36Sopenharmony_ci atomic_inc(&mtt->ref_count); 346062306a36Sopenharmony_ci cq->mtt = mtt; 346162306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 346262306a36Sopenharmony_ci res_end_move(dev, slave, RES_CQ, cqn); 346362306a36Sopenharmony_ci return 0; 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ciout_put: 346662306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 346762306a36Sopenharmony_ciout_move: 346862306a36Sopenharmony_ci res_abort_move(dev, slave, RES_CQ, cqn); 346962306a36Sopenharmony_ci return err; 347062306a36Sopenharmony_ci} 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ciint mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, 347362306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 347462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 347562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 347662306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 347762306a36Sopenharmony_ci{ 347862306a36Sopenharmony_ci int err; 347962306a36Sopenharmony_ci int cqn = vhcr->in_modifier; 348062306a36Sopenharmony_ci struct res_cq *cq = NULL; 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); 348362306a36Sopenharmony_ci if (err) 348462306a36Sopenharmony_ci return err; 348562306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 348662306a36Sopenharmony_ci if (err) 348762306a36Sopenharmony_ci goto out_move; 348862306a36Sopenharmony_ci atomic_dec(&cq->mtt->ref_count); 348962306a36Sopenharmony_ci res_end_move(dev, slave, RES_CQ, cqn); 349062306a36Sopenharmony_ci return 0; 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ciout_move: 349362306a36Sopenharmony_ci res_abort_move(dev, slave, RES_CQ, cqn); 349462306a36Sopenharmony_ci return err; 349562306a36Sopenharmony_ci} 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ciint mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, 349862306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 349962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 350062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 350162306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 350262306a36Sopenharmony_ci{ 350362306a36Sopenharmony_ci int cqn = vhcr->in_modifier; 350462306a36Sopenharmony_ci struct res_cq *cq; 350562306a36Sopenharmony_ci int err; 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci err = get_res(dev, slave, cqn, RES_CQ, &cq); 350862306a36Sopenharmony_ci if (err) 350962306a36Sopenharmony_ci return err; 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_ci if (cq->com.from_state != RES_CQ_HW) 351262306a36Sopenharmony_ci goto ex_put; 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 351562306a36Sopenharmony_ciex_put: 351662306a36Sopenharmony_ci put_res(dev, slave, cqn, RES_CQ); 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci return err; 351962306a36Sopenharmony_ci} 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_cistatic int handle_resize(struct mlx4_dev *dev, int slave, 352262306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 352362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 352462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 352562306a36Sopenharmony_ci struct mlx4_cmd_info *cmd, 352662306a36Sopenharmony_ci struct res_cq *cq) 352762306a36Sopenharmony_ci{ 352862306a36Sopenharmony_ci int err; 352962306a36Sopenharmony_ci struct res_mtt *orig_mtt; 353062306a36Sopenharmony_ci struct res_mtt *mtt; 353162306a36Sopenharmony_ci struct mlx4_cq_context *cqc = inbox->buf; 353262306a36Sopenharmony_ci int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); 353562306a36Sopenharmony_ci if (err) 353662306a36Sopenharmony_ci return err; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci if (orig_mtt != cq->mtt) { 353962306a36Sopenharmony_ci err = -EINVAL; 354062306a36Sopenharmony_ci goto ex_put; 354162306a36Sopenharmony_ci } 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 354462306a36Sopenharmony_ci if (err) 354562306a36Sopenharmony_ci goto ex_put; 354662306a36Sopenharmony_ci 354762306a36Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 354862306a36Sopenharmony_ci if (err) 354962306a36Sopenharmony_ci goto ex_put1; 355062306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 355162306a36Sopenharmony_ci if (err) 355262306a36Sopenharmony_ci goto ex_put1; 355362306a36Sopenharmony_ci atomic_dec(&orig_mtt->ref_count); 355462306a36Sopenharmony_ci put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 355562306a36Sopenharmony_ci atomic_inc(&mtt->ref_count); 355662306a36Sopenharmony_ci cq->mtt = mtt; 355762306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 355862306a36Sopenharmony_ci return 0; 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ciex_put1: 356162306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 356262306a36Sopenharmony_ciex_put: 356362306a36Sopenharmony_ci put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci return err; 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci} 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ciint mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, 357062306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 357162306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 357262306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 357362306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 357462306a36Sopenharmony_ci{ 357562306a36Sopenharmony_ci int cqn = vhcr->in_modifier; 357662306a36Sopenharmony_ci struct res_cq *cq; 357762306a36Sopenharmony_ci int err; 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci err = get_res(dev, slave, cqn, RES_CQ, &cq); 358062306a36Sopenharmony_ci if (err) 358162306a36Sopenharmony_ci return err; 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci if (cq->com.from_state != RES_CQ_HW) 358462306a36Sopenharmony_ci goto ex_put; 358562306a36Sopenharmony_ci 358662306a36Sopenharmony_ci if (vhcr->op_modifier == 0) { 358762306a36Sopenharmony_ci err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); 358862306a36Sopenharmony_ci goto ex_put; 358962306a36Sopenharmony_ci } 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 359262306a36Sopenharmony_ciex_put: 359362306a36Sopenharmony_ci put_res(dev, slave, cqn, RES_CQ); 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci return err; 359662306a36Sopenharmony_ci} 359762306a36Sopenharmony_ci 359862306a36Sopenharmony_cistatic int srq_get_mtt_size(struct mlx4_srq_context *srqc) 359962306a36Sopenharmony_ci{ 360062306a36Sopenharmony_ci int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; 360162306a36Sopenharmony_ci int log_rq_stride = srqc->logstride & 7; 360262306a36Sopenharmony_ci int page_shift = (srqc->log_page_size & 0x3f) + 12; 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci if (log_srq_size + log_rq_stride + 4 < page_shift) 360562306a36Sopenharmony_ci return 1; 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); 360862306a36Sopenharmony_ci} 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ciint mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 361162306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 361262306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 361362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 361462306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 361562306a36Sopenharmony_ci{ 361662306a36Sopenharmony_ci int err; 361762306a36Sopenharmony_ci int srqn = vhcr->in_modifier; 361862306a36Sopenharmony_ci struct res_mtt *mtt; 361962306a36Sopenharmony_ci struct res_srq *srq = NULL; 362062306a36Sopenharmony_ci struct mlx4_srq_context *srqc = inbox->buf; 362162306a36Sopenharmony_ci int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_ci if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) 362462306a36Sopenharmony_ci return -EINVAL; 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); 362762306a36Sopenharmony_ci if (err) 362862306a36Sopenharmony_ci return err; 362962306a36Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 363062306a36Sopenharmony_ci if (err) 363162306a36Sopenharmony_ci goto ex_abort; 363262306a36Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), 363362306a36Sopenharmony_ci mtt); 363462306a36Sopenharmony_ci if (err) 363562306a36Sopenharmony_ci goto ex_put_mtt; 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 363862306a36Sopenharmony_ci if (err) 363962306a36Sopenharmony_ci goto ex_put_mtt; 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci atomic_inc(&mtt->ref_count); 364262306a36Sopenharmony_ci srq->mtt = mtt; 364362306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 364462306a36Sopenharmony_ci res_end_move(dev, slave, RES_SRQ, srqn); 364562306a36Sopenharmony_ci return 0; 364662306a36Sopenharmony_ci 364762306a36Sopenharmony_ciex_put_mtt: 364862306a36Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 364962306a36Sopenharmony_ciex_abort: 365062306a36Sopenharmony_ci res_abort_move(dev, slave, RES_SRQ, srqn); 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci return err; 365362306a36Sopenharmony_ci} 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ciint mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 365662306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 365762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 365862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 365962306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 366062306a36Sopenharmony_ci{ 366162306a36Sopenharmony_ci int err; 366262306a36Sopenharmony_ci int srqn = vhcr->in_modifier; 366362306a36Sopenharmony_ci struct res_srq *srq = NULL; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); 366662306a36Sopenharmony_ci if (err) 366762306a36Sopenharmony_ci return err; 366862306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 366962306a36Sopenharmony_ci if (err) 367062306a36Sopenharmony_ci goto ex_abort; 367162306a36Sopenharmony_ci atomic_dec(&srq->mtt->ref_count); 367262306a36Sopenharmony_ci if (srq->cq) 367362306a36Sopenharmony_ci atomic_dec(&srq->cq->ref_count); 367462306a36Sopenharmony_ci res_end_move(dev, slave, RES_SRQ, srqn); 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci return 0; 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ciex_abort: 367962306a36Sopenharmony_ci res_abort_move(dev, slave, RES_SRQ, srqn); 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci return err; 368262306a36Sopenharmony_ci} 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ciint mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, 368562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 368662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 368762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 368862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 368962306a36Sopenharmony_ci{ 369062306a36Sopenharmony_ci int err; 369162306a36Sopenharmony_ci int srqn = vhcr->in_modifier; 369262306a36Sopenharmony_ci struct res_srq *srq; 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_ci err = get_res(dev, slave, srqn, RES_SRQ, &srq); 369562306a36Sopenharmony_ci if (err) 369662306a36Sopenharmony_ci return err; 369762306a36Sopenharmony_ci if (srq->com.from_state != RES_SRQ_HW) { 369862306a36Sopenharmony_ci err = -EBUSY; 369962306a36Sopenharmony_ci goto out; 370062306a36Sopenharmony_ci } 370162306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 370262306a36Sopenharmony_ciout: 370362306a36Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 370462306a36Sopenharmony_ci return err; 370562306a36Sopenharmony_ci} 370662306a36Sopenharmony_ci 370762306a36Sopenharmony_ciint mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, 370862306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 370962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 371062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 371162306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 371262306a36Sopenharmony_ci{ 371362306a36Sopenharmony_ci int err; 371462306a36Sopenharmony_ci int srqn = vhcr->in_modifier; 371562306a36Sopenharmony_ci struct res_srq *srq; 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_ci err = get_res(dev, slave, srqn, RES_SRQ, &srq); 371862306a36Sopenharmony_ci if (err) 371962306a36Sopenharmony_ci return err; 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci if (srq->com.from_state != RES_SRQ_HW) { 372262306a36Sopenharmony_ci err = -EBUSY; 372362306a36Sopenharmony_ci goto out; 372462306a36Sopenharmony_ci } 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 372762306a36Sopenharmony_ciout: 372862306a36Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 372962306a36Sopenharmony_ci return err; 373062306a36Sopenharmony_ci} 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ciint mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, 373362306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 373462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 373562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 373662306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 373762306a36Sopenharmony_ci{ 373862306a36Sopenharmony_ci int err; 373962306a36Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 374062306a36Sopenharmony_ci struct res_qp *qp; 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &qp); 374362306a36Sopenharmony_ci if (err) 374462306a36Sopenharmony_ci return err; 374562306a36Sopenharmony_ci if (qp->com.from_state != RES_QP_HW) { 374662306a36Sopenharmony_ci err = -EBUSY; 374762306a36Sopenharmony_ci goto out; 374862306a36Sopenharmony_ci } 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 375162306a36Sopenharmony_ciout: 375262306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 375362306a36Sopenharmony_ci return err; 375462306a36Sopenharmony_ci} 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ciint mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 375762306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 375862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 375962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 376062306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 376162306a36Sopenharmony_ci{ 376262306a36Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 376362306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 376462306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 376562306a36Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 376662306a36Sopenharmony_ci} 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_cistatic int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave, 376962306a36Sopenharmony_ci struct mlx4_qp_context *qpc, 377062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox) 377162306a36Sopenharmony_ci{ 377262306a36Sopenharmony_ci enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf); 377362306a36Sopenharmony_ci u8 pri_sched_queue; 377462306a36Sopenharmony_ci int port = mlx4_slave_convert_port( 377562306a36Sopenharmony_ci dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1; 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci if (port < 0) 377862306a36Sopenharmony_ci return -EINVAL; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) | 378162306a36Sopenharmony_ci ((port & 1) << 6); 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci if (optpar & (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | MLX4_QP_OPTPAR_SCHED_QUEUE) || 378462306a36Sopenharmony_ci qpc->pri_path.sched_queue || mlx4_is_eth(dev, port + 1)) { 378562306a36Sopenharmony_ci qpc->pri_path.sched_queue = pri_sched_queue; 378662306a36Sopenharmony_ci } 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 378962306a36Sopenharmony_ci port = mlx4_slave_convert_port( 379062306a36Sopenharmony_ci dev, slave, (qpc->alt_path.sched_queue >> 6 & 1) 379162306a36Sopenharmony_ci + 1) - 1; 379262306a36Sopenharmony_ci if (port < 0) 379362306a36Sopenharmony_ci return -EINVAL; 379462306a36Sopenharmony_ci qpc->alt_path.sched_queue = 379562306a36Sopenharmony_ci (qpc->alt_path.sched_queue & ~(1 << 6)) | 379662306a36Sopenharmony_ci (port & 1) << 6; 379762306a36Sopenharmony_ci } 379862306a36Sopenharmony_ci return 0; 379962306a36Sopenharmony_ci} 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_cistatic int roce_verify_mac(struct mlx4_dev *dev, int slave, 380262306a36Sopenharmony_ci struct mlx4_qp_context *qpc, 380362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox) 380462306a36Sopenharmony_ci{ 380562306a36Sopenharmony_ci u64 mac; 380662306a36Sopenharmony_ci int port; 380762306a36Sopenharmony_ci u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 380862306a36Sopenharmony_ci u8 sched = *(u8 *)(inbox->buf + 64); 380962306a36Sopenharmony_ci u8 smac_ix; 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_ci port = (sched >> 6 & 1) + 1; 381262306a36Sopenharmony_ci if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { 381362306a36Sopenharmony_ci smac_ix = qpc->pri_path.grh_mylmc & 0x7f; 381462306a36Sopenharmony_ci if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) 381562306a36Sopenharmony_ci return -ENOENT; 381662306a36Sopenharmony_ci } 381762306a36Sopenharmony_ci return 0; 381862306a36Sopenharmony_ci} 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ciint mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, 382162306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 382262306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 382362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 382462306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 382562306a36Sopenharmony_ci{ 382662306a36Sopenharmony_ci int err; 382762306a36Sopenharmony_ci struct mlx4_qp_context *qpc = inbox->buf + 8; 382862306a36Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 382962306a36Sopenharmony_ci struct res_qp *qp; 383062306a36Sopenharmony_ci u8 orig_sched_queue; 383162306a36Sopenharmony_ci u8 orig_vlan_control = qpc->pri_path.vlan_control; 383262306a36Sopenharmony_ci u8 orig_fvl_rx = qpc->pri_path.fvl_rx; 383362306a36Sopenharmony_ci u8 orig_pri_path_fl = qpc->pri_path.fl; 383462306a36Sopenharmony_ci u8 orig_vlan_index = qpc->pri_path.vlan_index; 383562306a36Sopenharmony_ci u8 orig_feup = qpc->pri_path.feup; 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, qpc, inbox); 383862306a36Sopenharmony_ci if (err) 383962306a36Sopenharmony_ci return err; 384062306a36Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave); 384162306a36Sopenharmony_ci if (err) 384262306a36Sopenharmony_ci return err; 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci if (roce_verify_mac(dev, slave, qpc, inbox)) 384562306a36Sopenharmony_ci return -EINVAL; 384662306a36Sopenharmony_ci 384762306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 384862306a36Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 384962306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, qpc); 385062306a36Sopenharmony_ci orig_sched_queue = qpc->pri_path.sched_queue; 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &qp); 385362306a36Sopenharmony_ci if (err) 385462306a36Sopenharmony_ci return err; 385562306a36Sopenharmony_ci if (qp->com.from_state != RES_QP_HW) { 385662306a36Sopenharmony_ci err = -EBUSY; 385762306a36Sopenharmony_ci goto out; 385862306a36Sopenharmony_ci } 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci err = update_vport_qp_param(dev, inbox, slave, qpn); 386162306a36Sopenharmony_ci if (err) 386262306a36Sopenharmony_ci goto out; 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 386562306a36Sopenharmony_ciout: 386662306a36Sopenharmony_ci /* if no error, save sched queue value passed in by VF. This is 386762306a36Sopenharmony_ci * essentially the QOS value provided by the VF. This will be useful 386862306a36Sopenharmony_ci * if we allow dynamic changes from VST back to VGT 386962306a36Sopenharmony_ci */ 387062306a36Sopenharmony_ci if (!err) { 387162306a36Sopenharmony_ci qp->sched_queue = orig_sched_queue; 387262306a36Sopenharmony_ci qp->vlan_control = orig_vlan_control; 387362306a36Sopenharmony_ci qp->fvl_rx = orig_fvl_rx; 387462306a36Sopenharmony_ci qp->pri_path_fl = orig_pri_path_fl; 387562306a36Sopenharmony_ci qp->vlan_index = orig_vlan_index; 387662306a36Sopenharmony_ci qp->feup = orig_feup; 387762306a36Sopenharmony_ci } 387862306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 387962306a36Sopenharmony_ci return err; 388062306a36Sopenharmony_ci} 388162306a36Sopenharmony_ci 388262306a36Sopenharmony_ciint mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 388362306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 388462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 388562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 388662306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 388762306a36Sopenharmony_ci{ 388862306a36Sopenharmony_ci int err; 388962306a36Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 389262306a36Sopenharmony_ci if (err) 389362306a36Sopenharmony_ci return err; 389462306a36Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave); 389562306a36Sopenharmony_ci if (err) 389662306a36Sopenharmony_ci return err; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 389962306a36Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 390062306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 390162306a36Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 390262306a36Sopenharmony_ci} 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_ciint mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 390562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 390662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 390762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 390862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 390962306a36Sopenharmony_ci{ 391062306a36Sopenharmony_ci int err; 391162306a36Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 391462306a36Sopenharmony_ci if (err) 391562306a36Sopenharmony_ci return err; 391662306a36Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave); 391762306a36Sopenharmony_ci if (err) 391862306a36Sopenharmony_ci return err; 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 392162306a36Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 392262306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 392362306a36Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 392462306a36Sopenharmony_ci} 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ciint mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 392862306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 392962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 393062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 393162306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 393262306a36Sopenharmony_ci{ 393362306a36Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 393462306a36Sopenharmony_ci int err = adjust_qp_sched_queue(dev, slave, context, inbox); 393562306a36Sopenharmony_ci if (err) 393662306a36Sopenharmony_ci return err; 393762306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 393862306a36Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 393962306a36Sopenharmony_ci} 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ciint mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, 394262306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 394362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 394462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 394562306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 394662306a36Sopenharmony_ci{ 394762306a36Sopenharmony_ci int err; 394862306a36Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 395162306a36Sopenharmony_ci if (err) 395262306a36Sopenharmony_ci return err; 395362306a36Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave); 395462306a36Sopenharmony_ci if (err) 395562306a36Sopenharmony_ci return err; 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 395862306a36Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 395962306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 396062306a36Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 396162306a36Sopenharmony_ci} 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ciint mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 396462306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 396562306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 396662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 396762306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 396862306a36Sopenharmony_ci{ 396962306a36Sopenharmony_ci int err; 397062306a36Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 397362306a36Sopenharmony_ci if (err) 397462306a36Sopenharmony_ci return err; 397562306a36Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave); 397662306a36Sopenharmony_ci if (err) 397762306a36Sopenharmony_ci return err; 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 398062306a36Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 398162306a36Sopenharmony_ci update_pkey_index(dev, slave, inbox); 398262306a36Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 398362306a36Sopenharmony_ci} 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ciint mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, 398662306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 398762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 398862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 398962306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 399062306a36Sopenharmony_ci{ 399162306a36Sopenharmony_ci int err; 399262306a36Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 399362306a36Sopenharmony_ci struct res_qp *qp; 399462306a36Sopenharmony_ci 399562306a36Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); 399662306a36Sopenharmony_ci if (err) 399762306a36Sopenharmony_ci return err; 399862306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 399962306a36Sopenharmony_ci if (err) 400062306a36Sopenharmony_ci goto ex_abort; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci atomic_dec(&qp->mtt->ref_count); 400362306a36Sopenharmony_ci atomic_dec(&qp->rcq->ref_count); 400462306a36Sopenharmony_ci atomic_dec(&qp->scq->ref_count); 400562306a36Sopenharmony_ci if (qp->srq) 400662306a36Sopenharmony_ci atomic_dec(&qp->srq->ref_count); 400762306a36Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 400862306a36Sopenharmony_ci return 0; 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ciex_abort: 401162306a36Sopenharmony_ci res_abort_move(dev, slave, RES_QP, qpn); 401262306a36Sopenharmony_ci 401362306a36Sopenharmony_ci return err; 401462306a36Sopenharmony_ci} 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_cistatic struct res_gid *find_gid(struct mlx4_dev *dev, int slave, 401762306a36Sopenharmony_ci struct res_qp *rqp, u8 *gid) 401862306a36Sopenharmony_ci{ 401962306a36Sopenharmony_ci struct res_gid *res; 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci list_for_each_entry(res, &rqp->mcg_list, list) { 402262306a36Sopenharmony_ci if (!memcmp(res->gid, gid, 16)) 402362306a36Sopenharmony_ci return res; 402462306a36Sopenharmony_ci } 402562306a36Sopenharmony_ci return NULL; 402662306a36Sopenharmony_ci} 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_cistatic int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 402962306a36Sopenharmony_ci u8 *gid, enum mlx4_protocol prot, 403062306a36Sopenharmony_ci enum mlx4_steer_type steer, u64 reg_id) 403162306a36Sopenharmony_ci{ 403262306a36Sopenharmony_ci struct res_gid *res; 403362306a36Sopenharmony_ci int err; 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci res = kzalloc(sizeof(*res), GFP_KERNEL); 403662306a36Sopenharmony_ci if (!res) 403762306a36Sopenharmony_ci return -ENOMEM; 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci spin_lock_irq(&rqp->mcg_spl); 404062306a36Sopenharmony_ci if (find_gid(dev, slave, rqp, gid)) { 404162306a36Sopenharmony_ci kfree(res); 404262306a36Sopenharmony_ci err = -EEXIST; 404362306a36Sopenharmony_ci } else { 404462306a36Sopenharmony_ci memcpy(res->gid, gid, 16); 404562306a36Sopenharmony_ci res->prot = prot; 404662306a36Sopenharmony_ci res->steer = steer; 404762306a36Sopenharmony_ci res->reg_id = reg_id; 404862306a36Sopenharmony_ci list_add_tail(&res->list, &rqp->mcg_list); 404962306a36Sopenharmony_ci err = 0; 405062306a36Sopenharmony_ci } 405162306a36Sopenharmony_ci spin_unlock_irq(&rqp->mcg_spl); 405262306a36Sopenharmony_ci 405362306a36Sopenharmony_ci return err; 405462306a36Sopenharmony_ci} 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_cistatic int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 405762306a36Sopenharmony_ci u8 *gid, enum mlx4_protocol prot, 405862306a36Sopenharmony_ci enum mlx4_steer_type steer, u64 *reg_id) 405962306a36Sopenharmony_ci{ 406062306a36Sopenharmony_ci struct res_gid *res; 406162306a36Sopenharmony_ci int err; 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci spin_lock_irq(&rqp->mcg_spl); 406462306a36Sopenharmony_ci res = find_gid(dev, slave, rqp, gid); 406562306a36Sopenharmony_ci if (!res || res->prot != prot || res->steer != steer) 406662306a36Sopenharmony_ci err = -EINVAL; 406762306a36Sopenharmony_ci else { 406862306a36Sopenharmony_ci *reg_id = res->reg_id; 406962306a36Sopenharmony_ci list_del(&res->list); 407062306a36Sopenharmony_ci kfree(res); 407162306a36Sopenharmony_ci err = 0; 407262306a36Sopenharmony_ci } 407362306a36Sopenharmony_ci spin_unlock_irq(&rqp->mcg_spl); 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci return err; 407662306a36Sopenharmony_ci} 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_cistatic int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp, 407962306a36Sopenharmony_ci u8 gid[16], int block_loopback, enum mlx4_protocol prot, 408062306a36Sopenharmony_ci enum mlx4_steer_type type, u64 *reg_id) 408162306a36Sopenharmony_ci{ 408262306a36Sopenharmony_ci switch (dev->caps.steering_mode) { 408362306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: { 408462306a36Sopenharmony_ci int port = mlx4_slave_convert_port(dev, slave, gid[5]); 408562306a36Sopenharmony_ci if (port < 0) 408662306a36Sopenharmony_ci return port; 408762306a36Sopenharmony_ci return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, 408862306a36Sopenharmony_ci block_loopback, prot, 408962306a36Sopenharmony_ci reg_id); 409062306a36Sopenharmony_ci } 409162306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 409262306a36Sopenharmony_ci if (prot == MLX4_PROT_ETH) { 409362306a36Sopenharmony_ci int port = mlx4_slave_convert_port(dev, slave, gid[5]); 409462306a36Sopenharmony_ci if (port < 0) 409562306a36Sopenharmony_ci return port; 409662306a36Sopenharmony_ci gid[5] = port; 409762306a36Sopenharmony_ci } 409862306a36Sopenharmony_ci return mlx4_qp_attach_common(dev, qp, gid, 409962306a36Sopenharmony_ci block_loopback, prot, type); 410062306a36Sopenharmony_ci default: 410162306a36Sopenharmony_ci return -EINVAL; 410262306a36Sopenharmony_ci } 410362306a36Sopenharmony_ci} 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_cistatic int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, 410662306a36Sopenharmony_ci u8 gid[16], enum mlx4_protocol prot, 410762306a36Sopenharmony_ci enum mlx4_steer_type type, u64 reg_id) 410862306a36Sopenharmony_ci{ 410962306a36Sopenharmony_ci switch (dev->caps.steering_mode) { 411062306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 411162306a36Sopenharmony_ci return mlx4_flow_detach(dev, reg_id); 411262306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 411362306a36Sopenharmony_ci return mlx4_qp_detach_common(dev, qp, gid, prot, type); 411462306a36Sopenharmony_ci default: 411562306a36Sopenharmony_ci return -EINVAL; 411662306a36Sopenharmony_ci } 411762306a36Sopenharmony_ci} 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_cistatic int mlx4_adjust_port(struct mlx4_dev *dev, int slave, 412062306a36Sopenharmony_ci u8 *gid, enum mlx4_protocol prot) 412162306a36Sopenharmony_ci{ 412262306a36Sopenharmony_ci int real_port; 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci if (prot != MLX4_PROT_ETH) 412562306a36Sopenharmony_ci return 0; 412662306a36Sopenharmony_ci 412762306a36Sopenharmony_ci if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 || 412862306a36Sopenharmony_ci dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { 412962306a36Sopenharmony_ci real_port = mlx4_slave_convert_port(dev, slave, gid[5]); 413062306a36Sopenharmony_ci if (real_port < 0) 413162306a36Sopenharmony_ci return -EINVAL; 413262306a36Sopenharmony_ci gid[5] = real_port; 413362306a36Sopenharmony_ci } 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci return 0; 413662306a36Sopenharmony_ci} 413762306a36Sopenharmony_ci 413862306a36Sopenharmony_ciint mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 413962306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 414062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 414162306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 414262306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 414362306a36Sopenharmony_ci{ 414462306a36Sopenharmony_ci struct mlx4_qp qp; /* dummy for calling attach/detach */ 414562306a36Sopenharmony_ci u8 *gid = inbox->buf; 414662306a36Sopenharmony_ci enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; 414762306a36Sopenharmony_ci int err; 414862306a36Sopenharmony_ci int qpn; 414962306a36Sopenharmony_ci struct res_qp *rqp; 415062306a36Sopenharmony_ci u64 reg_id = 0; 415162306a36Sopenharmony_ci int attach = vhcr->op_modifier; 415262306a36Sopenharmony_ci int block_loopback = vhcr->in_modifier >> 31; 415362306a36Sopenharmony_ci u8 steer_type_mask = 2; 415462306a36Sopenharmony_ci enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ci qpn = vhcr->in_modifier & 0xffffff; 415762306a36Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 415862306a36Sopenharmony_ci if (err) 415962306a36Sopenharmony_ci return err; 416062306a36Sopenharmony_ci 416162306a36Sopenharmony_ci qp.qpn = qpn; 416262306a36Sopenharmony_ci if (attach) { 416362306a36Sopenharmony_ci err = qp_attach(dev, slave, &qp, gid, block_loopback, prot, 416462306a36Sopenharmony_ci type, ®_id); 416562306a36Sopenharmony_ci if (err) { 416662306a36Sopenharmony_ci pr_err("Fail to attach rule to qp 0x%x\n", qpn); 416762306a36Sopenharmony_ci goto ex_put; 416862306a36Sopenharmony_ci } 416962306a36Sopenharmony_ci err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id); 417062306a36Sopenharmony_ci if (err) 417162306a36Sopenharmony_ci goto ex_detach; 417262306a36Sopenharmony_ci } else { 417362306a36Sopenharmony_ci err = mlx4_adjust_port(dev, slave, gid, prot); 417462306a36Sopenharmony_ci if (err) 417562306a36Sopenharmony_ci goto ex_put; 417662306a36Sopenharmony_ci 417762306a36Sopenharmony_ci err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id); 417862306a36Sopenharmony_ci if (err) 417962306a36Sopenharmony_ci goto ex_put; 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci err = qp_detach(dev, &qp, gid, prot, type, reg_id); 418262306a36Sopenharmony_ci if (err) 418362306a36Sopenharmony_ci pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n", 418462306a36Sopenharmony_ci qpn, reg_id); 418562306a36Sopenharmony_ci } 418662306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 418762306a36Sopenharmony_ci return err; 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_ciex_detach: 419062306a36Sopenharmony_ci qp_detach(dev, &qp, gid, prot, type, reg_id); 419162306a36Sopenharmony_ciex_put: 419262306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 419362306a36Sopenharmony_ci return err; 419462306a36Sopenharmony_ci} 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci/* 419762306a36Sopenharmony_ci * MAC validation for Flow Steering rules. 419862306a36Sopenharmony_ci * VF can attach rules only with a mac address which is assigned to it. 419962306a36Sopenharmony_ci */ 420062306a36Sopenharmony_cistatic int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, 420162306a36Sopenharmony_ci struct list_head *rlist) 420262306a36Sopenharmony_ci{ 420362306a36Sopenharmony_ci struct mac_res *res, *tmp; 420462306a36Sopenharmony_ci __be64 be_mac; 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci /* make sure it isn't multicast or broadcast mac*/ 420762306a36Sopenharmony_ci if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && 420862306a36Sopenharmony_ci !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { 420962306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, rlist, list) { 421062306a36Sopenharmony_ci be_mac = cpu_to_be64(res->mac << 16); 421162306a36Sopenharmony_ci if (ether_addr_equal((u8 *)&be_mac, eth_header->eth.dst_mac)) 421262306a36Sopenharmony_ci return 0; 421362306a36Sopenharmony_ci } 421462306a36Sopenharmony_ci pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", 421562306a36Sopenharmony_ci eth_header->eth.dst_mac, slave); 421662306a36Sopenharmony_ci return -EINVAL; 421762306a36Sopenharmony_ci } 421862306a36Sopenharmony_ci return 0; 421962306a36Sopenharmony_ci} 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci/* 422262306a36Sopenharmony_ci * In case of missing eth header, append eth header with a MAC address 422362306a36Sopenharmony_ci * assigned to the VF. 422462306a36Sopenharmony_ci */ 422562306a36Sopenharmony_cistatic int add_eth_header(struct mlx4_dev *dev, int slave, 422662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 422762306a36Sopenharmony_ci struct list_head *rlist, int header_id) 422862306a36Sopenharmony_ci{ 422962306a36Sopenharmony_ci struct mac_res *res, *tmp; 423062306a36Sopenharmony_ci u8 port; 423162306a36Sopenharmony_ci struct mlx4_net_trans_rule_hw_ctrl *ctrl; 423262306a36Sopenharmony_ci struct mlx4_net_trans_rule_hw_eth *eth_header; 423362306a36Sopenharmony_ci struct mlx4_net_trans_rule_hw_ipv4 *ip_header; 423462306a36Sopenharmony_ci struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; 423562306a36Sopenharmony_ci __be64 be_mac = 0; 423662306a36Sopenharmony_ci __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 423962306a36Sopenharmony_ci port = ctrl->port; 424062306a36Sopenharmony_ci eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci /* Clear a space in the inbox for eth header */ 424362306a36Sopenharmony_ci switch (header_id) { 424462306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_IPV4: 424562306a36Sopenharmony_ci ip_header = 424662306a36Sopenharmony_ci (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); 424762306a36Sopenharmony_ci memmove(ip_header, eth_header, 424862306a36Sopenharmony_ci sizeof(*ip_header) + sizeof(*l4_header)); 424962306a36Sopenharmony_ci break; 425062306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_TCP: 425162306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_UDP: 425262306a36Sopenharmony_ci l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) 425362306a36Sopenharmony_ci (eth_header + 1); 425462306a36Sopenharmony_ci memmove(l4_header, eth_header, sizeof(*l4_header)); 425562306a36Sopenharmony_ci break; 425662306a36Sopenharmony_ci default: 425762306a36Sopenharmony_ci return -EINVAL; 425862306a36Sopenharmony_ci } 425962306a36Sopenharmony_ci list_for_each_entry_safe(res, tmp, rlist, list) { 426062306a36Sopenharmony_ci if (port == res->port) { 426162306a36Sopenharmony_ci be_mac = cpu_to_be64(res->mac << 16); 426262306a36Sopenharmony_ci break; 426362306a36Sopenharmony_ci } 426462306a36Sopenharmony_ci } 426562306a36Sopenharmony_ci if (!be_mac) { 426662306a36Sopenharmony_ci pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d\n", 426762306a36Sopenharmony_ci port); 426862306a36Sopenharmony_ci return -EINVAL; 426962306a36Sopenharmony_ci } 427062306a36Sopenharmony_ci 427162306a36Sopenharmony_ci memset(eth_header, 0, sizeof(*eth_header)); 427262306a36Sopenharmony_ci eth_header->size = sizeof(*eth_header) >> 2; 427362306a36Sopenharmony_ci eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); 427462306a36Sopenharmony_ci memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); 427562306a36Sopenharmony_ci memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_ci return 0; 427862306a36Sopenharmony_ci 427962306a36Sopenharmony_ci} 428062306a36Sopenharmony_ci 428162306a36Sopenharmony_ci#define MLX4_UPD_QP_PATH_MASK_SUPPORTED ( \ 428262306a36Sopenharmony_ci 1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX |\ 428362306a36Sopenharmony_ci 1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB) 428462306a36Sopenharmony_ciint mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, 428562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 428662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 428762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 428862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd_info) 428962306a36Sopenharmony_ci{ 429062306a36Sopenharmony_ci int err; 429162306a36Sopenharmony_ci u32 qpn = vhcr->in_modifier & 0xffffff; 429262306a36Sopenharmony_ci struct res_qp *rqp; 429362306a36Sopenharmony_ci u64 mac; 429462306a36Sopenharmony_ci unsigned port; 429562306a36Sopenharmony_ci u64 pri_addr_path_mask; 429662306a36Sopenharmony_ci struct mlx4_update_qp_context *cmd; 429762306a36Sopenharmony_ci int smac_index; 429862306a36Sopenharmony_ci 429962306a36Sopenharmony_ci cmd = (struct mlx4_update_qp_context *)inbox->buf; 430062306a36Sopenharmony_ci 430162306a36Sopenharmony_ci pri_addr_path_mask = be64_to_cpu(cmd->primary_addr_path_mask); 430262306a36Sopenharmony_ci if (cmd->qp_mask || cmd->secondary_addr_path_mask || 430362306a36Sopenharmony_ci (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED)) 430462306a36Sopenharmony_ci return -EPERM; 430562306a36Sopenharmony_ci 430662306a36Sopenharmony_ci if ((pri_addr_path_mask & 430762306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) && 430862306a36Sopenharmony_ci !(dev->caps.flags2 & 430962306a36Sopenharmony_ci MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) { 431062306a36Sopenharmony_ci mlx4_warn(dev, "Src check LB for slave %d isn't supported\n", 431162306a36Sopenharmony_ci slave); 431262306a36Sopenharmony_ci return -EOPNOTSUPP; 431362306a36Sopenharmony_ci } 431462306a36Sopenharmony_ci 431562306a36Sopenharmony_ci /* Just change the smac for the QP */ 431662306a36Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 431762306a36Sopenharmony_ci if (err) { 431862306a36Sopenharmony_ci mlx4_err(dev, "Updating qpn 0x%x for slave %d rejected\n", qpn, slave); 431962306a36Sopenharmony_ci return err; 432062306a36Sopenharmony_ci } 432162306a36Sopenharmony_ci 432262306a36Sopenharmony_ci port = (rqp->sched_queue >> 6 & 1) + 1; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci if (pri_addr_path_mask & (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)) { 432562306a36Sopenharmony_ci smac_index = cmd->qp_context.pri_path.grh_mylmc; 432662306a36Sopenharmony_ci err = mac_find_smac_ix_in_slave(dev, slave, port, 432762306a36Sopenharmony_ci smac_index, &mac); 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci if (err) { 433062306a36Sopenharmony_ci mlx4_err(dev, "Failed to update qpn 0x%x, MAC is invalid. smac_ix: %d\n", 433162306a36Sopenharmony_ci qpn, smac_index); 433262306a36Sopenharmony_ci goto err_mac; 433362306a36Sopenharmony_ci } 433462306a36Sopenharmony_ci } 433562306a36Sopenharmony_ci 433662306a36Sopenharmony_ci err = mlx4_cmd(dev, inbox->dma, 433762306a36Sopenharmony_ci vhcr->in_modifier, 0, 433862306a36Sopenharmony_ci MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A, 433962306a36Sopenharmony_ci MLX4_CMD_NATIVE); 434062306a36Sopenharmony_ci if (err) { 434162306a36Sopenharmony_ci mlx4_err(dev, "Failed to update qpn on qpn 0x%x, command failed\n", qpn); 434262306a36Sopenharmony_ci goto err_mac; 434362306a36Sopenharmony_ci } 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_cierr_mac: 434662306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 434762306a36Sopenharmony_ci return err; 434862306a36Sopenharmony_ci} 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_cistatic u32 qp_attach_mbox_size(void *mbox) 435162306a36Sopenharmony_ci{ 435262306a36Sopenharmony_ci u32 size = sizeof(struct mlx4_net_trans_rule_hw_ctrl); 435362306a36Sopenharmony_ci struct _rule_hw *rule_header; 435462306a36Sopenharmony_ci 435562306a36Sopenharmony_ci rule_header = (struct _rule_hw *)(mbox + size); 435662306a36Sopenharmony_ci 435762306a36Sopenharmony_ci while (rule_header->size) { 435862306a36Sopenharmony_ci size += rule_header->size * sizeof(u32); 435962306a36Sopenharmony_ci rule_header += 1; 436062306a36Sopenharmony_ci } 436162306a36Sopenharmony_ci return size; 436262306a36Sopenharmony_ci} 436362306a36Sopenharmony_ci 436462306a36Sopenharmony_cistatic int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule); 436562306a36Sopenharmony_ci 436662306a36Sopenharmony_ciint mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 436762306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 436862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 436962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 437062306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 437162306a36Sopenharmony_ci{ 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 437462306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 437562306a36Sopenharmony_ci struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; 437662306a36Sopenharmony_ci int err; 437762306a36Sopenharmony_ci int qpn; 437862306a36Sopenharmony_ci struct res_qp *rqp; 437962306a36Sopenharmony_ci struct mlx4_net_trans_rule_hw_ctrl *ctrl; 438062306a36Sopenharmony_ci struct _rule_hw *rule_header; 438162306a36Sopenharmony_ci int header_id; 438262306a36Sopenharmony_ci struct res_fs_rule *rrule; 438362306a36Sopenharmony_ci u32 mbox_size; 438462306a36Sopenharmony_ci 438562306a36Sopenharmony_ci if (dev->caps.steering_mode != 438662306a36Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) 438762306a36Sopenharmony_ci return -EOPNOTSUPP; 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_ci ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 439062306a36Sopenharmony_ci err = mlx4_slave_convert_port(dev, slave, ctrl->port); 439162306a36Sopenharmony_ci if (err <= 0) 439262306a36Sopenharmony_ci return -EINVAL; 439362306a36Sopenharmony_ci ctrl->port = err; 439462306a36Sopenharmony_ci qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; 439562306a36Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 439662306a36Sopenharmony_ci if (err) { 439762306a36Sopenharmony_ci pr_err("Steering rule with qpn 0x%x rejected\n", qpn); 439862306a36Sopenharmony_ci return err; 439962306a36Sopenharmony_ci } 440062306a36Sopenharmony_ci rule_header = (struct _rule_hw *)(ctrl + 1); 440162306a36Sopenharmony_ci header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); 440262306a36Sopenharmony_ci 440362306a36Sopenharmony_ci if (header_id == MLX4_NET_TRANS_RULE_ID_ETH) 440462306a36Sopenharmony_ci mlx4_handle_eth_header_mcast_prio(ctrl, rule_header); 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_ci switch (header_id) { 440762306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_ETH: 440862306a36Sopenharmony_ci if (validate_eth_header_mac(slave, rule_header, rlist)) { 440962306a36Sopenharmony_ci err = -EINVAL; 441062306a36Sopenharmony_ci goto err_put_qp; 441162306a36Sopenharmony_ci } 441262306a36Sopenharmony_ci break; 441362306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_IB: 441462306a36Sopenharmony_ci break; 441562306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_IPV4: 441662306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_TCP: 441762306a36Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_UDP: 441862306a36Sopenharmony_ci pr_warn("Can't attach FS rule without L2 headers, adding L2 header\n"); 441962306a36Sopenharmony_ci if (add_eth_header(dev, slave, inbox, rlist, header_id)) { 442062306a36Sopenharmony_ci err = -EINVAL; 442162306a36Sopenharmony_ci goto err_put_qp; 442262306a36Sopenharmony_ci } 442362306a36Sopenharmony_ci vhcr->in_modifier += 442462306a36Sopenharmony_ci sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; 442562306a36Sopenharmony_ci break; 442662306a36Sopenharmony_ci default: 442762306a36Sopenharmony_ci pr_err("Corrupted mailbox\n"); 442862306a36Sopenharmony_ci err = -EINVAL; 442962306a36Sopenharmony_ci goto err_put_qp; 443062306a36Sopenharmony_ci } 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, 443362306a36Sopenharmony_ci vhcr->in_modifier, 0, 443462306a36Sopenharmony_ci MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 443562306a36Sopenharmony_ci MLX4_CMD_NATIVE); 443662306a36Sopenharmony_ci if (err) 443762306a36Sopenharmony_ci goto err_put_qp; 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci 444062306a36Sopenharmony_ci err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); 444162306a36Sopenharmony_ci if (err) { 444262306a36Sopenharmony_ci mlx4_err(dev, "Fail to add flow steering resources\n"); 444362306a36Sopenharmony_ci goto err_detach; 444462306a36Sopenharmony_ci } 444562306a36Sopenharmony_ci 444662306a36Sopenharmony_ci err = get_res(dev, slave, vhcr->out_param, RES_FS_RULE, &rrule); 444762306a36Sopenharmony_ci if (err) 444862306a36Sopenharmony_ci goto err_detach; 444962306a36Sopenharmony_ci 445062306a36Sopenharmony_ci mbox_size = qp_attach_mbox_size(inbox->buf); 445162306a36Sopenharmony_ci rrule->mirr_mbox = kmalloc(mbox_size, GFP_KERNEL); 445262306a36Sopenharmony_ci if (!rrule->mirr_mbox) { 445362306a36Sopenharmony_ci err = -ENOMEM; 445462306a36Sopenharmony_ci goto err_put_rule; 445562306a36Sopenharmony_ci } 445662306a36Sopenharmony_ci rrule->mirr_mbox_size = mbox_size; 445762306a36Sopenharmony_ci rrule->mirr_rule_id = 0; 445862306a36Sopenharmony_ci memcpy(rrule->mirr_mbox, inbox->buf, mbox_size); 445962306a36Sopenharmony_ci 446062306a36Sopenharmony_ci /* set different port */ 446162306a36Sopenharmony_ci ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)rrule->mirr_mbox; 446262306a36Sopenharmony_ci if (ctrl->port == 1) 446362306a36Sopenharmony_ci ctrl->port = 2; 446462306a36Sopenharmony_ci else 446562306a36Sopenharmony_ci ctrl->port = 1; 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci if (mlx4_is_bonded(dev)) 446862306a36Sopenharmony_ci mlx4_do_mirror_rule(dev, rrule); 446962306a36Sopenharmony_ci 447062306a36Sopenharmony_ci atomic_inc(&rqp->ref_count); 447162306a36Sopenharmony_ci 447262306a36Sopenharmony_cierr_put_rule: 447362306a36Sopenharmony_ci put_res(dev, slave, vhcr->out_param, RES_FS_RULE); 447462306a36Sopenharmony_cierr_detach: 447562306a36Sopenharmony_ci /* detach rule on error */ 447662306a36Sopenharmony_ci if (err) 447762306a36Sopenharmony_ci mlx4_cmd(dev, vhcr->out_param, 0, 0, 447862306a36Sopenharmony_ci MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 447962306a36Sopenharmony_ci MLX4_CMD_NATIVE); 448062306a36Sopenharmony_cierr_put_qp: 448162306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 448262306a36Sopenharmony_ci return err; 448362306a36Sopenharmony_ci} 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_cistatic int mlx4_undo_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule) 448662306a36Sopenharmony_ci{ 448762306a36Sopenharmony_ci int err; 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci err = rem_res_range(dev, fs_rule->com.owner, fs_rule->com.res_id, 1, RES_FS_RULE, 0); 449062306a36Sopenharmony_ci if (err) { 449162306a36Sopenharmony_ci mlx4_err(dev, "Fail to remove flow steering resources\n"); 449262306a36Sopenharmony_ci return err; 449362306a36Sopenharmony_ci } 449462306a36Sopenharmony_ci 449562306a36Sopenharmony_ci mlx4_cmd(dev, fs_rule->com.res_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, 449662306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 449762306a36Sopenharmony_ci return 0; 449862306a36Sopenharmony_ci} 449962306a36Sopenharmony_ci 450062306a36Sopenharmony_ciint mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, 450162306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 450262306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 450362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 450462306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 450562306a36Sopenharmony_ci{ 450662306a36Sopenharmony_ci int err; 450762306a36Sopenharmony_ci struct res_qp *rqp; 450862306a36Sopenharmony_ci struct res_fs_rule *rrule; 450962306a36Sopenharmony_ci u64 mirr_reg_id; 451062306a36Sopenharmony_ci int qpn; 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci if (dev->caps.steering_mode != 451362306a36Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) 451462306a36Sopenharmony_ci return -EOPNOTSUPP; 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_ci err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); 451762306a36Sopenharmony_ci if (err) 451862306a36Sopenharmony_ci return err; 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci if (!rrule->mirr_mbox) { 452162306a36Sopenharmony_ci mlx4_err(dev, "Mirror rules cannot be removed explicitly\n"); 452262306a36Sopenharmony_ci put_res(dev, slave, vhcr->in_param, RES_FS_RULE); 452362306a36Sopenharmony_ci return -EINVAL; 452462306a36Sopenharmony_ci } 452562306a36Sopenharmony_ci mirr_reg_id = rrule->mirr_rule_id; 452662306a36Sopenharmony_ci kfree(rrule->mirr_mbox); 452762306a36Sopenharmony_ci qpn = rrule->qpn; 452862306a36Sopenharmony_ci 452962306a36Sopenharmony_ci /* Release the rule form busy state before removal */ 453062306a36Sopenharmony_ci put_res(dev, slave, vhcr->in_param, RES_FS_RULE); 453162306a36Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 453262306a36Sopenharmony_ci if (err) 453362306a36Sopenharmony_ci return err; 453462306a36Sopenharmony_ci 453562306a36Sopenharmony_ci if (mirr_reg_id && mlx4_is_bonded(dev)) { 453662306a36Sopenharmony_ci err = get_res(dev, slave, mirr_reg_id, RES_FS_RULE, &rrule); 453762306a36Sopenharmony_ci if (err) { 453862306a36Sopenharmony_ci mlx4_err(dev, "Fail to get resource of mirror rule\n"); 453962306a36Sopenharmony_ci } else { 454062306a36Sopenharmony_ci put_res(dev, slave, mirr_reg_id, RES_FS_RULE); 454162306a36Sopenharmony_ci mlx4_undo_mirror_rule(dev, rrule); 454262306a36Sopenharmony_ci } 454362306a36Sopenharmony_ci } 454462306a36Sopenharmony_ci err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0); 454562306a36Sopenharmony_ci if (err) { 454662306a36Sopenharmony_ci mlx4_err(dev, "Fail to remove flow steering resources\n"); 454762306a36Sopenharmony_ci goto out; 454862306a36Sopenharmony_ci } 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_ci err = mlx4_cmd(dev, vhcr->in_param, 0, 0, 455162306a36Sopenharmony_ci MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 455262306a36Sopenharmony_ci MLX4_CMD_NATIVE); 455362306a36Sopenharmony_ci if (!err) 455462306a36Sopenharmony_ci atomic_dec(&rqp->ref_count); 455562306a36Sopenharmony_ciout: 455662306a36Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 455762306a36Sopenharmony_ci return err; 455862306a36Sopenharmony_ci} 455962306a36Sopenharmony_ci 456062306a36Sopenharmony_cienum { 456162306a36Sopenharmony_ci BUSY_MAX_RETRIES = 10 456262306a36Sopenharmony_ci}; 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ciint mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, 456562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 456662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 456762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 456862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 456962306a36Sopenharmony_ci{ 457062306a36Sopenharmony_ci int err; 457162306a36Sopenharmony_ci int index = vhcr->in_modifier & 0xffff; 457262306a36Sopenharmony_ci 457362306a36Sopenharmony_ci err = get_res(dev, slave, index, RES_COUNTER, NULL); 457462306a36Sopenharmony_ci if (err) 457562306a36Sopenharmony_ci return err; 457662306a36Sopenharmony_ci 457762306a36Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 457862306a36Sopenharmony_ci put_res(dev, slave, index, RES_COUNTER); 457962306a36Sopenharmony_ci return err; 458062306a36Sopenharmony_ci} 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_cistatic void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) 458362306a36Sopenharmony_ci{ 458462306a36Sopenharmony_ci struct res_gid *rgid; 458562306a36Sopenharmony_ci struct res_gid *tmp; 458662306a36Sopenharmony_ci struct mlx4_qp qp; /* dummy for calling attach/detach */ 458762306a36Sopenharmony_ci 458862306a36Sopenharmony_ci list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { 458962306a36Sopenharmony_ci switch (dev->caps.steering_mode) { 459062306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 459162306a36Sopenharmony_ci mlx4_flow_detach(dev, rgid->reg_id); 459262306a36Sopenharmony_ci break; 459362306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 459462306a36Sopenharmony_ci qp.qpn = rqp->local_qpn; 459562306a36Sopenharmony_ci (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, 459662306a36Sopenharmony_ci rgid->prot, rgid->steer); 459762306a36Sopenharmony_ci break; 459862306a36Sopenharmony_ci } 459962306a36Sopenharmony_ci list_del(&rgid->list); 460062306a36Sopenharmony_ci kfree(rgid); 460162306a36Sopenharmony_ci } 460262306a36Sopenharmony_ci} 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_cistatic int _move_all_busy(struct mlx4_dev *dev, int slave, 460562306a36Sopenharmony_ci enum mlx4_resource type, int print) 460662306a36Sopenharmony_ci{ 460762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 460862306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = 460962306a36Sopenharmony_ci &priv->mfunc.master.res_tracker; 461062306a36Sopenharmony_ci struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; 461162306a36Sopenharmony_ci struct res_common *r; 461262306a36Sopenharmony_ci struct res_common *tmp; 461362306a36Sopenharmony_ci int busy; 461462306a36Sopenharmony_ci 461562306a36Sopenharmony_ci busy = 0; 461662306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 461762306a36Sopenharmony_ci list_for_each_entry_safe(r, tmp, rlist, list) { 461862306a36Sopenharmony_ci if (r->owner == slave) { 461962306a36Sopenharmony_ci if (!r->removing) { 462062306a36Sopenharmony_ci if (r->state == RES_ANY_BUSY) { 462162306a36Sopenharmony_ci if (print) 462262306a36Sopenharmony_ci mlx4_dbg(dev, 462362306a36Sopenharmony_ci "%s id 0x%llx is busy\n", 462462306a36Sopenharmony_ci resource_str(type), 462562306a36Sopenharmony_ci r->res_id); 462662306a36Sopenharmony_ci ++busy; 462762306a36Sopenharmony_ci } else { 462862306a36Sopenharmony_ci r->from_state = r->state; 462962306a36Sopenharmony_ci r->state = RES_ANY_BUSY; 463062306a36Sopenharmony_ci r->removing = 1; 463162306a36Sopenharmony_ci } 463262306a36Sopenharmony_ci } 463362306a36Sopenharmony_ci } 463462306a36Sopenharmony_ci } 463562306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_ci return busy; 463862306a36Sopenharmony_ci} 463962306a36Sopenharmony_ci 464062306a36Sopenharmony_cistatic int move_all_busy(struct mlx4_dev *dev, int slave, 464162306a36Sopenharmony_ci enum mlx4_resource type) 464262306a36Sopenharmony_ci{ 464362306a36Sopenharmony_ci unsigned long begin; 464462306a36Sopenharmony_ci int busy; 464562306a36Sopenharmony_ci 464662306a36Sopenharmony_ci begin = jiffies; 464762306a36Sopenharmony_ci do { 464862306a36Sopenharmony_ci busy = _move_all_busy(dev, slave, type, 0); 464962306a36Sopenharmony_ci if (time_after(jiffies, begin + 5 * HZ)) 465062306a36Sopenharmony_ci break; 465162306a36Sopenharmony_ci if (busy) 465262306a36Sopenharmony_ci cond_resched(); 465362306a36Sopenharmony_ci } while (busy); 465462306a36Sopenharmony_ci 465562306a36Sopenharmony_ci if (busy) 465662306a36Sopenharmony_ci busy = _move_all_busy(dev, slave, type, 1); 465762306a36Sopenharmony_ci 465862306a36Sopenharmony_ci return busy; 465962306a36Sopenharmony_ci} 466062306a36Sopenharmony_cistatic void rem_slave_qps(struct mlx4_dev *dev, int slave) 466162306a36Sopenharmony_ci{ 466262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 466362306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 466462306a36Sopenharmony_ci struct list_head *qp_list = 466562306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_QP]; 466662306a36Sopenharmony_ci struct res_qp *qp; 466762306a36Sopenharmony_ci struct res_qp *tmp; 466862306a36Sopenharmony_ci int state; 466962306a36Sopenharmony_ci u64 in_param; 467062306a36Sopenharmony_ci int qpn; 467162306a36Sopenharmony_ci int err; 467262306a36Sopenharmony_ci 467362306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_QP); 467462306a36Sopenharmony_ci if (err) 467562306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy for slave %d\n", 467662306a36Sopenharmony_ci slave); 467762306a36Sopenharmony_ci 467862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 467962306a36Sopenharmony_ci list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 468062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 468162306a36Sopenharmony_ci if (qp->com.owner == slave) { 468262306a36Sopenharmony_ci qpn = qp->com.res_id; 468362306a36Sopenharmony_ci detach_qp(dev, slave, qp); 468462306a36Sopenharmony_ci state = qp->com.from_state; 468562306a36Sopenharmony_ci while (state != 0) { 468662306a36Sopenharmony_ci switch (state) { 468762306a36Sopenharmony_ci case RES_QP_RESERVED: 468862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 468962306a36Sopenharmony_ci rb_erase(&qp->com.node, 469062306a36Sopenharmony_ci &tracker->res_tree[RES_QP]); 469162306a36Sopenharmony_ci list_del(&qp->com.list); 469262306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 469362306a36Sopenharmony_ci if (!valid_reserved(dev, slave, qpn)) { 469462306a36Sopenharmony_ci __mlx4_qp_release_range(dev, qpn, 1); 469562306a36Sopenharmony_ci mlx4_release_resource(dev, slave, 469662306a36Sopenharmony_ci RES_QP, 1, 0); 469762306a36Sopenharmony_ci } 469862306a36Sopenharmony_ci kfree(qp); 469962306a36Sopenharmony_ci state = 0; 470062306a36Sopenharmony_ci break; 470162306a36Sopenharmony_ci case RES_QP_MAPPED: 470262306a36Sopenharmony_ci if (!valid_reserved(dev, slave, qpn)) 470362306a36Sopenharmony_ci __mlx4_qp_free_icm(dev, qpn); 470462306a36Sopenharmony_ci state = RES_QP_RESERVED; 470562306a36Sopenharmony_ci break; 470662306a36Sopenharmony_ci case RES_QP_HW: 470762306a36Sopenharmony_ci in_param = slave; 470862306a36Sopenharmony_ci err = mlx4_cmd(dev, in_param, 470962306a36Sopenharmony_ci qp->local_qpn, 2, 471062306a36Sopenharmony_ci MLX4_CMD_2RST_QP, 471162306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 471262306a36Sopenharmony_ci MLX4_CMD_NATIVE); 471362306a36Sopenharmony_ci if (err) 471462306a36Sopenharmony_ci mlx4_dbg(dev, "rem_slave_qps: failed to move slave %d qpn %d to reset\n", 471562306a36Sopenharmony_ci slave, qp->local_qpn); 471662306a36Sopenharmony_ci atomic_dec(&qp->rcq->ref_count); 471762306a36Sopenharmony_ci atomic_dec(&qp->scq->ref_count); 471862306a36Sopenharmony_ci atomic_dec(&qp->mtt->ref_count); 471962306a36Sopenharmony_ci if (qp->srq) 472062306a36Sopenharmony_ci atomic_dec(&qp->srq->ref_count); 472162306a36Sopenharmony_ci state = RES_QP_MAPPED; 472262306a36Sopenharmony_ci break; 472362306a36Sopenharmony_ci default: 472462306a36Sopenharmony_ci state = 0; 472562306a36Sopenharmony_ci } 472662306a36Sopenharmony_ci } 472762306a36Sopenharmony_ci } 472862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 472962306a36Sopenharmony_ci } 473062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 473162306a36Sopenharmony_ci} 473262306a36Sopenharmony_ci 473362306a36Sopenharmony_cistatic void rem_slave_srqs(struct mlx4_dev *dev, int slave) 473462306a36Sopenharmony_ci{ 473562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 473662306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 473762306a36Sopenharmony_ci struct list_head *srq_list = 473862306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_SRQ]; 473962306a36Sopenharmony_ci struct res_srq *srq; 474062306a36Sopenharmony_ci struct res_srq *tmp; 474162306a36Sopenharmony_ci int state; 474262306a36Sopenharmony_ci u64 in_param; 474362306a36Sopenharmony_ci int srqn; 474462306a36Sopenharmony_ci int err; 474562306a36Sopenharmony_ci 474662306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_SRQ); 474762306a36Sopenharmony_ci if (err) 474862306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs - too busy for slave %d\n", 474962306a36Sopenharmony_ci slave); 475062306a36Sopenharmony_ci 475162306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 475262306a36Sopenharmony_ci list_for_each_entry_safe(srq, tmp, srq_list, com.list) { 475362306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 475462306a36Sopenharmony_ci if (srq->com.owner == slave) { 475562306a36Sopenharmony_ci srqn = srq->com.res_id; 475662306a36Sopenharmony_ci state = srq->com.from_state; 475762306a36Sopenharmony_ci while (state != 0) { 475862306a36Sopenharmony_ci switch (state) { 475962306a36Sopenharmony_ci case RES_SRQ_ALLOCATED: 476062306a36Sopenharmony_ci __mlx4_srq_free_icm(dev, srqn); 476162306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 476262306a36Sopenharmony_ci rb_erase(&srq->com.node, 476362306a36Sopenharmony_ci &tracker->res_tree[RES_SRQ]); 476462306a36Sopenharmony_ci list_del(&srq->com.list); 476562306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 476662306a36Sopenharmony_ci mlx4_release_resource(dev, slave, 476762306a36Sopenharmony_ci RES_SRQ, 1, 0); 476862306a36Sopenharmony_ci kfree(srq); 476962306a36Sopenharmony_ci state = 0; 477062306a36Sopenharmony_ci break; 477162306a36Sopenharmony_ci 477262306a36Sopenharmony_ci case RES_SRQ_HW: 477362306a36Sopenharmony_ci in_param = slave; 477462306a36Sopenharmony_ci err = mlx4_cmd(dev, in_param, srqn, 1, 477562306a36Sopenharmony_ci MLX4_CMD_HW2SW_SRQ, 477662306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 477762306a36Sopenharmony_ci MLX4_CMD_NATIVE); 477862306a36Sopenharmony_ci if (err) 477962306a36Sopenharmony_ci mlx4_dbg(dev, "rem_slave_srqs: failed to move slave %d srq %d to SW ownership\n", 478062306a36Sopenharmony_ci slave, srqn); 478162306a36Sopenharmony_ci 478262306a36Sopenharmony_ci atomic_dec(&srq->mtt->ref_count); 478362306a36Sopenharmony_ci if (srq->cq) 478462306a36Sopenharmony_ci atomic_dec(&srq->cq->ref_count); 478562306a36Sopenharmony_ci state = RES_SRQ_ALLOCATED; 478662306a36Sopenharmony_ci break; 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_ci default: 478962306a36Sopenharmony_ci state = 0; 479062306a36Sopenharmony_ci } 479162306a36Sopenharmony_ci } 479262306a36Sopenharmony_ci } 479362306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 479462306a36Sopenharmony_ci } 479562306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 479662306a36Sopenharmony_ci} 479762306a36Sopenharmony_ci 479862306a36Sopenharmony_cistatic void rem_slave_cqs(struct mlx4_dev *dev, int slave) 479962306a36Sopenharmony_ci{ 480062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 480162306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 480262306a36Sopenharmony_ci struct list_head *cq_list = 480362306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_CQ]; 480462306a36Sopenharmony_ci struct res_cq *cq; 480562306a36Sopenharmony_ci struct res_cq *tmp; 480662306a36Sopenharmony_ci int state; 480762306a36Sopenharmony_ci u64 in_param; 480862306a36Sopenharmony_ci int cqn; 480962306a36Sopenharmony_ci int err; 481062306a36Sopenharmony_ci 481162306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_CQ); 481262306a36Sopenharmony_ci if (err) 481362306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs - too busy for slave %d\n", 481462306a36Sopenharmony_ci slave); 481562306a36Sopenharmony_ci 481662306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 481762306a36Sopenharmony_ci list_for_each_entry_safe(cq, tmp, cq_list, com.list) { 481862306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 481962306a36Sopenharmony_ci if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { 482062306a36Sopenharmony_ci cqn = cq->com.res_id; 482162306a36Sopenharmony_ci state = cq->com.from_state; 482262306a36Sopenharmony_ci while (state != 0) { 482362306a36Sopenharmony_ci switch (state) { 482462306a36Sopenharmony_ci case RES_CQ_ALLOCATED: 482562306a36Sopenharmony_ci __mlx4_cq_free_icm(dev, cqn); 482662306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 482762306a36Sopenharmony_ci rb_erase(&cq->com.node, 482862306a36Sopenharmony_ci &tracker->res_tree[RES_CQ]); 482962306a36Sopenharmony_ci list_del(&cq->com.list); 483062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 483162306a36Sopenharmony_ci mlx4_release_resource(dev, slave, 483262306a36Sopenharmony_ci RES_CQ, 1, 0); 483362306a36Sopenharmony_ci kfree(cq); 483462306a36Sopenharmony_ci state = 0; 483562306a36Sopenharmony_ci break; 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci case RES_CQ_HW: 483862306a36Sopenharmony_ci in_param = slave; 483962306a36Sopenharmony_ci err = mlx4_cmd(dev, in_param, cqn, 1, 484062306a36Sopenharmony_ci MLX4_CMD_HW2SW_CQ, 484162306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 484262306a36Sopenharmony_ci MLX4_CMD_NATIVE); 484362306a36Sopenharmony_ci if (err) 484462306a36Sopenharmony_ci mlx4_dbg(dev, "rem_slave_cqs: failed to move slave %d cq %d to SW ownership\n", 484562306a36Sopenharmony_ci slave, cqn); 484662306a36Sopenharmony_ci atomic_dec(&cq->mtt->ref_count); 484762306a36Sopenharmony_ci state = RES_CQ_ALLOCATED; 484862306a36Sopenharmony_ci break; 484962306a36Sopenharmony_ci 485062306a36Sopenharmony_ci default: 485162306a36Sopenharmony_ci state = 0; 485262306a36Sopenharmony_ci } 485362306a36Sopenharmony_ci } 485462306a36Sopenharmony_ci } 485562306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 485662306a36Sopenharmony_ci } 485762306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 485862306a36Sopenharmony_ci} 485962306a36Sopenharmony_ci 486062306a36Sopenharmony_cistatic void rem_slave_mrs(struct mlx4_dev *dev, int slave) 486162306a36Sopenharmony_ci{ 486262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 486362306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 486462306a36Sopenharmony_ci struct list_head *mpt_list = 486562306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MPT]; 486662306a36Sopenharmony_ci struct res_mpt *mpt; 486762306a36Sopenharmony_ci struct res_mpt *tmp; 486862306a36Sopenharmony_ci int state; 486962306a36Sopenharmony_ci u64 in_param; 487062306a36Sopenharmony_ci int mptn; 487162306a36Sopenharmony_ci int err; 487262306a36Sopenharmony_ci 487362306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_MPT); 487462306a36Sopenharmony_ci if (err) 487562306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts - too busy for slave %d\n", 487662306a36Sopenharmony_ci slave); 487762306a36Sopenharmony_ci 487862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 487962306a36Sopenharmony_ci list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { 488062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 488162306a36Sopenharmony_ci if (mpt->com.owner == slave) { 488262306a36Sopenharmony_ci mptn = mpt->com.res_id; 488362306a36Sopenharmony_ci state = mpt->com.from_state; 488462306a36Sopenharmony_ci while (state != 0) { 488562306a36Sopenharmony_ci switch (state) { 488662306a36Sopenharmony_ci case RES_MPT_RESERVED: 488762306a36Sopenharmony_ci __mlx4_mpt_release(dev, mpt->key); 488862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 488962306a36Sopenharmony_ci rb_erase(&mpt->com.node, 489062306a36Sopenharmony_ci &tracker->res_tree[RES_MPT]); 489162306a36Sopenharmony_ci list_del(&mpt->com.list); 489262306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 489362306a36Sopenharmony_ci mlx4_release_resource(dev, slave, 489462306a36Sopenharmony_ci RES_MPT, 1, 0); 489562306a36Sopenharmony_ci kfree(mpt); 489662306a36Sopenharmony_ci state = 0; 489762306a36Sopenharmony_ci break; 489862306a36Sopenharmony_ci 489962306a36Sopenharmony_ci case RES_MPT_MAPPED: 490062306a36Sopenharmony_ci __mlx4_mpt_free_icm(dev, mpt->key); 490162306a36Sopenharmony_ci state = RES_MPT_RESERVED; 490262306a36Sopenharmony_ci break; 490362306a36Sopenharmony_ci 490462306a36Sopenharmony_ci case RES_MPT_HW: 490562306a36Sopenharmony_ci in_param = slave; 490662306a36Sopenharmony_ci err = mlx4_cmd(dev, in_param, mptn, 0, 490762306a36Sopenharmony_ci MLX4_CMD_HW2SW_MPT, 490862306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 490962306a36Sopenharmony_ci MLX4_CMD_NATIVE); 491062306a36Sopenharmony_ci if (err) 491162306a36Sopenharmony_ci mlx4_dbg(dev, "rem_slave_mrs: failed to move slave %d mpt %d to SW ownership\n", 491262306a36Sopenharmony_ci slave, mptn); 491362306a36Sopenharmony_ci if (mpt->mtt) 491462306a36Sopenharmony_ci atomic_dec(&mpt->mtt->ref_count); 491562306a36Sopenharmony_ci state = RES_MPT_MAPPED; 491662306a36Sopenharmony_ci break; 491762306a36Sopenharmony_ci default: 491862306a36Sopenharmony_ci state = 0; 491962306a36Sopenharmony_ci } 492062306a36Sopenharmony_ci } 492162306a36Sopenharmony_ci } 492262306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 492362306a36Sopenharmony_ci } 492462306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 492562306a36Sopenharmony_ci} 492662306a36Sopenharmony_ci 492762306a36Sopenharmony_cistatic void rem_slave_mtts(struct mlx4_dev *dev, int slave) 492862306a36Sopenharmony_ci{ 492962306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 493062306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = 493162306a36Sopenharmony_ci &priv->mfunc.master.res_tracker; 493262306a36Sopenharmony_ci struct list_head *mtt_list = 493362306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MTT]; 493462306a36Sopenharmony_ci struct res_mtt *mtt; 493562306a36Sopenharmony_ci struct res_mtt *tmp; 493662306a36Sopenharmony_ci int state; 493762306a36Sopenharmony_ci int base; 493862306a36Sopenharmony_ci int err; 493962306a36Sopenharmony_ci 494062306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_MTT); 494162306a36Sopenharmony_ci if (err) 494262306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts - too busy for slave %d\n", 494362306a36Sopenharmony_ci slave); 494462306a36Sopenharmony_ci 494562306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 494662306a36Sopenharmony_ci list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { 494762306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 494862306a36Sopenharmony_ci if (mtt->com.owner == slave) { 494962306a36Sopenharmony_ci base = mtt->com.res_id; 495062306a36Sopenharmony_ci state = mtt->com.from_state; 495162306a36Sopenharmony_ci while (state != 0) { 495262306a36Sopenharmony_ci switch (state) { 495362306a36Sopenharmony_ci case RES_MTT_ALLOCATED: 495462306a36Sopenharmony_ci __mlx4_free_mtt_range(dev, base, 495562306a36Sopenharmony_ci mtt->order); 495662306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 495762306a36Sopenharmony_ci rb_erase(&mtt->com.node, 495862306a36Sopenharmony_ci &tracker->res_tree[RES_MTT]); 495962306a36Sopenharmony_ci list_del(&mtt->com.list); 496062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 496162306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 496262306a36Sopenharmony_ci 1 << mtt->order, 0); 496362306a36Sopenharmony_ci kfree(mtt); 496462306a36Sopenharmony_ci state = 0; 496562306a36Sopenharmony_ci break; 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci default: 496862306a36Sopenharmony_ci state = 0; 496962306a36Sopenharmony_ci } 497062306a36Sopenharmony_ci } 497162306a36Sopenharmony_ci } 497262306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 497362306a36Sopenharmony_ci } 497462306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 497562306a36Sopenharmony_ci} 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_cistatic int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule) 497862306a36Sopenharmony_ci{ 497962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 498062306a36Sopenharmony_ci int err; 498162306a36Sopenharmony_ci struct res_fs_rule *mirr_rule; 498262306a36Sopenharmony_ci u64 reg_id; 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 498562306a36Sopenharmony_ci if (IS_ERR(mailbox)) 498662306a36Sopenharmony_ci return PTR_ERR(mailbox); 498762306a36Sopenharmony_ci 498862306a36Sopenharmony_ci if (!fs_rule->mirr_mbox) { 498962306a36Sopenharmony_ci mlx4_err(dev, "rule mirroring mailbox is null\n"); 499062306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 499162306a36Sopenharmony_ci return -EINVAL; 499262306a36Sopenharmony_ci } 499362306a36Sopenharmony_ci memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size); 499462306a36Sopenharmony_ci err = mlx4_cmd_imm(dev, mailbox->dma, ®_id, fs_rule->mirr_mbox_size >> 2, 0, 499562306a36Sopenharmony_ci MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 499662306a36Sopenharmony_ci MLX4_CMD_NATIVE); 499762306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 499862306a36Sopenharmony_ci 499962306a36Sopenharmony_ci if (err) 500062306a36Sopenharmony_ci goto err; 500162306a36Sopenharmony_ci 500262306a36Sopenharmony_ci err = add_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, fs_rule->qpn); 500362306a36Sopenharmony_ci if (err) 500462306a36Sopenharmony_ci goto err_detach; 500562306a36Sopenharmony_ci 500662306a36Sopenharmony_ci err = get_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE, &mirr_rule); 500762306a36Sopenharmony_ci if (err) 500862306a36Sopenharmony_ci goto err_rem; 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci fs_rule->mirr_rule_id = reg_id; 501162306a36Sopenharmony_ci mirr_rule->mirr_rule_id = 0; 501262306a36Sopenharmony_ci mirr_rule->mirr_mbox_size = 0; 501362306a36Sopenharmony_ci mirr_rule->mirr_mbox = NULL; 501462306a36Sopenharmony_ci put_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE); 501562306a36Sopenharmony_ci 501662306a36Sopenharmony_ci return 0; 501762306a36Sopenharmony_cierr_rem: 501862306a36Sopenharmony_ci rem_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, 0); 501962306a36Sopenharmony_cierr_detach: 502062306a36Sopenharmony_ci mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, 502162306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 502262306a36Sopenharmony_cierr: 502362306a36Sopenharmony_ci return err; 502462306a36Sopenharmony_ci} 502562306a36Sopenharmony_ci 502662306a36Sopenharmony_cistatic int mlx4_mirror_fs_rules(struct mlx4_dev *dev, bool bond) 502762306a36Sopenharmony_ci{ 502862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 502962306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = 503062306a36Sopenharmony_ci &priv->mfunc.master.res_tracker; 503162306a36Sopenharmony_ci struct rb_root *root = &tracker->res_tree[RES_FS_RULE]; 503262306a36Sopenharmony_ci struct rb_node *p; 503362306a36Sopenharmony_ci struct res_fs_rule *fs_rule; 503462306a36Sopenharmony_ci int err = 0; 503562306a36Sopenharmony_ci LIST_HEAD(mirr_list); 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci for (p = rb_first(root); p; p = rb_next(p)) { 503862306a36Sopenharmony_ci fs_rule = rb_entry(p, struct res_fs_rule, com.node); 503962306a36Sopenharmony_ci if ((bond && fs_rule->mirr_mbox_size) || 504062306a36Sopenharmony_ci (!bond && !fs_rule->mirr_mbox_size)) 504162306a36Sopenharmony_ci list_add_tail(&fs_rule->mirr_list, &mirr_list); 504262306a36Sopenharmony_ci } 504362306a36Sopenharmony_ci 504462306a36Sopenharmony_ci list_for_each_entry(fs_rule, &mirr_list, mirr_list) { 504562306a36Sopenharmony_ci if (bond) 504662306a36Sopenharmony_ci err += mlx4_do_mirror_rule(dev, fs_rule); 504762306a36Sopenharmony_ci else 504862306a36Sopenharmony_ci err += mlx4_undo_mirror_rule(dev, fs_rule); 504962306a36Sopenharmony_ci } 505062306a36Sopenharmony_ci return err; 505162306a36Sopenharmony_ci} 505262306a36Sopenharmony_ci 505362306a36Sopenharmony_ciint mlx4_bond_fs_rules(struct mlx4_dev *dev) 505462306a36Sopenharmony_ci{ 505562306a36Sopenharmony_ci return mlx4_mirror_fs_rules(dev, true); 505662306a36Sopenharmony_ci} 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ciint mlx4_unbond_fs_rules(struct mlx4_dev *dev) 505962306a36Sopenharmony_ci{ 506062306a36Sopenharmony_ci return mlx4_mirror_fs_rules(dev, false); 506162306a36Sopenharmony_ci} 506262306a36Sopenharmony_ci 506362306a36Sopenharmony_cistatic void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) 506462306a36Sopenharmony_ci{ 506562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 506662306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = 506762306a36Sopenharmony_ci &priv->mfunc.master.res_tracker; 506862306a36Sopenharmony_ci struct list_head *fs_rule_list = 506962306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_FS_RULE]; 507062306a36Sopenharmony_ci struct res_fs_rule *fs_rule; 507162306a36Sopenharmony_ci struct res_fs_rule *tmp; 507262306a36Sopenharmony_ci int state; 507362306a36Sopenharmony_ci u64 base; 507462306a36Sopenharmony_ci int err; 507562306a36Sopenharmony_ci 507662306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_FS_RULE); 507762306a36Sopenharmony_ci if (err) 507862306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", 507962306a36Sopenharmony_ci slave); 508062306a36Sopenharmony_ci 508162306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 508262306a36Sopenharmony_ci list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { 508362306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 508462306a36Sopenharmony_ci if (fs_rule->com.owner == slave) { 508562306a36Sopenharmony_ci base = fs_rule->com.res_id; 508662306a36Sopenharmony_ci state = fs_rule->com.from_state; 508762306a36Sopenharmony_ci while (state != 0) { 508862306a36Sopenharmony_ci switch (state) { 508962306a36Sopenharmony_ci case RES_FS_RULE_ALLOCATED: 509062306a36Sopenharmony_ci /* detach rule */ 509162306a36Sopenharmony_ci err = mlx4_cmd(dev, base, 0, 0, 509262306a36Sopenharmony_ci MLX4_QP_FLOW_STEERING_DETACH, 509362306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 509462306a36Sopenharmony_ci MLX4_CMD_NATIVE); 509562306a36Sopenharmony_ci 509662306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 509762306a36Sopenharmony_ci rb_erase(&fs_rule->com.node, 509862306a36Sopenharmony_ci &tracker->res_tree[RES_FS_RULE]); 509962306a36Sopenharmony_ci list_del(&fs_rule->com.list); 510062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 510162306a36Sopenharmony_ci kfree(fs_rule->mirr_mbox); 510262306a36Sopenharmony_ci kfree(fs_rule); 510362306a36Sopenharmony_ci state = 0; 510462306a36Sopenharmony_ci break; 510562306a36Sopenharmony_ci 510662306a36Sopenharmony_ci default: 510762306a36Sopenharmony_ci state = 0; 510862306a36Sopenharmony_ci } 510962306a36Sopenharmony_ci } 511062306a36Sopenharmony_ci } 511162306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 511262306a36Sopenharmony_ci } 511362306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 511462306a36Sopenharmony_ci} 511562306a36Sopenharmony_ci 511662306a36Sopenharmony_cistatic void rem_slave_eqs(struct mlx4_dev *dev, int slave) 511762306a36Sopenharmony_ci{ 511862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 511962306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 512062306a36Sopenharmony_ci struct list_head *eq_list = 512162306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_EQ]; 512262306a36Sopenharmony_ci struct res_eq *eq; 512362306a36Sopenharmony_ci struct res_eq *tmp; 512462306a36Sopenharmony_ci int err; 512562306a36Sopenharmony_ci int state; 512662306a36Sopenharmony_ci int eqn; 512762306a36Sopenharmony_ci 512862306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_EQ); 512962306a36Sopenharmony_ci if (err) 513062306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs - too busy for slave %d\n", 513162306a36Sopenharmony_ci slave); 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 513462306a36Sopenharmony_ci list_for_each_entry_safe(eq, tmp, eq_list, com.list) { 513562306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 513662306a36Sopenharmony_ci if (eq->com.owner == slave) { 513762306a36Sopenharmony_ci eqn = eq->com.res_id; 513862306a36Sopenharmony_ci state = eq->com.from_state; 513962306a36Sopenharmony_ci while (state != 0) { 514062306a36Sopenharmony_ci switch (state) { 514162306a36Sopenharmony_ci case RES_EQ_RESERVED: 514262306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 514362306a36Sopenharmony_ci rb_erase(&eq->com.node, 514462306a36Sopenharmony_ci &tracker->res_tree[RES_EQ]); 514562306a36Sopenharmony_ci list_del(&eq->com.list); 514662306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 514762306a36Sopenharmony_ci kfree(eq); 514862306a36Sopenharmony_ci state = 0; 514962306a36Sopenharmony_ci break; 515062306a36Sopenharmony_ci 515162306a36Sopenharmony_ci case RES_EQ_HW: 515262306a36Sopenharmony_ci err = mlx4_cmd(dev, slave, eqn & 0x3ff, 515362306a36Sopenharmony_ci 1, MLX4_CMD_HW2SW_EQ, 515462306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 515562306a36Sopenharmony_ci MLX4_CMD_NATIVE); 515662306a36Sopenharmony_ci if (err) 515762306a36Sopenharmony_ci mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n", 515862306a36Sopenharmony_ci slave, eqn & 0x3ff); 515962306a36Sopenharmony_ci atomic_dec(&eq->mtt->ref_count); 516062306a36Sopenharmony_ci state = RES_EQ_RESERVED; 516162306a36Sopenharmony_ci break; 516262306a36Sopenharmony_ci 516362306a36Sopenharmony_ci default: 516462306a36Sopenharmony_ci state = 0; 516562306a36Sopenharmony_ci } 516662306a36Sopenharmony_ci } 516762306a36Sopenharmony_ci } 516862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 516962306a36Sopenharmony_ci } 517062306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 517162306a36Sopenharmony_ci} 517262306a36Sopenharmony_ci 517362306a36Sopenharmony_cistatic void rem_slave_counters(struct mlx4_dev *dev, int slave) 517462306a36Sopenharmony_ci{ 517562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 517662306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 517762306a36Sopenharmony_ci struct list_head *counter_list = 517862306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_COUNTER]; 517962306a36Sopenharmony_ci struct res_counter *counter; 518062306a36Sopenharmony_ci struct res_counter *tmp; 518162306a36Sopenharmony_ci int err; 518262306a36Sopenharmony_ci int *counters_arr = NULL; 518362306a36Sopenharmony_ci int i, j; 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_COUNTER); 518662306a36Sopenharmony_ci if (err) 518762306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n", 518862306a36Sopenharmony_ci slave); 518962306a36Sopenharmony_ci 519062306a36Sopenharmony_ci counters_arr = kmalloc_array(dev->caps.max_counters, 519162306a36Sopenharmony_ci sizeof(*counters_arr), GFP_KERNEL); 519262306a36Sopenharmony_ci if (!counters_arr) 519362306a36Sopenharmony_ci return; 519462306a36Sopenharmony_ci 519562306a36Sopenharmony_ci do { 519662306a36Sopenharmony_ci i = 0; 519762306a36Sopenharmony_ci j = 0; 519862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 519962306a36Sopenharmony_ci list_for_each_entry_safe(counter, tmp, counter_list, com.list) { 520062306a36Sopenharmony_ci if (counter->com.owner == slave) { 520162306a36Sopenharmony_ci counters_arr[i++] = counter->com.res_id; 520262306a36Sopenharmony_ci rb_erase(&counter->com.node, 520362306a36Sopenharmony_ci &tracker->res_tree[RES_COUNTER]); 520462306a36Sopenharmony_ci list_del(&counter->com.list); 520562306a36Sopenharmony_ci kfree(counter); 520662306a36Sopenharmony_ci } 520762306a36Sopenharmony_ci } 520862306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 520962306a36Sopenharmony_ci 521062306a36Sopenharmony_ci while (j < i) { 521162306a36Sopenharmony_ci __mlx4_counter_free(dev, counters_arr[j++]); 521262306a36Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 521362306a36Sopenharmony_ci } 521462306a36Sopenharmony_ci } while (i); 521562306a36Sopenharmony_ci 521662306a36Sopenharmony_ci kfree(counters_arr); 521762306a36Sopenharmony_ci} 521862306a36Sopenharmony_ci 521962306a36Sopenharmony_cistatic void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) 522062306a36Sopenharmony_ci{ 522162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 522262306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 522362306a36Sopenharmony_ci struct list_head *xrcdn_list = 522462306a36Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_XRCD]; 522562306a36Sopenharmony_ci struct res_xrcdn *xrcd; 522662306a36Sopenharmony_ci struct res_xrcdn *tmp; 522762306a36Sopenharmony_ci int err; 522862306a36Sopenharmony_ci int xrcdn; 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci err = move_all_busy(dev, slave, RES_XRCD); 523162306a36Sopenharmony_ci if (err) 523262306a36Sopenharmony_ci mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns - too busy for slave %d\n", 523362306a36Sopenharmony_ci slave); 523462306a36Sopenharmony_ci 523562306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 523662306a36Sopenharmony_ci list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { 523762306a36Sopenharmony_ci if (xrcd->com.owner == slave) { 523862306a36Sopenharmony_ci xrcdn = xrcd->com.res_id; 523962306a36Sopenharmony_ci rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); 524062306a36Sopenharmony_ci list_del(&xrcd->com.list); 524162306a36Sopenharmony_ci kfree(xrcd); 524262306a36Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 524362306a36Sopenharmony_ci } 524462306a36Sopenharmony_ci } 524562306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 524662306a36Sopenharmony_ci} 524762306a36Sopenharmony_ci 524862306a36Sopenharmony_civoid mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) 524962306a36Sopenharmony_ci{ 525062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 525162306a36Sopenharmony_ci mlx4_reset_roce_gids(dev, slave); 525262306a36Sopenharmony_ci mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 525362306a36Sopenharmony_ci rem_slave_vlans(dev, slave); 525462306a36Sopenharmony_ci rem_slave_macs(dev, slave); 525562306a36Sopenharmony_ci rem_slave_fs_rule(dev, slave); 525662306a36Sopenharmony_ci rem_slave_qps(dev, slave); 525762306a36Sopenharmony_ci rem_slave_srqs(dev, slave); 525862306a36Sopenharmony_ci rem_slave_cqs(dev, slave); 525962306a36Sopenharmony_ci rem_slave_mrs(dev, slave); 526062306a36Sopenharmony_ci rem_slave_eqs(dev, slave); 526162306a36Sopenharmony_ci rem_slave_mtts(dev, slave); 526262306a36Sopenharmony_ci rem_slave_counters(dev, slave); 526362306a36Sopenharmony_ci rem_slave_xrcdns(dev, slave); 526462306a36Sopenharmony_ci mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 526562306a36Sopenharmony_ci} 526662306a36Sopenharmony_ci 526762306a36Sopenharmony_cistatic void update_qos_vpp(struct mlx4_update_qp_context *ctx, 526862306a36Sopenharmony_ci struct mlx4_vf_immed_vlan_work *work) 526962306a36Sopenharmony_ci{ 527062306a36Sopenharmony_ci ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP); 527162306a36Sopenharmony_ci ctx->qp_context.qos_vport = work->qos_vport; 527262306a36Sopenharmony_ci} 527362306a36Sopenharmony_ci 527462306a36Sopenharmony_civoid mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) 527562306a36Sopenharmony_ci{ 527662306a36Sopenharmony_ci struct mlx4_vf_immed_vlan_work *work = 527762306a36Sopenharmony_ci container_of(_work, struct mlx4_vf_immed_vlan_work, work); 527862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 527962306a36Sopenharmony_ci struct mlx4_update_qp_context *upd_context; 528062306a36Sopenharmony_ci struct mlx4_dev *dev = &work->priv->dev; 528162306a36Sopenharmony_ci struct mlx4_resource_tracker *tracker = 528262306a36Sopenharmony_ci &work->priv->mfunc.master.res_tracker; 528362306a36Sopenharmony_ci struct list_head *qp_list = 528462306a36Sopenharmony_ci &tracker->slave_list[work->slave].res_list[RES_QP]; 528562306a36Sopenharmony_ci struct res_qp *qp; 528662306a36Sopenharmony_ci struct res_qp *tmp; 528762306a36Sopenharmony_ci u64 qp_path_mask_vlan_ctrl = 528862306a36Sopenharmony_ci ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | 528962306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | 529062306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | 529162306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | 529262306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | 529362306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED)); 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | 529662306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) | 529762306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_CV) | 529862306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_SV) | 529962306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) | 530062306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) | 530162306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) | 530262306a36Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); 530362306a36Sopenharmony_ci 530462306a36Sopenharmony_ci int err; 530562306a36Sopenharmony_ci int port, errors = 0; 530662306a36Sopenharmony_ci u8 vlan_control; 530762306a36Sopenharmony_ci 530862306a36Sopenharmony_ci if (mlx4_is_slave(dev)) { 530962306a36Sopenharmony_ci mlx4_warn(dev, "Trying to update-qp in slave %d\n", 531062306a36Sopenharmony_ci work->slave); 531162306a36Sopenharmony_ci goto out; 531262306a36Sopenharmony_ci } 531362306a36Sopenharmony_ci 531462306a36Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 531562306a36Sopenharmony_ci if (IS_ERR(mailbox)) 531662306a36Sopenharmony_ci goto out; 531762306a36Sopenharmony_ci if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE) /* block all */ 531862306a36Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 531962306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 532062306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED | 532162306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 532262306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED | 532362306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 532462306a36Sopenharmony_ci else if (!work->vlan_id) 532562306a36Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 532662306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 532762306a36Sopenharmony_ci else if (work->vlan_proto == htons(ETH_P_8021AD)) 532862306a36Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 532962306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 533062306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 533162306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 533262306a36Sopenharmony_ci else /* vst 802.1Q */ 533362306a36Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 533462306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 533562306a36Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 533662306a36Sopenharmony_ci 533762306a36Sopenharmony_ci upd_context = mailbox->buf; 533862306a36Sopenharmony_ci upd_context->qp_mask = cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_VSD); 533962306a36Sopenharmony_ci 534062306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 534162306a36Sopenharmony_ci list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 534262306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 534362306a36Sopenharmony_ci if (qp->com.owner == work->slave) { 534462306a36Sopenharmony_ci if (qp->com.from_state != RES_QP_HW || 534562306a36Sopenharmony_ci !qp->sched_queue || /* no INIT2RTR trans yet */ 534662306a36Sopenharmony_ci mlx4_is_qp_reserved(dev, qp->local_qpn) || 534762306a36Sopenharmony_ci qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { 534862306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 534962306a36Sopenharmony_ci continue; 535062306a36Sopenharmony_ci } 535162306a36Sopenharmony_ci port = (qp->sched_queue >> 6 & 1) + 1; 535262306a36Sopenharmony_ci if (port != work->port) { 535362306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 535462306a36Sopenharmony_ci continue; 535562306a36Sopenharmony_ci } 535662306a36Sopenharmony_ci if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff)) 535762306a36Sopenharmony_ci upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask); 535862306a36Sopenharmony_ci else 535962306a36Sopenharmony_ci upd_context->primary_addr_path_mask = 536062306a36Sopenharmony_ci cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl); 536162306a36Sopenharmony_ci if (work->vlan_id == MLX4_VGT) { 536262306a36Sopenharmony_ci upd_context->qp_context.param3 = qp->param3; 536362306a36Sopenharmony_ci upd_context->qp_context.pri_path.vlan_control = qp->vlan_control; 536462306a36Sopenharmony_ci upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx; 536562306a36Sopenharmony_ci upd_context->qp_context.pri_path.vlan_index = qp->vlan_index; 536662306a36Sopenharmony_ci upd_context->qp_context.pri_path.fl = qp->pri_path_fl; 536762306a36Sopenharmony_ci upd_context->qp_context.pri_path.feup = qp->feup; 536862306a36Sopenharmony_ci upd_context->qp_context.pri_path.sched_queue = 536962306a36Sopenharmony_ci qp->sched_queue; 537062306a36Sopenharmony_ci } else { 537162306a36Sopenharmony_ci upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN); 537262306a36Sopenharmony_ci upd_context->qp_context.pri_path.vlan_control = vlan_control; 537362306a36Sopenharmony_ci upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; 537462306a36Sopenharmony_ci upd_context->qp_context.pri_path.fvl_rx = 537562306a36Sopenharmony_ci qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN; 537662306a36Sopenharmony_ci upd_context->qp_context.pri_path.fl = 537762306a36Sopenharmony_ci qp->pri_path_fl | MLX4_FL_ETH_HIDE_CQE_VLAN; 537862306a36Sopenharmony_ci if (work->vlan_proto == htons(ETH_P_8021AD)) 537962306a36Sopenharmony_ci upd_context->qp_context.pri_path.fl |= MLX4_FL_SV; 538062306a36Sopenharmony_ci else 538162306a36Sopenharmony_ci upd_context->qp_context.pri_path.fl |= MLX4_FL_CV; 538262306a36Sopenharmony_ci upd_context->qp_context.pri_path.feup = 538362306a36Sopenharmony_ci qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 538462306a36Sopenharmony_ci upd_context->qp_context.pri_path.sched_queue = 538562306a36Sopenharmony_ci qp->sched_queue & 0xC7; 538662306a36Sopenharmony_ci upd_context->qp_context.pri_path.sched_queue |= 538762306a36Sopenharmony_ci ((work->qos & 0x7) << 3); 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci if (dev->caps.flags2 & 539062306a36Sopenharmony_ci MLX4_DEV_CAP_FLAG2_QOS_VPP) 539162306a36Sopenharmony_ci update_qos_vpp(upd_context, work); 539262306a36Sopenharmony_ci } 539362306a36Sopenharmony_ci 539462306a36Sopenharmony_ci err = mlx4_cmd(dev, mailbox->dma, 539562306a36Sopenharmony_ci qp->local_qpn & 0xffffff, 539662306a36Sopenharmony_ci 0, MLX4_CMD_UPDATE_QP, 539762306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 539862306a36Sopenharmony_ci if (err) { 539962306a36Sopenharmony_ci mlx4_info(dev, "UPDATE_QP failed for slave %d, port %d, qpn %d (%d)\n", 540062306a36Sopenharmony_ci work->slave, port, qp->local_qpn, err); 540162306a36Sopenharmony_ci errors++; 540262306a36Sopenharmony_ci } 540362306a36Sopenharmony_ci } 540462306a36Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 540562306a36Sopenharmony_ci } 540662306a36Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 540762306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 540862306a36Sopenharmony_ci 540962306a36Sopenharmony_ci if (errors) 541062306a36Sopenharmony_ci mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", 541162306a36Sopenharmony_ci errors, work->slave, work->port); 541262306a36Sopenharmony_ci 541362306a36Sopenharmony_ci /* unregister previous vlan_id if needed and we had no errors 541462306a36Sopenharmony_ci * while updating the QPs 541562306a36Sopenharmony_ci */ 541662306a36Sopenharmony_ci if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && 541762306a36Sopenharmony_ci NO_INDX != work->orig_vlan_ix) 541862306a36Sopenharmony_ci __mlx4_unregister_vlan(&work->priv->dev, work->port, 541962306a36Sopenharmony_ci work->orig_vlan_id); 542062306a36Sopenharmony_ciout: 542162306a36Sopenharmony_ci kfree(work); 542262306a36Sopenharmony_ci return; 542362306a36Sopenharmony_ci} 5424