18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 88c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 118c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 148c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 158c2ecf20Sopenharmony_ci * conditions are met: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 188c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 198c2ecf20Sopenharmony_ci * disclaimer. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 228c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 238c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 248c2ecf20Sopenharmony_ci * provided with the distribution. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 278c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 288c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 298c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 308c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 318c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 328c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 338c2ecf20Sopenharmony_ci * SOFTWARE. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/sched.h> 378c2ecf20Sopenharmony_ci#include <linux/pci.h> 388c2ecf20Sopenharmony_ci#include <linux/errno.h> 398c2ecf20Sopenharmony_ci#include <linux/kernel.h> 408c2ecf20Sopenharmony_ci#include <linux/io.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 438c2ecf20Sopenharmony_ci#include <linux/mlx4/qp.h> 448c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 458c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "mlx4.h" 488c2ecf20Sopenharmony_ci#include "fw.h" 498c2ecf20Sopenharmony_ci#include "mlx4_stats.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define MLX4_MAC_VALID (1ull << 63) 528c2ecf20Sopenharmony_ci#define MLX4_PF_COUNTERS_PER_PORT 2 538c2ecf20Sopenharmony_ci#define MLX4_VF_COUNTERS_PER_PORT 1 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct mac_res { 568c2ecf20Sopenharmony_ci struct list_head list; 578c2ecf20Sopenharmony_ci u64 mac; 588c2ecf20Sopenharmony_ci int ref_count; 598c2ecf20Sopenharmony_ci u8 smac_index; 608c2ecf20Sopenharmony_ci u8 port; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct vlan_res { 648c2ecf20Sopenharmony_ci struct list_head list; 658c2ecf20Sopenharmony_ci u16 vlan; 668c2ecf20Sopenharmony_ci int ref_count; 678c2ecf20Sopenharmony_ci int vlan_index; 688c2ecf20Sopenharmony_ci u8 port; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct res_common { 728c2ecf20Sopenharmony_ci struct list_head list; 738c2ecf20Sopenharmony_ci struct rb_node node; 748c2ecf20Sopenharmony_ci u64 res_id; 758c2ecf20Sopenharmony_ci int owner; 768c2ecf20Sopenharmony_ci int state; 778c2ecf20Sopenharmony_ci int from_state; 788c2ecf20Sopenharmony_ci int to_state; 798c2ecf20Sopenharmony_ci int removing; 808c2ecf20Sopenharmony_ci const char *func_name; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cienum { 848c2ecf20Sopenharmony_ci RES_ANY_BUSY = 1 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct res_gid { 888c2ecf20Sopenharmony_ci struct list_head list; 898c2ecf20Sopenharmony_ci u8 gid[16]; 908c2ecf20Sopenharmony_ci enum mlx4_protocol prot; 918c2ecf20Sopenharmony_ci enum mlx4_steer_type steer; 928c2ecf20Sopenharmony_ci u64 reg_id; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cienum res_qp_states { 968c2ecf20Sopenharmony_ci RES_QP_BUSY = RES_ANY_BUSY, 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* QP number was allocated */ 998c2ecf20Sopenharmony_ci RES_QP_RESERVED, 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* ICM memory for QP context was mapped */ 1028c2ecf20Sopenharmony_ci RES_QP_MAPPED, 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* QP is in hw ownership */ 1058c2ecf20Sopenharmony_ci RES_QP_HW 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistruct res_qp { 1098c2ecf20Sopenharmony_ci struct res_common com; 1108c2ecf20Sopenharmony_ci struct res_mtt *mtt; 1118c2ecf20Sopenharmony_ci struct res_cq *rcq; 1128c2ecf20Sopenharmony_ci struct res_cq *scq; 1138c2ecf20Sopenharmony_ci struct res_srq *srq; 1148c2ecf20Sopenharmony_ci struct list_head mcg_list; 1158c2ecf20Sopenharmony_ci spinlock_t mcg_spl; 1168c2ecf20Sopenharmony_ci int local_qpn; 1178c2ecf20Sopenharmony_ci atomic_t ref_count; 1188c2ecf20Sopenharmony_ci u32 qpc_flags; 1198c2ecf20Sopenharmony_ci /* saved qp params before VST enforcement in order to restore on VGT */ 1208c2ecf20Sopenharmony_ci u8 sched_queue; 1218c2ecf20Sopenharmony_ci __be32 param3; 1228c2ecf20Sopenharmony_ci u8 vlan_control; 1238c2ecf20Sopenharmony_ci u8 fvl_rx; 1248c2ecf20Sopenharmony_ci u8 pri_path_fl; 1258c2ecf20Sopenharmony_ci u8 vlan_index; 1268c2ecf20Sopenharmony_ci u8 feup; 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cienum res_mtt_states { 1308c2ecf20Sopenharmony_ci RES_MTT_BUSY = RES_ANY_BUSY, 1318c2ecf20Sopenharmony_ci RES_MTT_ALLOCATED, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic inline const char *mtt_states_str(enum res_mtt_states state) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci switch (state) { 1378c2ecf20Sopenharmony_ci case RES_MTT_BUSY: return "RES_MTT_BUSY"; 1388c2ecf20Sopenharmony_ci case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED"; 1398c2ecf20Sopenharmony_ci default: return "Unknown"; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistruct res_mtt { 1448c2ecf20Sopenharmony_ci struct res_common com; 1458c2ecf20Sopenharmony_ci int order; 1468c2ecf20Sopenharmony_ci atomic_t ref_count; 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cienum res_mpt_states { 1508c2ecf20Sopenharmony_ci RES_MPT_BUSY = RES_ANY_BUSY, 1518c2ecf20Sopenharmony_ci RES_MPT_RESERVED, 1528c2ecf20Sopenharmony_ci RES_MPT_MAPPED, 1538c2ecf20Sopenharmony_ci RES_MPT_HW, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistruct res_mpt { 1578c2ecf20Sopenharmony_ci struct res_common com; 1588c2ecf20Sopenharmony_ci struct res_mtt *mtt; 1598c2ecf20Sopenharmony_ci int key; 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cienum res_eq_states { 1638c2ecf20Sopenharmony_ci RES_EQ_BUSY = RES_ANY_BUSY, 1648c2ecf20Sopenharmony_ci RES_EQ_RESERVED, 1658c2ecf20Sopenharmony_ci RES_EQ_HW, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistruct res_eq { 1698c2ecf20Sopenharmony_ci struct res_common com; 1708c2ecf20Sopenharmony_ci struct res_mtt *mtt; 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cienum res_cq_states { 1748c2ecf20Sopenharmony_ci RES_CQ_BUSY = RES_ANY_BUSY, 1758c2ecf20Sopenharmony_ci RES_CQ_ALLOCATED, 1768c2ecf20Sopenharmony_ci RES_CQ_HW, 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistruct res_cq { 1808c2ecf20Sopenharmony_ci struct res_common com; 1818c2ecf20Sopenharmony_ci struct res_mtt *mtt; 1828c2ecf20Sopenharmony_ci atomic_t ref_count; 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cienum res_srq_states { 1868c2ecf20Sopenharmony_ci RES_SRQ_BUSY = RES_ANY_BUSY, 1878c2ecf20Sopenharmony_ci RES_SRQ_ALLOCATED, 1888c2ecf20Sopenharmony_ci RES_SRQ_HW, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct res_srq { 1928c2ecf20Sopenharmony_ci struct res_common com; 1938c2ecf20Sopenharmony_ci struct res_mtt *mtt; 1948c2ecf20Sopenharmony_ci struct res_cq *cq; 1958c2ecf20Sopenharmony_ci atomic_t ref_count; 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cienum res_counter_states { 1998c2ecf20Sopenharmony_ci RES_COUNTER_BUSY = RES_ANY_BUSY, 2008c2ecf20Sopenharmony_ci RES_COUNTER_ALLOCATED, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistruct res_counter { 2048c2ecf20Sopenharmony_ci struct res_common com; 2058c2ecf20Sopenharmony_ci int port; 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cienum res_xrcdn_states { 2098c2ecf20Sopenharmony_ci RES_XRCD_BUSY = RES_ANY_BUSY, 2108c2ecf20Sopenharmony_ci RES_XRCD_ALLOCATED, 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistruct res_xrcdn { 2148c2ecf20Sopenharmony_ci struct res_common com; 2158c2ecf20Sopenharmony_ci int port; 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cienum res_fs_rule_states { 2198c2ecf20Sopenharmony_ci RES_FS_RULE_BUSY = RES_ANY_BUSY, 2208c2ecf20Sopenharmony_ci RES_FS_RULE_ALLOCATED, 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistruct res_fs_rule { 2248c2ecf20Sopenharmony_ci struct res_common com; 2258c2ecf20Sopenharmony_ci int qpn; 2268c2ecf20Sopenharmony_ci /* VF DMFS mbox with port flipped */ 2278c2ecf20Sopenharmony_ci void *mirr_mbox; 2288c2ecf20Sopenharmony_ci /* > 0 --> apply mirror when getting into HA mode */ 2298c2ecf20Sopenharmony_ci /* = 0 --> un-apply mirror when getting out of HA mode */ 2308c2ecf20Sopenharmony_ci u32 mirr_mbox_size; 2318c2ecf20Sopenharmony_ci struct list_head mirr_list; 2328c2ecf20Sopenharmony_ci u64 mirr_rule_id; 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void *res_tracker_lookup(struct rb_root *root, u64 res_id) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct rb_node *node = root->rb_node; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci while (node) { 2408c2ecf20Sopenharmony_ci struct res_common *res = rb_entry(node, struct res_common, 2418c2ecf20Sopenharmony_ci node); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (res_id < res->res_id) 2448c2ecf20Sopenharmony_ci node = node->rb_left; 2458c2ecf20Sopenharmony_ci else if (res_id > res->res_id) 2468c2ecf20Sopenharmony_ci node = node->rb_right; 2478c2ecf20Sopenharmony_ci else 2488c2ecf20Sopenharmony_ci return res; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci return NULL; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic int res_tracker_insert(struct rb_root *root, struct res_common *res) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct rb_node **new = &(root->rb_node), *parent = NULL; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Figure out where to put new node */ 2588c2ecf20Sopenharmony_ci while (*new) { 2598c2ecf20Sopenharmony_ci struct res_common *this = rb_entry(*new, struct res_common, 2608c2ecf20Sopenharmony_ci node); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci parent = *new; 2638c2ecf20Sopenharmony_ci if (res->res_id < this->res_id) 2648c2ecf20Sopenharmony_ci new = &((*new)->rb_left); 2658c2ecf20Sopenharmony_ci else if (res->res_id > this->res_id) 2668c2ecf20Sopenharmony_ci new = &((*new)->rb_right); 2678c2ecf20Sopenharmony_ci else 2688c2ecf20Sopenharmony_ci return -EEXIST; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Add new node and rebalance tree. */ 2728c2ecf20Sopenharmony_ci rb_link_node(&res->node, parent, new); 2738c2ecf20Sopenharmony_ci rb_insert_color(&res->node, root); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cienum qp_transition { 2798c2ecf20Sopenharmony_ci QP_TRANS_INIT2RTR, 2808c2ecf20Sopenharmony_ci QP_TRANS_RTR2RTS, 2818c2ecf20Sopenharmony_ci QP_TRANS_RTS2RTS, 2828c2ecf20Sopenharmony_ci QP_TRANS_SQERR2RTS, 2838c2ecf20Sopenharmony_ci QP_TRANS_SQD2SQD, 2848c2ecf20Sopenharmony_ci QP_TRANS_SQD2RTS 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* For Debug uses */ 2888c2ecf20Sopenharmony_cistatic const char *resource_str(enum mlx4_resource rt) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci switch (rt) { 2918c2ecf20Sopenharmony_ci case RES_QP: return "RES_QP"; 2928c2ecf20Sopenharmony_ci case RES_CQ: return "RES_CQ"; 2938c2ecf20Sopenharmony_ci case RES_SRQ: return "RES_SRQ"; 2948c2ecf20Sopenharmony_ci case RES_MPT: return "RES_MPT"; 2958c2ecf20Sopenharmony_ci case RES_MTT: return "RES_MTT"; 2968c2ecf20Sopenharmony_ci case RES_MAC: return "RES_MAC"; 2978c2ecf20Sopenharmony_ci case RES_VLAN: return "RES_VLAN"; 2988c2ecf20Sopenharmony_ci case RES_EQ: return "RES_EQ"; 2998c2ecf20Sopenharmony_ci case RES_COUNTER: return "RES_COUNTER"; 3008c2ecf20Sopenharmony_ci case RES_FS_RULE: return "RES_FS_RULE"; 3018c2ecf20Sopenharmony_ci case RES_XRCD: return "RES_XRCD"; 3028c2ecf20Sopenharmony_ci default: return "Unknown resource type !!!"; 3038c2ecf20Sopenharmony_ci }; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void rem_slave_vlans(struct mlx4_dev *dev, int slave); 3078c2ecf20Sopenharmony_cistatic inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, 3088c2ecf20Sopenharmony_ci enum mlx4_resource res_type, int count, 3098c2ecf20Sopenharmony_ci int port) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 3128c2ecf20Sopenharmony_ci struct resource_allocator *res_alloc = 3138c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker.res_alloc[res_type]; 3148c2ecf20Sopenharmony_ci int err = -EDQUOT; 3158c2ecf20Sopenharmony_ci int allocated, free, reserved, guaranteed, from_free; 3168c2ecf20Sopenharmony_ci int from_rsvd; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (slave > dev->persist->num_vfs) 3198c2ecf20Sopenharmony_ci return -EINVAL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci spin_lock(&res_alloc->alloc_lock); 3228c2ecf20Sopenharmony_ci allocated = (port > 0) ? 3238c2ecf20Sopenharmony_ci res_alloc->allocated[(port - 1) * 3248c2ecf20Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] : 3258c2ecf20Sopenharmony_ci res_alloc->allocated[slave]; 3268c2ecf20Sopenharmony_ci free = (port > 0) ? res_alloc->res_port_free[port - 1] : 3278c2ecf20Sopenharmony_ci res_alloc->res_free; 3288c2ecf20Sopenharmony_ci reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] : 3298c2ecf20Sopenharmony_ci res_alloc->res_reserved; 3308c2ecf20Sopenharmony_ci guaranteed = res_alloc->guaranteed[slave]; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (allocated + count > res_alloc->quota[slave]) { 3338c2ecf20Sopenharmony_ci mlx4_warn(dev, "VF %d port %d res %s: quota exceeded, count %d alloc %d quota %d\n", 3348c2ecf20Sopenharmony_ci slave, port, resource_str(res_type), count, 3358c2ecf20Sopenharmony_ci allocated, res_alloc->quota[slave]); 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (allocated + count <= guaranteed) { 3408c2ecf20Sopenharmony_ci err = 0; 3418c2ecf20Sopenharmony_ci from_rsvd = count; 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci /* portion may need to be obtained from free area */ 3448c2ecf20Sopenharmony_ci if (guaranteed - allocated > 0) 3458c2ecf20Sopenharmony_ci from_free = count - (guaranteed - allocated); 3468c2ecf20Sopenharmony_ci else 3478c2ecf20Sopenharmony_ci from_free = count; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci from_rsvd = count - from_free; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (free - from_free >= reserved) 3528c2ecf20Sopenharmony_ci err = 0; 3538c2ecf20Sopenharmony_ci else 3548c2ecf20Sopenharmony_ci mlx4_warn(dev, "VF %d port %d res %s: free pool empty, free %d from_free %d rsvd %d\n", 3558c2ecf20Sopenharmony_ci slave, port, resource_str(res_type), free, 3568c2ecf20Sopenharmony_ci from_free, reserved); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (!err) { 3608c2ecf20Sopenharmony_ci /* grant the request */ 3618c2ecf20Sopenharmony_ci if (port > 0) { 3628c2ecf20Sopenharmony_ci res_alloc->allocated[(port - 1) * 3638c2ecf20Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] += count; 3648c2ecf20Sopenharmony_ci res_alloc->res_port_free[port - 1] -= count; 3658c2ecf20Sopenharmony_ci res_alloc->res_port_rsvd[port - 1] -= from_rsvd; 3668c2ecf20Sopenharmony_ci } else { 3678c2ecf20Sopenharmony_ci res_alloc->allocated[slave] += count; 3688c2ecf20Sopenharmony_ci res_alloc->res_free -= count; 3698c2ecf20Sopenharmony_ci res_alloc->res_reserved -= from_rsvd; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ciout: 3748c2ecf20Sopenharmony_ci spin_unlock(&res_alloc->alloc_lock); 3758c2ecf20Sopenharmony_ci return err; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, 3798c2ecf20Sopenharmony_ci enum mlx4_resource res_type, int count, 3808c2ecf20Sopenharmony_ci int port) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 3838c2ecf20Sopenharmony_ci struct resource_allocator *res_alloc = 3848c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker.res_alloc[res_type]; 3858c2ecf20Sopenharmony_ci int allocated, guaranteed, from_rsvd; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (slave > dev->persist->num_vfs) 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci spin_lock(&res_alloc->alloc_lock); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci allocated = (port > 0) ? 3938c2ecf20Sopenharmony_ci res_alloc->allocated[(port - 1) * 3948c2ecf20Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] : 3958c2ecf20Sopenharmony_ci res_alloc->allocated[slave]; 3968c2ecf20Sopenharmony_ci guaranteed = res_alloc->guaranteed[slave]; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (allocated - count >= guaranteed) { 3998c2ecf20Sopenharmony_ci from_rsvd = 0; 4008c2ecf20Sopenharmony_ci } else { 4018c2ecf20Sopenharmony_ci /* portion may need to be returned to reserved area */ 4028c2ecf20Sopenharmony_ci if (allocated - guaranteed > 0) 4038c2ecf20Sopenharmony_ci from_rsvd = count - (allocated - guaranteed); 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci from_rsvd = count; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (port > 0) { 4098c2ecf20Sopenharmony_ci res_alloc->allocated[(port - 1) * 4108c2ecf20Sopenharmony_ci (dev->persist->num_vfs + 1) + slave] -= count; 4118c2ecf20Sopenharmony_ci res_alloc->res_port_free[port - 1] += count; 4128c2ecf20Sopenharmony_ci res_alloc->res_port_rsvd[port - 1] += from_rsvd; 4138c2ecf20Sopenharmony_ci } else { 4148c2ecf20Sopenharmony_ci res_alloc->allocated[slave] -= count; 4158c2ecf20Sopenharmony_ci res_alloc->res_free += count; 4168c2ecf20Sopenharmony_ci res_alloc->res_reserved += from_rsvd; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci spin_unlock(&res_alloc->alloc_lock); 4208c2ecf20Sopenharmony_ci return; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic inline void initialize_res_quotas(struct mlx4_dev *dev, 4248c2ecf20Sopenharmony_ci struct resource_allocator *res_alloc, 4258c2ecf20Sopenharmony_ci enum mlx4_resource res_type, 4268c2ecf20Sopenharmony_ci int vf, int num_instances) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci res_alloc->guaranteed[vf] = num_instances / 4298c2ecf20Sopenharmony_ci (2 * (dev->persist->num_vfs + 1)); 4308c2ecf20Sopenharmony_ci res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; 4318c2ecf20Sopenharmony_ci if (vf == mlx4_master_func_num(dev)) { 4328c2ecf20Sopenharmony_ci res_alloc->res_free = num_instances; 4338c2ecf20Sopenharmony_ci if (res_type == RES_MTT) { 4348c2ecf20Sopenharmony_ci /* reserved mtts will be taken out of the PF allocation */ 4358c2ecf20Sopenharmony_ci res_alloc->res_free += dev->caps.reserved_mtts; 4368c2ecf20Sopenharmony_ci res_alloc->guaranteed[vf] += dev->caps.reserved_mtts; 4378c2ecf20Sopenharmony_ci res_alloc->quota[vf] += dev->caps.reserved_mtts; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_civoid mlx4_init_quotas(struct mlx4_dev *dev) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 4458c2ecf20Sopenharmony_ci int pf; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* quotas for VFs are initialized in mlx4_slave_cap */ 4488c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev)) 4498c2ecf20Sopenharmony_ci return; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!mlx4_is_mfunc(dev)) { 4528c2ecf20Sopenharmony_ci dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps - 4538c2ecf20Sopenharmony_ci mlx4_num_reserved_sqps(dev); 4548c2ecf20Sopenharmony_ci dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs; 4558c2ecf20Sopenharmony_ci dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs; 4568c2ecf20Sopenharmony_ci dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts; 4578c2ecf20Sopenharmony_ci dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws; 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci pf = mlx4_master_func_num(dev); 4628c2ecf20Sopenharmony_ci dev->quotas.qp = 4638c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf]; 4648c2ecf20Sopenharmony_ci dev->quotas.cq = 4658c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf]; 4668c2ecf20Sopenharmony_ci dev->quotas.srq = 4678c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf]; 4688c2ecf20Sopenharmony_ci dev->quotas.mtt = 4698c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf]; 4708c2ecf20Sopenharmony_ci dev->quotas.mpt = 4718c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int 4758c2ecf20Sopenharmony_cimlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev, 4768c2ecf20Sopenharmony_ci struct resource_allocator *res_alloc, 4778c2ecf20Sopenharmony_ci int vf) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports; 4808c2ecf20Sopenharmony_ci int ports, counters_guaranteed; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* For master, only allocate according to the number of phys ports */ 4838c2ecf20Sopenharmony_ci if (vf == mlx4_master_func_num(dev)) 4848c2ecf20Sopenharmony_ci return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* calculate real number of ports for the VF */ 4878c2ecf20Sopenharmony_ci actv_ports = mlx4_get_active_ports(dev, vf); 4888c2ecf20Sopenharmony_ci ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports); 4898c2ecf20Sopenharmony_ci counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* If we do not have enough counters for this VF, do not 4928c2ecf20Sopenharmony_ci * allocate any for it. '-1' to reduce the sink counter. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci if ((res_alloc->res_reserved + counters_guaranteed) > 4958c2ecf20Sopenharmony_ci (dev->caps.max_counters - 1)) 4968c2ecf20Sopenharmony_ci return 0; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return counters_guaranteed; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ciint mlx4_init_resource_tracker(struct mlx4_dev *dev) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 5048c2ecf20Sopenharmony_ci int i, j; 5058c2ecf20Sopenharmony_ci int t; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.slave_list = 5088c2ecf20Sopenharmony_ci kcalloc(dev->num_slaves, sizeof(struct slave_list), 5098c2ecf20Sopenharmony_ci GFP_KERNEL); 5108c2ecf20Sopenharmony_ci if (!priv->mfunc.master.res_tracker.slave_list) 5118c2ecf20Sopenharmony_ci return -ENOMEM; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci for (i = 0 ; i < dev->num_slaves; i++) { 5148c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t) 5158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->mfunc.master.res_tracker. 5168c2ecf20Sopenharmony_ci slave_list[i].res_list[t]); 5178c2ecf20Sopenharmony_ci mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n", 5218c2ecf20Sopenharmony_ci dev->num_slaves); 5228c2ecf20Sopenharmony_ci for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) 5238c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 5268c2ecf20Sopenharmony_ci struct resource_allocator *res_alloc = 5278c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker.res_alloc[i]; 5288c2ecf20Sopenharmony_ci res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1, 5298c2ecf20Sopenharmony_ci sizeof(int), 5308c2ecf20Sopenharmony_ci GFP_KERNEL); 5318c2ecf20Sopenharmony_ci res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1, 5328c2ecf20Sopenharmony_ci sizeof(int), 5338c2ecf20Sopenharmony_ci GFP_KERNEL); 5348c2ecf20Sopenharmony_ci if (i == RES_MAC || i == RES_VLAN) 5358c2ecf20Sopenharmony_ci res_alloc->allocated = 5368c2ecf20Sopenharmony_ci kcalloc(MLX4_MAX_PORTS * 5378c2ecf20Sopenharmony_ci (dev->persist->num_vfs + 1), 5388c2ecf20Sopenharmony_ci sizeof(int), GFP_KERNEL); 5398c2ecf20Sopenharmony_ci else 5408c2ecf20Sopenharmony_ci res_alloc->allocated = 5418c2ecf20Sopenharmony_ci kcalloc(dev->persist->num_vfs + 1, 5428c2ecf20Sopenharmony_ci sizeof(int), GFP_KERNEL); 5438c2ecf20Sopenharmony_ci /* Reduce the sink counter */ 5448c2ecf20Sopenharmony_ci if (i == RES_COUNTER) 5458c2ecf20Sopenharmony_ci res_alloc->res_free = dev->caps.max_counters - 1; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (!res_alloc->quota || !res_alloc->guaranteed || 5488c2ecf20Sopenharmony_ci !res_alloc->allocated) 5498c2ecf20Sopenharmony_ci goto no_mem_err; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci spin_lock_init(&res_alloc->alloc_lock); 5528c2ecf20Sopenharmony_ci for (t = 0; t < dev->persist->num_vfs + 1; t++) { 5538c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = 5548c2ecf20Sopenharmony_ci mlx4_get_active_ports(dev, t); 5558c2ecf20Sopenharmony_ci switch (i) { 5568c2ecf20Sopenharmony_ci case RES_QP: 5578c2ecf20Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_QP, 5588c2ecf20Sopenharmony_ci t, dev->caps.num_qps - 5598c2ecf20Sopenharmony_ci dev->caps.reserved_qps - 5608c2ecf20Sopenharmony_ci mlx4_num_reserved_sqps(dev)); 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case RES_CQ: 5638c2ecf20Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_CQ, 5648c2ecf20Sopenharmony_ci t, dev->caps.num_cqs - 5658c2ecf20Sopenharmony_ci dev->caps.reserved_cqs); 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci case RES_SRQ: 5688c2ecf20Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_SRQ, 5698c2ecf20Sopenharmony_ci t, dev->caps.num_srqs - 5708c2ecf20Sopenharmony_ci dev->caps.reserved_srqs); 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci case RES_MPT: 5738c2ecf20Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_MPT, 5748c2ecf20Sopenharmony_ci t, dev->caps.num_mpts - 5758c2ecf20Sopenharmony_ci dev->caps.reserved_mrws); 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci case RES_MTT: 5788c2ecf20Sopenharmony_ci initialize_res_quotas(dev, res_alloc, RES_MTT, 5798c2ecf20Sopenharmony_ci t, dev->caps.num_mtts - 5808c2ecf20Sopenharmony_ci dev->caps.reserved_mtts); 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci case RES_MAC: 5838c2ecf20Sopenharmony_ci if (t == mlx4_master_func_num(dev)) { 5848c2ecf20Sopenharmony_ci int max_vfs_pport = 0; 5858c2ecf20Sopenharmony_ci /* Calculate the max vfs per port for */ 5868c2ecf20Sopenharmony_ci /* both ports. */ 5878c2ecf20Sopenharmony_ci for (j = 0; j < dev->caps.num_ports; 5888c2ecf20Sopenharmony_ci j++) { 5898c2ecf20Sopenharmony_ci struct mlx4_slaves_pport slaves_pport = 5908c2ecf20Sopenharmony_ci mlx4_phys_to_slaves_pport(dev, j + 1); 5918c2ecf20Sopenharmony_ci unsigned current_slaves = 5928c2ecf20Sopenharmony_ci bitmap_weight(slaves_pport.slaves, 5938c2ecf20Sopenharmony_ci dev->caps.num_ports) - 1; 5948c2ecf20Sopenharmony_ci if (max_vfs_pport < current_slaves) 5958c2ecf20Sopenharmony_ci max_vfs_pport = 5968c2ecf20Sopenharmony_ci current_slaves; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci res_alloc->quota[t] = 5998c2ecf20Sopenharmony_ci MLX4_MAX_MAC_NUM - 6008c2ecf20Sopenharmony_ci 2 * max_vfs_pport; 6018c2ecf20Sopenharmony_ci res_alloc->guaranteed[t] = 2; 6028c2ecf20Sopenharmony_ci for (j = 0; j < MLX4_MAX_PORTS; j++) 6038c2ecf20Sopenharmony_ci res_alloc->res_port_free[j] = 6048c2ecf20Sopenharmony_ci MLX4_MAX_MAC_NUM; 6058c2ecf20Sopenharmony_ci } else { 6068c2ecf20Sopenharmony_ci res_alloc->quota[t] = MLX4_MAX_MAC_NUM; 6078c2ecf20Sopenharmony_ci res_alloc->guaranteed[t] = 2; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case RES_VLAN: 6118c2ecf20Sopenharmony_ci if (t == mlx4_master_func_num(dev)) { 6128c2ecf20Sopenharmony_ci res_alloc->quota[t] = MLX4_MAX_VLAN_NUM; 6138c2ecf20Sopenharmony_ci res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2; 6148c2ecf20Sopenharmony_ci for (j = 0; j < MLX4_MAX_PORTS; j++) 6158c2ecf20Sopenharmony_ci res_alloc->res_port_free[j] = 6168c2ecf20Sopenharmony_ci res_alloc->quota[t]; 6178c2ecf20Sopenharmony_ci } else { 6188c2ecf20Sopenharmony_ci res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2; 6198c2ecf20Sopenharmony_ci res_alloc->guaranteed[t] = 0; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci case RES_COUNTER: 6238c2ecf20Sopenharmony_ci res_alloc->quota[t] = dev->caps.max_counters; 6248c2ecf20Sopenharmony_ci res_alloc->guaranteed[t] = 6258c2ecf20Sopenharmony_ci mlx4_calc_res_counter_guaranteed(dev, res_alloc, t); 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci default: 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci if (i == RES_MAC || i == RES_VLAN) { 6318c2ecf20Sopenharmony_ci for (j = 0; j < dev->caps.num_ports; j++) 6328c2ecf20Sopenharmony_ci if (test_bit(j, actv_ports.ports)) 6338c2ecf20Sopenharmony_ci res_alloc->res_port_rsvd[j] += 6348c2ecf20Sopenharmony_ci res_alloc->guaranteed[t]; 6358c2ecf20Sopenharmony_ci } else { 6368c2ecf20Sopenharmony_ci res_alloc->res_reserved += res_alloc->guaranteed[t]; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci spin_lock_init(&priv->mfunc.master.res_tracker.lock); 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cino_mem_err: 6448c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 6458c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 6468c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 6478c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 6488c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 6498c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 6508c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci return -ENOMEM; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_civoid mlx4_free_resource_tracker(struct mlx4_dev *dev, 6568c2ecf20Sopenharmony_ci enum mlx4_res_tracker_free_type type) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 6598c2ecf20Sopenharmony_ci int i; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (priv->mfunc.master.res_tracker.slave_list) { 6628c2ecf20Sopenharmony_ci if (type != RES_TR_FREE_STRUCTS_ONLY) { 6638c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_slaves; i++) { 6648c2ecf20Sopenharmony_ci if (type == RES_TR_FREE_ALL || 6658c2ecf20Sopenharmony_ci dev->caps.function != i) 6668c2ecf20Sopenharmony_ci mlx4_delete_all_resources_for_slave(dev, i); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci /* free master's vlans */ 6698c2ecf20Sopenharmony_ci i = dev->caps.function; 6708c2ecf20Sopenharmony_ci mlx4_reset_roce_gids(dev, i); 6718c2ecf20Sopenharmony_ci mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 6728c2ecf20Sopenharmony_ci rem_slave_vlans(dev, i); 6738c2ecf20Sopenharmony_ci mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (type != RES_TR_FREE_SLAVES_ONLY) { 6778c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 6788c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 6798c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 6808c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 6818c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 6828c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 6838c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.res_tracker.slave_list); 6868c2ecf20Sopenharmony_ci priv->mfunc.master.res_tracker.slave_list = NULL; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic void update_pkey_index(struct mlx4_dev *dev, int slave, 6928c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci u8 sched = *(u8 *)(inbox->buf + 64); 6958c2ecf20Sopenharmony_ci u8 orig_index = *(u8 *)(inbox->buf + 35); 6968c2ecf20Sopenharmony_ci u8 new_index; 6978c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 6988c2ecf20Sopenharmony_ci int port; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci port = (sched >> 6 & 1) + 1; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci new_index = priv->virt2phys_pkey[slave][port - 1][orig_index]; 7038c2ecf20Sopenharmony_ci *(u8 *)(inbox->buf + 35) = new_index; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, 7078c2ecf20Sopenharmony_ci u8 slave) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct mlx4_qp_context *qp_ctx = inbox->buf + 8; 7108c2ecf20Sopenharmony_ci enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); 7118c2ecf20Sopenharmony_ci u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 7128c2ecf20Sopenharmony_ci int port; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (MLX4_QP_ST_UD == ts) { 7158c2ecf20Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 7168c2ecf20Sopenharmony_ci if (mlx4_is_eth(dev, port)) 7178c2ecf20Sopenharmony_ci qp_ctx->pri_path.mgid_index = 7188c2ecf20Sopenharmony_ci mlx4_get_base_gid_ix(dev, slave, port) | 0x80; 7198c2ecf20Sopenharmony_ci else 7208c2ecf20Sopenharmony_ci qp_ctx->pri_path.mgid_index = slave | 0x80; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) { 7238c2ecf20Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 7248c2ecf20Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 7258c2ecf20Sopenharmony_ci if (mlx4_is_eth(dev, port)) { 7268c2ecf20Sopenharmony_ci qp_ctx->pri_path.mgid_index += 7278c2ecf20Sopenharmony_ci mlx4_get_base_gid_ix(dev, slave, port); 7288c2ecf20Sopenharmony_ci qp_ctx->pri_path.mgid_index &= 0x7f; 7298c2ecf20Sopenharmony_ci } else { 7308c2ecf20Sopenharmony_ci qp_ctx->pri_path.mgid_index = slave & 0x7F; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 7348c2ecf20Sopenharmony_ci port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 7358c2ecf20Sopenharmony_ci if (mlx4_is_eth(dev, port)) { 7368c2ecf20Sopenharmony_ci qp_ctx->alt_path.mgid_index += 7378c2ecf20Sopenharmony_ci mlx4_get_base_gid_ix(dev, slave, port); 7388c2ecf20Sopenharmony_ci qp_ctx->alt_path.mgid_index &= 0x7f; 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci qp_ctx->alt_path.mgid_index = slave & 0x7F; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc, 7478c2ecf20Sopenharmony_ci u8 slave, int port); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int update_vport_qp_param(struct mlx4_dev *dev, 7508c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 7518c2ecf20Sopenharmony_ci u8 slave, u32 qpn) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc = inbox->buf + 8; 7548c2ecf20Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 7558c2ecf20Sopenharmony_ci struct mlx4_priv *priv; 7568c2ecf20Sopenharmony_ci u32 qp_type; 7578c2ecf20Sopenharmony_ci int port, err = 0; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; 7608c2ecf20Sopenharmony_ci priv = mlx4_priv(dev); 7618c2ecf20Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 7628c2ecf20Sopenharmony_ci qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci err = handle_counter(dev, qpc, slave, port); 7658c2ecf20Sopenharmony_ci if (err) 7668c2ecf20Sopenharmony_ci goto out; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (MLX4_VGT != vp_oper->state.default_vlan) { 7698c2ecf20Sopenharmony_ci /* the reserved QPs (special, proxy, tunnel) 7708c2ecf20Sopenharmony_ci * do not operate over vlans 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (mlx4_is_qp_reserved(dev, qpn)) 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* force strip vlan by clear vsd, MLX QP refers to Raw Ethernet */ 7768c2ecf20Sopenharmony_ci if (qp_type == MLX4_QP_ST_UD || 7778c2ecf20Sopenharmony_ci (qp_type == MLX4_QP_ST_MLX && mlx4_is_eth(dev, port))) { 7788c2ecf20Sopenharmony_ci if (dev->caps.bmme_flags & MLX4_BMME_FLAG_VSD_INIT2RTR) { 7798c2ecf20Sopenharmony_ci *(__be32 *)inbox->buf = 7808c2ecf20Sopenharmony_ci cpu_to_be32(be32_to_cpu(*(__be32 *)inbox->buf) | 7818c2ecf20Sopenharmony_ci MLX4_QP_OPTPAR_VLAN_STRIPPING); 7828c2ecf20Sopenharmony_ci qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); 7838c2ecf20Sopenharmony_ci } else { 7848c2ecf20Sopenharmony_ci struct mlx4_update_qp_params params = {.flags = 0}; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, ¶ms); 7878c2ecf20Sopenharmony_ci if (err) 7888c2ecf20Sopenharmony_ci goto out; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* preserve IF_COUNTER flag */ 7938c2ecf20Sopenharmony_ci qpc->pri_path.vlan_control &= 7948c2ecf20Sopenharmony_ci MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER; 7958c2ecf20Sopenharmony_ci if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE && 7968c2ecf20Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) { 7978c2ecf20Sopenharmony_ci qpc->pri_path.vlan_control |= 7988c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 7998c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 8008c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED | 8018c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 8028c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED | 8038c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 8048c2ecf20Sopenharmony_ci } else if (0 != vp_oper->state.default_vlan) { 8058c2ecf20Sopenharmony_ci if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) { 8068c2ecf20Sopenharmony_ci /* vst QinQ should block untagged on TX, 8078c2ecf20Sopenharmony_ci * but cvlan is in payload and phv is set so 8088c2ecf20Sopenharmony_ci * hw see it as untagged. Block tagged instead. 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci qpc->pri_path.vlan_control |= 8118c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 8128c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 8138c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 8148c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 8158c2ecf20Sopenharmony_ci } else { /* vst 802.1Q */ 8168c2ecf20Sopenharmony_ci qpc->pri_path.vlan_control |= 8178c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 8188c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 8198c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci } else { /* priority tagged */ 8228c2ecf20Sopenharmony_ci qpc->pri_path.vlan_control |= 8238c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 8248c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN; 8288c2ecf20Sopenharmony_ci qpc->pri_path.vlan_index = vp_oper->vlan_idx; 8298c2ecf20Sopenharmony_ci qpc->pri_path.fl |= MLX4_FL_ETH_HIDE_CQE_VLAN; 8308c2ecf20Sopenharmony_ci if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) 8318c2ecf20Sopenharmony_ci qpc->pri_path.fl |= MLX4_FL_SV; 8328c2ecf20Sopenharmony_ci else 8338c2ecf20Sopenharmony_ci qpc->pri_path.fl |= MLX4_FL_CV; 8348c2ecf20Sopenharmony_ci qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 8358c2ecf20Sopenharmony_ci qpc->pri_path.sched_queue &= 0xC7; 8368c2ecf20Sopenharmony_ci qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; 8378c2ecf20Sopenharmony_ci qpc->qos_vport = vp_oper->state.qos_vport; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci if (vp_oper->state.spoofchk) { 8408c2ecf20Sopenharmony_ci qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC; 8418c2ecf20Sopenharmony_ci qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ciout: 8448c2ecf20Sopenharmony_ci return err; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int mpt_mask(struct mlx4_dev *dev) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci return dev->caps.num_mpts - 1; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic const char *mlx4_resource_type_to_str(enum mlx4_resource t) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci switch (t) { 8558c2ecf20Sopenharmony_ci case RES_QP: 8568c2ecf20Sopenharmony_ci return "QP"; 8578c2ecf20Sopenharmony_ci case RES_CQ: 8588c2ecf20Sopenharmony_ci return "CQ"; 8598c2ecf20Sopenharmony_ci case RES_SRQ: 8608c2ecf20Sopenharmony_ci return "SRQ"; 8618c2ecf20Sopenharmony_ci case RES_XRCD: 8628c2ecf20Sopenharmony_ci return "XRCD"; 8638c2ecf20Sopenharmony_ci case RES_MPT: 8648c2ecf20Sopenharmony_ci return "MPT"; 8658c2ecf20Sopenharmony_ci case RES_MTT: 8668c2ecf20Sopenharmony_ci return "MTT"; 8678c2ecf20Sopenharmony_ci case RES_MAC: 8688c2ecf20Sopenharmony_ci return "MAC"; 8698c2ecf20Sopenharmony_ci case RES_VLAN: 8708c2ecf20Sopenharmony_ci return "VLAN"; 8718c2ecf20Sopenharmony_ci case RES_COUNTER: 8728c2ecf20Sopenharmony_ci return "COUNTER"; 8738c2ecf20Sopenharmony_ci case RES_FS_RULE: 8748c2ecf20Sopenharmony_ci return "FS_RULE"; 8758c2ecf20Sopenharmony_ci case RES_EQ: 8768c2ecf20Sopenharmony_ci return "EQ"; 8778c2ecf20Sopenharmony_ci default: 8788c2ecf20Sopenharmony_ci return "INVALID RESOURCE"; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void *find_res(struct mlx4_dev *dev, u64 res_id, 8838c2ecf20Sopenharmony_ci enum mlx4_resource type) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type], 8888c2ecf20Sopenharmony_ci res_id); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int _get_res(struct mlx4_dev *dev, int slave, u64 res_id, 8928c2ecf20Sopenharmony_ci enum mlx4_resource type, 8938c2ecf20Sopenharmony_ci void *res, const char *func_name) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct res_common *r; 8968c2ecf20Sopenharmony_ci int err = 0; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 8998c2ecf20Sopenharmony_ci r = find_res(dev, res_id, type); 9008c2ecf20Sopenharmony_ci if (!r) { 9018c2ecf20Sopenharmony_ci err = -ENONET; 9028c2ecf20Sopenharmony_ci goto exit; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (r->state == RES_ANY_BUSY) { 9068c2ecf20Sopenharmony_ci mlx4_warn(dev, 9078c2ecf20Sopenharmony_ci "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n", 9088c2ecf20Sopenharmony_ci func_name, slave, res_id, mlx4_resource_type_to_str(type), 9098c2ecf20Sopenharmony_ci r->func_name); 9108c2ecf20Sopenharmony_ci err = -EBUSY; 9118c2ecf20Sopenharmony_ci goto exit; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (r->owner != slave) { 9158c2ecf20Sopenharmony_ci err = -EPERM; 9168c2ecf20Sopenharmony_ci goto exit; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci r->from_state = r->state; 9208c2ecf20Sopenharmony_ci r->state = RES_ANY_BUSY; 9218c2ecf20Sopenharmony_ci r->func_name = func_name; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (res) 9248c2ecf20Sopenharmony_ci *((struct res_common **)res) = r; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ciexit: 9278c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 9288c2ecf20Sopenharmony_ci return err; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci#define get_res(dev, slave, res_id, type, res) \ 9328c2ecf20Sopenharmony_ci _get_res((dev), (slave), (res_id), (type), (res), __func__) 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ciint mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, 9358c2ecf20Sopenharmony_ci enum mlx4_resource type, 9368c2ecf20Sopenharmony_ci u64 res_id, int *slave) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci struct res_common *r; 9408c2ecf20Sopenharmony_ci int err = -ENOENT; 9418c2ecf20Sopenharmony_ci int id = res_id; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (type == RES_QP) 9448c2ecf20Sopenharmony_ci id &= 0x7fffff; 9458c2ecf20Sopenharmony_ci spin_lock(mlx4_tlock(dev)); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci r = find_res(dev, id, type); 9488c2ecf20Sopenharmony_ci if (r) { 9498c2ecf20Sopenharmony_ci *slave = r->owner; 9508c2ecf20Sopenharmony_ci err = 0; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci spin_unlock(mlx4_tlock(dev)); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci return err; 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic void put_res(struct mlx4_dev *dev, int slave, u64 res_id, 9588c2ecf20Sopenharmony_ci enum mlx4_resource type) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct res_common *r; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 9638c2ecf20Sopenharmony_ci r = find_res(dev, res_id, type); 9648c2ecf20Sopenharmony_ci if (r) { 9658c2ecf20Sopenharmony_ci r->state = r->from_state; 9668c2ecf20Sopenharmony_ci r->func_name = ""; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 9728c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param, int port); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port, 9758c2ecf20Sopenharmony_ci int counter_index) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci struct res_common *r; 9788c2ecf20Sopenharmony_ci struct res_counter *counter; 9798c2ecf20Sopenharmony_ci int ret = 0; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (counter_index == MLX4_SINK_COUNTER_INDEX(dev)) 9828c2ecf20Sopenharmony_ci return ret; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 9858c2ecf20Sopenharmony_ci r = find_res(dev, counter_index, RES_COUNTER); 9868c2ecf20Sopenharmony_ci if (!r || r->owner != slave) { 9878c2ecf20Sopenharmony_ci ret = -EINVAL; 9888c2ecf20Sopenharmony_ci } else { 9898c2ecf20Sopenharmony_ci counter = container_of(r, struct res_counter, com); 9908c2ecf20Sopenharmony_ci if (!counter->port) 9918c2ecf20Sopenharmony_ci counter->port = port; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 9958c2ecf20Sopenharmony_ci return ret; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int handle_unexisting_counter(struct mlx4_dev *dev, 9998c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc, u8 slave, 10008c2ecf20Sopenharmony_ci int port) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 10038c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 10048c2ecf20Sopenharmony_ci struct res_common *tmp; 10058c2ecf20Sopenharmony_ci struct res_counter *counter; 10068c2ecf20Sopenharmony_ci u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev); 10078c2ecf20Sopenharmony_ci int err = 0; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 10108c2ecf20Sopenharmony_ci list_for_each_entry(tmp, 10118c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_COUNTER], 10128c2ecf20Sopenharmony_ci list) { 10138c2ecf20Sopenharmony_ci counter = container_of(tmp, struct res_counter, com); 10148c2ecf20Sopenharmony_ci if (port == counter->port) { 10158c2ecf20Sopenharmony_ci qpc->pri_path.counter_index = counter->com.res_id; 10168c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 10178c2ecf20Sopenharmony_ci return 0; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* No existing counter, need to allocate a new counter */ 10238c2ecf20Sopenharmony_ci err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx, 10248c2ecf20Sopenharmony_ci port); 10258c2ecf20Sopenharmony_ci if (err == -ENOENT) { 10268c2ecf20Sopenharmony_ci err = 0; 10278c2ecf20Sopenharmony_ci } else if (err && err != -ENOSPC) { 10288c2ecf20Sopenharmony_ci mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n", 10298c2ecf20Sopenharmony_ci __func__, slave, err); 10308c2ecf20Sopenharmony_ci } else { 10318c2ecf20Sopenharmony_ci qpc->pri_path.counter_index = counter_idx; 10328c2ecf20Sopenharmony_ci mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n", 10338c2ecf20Sopenharmony_ci __func__, slave, qpc->pri_path.counter_index); 10348c2ecf20Sopenharmony_ci err = 0; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci return err; 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc, 10418c2ecf20Sopenharmony_ci u8 slave, int port) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev)) 10448c2ecf20Sopenharmony_ci return handle_existing_counter(dev, slave, port, 10458c2ecf20Sopenharmony_ci qpc->pri_path.counter_index); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return handle_unexisting_counter(dev, qpc, slave, port); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic struct res_common *alloc_qp_tr(int id) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct res_qp *ret; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 10558c2ecf20Sopenharmony_ci if (!ret) 10568c2ecf20Sopenharmony_ci return NULL; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci ret->com.res_id = id; 10598c2ecf20Sopenharmony_ci ret->com.state = RES_QP_RESERVED; 10608c2ecf20Sopenharmony_ci ret->local_qpn = id; 10618c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ret->mcg_list); 10628c2ecf20Sopenharmony_ci spin_lock_init(&ret->mcg_spl); 10638c2ecf20Sopenharmony_ci atomic_set(&ret->ref_count, 0); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci return &ret->com; 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic struct res_common *alloc_mtt_tr(int id, int order) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct res_mtt *ret; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 10738c2ecf20Sopenharmony_ci if (!ret) 10748c2ecf20Sopenharmony_ci return NULL; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci ret->com.res_id = id; 10778c2ecf20Sopenharmony_ci ret->order = order; 10788c2ecf20Sopenharmony_ci ret->com.state = RES_MTT_ALLOCATED; 10798c2ecf20Sopenharmony_ci atomic_set(&ret->ref_count, 0); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci return &ret->com; 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic struct res_common *alloc_mpt_tr(int id, int key) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct res_mpt *ret; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 10898c2ecf20Sopenharmony_ci if (!ret) 10908c2ecf20Sopenharmony_ci return NULL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci ret->com.res_id = id; 10938c2ecf20Sopenharmony_ci ret->com.state = RES_MPT_RESERVED; 10948c2ecf20Sopenharmony_ci ret->key = key; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci return &ret->com; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic struct res_common *alloc_eq_tr(int id) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci struct res_eq *ret; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 11048c2ecf20Sopenharmony_ci if (!ret) 11058c2ecf20Sopenharmony_ci return NULL; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci ret->com.res_id = id; 11088c2ecf20Sopenharmony_ci ret->com.state = RES_EQ_RESERVED; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci return &ret->com; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic struct res_common *alloc_cq_tr(int id) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci struct res_cq *ret; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 11188c2ecf20Sopenharmony_ci if (!ret) 11198c2ecf20Sopenharmony_ci return NULL; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci ret->com.res_id = id; 11228c2ecf20Sopenharmony_ci ret->com.state = RES_CQ_ALLOCATED; 11238c2ecf20Sopenharmony_ci atomic_set(&ret->ref_count, 0); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci return &ret->com; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic struct res_common *alloc_srq_tr(int id) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct res_srq *ret; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 11338c2ecf20Sopenharmony_ci if (!ret) 11348c2ecf20Sopenharmony_ci return NULL; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci ret->com.res_id = id; 11378c2ecf20Sopenharmony_ci ret->com.state = RES_SRQ_ALLOCATED; 11388c2ecf20Sopenharmony_ci atomic_set(&ret->ref_count, 0); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return &ret->com; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic struct res_common *alloc_counter_tr(int id, int port) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct res_counter *ret; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 11488c2ecf20Sopenharmony_ci if (!ret) 11498c2ecf20Sopenharmony_ci return NULL; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci ret->com.res_id = id; 11528c2ecf20Sopenharmony_ci ret->com.state = RES_COUNTER_ALLOCATED; 11538c2ecf20Sopenharmony_ci ret->port = port; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return &ret->com; 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic struct res_common *alloc_xrcdn_tr(int id) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct res_xrcdn *ret; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 11638c2ecf20Sopenharmony_ci if (!ret) 11648c2ecf20Sopenharmony_ci return NULL; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci ret->com.res_id = id; 11678c2ecf20Sopenharmony_ci ret->com.state = RES_XRCD_ALLOCATED; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci return &ret->com; 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic struct res_common *alloc_fs_rule_tr(u64 id, int qpn) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct res_fs_rule *ret; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci ret = kzalloc(sizeof(*ret), GFP_KERNEL); 11778c2ecf20Sopenharmony_ci if (!ret) 11788c2ecf20Sopenharmony_ci return NULL; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci ret->com.res_id = id; 11818c2ecf20Sopenharmony_ci ret->com.state = RES_FS_RULE_ALLOCATED; 11828c2ecf20Sopenharmony_ci ret->qpn = qpn; 11838c2ecf20Sopenharmony_ci return &ret->com; 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, 11878c2ecf20Sopenharmony_ci int extra) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct res_common *ret; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci switch (type) { 11928c2ecf20Sopenharmony_ci case RES_QP: 11938c2ecf20Sopenharmony_ci ret = alloc_qp_tr(id); 11948c2ecf20Sopenharmony_ci break; 11958c2ecf20Sopenharmony_ci case RES_MPT: 11968c2ecf20Sopenharmony_ci ret = alloc_mpt_tr(id, extra); 11978c2ecf20Sopenharmony_ci break; 11988c2ecf20Sopenharmony_ci case RES_MTT: 11998c2ecf20Sopenharmony_ci ret = alloc_mtt_tr(id, extra); 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci case RES_EQ: 12028c2ecf20Sopenharmony_ci ret = alloc_eq_tr(id); 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case RES_CQ: 12058c2ecf20Sopenharmony_ci ret = alloc_cq_tr(id); 12068c2ecf20Sopenharmony_ci break; 12078c2ecf20Sopenharmony_ci case RES_SRQ: 12088c2ecf20Sopenharmony_ci ret = alloc_srq_tr(id); 12098c2ecf20Sopenharmony_ci break; 12108c2ecf20Sopenharmony_ci case RES_MAC: 12118c2ecf20Sopenharmony_ci pr_err("implementation missing\n"); 12128c2ecf20Sopenharmony_ci return NULL; 12138c2ecf20Sopenharmony_ci case RES_COUNTER: 12148c2ecf20Sopenharmony_ci ret = alloc_counter_tr(id, extra); 12158c2ecf20Sopenharmony_ci break; 12168c2ecf20Sopenharmony_ci case RES_XRCD: 12178c2ecf20Sopenharmony_ci ret = alloc_xrcdn_tr(id); 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci case RES_FS_RULE: 12208c2ecf20Sopenharmony_ci ret = alloc_fs_rule_tr(id, extra); 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci default: 12238c2ecf20Sopenharmony_ci return NULL; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci if (ret) 12268c2ecf20Sopenharmony_ci ret->owner = slave; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return ret; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ciint mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port, 12328c2ecf20Sopenharmony_ci struct mlx4_counter *data) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 12358c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 12368c2ecf20Sopenharmony_ci struct res_common *tmp; 12378c2ecf20Sopenharmony_ci struct res_counter *counter; 12388c2ecf20Sopenharmony_ci int *counters_arr; 12398c2ecf20Sopenharmony_ci int i = 0, err = 0; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci counters_arr = kmalloc_array(dev->caps.max_counters, 12448c2ecf20Sopenharmony_ci sizeof(*counters_arr), GFP_KERNEL); 12458c2ecf20Sopenharmony_ci if (!counters_arr) 12468c2ecf20Sopenharmony_ci return -ENOMEM; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 12498c2ecf20Sopenharmony_ci list_for_each_entry(tmp, 12508c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_COUNTER], 12518c2ecf20Sopenharmony_ci list) { 12528c2ecf20Sopenharmony_ci counter = container_of(tmp, struct res_counter, com); 12538c2ecf20Sopenharmony_ci if (counter->port == port) { 12548c2ecf20Sopenharmony_ci counters_arr[i] = (int)tmp->res_id; 12558c2ecf20Sopenharmony_ci i++; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 12598c2ecf20Sopenharmony_ci counters_arr[i] = -1; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci i = 0; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci while (counters_arr[i] != -1) { 12648c2ecf20Sopenharmony_ci err = mlx4_get_counter_stats(dev, counters_arr[i], data, 12658c2ecf20Sopenharmony_ci 0); 12668c2ecf20Sopenharmony_ci if (err) { 12678c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 12688c2ecf20Sopenharmony_ci goto table_changed; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci i++; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_citable_changed: 12748c2ecf20Sopenharmony_ci kfree(counters_arr); 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 12798c2ecf20Sopenharmony_ci enum mlx4_resource type, int extra) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci int i; 12828c2ecf20Sopenharmony_ci int err; 12838c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 12848c2ecf20Sopenharmony_ci struct res_common **res_arr; 12858c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 12868c2ecf20Sopenharmony_ci struct rb_root *root = &tracker->res_tree[type]; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci res_arr = kcalloc(count, sizeof(*res_arr), GFP_KERNEL); 12898c2ecf20Sopenharmony_ci if (!res_arr) 12908c2ecf20Sopenharmony_ci return -ENOMEM; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) { 12938c2ecf20Sopenharmony_ci res_arr[i] = alloc_tr(base + i, type, slave, extra); 12948c2ecf20Sopenharmony_ci if (!res_arr[i]) { 12958c2ecf20Sopenharmony_ci for (--i; i >= 0; --i) 12968c2ecf20Sopenharmony_ci kfree(res_arr[i]); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci kfree(res_arr); 12998c2ecf20Sopenharmony_ci return -ENOMEM; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 13048c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) { 13058c2ecf20Sopenharmony_ci if (find_res(dev, base + i, type)) { 13068c2ecf20Sopenharmony_ci err = -EEXIST; 13078c2ecf20Sopenharmony_ci goto undo; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci err = res_tracker_insert(root, res_arr[i]); 13108c2ecf20Sopenharmony_ci if (err) 13118c2ecf20Sopenharmony_ci goto undo; 13128c2ecf20Sopenharmony_ci list_add_tail(&res_arr[i]->list, 13138c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[type]); 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 13168c2ecf20Sopenharmony_ci kfree(res_arr); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return 0; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ciundo: 13218c2ecf20Sopenharmony_ci for (--i; i >= 0; --i) { 13228c2ecf20Sopenharmony_ci rb_erase(&res_arr[i]->node, root); 13238c2ecf20Sopenharmony_ci list_del_init(&res_arr[i]->list); 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) 13298c2ecf20Sopenharmony_ci kfree(res_arr[i]); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci kfree(res_arr); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci return err; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic int remove_qp_ok(struct res_qp *res) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || 13398c2ecf20Sopenharmony_ci !list_empty(&res->mcg_list)) { 13408c2ecf20Sopenharmony_ci pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", 13418c2ecf20Sopenharmony_ci res->com.state, atomic_read(&res->ref_count)); 13428c2ecf20Sopenharmony_ci return -EBUSY; 13438c2ecf20Sopenharmony_ci } else if (res->com.state != RES_QP_RESERVED) { 13448c2ecf20Sopenharmony_ci return -EPERM; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic int remove_mtt_ok(struct res_mtt *res, int order) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci if (res->com.state == RES_MTT_BUSY || 13538c2ecf20Sopenharmony_ci atomic_read(&res->ref_count)) { 13548c2ecf20Sopenharmony_ci pr_devel("%s-%d: state %s, ref_count %d\n", 13558c2ecf20Sopenharmony_ci __func__, __LINE__, 13568c2ecf20Sopenharmony_ci mtt_states_str(res->com.state), 13578c2ecf20Sopenharmony_ci atomic_read(&res->ref_count)); 13588c2ecf20Sopenharmony_ci return -EBUSY; 13598c2ecf20Sopenharmony_ci } else if (res->com.state != RES_MTT_ALLOCATED) 13608c2ecf20Sopenharmony_ci return -EPERM; 13618c2ecf20Sopenharmony_ci else if (res->order != order) 13628c2ecf20Sopenharmony_ci return -EINVAL; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci return 0; 13658c2ecf20Sopenharmony_ci} 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_cistatic int remove_mpt_ok(struct res_mpt *res) 13688c2ecf20Sopenharmony_ci{ 13698c2ecf20Sopenharmony_ci if (res->com.state == RES_MPT_BUSY) 13708c2ecf20Sopenharmony_ci return -EBUSY; 13718c2ecf20Sopenharmony_ci else if (res->com.state != RES_MPT_RESERVED) 13728c2ecf20Sopenharmony_ci return -EPERM; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return 0; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic int remove_eq_ok(struct res_eq *res) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci if (res->com.state == RES_MPT_BUSY) 13808c2ecf20Sopenharmony_ci return -EBUSY; 13818c2ecf20Sopenharmony_ci else if (res->com.state != RES_MPT_RESERVED) 13828c2ecf20Sopenharmony_ci return -EPERM; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci return 0; 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic int remove_counter_ok(struct res_counter *res) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci if (res->com.state == RES_COUNTER_BUSY) 13908c2ecf20Sopenharmony_ci return -EBUSY; 13918c2ecf20Sopenharmony_ci else if (res->com.state != RES_COUNTER_ALLOCATED) 13928c2ecf20Sopenharmony_ci return -EPERM; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int remove_xrcdn_ok(struct res_xrcdn *res) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci if (res->com.state == RES_XRCD_BUSY) 14008c2ecf20Sopenharmony_ci return -EBUSY; 14018c2ecf20Sopenharmony_ci else if (res->com.state != RES_XRCD_ALLOCATED) 14028c2ecf20Sopenharmony_ci return -EPERM; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return 0; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic int remove_fs_rule_ok(struct res_fs_rule *res) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci if (res->com.state == RES_FS_RULE_BUSY) 14108c2ecf20Sopenharmony_ci return -EBUSY; 14118c2ecf20Sopenharmony_ci else if (res->com.state != RES_FS_RULE_ALLOCATED) 14128c2ecf20Sopenharmony_ci return -EPERM; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci return 0; 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic int remove_cq_ok(struct res_cq *res) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci if (res->com.state == RES_CQ_BUSY) 14208c2ecf20Sopenharmony_ci return -EBUSY; 14218c2ecf20Sopenharmony_ci else if (res->com.state != RES_CQ_ALLOCATED) 14228c2ecf20Sopenharmony_ci return -EPERM; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci return 0; 14258c2ecf20Sopenharmony_ci} 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_cistatic int remove_srq_ok(struct res_srq *res) 14288c2ecf20Sopenharmony_ci{ 14298c2ecf20Sopenharmony_ci if (res->com.state == RES_SRQ_BUSY) 14308c2ecf20Sopenharmony_ci return -EBUSY; 14318c2ecf20Sopenharmony_ci else if (res->com.state != RES_SRQ_ALLOCATED) 14328c2ecf20Sopenharmony_ci return -EPERM; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci return 0; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci switch (type) { 14408c2ecf20Sopenharmony_ci case RES_QP: 14418c2ecf20Sopenharmony_ci return remove_qp_ok((struct res_qp *)res); 14428c2ecf20Sopenharmony_ci case RES_CQ: 14438c2ecf20Sopenharmony_ci return remove_cq_ok((struct res_cq *)res); 14448c2ecf20Sopenharmony_ci case RES_SRQ: 14458c2ecf20Sopenharmony_ci return remove_srq_ok((struct res_srq *)res); 14468c2ecf20Sopenharmony_ci case RES_MPT: 14478c2ecf20Sopenharmony_ci return remove_mpt_ok((struct res_mpt *)res); 14488c2ecf20Sopenharmony_ci case RES_MTT: 14498c2ecf20Sopenharmony_ci return remove_mtt_ok((struct res_mtt *)res, extra); 14508c2ecf20Sopenharmony_ci case RES_MAC: 14518c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14528c2ecf20Sopenharmony_ci case RES_EQ: 14538c2ecf20Sopenharmony_ci return remove_eq_ok((struct res_eq *)res); 14548c2ecf20Sopenharmony_ci case RES_COUNTER: 14558c2ecf20Sopenharmony_ci return remove_counter_ok((struct res_counter *)res); 14568c2ecf20Sopenharmony_ci case RES_XRCD: 14578c2ecf20Sopenharmony_ci return remove_xrcdn_ok((struct res_xrcdn *)res); 14588c2ecf20Sopenharmony_ci case RES_FS_RULE: 14598c2ecf20Sopenharmony_ci return remove_fs_rule_ok((struct res_fs_rule *)res); 14608c2ecf20Sopenharmony_ci default: 14618c2ecf20Sopenharmony_ci return -EINVAL; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 14668c2ecf20Sopenharmony_ci enum mlx4_resource type, int extra) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci u64 i; 14698c2ecf20Sopenharmony_ci int err; 14708c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 14718c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 14728c2ecf20Sopenharmony_ci struct res_common *r; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 14758c2ecf20Sopenharmony_ci for (i = base; i < base + count; ++i) { 14768c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], i); 14778c2ecf20Sopenharmony_ci if (!r) { 14788c2ecf20Sopenharmony_ci err = -ENOENT; 14798c2ecf20Sopenharmony_ci goto out; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci if (r->owner != slave) { 14828c2ecf20Sopenharmony_ci err = -EPERM; 14838c2ecf20Sopenharmony_ci goto out; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci err = remove_ok(r, type, extra); 14868c2ecf20Sopenharmony_ci if (err) 14878c2ecf20Sopenharmony_ci goto out; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci for (i = base; i < base + count; ++i) { 14918c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], i); 14928c2ecf20Sopenharmony_ci rb_erase(&r->node, &tracker->res_tree[type]); 14938c2ecf20Sopenharmony_ci list_del(&r->list); 14948c2ecf20Sopenharmony_ci kfree(r); 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci err = 0; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ciout: 14998c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci return err; 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn, 15058c2ecf20Sopenharmony_ci enum res_qp_states state, struct res_qp **qp, 15068c2ecf20Sopenharmony_ci int alloc) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 15098c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 15108c2ecf20Sopenharmony_ci struct res_qp *r; 15118c2ecf20Sopenharmony_ci int err = 0; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 15148c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn); 15158c2ecf20Sopenharmony_ci if (!r) 15168c2ecf20Sopenharmony_ci err = -ENOENT; 15178c2ecf20Sopenharmony_ci else if (r->com.owner != slave) 15188c2ecf20Sopenharmony_ci err = -EPERM; 15198c2ecf20Sopenharmony_ci else { 15208c2ecf20Sopenharmony_ci switch (state) { 15218c2ecf20Sopenharmony_ci case RES_QP_BUSY: 15228c2ecf20Sopenharmony_ci mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n", 15238c2ecf20Sopenharmony_ci __func__, r->com.res_id); 15248c2ecf20Sopenharmony_ci err = -EBUSY; 15258c2ecf20Sopenharmony_ci break; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci case RES_QP_RESERVED: 15288c2ecf20Sopenharmony_ci if (r->com.state == RES_QP_MAPPED && !alloc) 15298c2ecf20Sopenharmony_ci break; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id); 15328c2ecf20Sopenharmony_ci err = -EINVAL; 15338c2ecf20Sopenharmony_ci break; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci case RES_QP_MAPPED: 15368c2ecf20Sopenharmony_ci if ((r->com.state == RES_QP_RESERVED && alloc) || 15378c2ecf20Sopenharmony_ci r->com.state == RES_QP_HW) 15388c2ecf20Sopenharmony_ci break; 15398c2ecf20Sopenharmony_ci else { 15408c2ecf20Sopenharmony_ci mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", 15418c2ecf20Sopenharmony_ci r->com.res_id); 15428c2ecf20Sopenharmony_ci err = -EINVAL; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci break; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci case RES_QP_HW: 15488c2ecf20Sopenharmony_ci if (r->com.state != RES_QP_MAPPED) 15498c2ecf20Sopenharmony_ci err = -EINVAL; 15508c2ecf20Sopenharmony_ci break; 15518c2ecf20Sopenharmony_ci default: 15528c2ecf20Sopenharmony_ci err = -EINVAL; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (!err) { 15568c2ecf20Sopenharmony_ci r->com.from_state = r->com.state; 15578c2ecf20Sopenharmony_ci r->com.to_state = state; 15588c2ecf20Sopenharmony_ci r->com.state = RES_QP_BUSY; 15598c2ecf20Sopenharmony_ci if (qp) 15608c2ecf20Sopenharmony_ci *qp = r; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci return err; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 15708c2ecf20Sopenharmony_ci enum res_mpt_states state, struct res_mpt **mpt) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 15738c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 15748c2ecf20Sopenharmony_ci struct res_mpt *r; 15758c2ecf20Sopenharmony_ci int err = 0; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 15788c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index); 15798c2ecf20Sopenharmony_ci if (!r) 15808c2ecf20Sopenharmony_ci err = -ENOENT; 15818c2ecf20Sopenharmony_ci else if (r->com.owner != slave) 15828c2ecf20Sopenharmony_ci err = -EPERM; 15838c2ecf20Sopenharmony_ci else { 15848c2ecf20Sopenharmony_ci switch (state) { 15858c2ecf20Sopenharmony_ci case RES_MPT_BUSY: 15868c2ecf20Sopenharmony_ci err = -EINVAL; 15878c2ecf20Sopenharmony_ci break; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci case RES_MPT_RESERVED: 15908c2ecf20Sopenharmony_ci if (r->com.state != RES_MPT_MAPPED) 15918c2ecf20Sopenharmony_ci err = -EINVAL; 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci case RES_MPT_MAPPED: 15958c2ecf20Sopenharmony_ci if (r->com.state != RES_MPT_RESERVED && 15968c2ecf20Sopenharmony_ci r->com.state != RES_MPT_HW) 15978c2ecf20Sopenharmony_ci err = -EINVAL; 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci case RES_MPT_HW: 16018c2ecf20Sopenharmony_ci if (r->com.state != RES_MPT_MAPPED) 16028c2ecf20Sopenharmony_ci err = -EINVAL; 16038c2ecf20Sopenharmony_ci break; 16048c2ecf20Sopenharmony_ci default: 16058c2ecf20Sopenharmony_ci err = -EINVAL; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (!err) { 16098c2ecf20Sopenharmony_ci r->com.from_state = r->com.state; 16108c2ecf20Sopenharmony_ci r->com.to_state = state; 16118c2ecf20Sopenharmony_ci r->com.state = RES_MPT_BUSY; 16128c2ecf20Sopenharmony_ci if (mpt) 16138c2ecf20Sopenharmony_ci *mpt = r; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci return err; 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 16238c2ecf20Sopenharmony_ci enum res_eq_states state, struct res_eq **eq) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 16268c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 16278c2ecf20Sopenharmony_ci struct res_eq *r; 16288c2ecf20Sopenharmony_ci int err = 0; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 16318c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index); 16328c2ecf20Sopenharmony_ci if (!r) 16338c2ecf20Sopenharmony_ci err = -ENOENT; 16348c2ecf20Sopenharmony_ci else if (r->com.owner != slave) 16358c2ecf20Sopenharmony_ci err = -EPERM; 16368c2ecf20Sopenharmony_ci else { 16378c2ecf20Sopenharmony_ci switch (state) { 16388c2ecf20Sopenharmony_ci case RES_EQ_BUSY: 16398c2ecf20Sopenharmony_ci err = -EINVAL; 16408c2ecf20Sopenharmony_ci break; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci case RES_EQ_RESERVED: 16438c2ecf20Sopenharmony_ci if (r->com.state != RES_EQ_HW) 16448c2ecf20Sopenharmony_ci err = -EINVAL; 16458c2ecf20Sopenharmony_ci break; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci case RES_EQ_HW: 16488c2ecf20Sopenharmony_ci if (r->com.state != RES_EQ_RESERVED) 16498c2ecf20Sopenharmony_ci err = -EINVAL; 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci default: 16538c2ecf20Sopenharmony_ci err = -EINVAL; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (!err) { 16578c2ecf20Sopenharmony_ci r->com.from_state = r->com.state; 16588c2ecf20Sopenharmony_ci r->com.to_state = state; 16598c2ecf20Sopenharmony_ci r->com.state = RES_EQ_BUSY; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (!err && eq) 16668c2ecf20Sopenharmony_ci *eq = r; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci return err; 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_cistatic int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn, 16728c2ecf20Sopenharmony_ci enum res_cq_states state, struct res_cq **cq) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 16758c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 16768c2ecf20Sopenharmony_ci struct res_cq *r; 16778c2ecf20Sopenharmony_ci int err; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 16808c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn); 16818c2ecf20Sopenharmony_ci if (!r) { 16828c2ecf20Sopenharmony_ci err = -ENOENT; 16838c2ecf20Sopenharmony_ci } else if (r->com.owner != slave) { 16848c2ecf20Sopenharmony_ci err = -EPERM; 16858c2ecf20Sopenharmony_ci } else if (state == RES_CQ_ALLOCATED) { 16868c2ecf20Sopenharmony_ci if (r->com.state != RES_CQ_HW) 16878c2ecf20Sopenharmony_ci err = -EINVAL; 16888c2ecf20Sopenharmony_ci else if (atomic_read(&r->ref_count)) 16898c2ecf20Sopenharmony_ci err = -EBUSY; 16908c2ecf20Sopenharmony_ci else 16918c2ecf20Sopenharmony_ci err = 0; 16928c2ecf20Sopenharmony_ci } else if (state != RES_CQ_HW || r->com.state != RES_CQ_ALLOCATED) { 16938c2ecf20Sopenharmony_ci err = -EINVAL; 16948c2ecf20Sopenharmony_ci } else { 16958c2ecf20Sopenharmony_ci err = 0; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (!err) { 16998c2ecf20Sopenharmony_ci r->com.from_state = r->com.state; 17008c2ecf20Sopenharmony_ci r->com.to_state = state; 17018c2ecf20Sopenharmony_ci r->com.state = RES_CQ_BUSY; 17028c2ecf20Sopenharmony_ci if (cq) 17038c2ecf20Sopenharmony_ci *cq = r; 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci return err; 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 17128c2ecf20Sopenharmony_ci enum res_srq_states state, struct res_srq **srq) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 17158c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 17168c2ecf20Sopenharmony_ci struct res_srq *r; 17178c2ecf20Sopenharmony_ci int err = 0; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 17208c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index); 17218c2ecf20Sopenharmony_ci if (!r) { 17228c2ecf20Sopenharmony_ci err = -ENOENT; 17238c2ecf20Sopenharmony_ci } else if (r->com.owner != slave) { 17248c2ecf20Sopenharmony_ci err = -EPERM; 17258c2ecf20Sopenharmony_ci } else if (state == RES_SRQ_ALLOCATED) { 17268c2ecf20Sopenharmony_ci if (r->com.state != RES_SRQ_HW) 17278c2ecf20Sopenharmony_ci err = -EINVAL; 17288c2ecf20Sopenharmony_ci else if (atomic_read(&r->ref_count)) 17298c2ecf20Sopenharmony_ci err = -EBUSY; 17308c2ecf20Sopenharmony_ci } else if (state != RES_SRQ_HW || r->com.state != RES_SRQ_ALLOCATED) { 17318c2ecf20Sopenharmony_ci err = -EINVAL; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (!err) { 17358c2ecf20Sopenharmony_ci r->com.from_state = r->com.state; 17368c2ecf20Sopenharmony_ci r->com.to_state = state; 17378c2ecf20Sopenharmony_ci r->com.state = RES_SRQ_BUSY; 17388c2ecf20Sopenharmony_ci if (srq) 17398c2ecf20Sopenharmony_ci *srq = r; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci return err; 17458c2ecf20Sopenharmony_ci} 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistatic void res_abort_move(struct mlx4_dev *dev, int slave, 17488c2ecf20Sopenharmony_ci enum mlx4_resource type, int id) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 17518c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 17528c2ecf20Sopenharmony_ci struct res_common *r; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 17558c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], id); 17568c2ecf20Sopenharmony_ci if (r && (r->owner == slave)) 17578c2ecf20Sopenharmony_ci r->state = r->from_state; 17588c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_cistatic void res_end_move(struct mlx4_dev *dev, int slave, 17628c2ecf20Sopenharmony_ci enum mlx4_resource type, int id) 17638c2ecf20Sopenharmony_ci{ 17648c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 17658c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 17668c2ecf20Sopenharmony_ci struct res_common *r; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 17698c2ecf20Sopenharmony_ci r = res_tracker_lookup(&tracker->res_tree[type], id); 17708c2ecf20Sopenharmony_ci if (r && (r->owner == slave)) 17718c2ecf20Sopenharmony_ci r->state = r->to_state; 17728c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 17738c2ecf20Sopenharmony_ci} 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_cistatic int valid_reserved(struct mlx4_dev *dev, int slave, int qpn) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci return mlx4_is_qp_reserved(dev, qpn) && 17788c2ecf20Sopenharmony_ci (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn)); 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic int fw_reserved(struct mlx4_dev *dev, int qpn) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_cistatic int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 17878c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 17888c2ecf20Sopenharmony_ci{ 17898c2ecf20Sopenharmony_ci int err; 17908c2ecf20Sopenharmony_ci int count; 17918c2ecf20Sopenharmony_ci int align; 17928c2ecf20Sopenharmony_ci int base; 17938c2ecf20Sopenharmony_ci int qpn; 17948c2ecf20Sopenharmony_ci u8 flags; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci switch (op) { 17978c2ecf20Sopenharmony_ci case RES_OP_RESERVE: 17988c2ecf20Sopenharmony_ci count = get_param_l(&in_param) & 0xffffff; 17998c2ecf20Sopenharmony_ci /* Turn off all unsupported QP allocation flags that the 18008c2ecf20Sopenharmony_ci * slave tries to set. 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_ci flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask; 18038c2ecf20Sopenharmony_ci align = get_param_h(&in_param); 18048c2ecf20Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); 18058c2ecf20Sopenharmony_ci if (err) 18068c2ecf20Sopenharmony_ci return err; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci err = __mlx4_qp_reserve_range(dev, count, align, &base, flags); 18098c2ecf20Sopenharmony_ci if (err) { 18108c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_QP, count, 0); 18118c2ecf20Sopenharmony_ci return err; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, base, count, RES_QP, 0); 18158c2ecf20Sopenharmony_ci if (err) { 18168c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_QP, count, 0); 18178c2ecf20Sopenharmony_ci __mlx4_qp_release_range(dev, base, count); 18188c2ecf20Sopenharmony_ci return err; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci set_param_l(out_param, base); 18218c2ecf20Sopenharmony_ci break; 18228c2ecf20Sopenharmony_ci case RES_OP_MAP_ICM: 18238c2ecf20Sopenharmony_ci qpn = get_param_l(&in_param) & 0x7fffff; 18248c2ecf20Sopenharmony_ci if (valid_reserved(dev, slave, qpn)) { 18258c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); 18268c2ecf20Sopenharmony_ci if (err) 18278c2ecf20Sopenharmony_ci return err; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, 18318c2ecf20Sopenharmony_ci NULL, 1); 18328c2ecf20Sopenharmony_ci if (err) 18338c2ecf20Sopenharmony_ci return err; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (!fw_reserved(dev, qpn)) { 18368c2ecf20Sopenharmony_ci err = __mlx4_qp_alloc_icm(dev, qpn); 18378c2ecf20Sopenharmony_ci if (err) { 18388c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_QP, qpn); 18398c2ecf20Sopenharmony_ci return err; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 18448c2ecf20Sopenharmony_ci break; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci default: 18478c2ecf20Sopenharmony_ci err = -EINVAL; 18488c2ecf20Sopenharmony_ci break; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci return err; 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 18548c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci int err = -EINVAL; 18578c2ecf20Sopenharmony_ci int base; 18588c2ecf20Sopenharmony_ci int order; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE_AND_MAP) 18618c2ecf20Sopenharmony_ci return err; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci order = get_param_l(&in_param); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); 18668c2ecf20Sopenharmony_ci if (err) 18678c2ecf20Sopenharmony_ci return err; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci base = __mlx4_alloc_mtt_range(dev, order); 18708c2ecf20Sopenharmony_ci if (base == -1) { 18718c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 18728c2ecf20Sopenharmony_ci return -ENOMEM; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, base, 1, RES_MTT, order); 18768c2ecf20Sopenharmony_ci if (err) { 18778c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 18788c2ecf20Sopenharmony_ci __mlx4_free_mtt_range(dev, base, order); 18798c2ecf20Sopenharmony_ci } else { 18808c2ecf20Sopenharmony_ci set_param_l(out_param, base); 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci return err; 18848c2ecf20Sopenharmony_ci} 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_cistatic int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 18878c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci int err = -EINVAL; 18908c2ecf20Sopenharmony_ci int index; 18918c2ecf20Sopenharmony_ci int id; 18928c2ecf20Sopenharmony_ci struct res_mpt *mpt; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci switch (op) { 18958c2ecf20Sopenharmony_ci case RES_OP_RESERVE: 18968c2ecf20Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); 18978c2ecf20Sopenharmony_ci if (err) 18988c2ecf20Sopenharmony_ci break; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci index = __mlx4_mpt_reserve(dev); 19018c2ecf20Sopenharmony_ci if (index == -1) { 19028c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 19038c2ecf20Sopenharmony_ci break; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, id, 1, RES_MPT, index); 19088c2ecf20Sopenharmony_ci if (err) { 19098c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 19108c2ecf20Sopenharmony_ci __mlx4_mpt_release(dev, index); 19118c2ecf20Sopenharmony_ci break; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci set_param_l(out_param, index); 19148c2ecf20Sopenharmony_ci break; 19158c2ecf20Sopenharmony_ci case RES_OP_MAP_ICM: 19168c2ecf20Sopenharmony_ci index = get_param_l(&in_param); 19178c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 19188c2ecf20Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, 19198c2ecf20Sopenharmony_ci RES_MPT_MAPPED, &mpt); 19208c2ecf20Sopenharmony_ci if (err) 19218c2ecf20Sopenharmony_ci return err; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci err = __mlx4_mpt_alloc_icm(dev, mpt->key); 19248c2ecf20Sopenharmony_ci if (err) { 19258c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_MPT, id); 19268c2ecf20Sopenharmony_ci return err; 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci return err; 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_cistatic int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 19368c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 19378c2ecf20Sopenharmony_ci{ 19388c2ecf20Sopenharmony_ci int cqn; 19398c2ecf20Sopenharmony_ci int err; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci switch (op) { 19428c2ecf20Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 19438c2ecf20Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); 19448c2ecf20Sopenharmony_ci if (err) 19458c2ecf20Sopenharmony_ci break; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci err = __mlx4_cq_alloc_icm(dev, &cqn); 19488c2ecf20Sopenharmony_ci if (err) { 19498c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 19508c2ecf20Sopenharmony_ci break; 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); 19548c2ecf20Sopenharmony_ci if (err) { 19558c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 19568c2ecf20Sopenharmony_ci __mlx4_cq_free_icm(dev, cqn); 19578c2ecf20Sopenharmony_ci break; 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci set_param_l(out_param, cqn); 19618c2ecf20Sopenharmony_ci break; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci default: 19648c2ecf20Sopenharmony_ci err = -EINVAL; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci return err; 19688c2ecf20Sopenharmony_ci} 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_cistatic int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 19718c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 19728c2ecf20Sopenharmony_ci{ 19738c2ecf20Sopenharmony_ci int srqn; 19748c2ecf20Sopenharmony_ci int err; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci switch (op) { 19778c2ecf20Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 19788c2ecf20Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); 19798c2ecf20Sopenharmony_ci if (err) 19808c2ecf20Sopenharmony_ci break; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci err = __mlx4_srq_alloc_icm(dev, &srqn); 19838c2ecf20Sopenharmony_ci if (err) { 19848c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 19858c2ecf20Sopenharmony_ci break; 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 19898c2ecf20Sopenharmony_ci if (err) { 19908c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 19918c2ecf20Sopenharmony_ci __mlx4_srq_free_icm(dev, srqn); 19928c2ecf20Sopenharmony_ci break; 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci set_param_l(out_param, srqn); 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci default: 19998c2ecf20Sopenharmony_ci err = -EINVAL; 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci return err; 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cistatic int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, 20068c2ecf20Sopenharmony_ci u8 smac_index, u64 *mac) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 20098c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 20108c2ecf20Sopenharmony_ci struct list_head *mac_list = 20118c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 20128c2ecf20Sopenharmony_ci struct mac_res *res, *tmp; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 20158c2ecf20Sopenharmony_ci if (res->smac_index == smac_index && res->port == (u8) port) { 20168c2ecf20Sopenharmony_ci *mac = res->mac; 20178c2ecf20Sopenharmony_ci return 0; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci return -ENOENT; 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_cistatic int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 20268c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 20278c2ecf20Sopenharmony_ci struct list_head *mac_list = 20288c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 20298c2ecf20Sopenharmony_ci struct mac_res *res, *tmp; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 20328c2ecf20Sopenharmony_ci if (res->mac == mac && res->port == (u8) port) { 20338c2ecf20Sopenharmony_ci /* mac found. update ref count */ 20348c2ecf20Sopenharmony_ci ++res->ref_count; 20358c2ecf20Sopenharmony_ci return 0; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) 20408c2ecf20Sopenharmony_ci return -EINVAL; 20418c2ecf20Sopenharmony_ci res = kzalloc(sizeof(*res), GFP_KERNEL); 20428c2ecf20Sopenharmony_ci if (!res) { 20438c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MAC, 1, port); 20448c2ecf20Sopenharmony_ci return -ENOMEM; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci res->mac = mac; 20478c2ecf20Sopenharmony_ci res->port = (u8) port; 20488c2ecf20Sopenharmony_ci res->smac_index = smac_index; 20498c2ecf20Sopenharmony_ci res->ref_count = 1; 20508c2ecf20Sopenharmony_ci list_add_tail(&res->list, 20518c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]); 20528c2ecf20Sopenharmony_ci return 0; 20538c2ecf20Sopenharmony_ci} 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_cistatic void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, 20568c2ecf20Sopenharmony_ci int port) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 20598c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 20608c2ecf20Sopenharmony_ci struct list_head *mac_list = 20618c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 20628c2ecf20Sopenharmony_ci struct mac_res *res, *tmp; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 20658c2ecf20Sopenharmony_ci if (res->mac == mac && res->port == (u8) port) { 20668c2ecf20Sopenharmony_ci if (!--res->ref_count) { 20678c2ecf20Sopenharmony_ci list_del(&res->list); 20688c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MAC, 1, port); 20698c2ecf20Sopenharmony_ci kfree(res); 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci break; 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci} 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic void rem_slave_macs(struct mlx4_dev *dev, int slave) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 20798c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 20808c2ecf20Sopenharmony_ci struct list_head *mac_list = 20818c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MAC]; 20828c2ecf20Sopenharmony_ci struct mac_res *res, *tmp; 20838c2ecf20Sopenharmony_ci int i; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, mac_list, list) { 20868c2ecf20Sopenharmony_ci list_del(&res->list); 20878c2ecf20Sopenharmony_ci /* dereference the mac the num times the slave referenced it */ 20888c2ecf20Sopenharmony_ci for (i = 0; i < res->ref_count; i++) 20898c2ecf20Sopenharmony_ci __mlx4_unregister_mac(dev, res->port, res->mac); 20908c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); 20918c2ecf20Sopenharmony_ci kfree(res); 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 20968c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param, int in_port) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci int err = -EINVAL; 20998c2ecf20Sopenharmony_ci int port; 21008c2ecf20Sopenharmony_ci u64 mac; 21018c2ecf20Sopenharmony_ci u8 smac_index; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE_AND_MAP) 21048c2ecf20Sopenharmony_ci return err; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci port = !in_port ? get_param_l(out_param) : in_port; 21078c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port( 21088c2ecf20Sopenharmony_ci dev, slave, port); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci if (port < 0) 21118c2ecf20Sopenharmony_ci return -EINVAL; 21128c2ecf20Sopenharmony_ci mac = in_param; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci err = __mlx4_register_mac(dev, port, mac); 21158c2ecf20Sopenharmony_ci if (err >= 0) { 21168c2ecf20Sopenharmony_ci smac_index = err; 21178c2ecf20Sopenharmony_ci set_param_l(out_param, err); 21188c2ecf20Sopenharmony_ci err = 0; 21198c2ecf20Sopenharmony_ci } 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci if (!err) { 21228c2ecf20Sopenharmony_ci err = mac_add_to_slave(dev, slave, mac, port, smac_index); 21238c2ecf20Sopenharmony_ci if (err) 21248c2ecf20Sopenharmony_ci __mlx4_unregister_mac(dev, port, mac); 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci return err; 21278c2ecf20Sopenharmony_ci} 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_cistatic int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, 21308c2ecf20Sopenharmony_ci int port, int vlan_index) 21318c2ecf20Sopenharmony_ci{ 21328c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 21338c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 21348c2ecf20Sopenharmony_ci struct list_head *vlan_list = 21358c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]; 21368c2ecf20Sopenharmony_ci struct vlan_res *res, *tmp; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, vlan_list, list) { 21398c2ecf20Sopenharmony_ci if (res->vlan == vlan && res->port == (u8) port) { 21408c2ecf20Sopenharmony_ci /* vlan found. update ref count */ 21418c2ecf20Sopenharmony_ci ++res->ref_count; 21428c2ecf20Sopenharmony_ci return 0; 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) 21478c2ecf20Sopenharmony_ci return -EINVAL; 21488c2ecf20Sopenharmony_ci res = kzalloc(sizeof(*res), GFP_KERNEL); 21498c2ecf20Sopenharmony_ci if (!res) { 21508c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_VLAN, 1, port); 21518c2ecf20Sopenharmony_ci return -ENOMEM; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci res->vlan = vlan; 21548c2ecf20Sopenharmony_ci res->port = (u8) port; 21558c2ecf20Sopenharmony_ci res->vlan_index = vlan_index; 21568c2ecf20Sopenharmony_ci res->ref_count = 1; 21578c2ecf20Sopenharmony_ci list_add_tail(&res->list, 21588c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]); 21598c2ecf20Sopenharmony_ci return 0; 21608c2ecf20Sopenharmony_ci} 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_cistatic void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, 21648c2ecf20Sopenharmony_ci int port) 21658c2ecf20Sopenharmony_ci{ 21668c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 21678c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 21688c2ecf20Sopenharmony_ci struct list_head *vlan_list = 21698c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]; 21708c2ecf20Sopenharmony_ci struct vlan_res *res, *tmp; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, vlan_list, list) { 21738c2ecf20Sopenharmony_ci if (res->vlan == vlan && res->port == (u8) port) { 21748c2ecf20Sopenharmony_ci if (!--res->ref_count) { 21758c2ecf20Sopenharmony_ci list_del(&res->list); 21768c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_VLAN, 21778c2ecf20Sopenharmony_ci 1, port); 21788c2ecf20Sopenharmony_ci kfree(res); 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci break; 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_cistatic void rem_slave_vlans(struct mlx4_dev *dev, int slave) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 21888c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 21898c2ecf20Sopenharmony_ci struct list_head *vlan_list = 21908c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_VLAN]; 21918c2ecf20Sopenharmony_ci struct vlan_res *res, *tmp; 21928c2ecf20Sopenharmony_ci int i; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, vlan_list, list) { 21958c2ecf20Sopenharmony_ci list_del(&res->list); 21968c2ecf20Sopenharmony_ci /* dereference the vlan the num times the slave referenced it */ 21978c2ecf20Sopenharmony_ci for (i = 0; i < res->ref_count; i++) 21988c2ecf20Sopenharmony_ci __mlx4_unregister_vlan(dev, res->port, res->vlan); 21998c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); 22008c2ecf20Sopenharmony_ci kfree(res); 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci} 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_cistatic int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 22058c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param, int in_port) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 22088c2ecf20Sopenharmony_ci struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 22098c2ecf20Sopenharmony_ci int err; 22108c2ecf20Sopenharmony_ci u16 vlan; 22118c2ecf20Sopenharmony_ci int vlan_index; 22128c2ecf20Sopenharmony_ci int port; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci port = !in_port ? get_param_l(out_param) : in_port; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci if (!port || op != RES_OP_RESERVE_AND_MAP) 22178c2ecf20Sopenharmony_ci return -EINVAL; 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port( 22208c2ecf20Sopenharmony_ci dev, slave, port); 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (port < 0) 22238c2ecf20Sopenharmony_ci return -EINVAL; 22248c2ecf20Sopenharmony_ci /* upstream kernels had NOP for reg/unreg vlan. Continue this. */ 22258c2ecf20Sopenharmony_ci if (!in_port && port > 0 && port <= dev->caps.num_ports) { 22268c2ecf20Sopenharmony_ci slave_state[slave].old_vlan_api = true; 22278c2ecf20Sopenharmony_ci return 0; 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci vlan = (u16) in_param; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); 22338c2ecf20Sopenharmony_ci if (!err) { 22348c2ecf20Sopenharmony_ci set_param_l(out_param, (u32) vlan_index); 22358c2ecf20Sopenharmony_ci err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); 22368c2ecf20Sopenharmony_ci if (err) 22378c2ecf20Sopenharmony_ci __mlx4_unregister_vlan(dev, port, vlan); 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci return err; 22408c2ecf20Sopenharmony_ci} 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_cistatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 22438c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param, int port) 22448c2ecf20Sopenharmony_ci{ 22458c2ecf20Sopenharmony_ci u32 index; 22468c2ecf20Sopenharmony_ci int err; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE) 22498c2ecf20Sopenharmony_ci return -EINVAL; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0); 22528c2ecf20Sopenharmony_ci if (err) 22538c2ecf20Sopenharmony_ci return err; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci err = __mlx4_counter_alloc(dev, &index); 22568c2ecf20Sopenharmony_ci if (err) { 22578c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 22588c2ecf20Sopenharmony_ci return err; 22598c2ecf20Sopenharmony_ci } 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, index, 1, RES_COUNTER, port); 22628c2ecf20Sopenharmony_ci if (err) { 22638c2ecf20Sopenharmony_ci __mlx4_counter_free(dev, index); 22648c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 22658c2ecf20Sopenharmony_ci } else { 22668c2ecf20Sopenharmony_ci set_param_l(out_param, index); 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci return err; 22708c2ecf20Sopenharmony_ci} 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_cistatic int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 22738c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci u32 xrcdn; 22768c2ecf20Sopenharmony_ci int err; 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE) 22798c2ecf20Sopenharmony_ci return -EINVAL; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci err = __mlx4_xrcd_alloc(dev, &xrcdn); 22828c2ecf20Sopenharmony_ci if (err) 22838c2ecf20Sopenharmony_ci return err; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 22868c2ecf20Sopenharmony_ci if (err) 22878c2ecf20Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 22888c2ecf20Sopenharmony_ci else 22898c2ecf20Sopenharmony_ci set_param_l(out_param, xrcdn); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci return err; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ciint mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, 22958c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 22968c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 22978c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 22988c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 22998c2ecf20Sopenharmony_ci{ 23008c2ecf20Sopenharmony_ci int err; 23018c2ecf20Sopenharmony_ci int alop = vhcr->op_modifier; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci switch (vhcr->in_modifier & 0xFF) { 23048c2ecf20Sopenharmony_ci case RES_QP: 23058c2ecf20Sopenharmony_ci err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, 23068c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 23078c2ecf20Sopenharmony_ci break; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci case RES_MTT: 23108c2ecf20Sopenharmony_ci err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, 23118c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 23128c2ecf20Sopenharmony_ci break; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci case RES_MPT: 23158c2ecf20Sopenharmony_ci err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, 23168c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 23178c2ecf20Sopenharmony_ci break; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci case RES_CQ: 23208c2ecf20Sopenharmony_ci err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, 23218c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 23228c2ecf20Sopenharmony_ci break; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci case RES_SRQ: 23258c2ecf20Sopenharmony_ci err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, 23268c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 23278c2ecf20Sopenharmony_ci break; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci case RES_MAC: 23308c2ecf20Sopenharmony_ci err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, 23318c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 23328c2ecf20Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 23338c2ecf20Sopenharmony_ci break; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci case RES_VLAN: 23368c2ecf20Sopenharmony_ci err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, 23378c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 23388c2ecf20Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 23398c2ecf20Sopenharmony_ci break; 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci case RES_COUNTER: 23428c2ecf20Sopenharmony_ci err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, 23438c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 0); 23448c2ecf20Sopenharmony_ci break; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci case RES_XRCD: 23478c2ecf20Sopenharmony_ci err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, 23488c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 23498c2ecf20Sopenharmony_ci break; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci default: 23528c2ecf20Sopenharmony_ci err = -EINVAL; 23538c2ecf20Sopenharmony_ci break; 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci return err; 23578c2ecf20Sopenharmony_ci} 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cistatic int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 23608c2ecf20Sopenharmony_ci u64 in_param) 23618c2ecf20Sopenharmony_ci{ 23628c2ecf20Sopenharmony_ci int err; 23638c2ecf20Sopenharmony_ci int count; 23648c2ecf20Sopenharmony_ci int base; 23658c2ecf20Sopenharmony_ci int qpn; 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci switch (op) { 23688c2ecf20Sopenharmony_ci case RES_OP_RESERVE: 23698c2ecf20Sopenharmony_ci base = get_param_l(&in_param) & 0x7fffff; 23708c2ecf20Sopenharmony_ci count = get_param_h(&in_param); 23718c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, base, count, RES_QP, 0); 23728c2ecf20Sopenharmony_ci if (err) 23738c2ecf20Sopenharmony_ci break; 23748c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_QP, count, 0); 23758c2ecf20Sopenharmony_ci __mlx4_qp_release_range(dev, base, count); 23768c2ecf20Sopenharmony_ci break; 23778c2ecf20Sopenharmony_ci case RES_OP_MAP_ICM: 23788c2ecf20Sopenharmony_ci qpn = get_param_l(&in_param) & 0x7fffff; 23798c2ecf20Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, 23808c2ecf20Sopenharmony_ci NULL, 0); 23818c2ecf20Sopenharmony_ci if (err) 23828c2ecf20Sopenharmony_ci return err; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci if (!fw_reserved(dev, qpn)) 23858c2ecf20Sopenharmony_ci __mlx4_qp_free_icm(dev, qpn); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci if (valid_reserved(dev, slave, qpn)) 23908c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); 23918c2ecf20Sopenharmony_ci break; 23928c2ecf20Sopenharmony_ci default: 23938c2ecf20Sopenharmony_ci err = -EINVAL; 23948c2ecf20Sopenharmony_ci break; 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci return err; 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_cistatic int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 24008c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci int err = -EINVAL; 24038c2ecf20Sopenharmony_ci int base; 24048c2ecf20Sopenharmony_ci int order; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE_AND_MAP) 24078c2ecf20Sopenharmony_ci return err; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci base = get_param_l(&in_param); 24108c2ecf20Sopenharmony_ci order = get_param_h(&in_param); 24118c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, base, 1, RES_MTT, order); 24128c2ecf20Sopenharmony_ci if (!err) { 24138c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 24148c2ecf20Sopenharmony_ci __mlx4_free_mtt_range(dev, base, order); 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci return err; 24178c2ecf20Sopenharmony_ci} 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_cistatic int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 24208c2ecf20Sopenharmony_ci u64 in_param) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci int err = -EINVAL; 24238c2ecf20Sopenharmony_ci int index; 24248c2ecf20Sopenharmony_ci int id; 24258c2ecf20Sopenharmony_ci struct res_mpt *mpt; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci switch (op) { 24288c2ecf20Sopenharmony_ci case RES_OP_RESERVE: 24298c2ecf20Sopenharmony_ci index = get_param_l(&in_param); 24308c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 24318c2ecf20Sopenharmony_ci err = get_res(dev, slave, id, RES_MPT, &mpt); 24328c2ecf20Sopenharmony_ci if (err) 24338c2ecf20Sopenharmony_ci break; 24348c2ecf20Sopenharmony_ci index = mpt->key; 24358c2ecf20Sopenharmony_ci put_res(dev, slave, id, RES_MPT); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); 24388c2ecf20Sopenharmony_ci if (err) 24398c2ecf20Sopenharmony_ci break; 24408c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 24418c2ecf20Sopenharmony_ci __mlx4_mpt_release(dev, index); 24428c2ecf20Sopenharmony_ci break; 24438c2ecf20Sopenharmony_ci case RES_OP_MAP_ICM: 24448c2ecf20Sopenharmony_ci index = get_param_l(&in_param); 24458c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 24468c2ecf20Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, 24478c2ecf20Sopenharmony_ci RES_MPT_RESERVED, &mpt); 24488c2ecf20Sopenharmony_ci if (err) 24498c2ecf20Sopenharmony_ci return err; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci __mlx4_mpt_free_icm(dev, mpt->key); 24528c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 24538c2ecf20Sopenharmony_ci break; 24548c2ecf20Sopenharmony_ci default: 24558c2ecf20Sopenharmony_ci err = -EINVAL; 24568c2ecf20Sopenharmony_ci break; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci return err; 24598c2ecf20Sopenharmony_ci} 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_cistatic int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 24628c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 24638c2ecf20Sopenharmony_ci{ 24648c2ecf20Sopenharmony_ci int cqn; 24658c2ecf20Sopenharmony_ci int err; 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci switch (op) { 24688c2ecf20Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 24698c2ecf20Sopenharmony_ci cqn = get_param_l(&in_param); 24708c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); 24718c2ecf20Sopenharmony_ci if (err) 24728c2ecf20Sopenharmony_ci break; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 24758c2ecf20Sopenharmony_ci __mlx4_cq_free_icm(dev, cqn); 24768c2ecf20Sopenharmony_ci break; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci default: 24798c2ecf20Sopenharmony_ci err = -EINVAL; 24808c2ecf20Sopenharmony_ci break; 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci return err; 24848c2ecf20Sopenharmony_ci} 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_cistatic int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 24878c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 24888c2ecf20Sopenharmony_ci{ 24898c2ecf20Sopenharmony_ci int srqn; 24908c2ecf20Sopenharmony_ci int err; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci switch (op) { 24938c2ecf20Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 24948c2ecf20Sopenharmony_ci srqn = get_param_l(&in_param); 24958c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 24968c2ecf20Sopenharmony_ci if (err) 24978c2ecf20Sopenharmony_ci break; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 25008c2ecf20Sopenharmony_ci __mlx4_srq_free_icm(dev, srqn); 25018c2ecf20Sopenharmony_ci break; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci default: 25048c2ecf20Sopenharmony_ci err = -EINVAL; 25058c2ecf20Sopenharmony_ci break; 25068c2ecf20Sopenharmony_ci } 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci return err; 25098c2ecf20Sopenharmony_ci} 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_cistatic int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 25128c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param, int in_port) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci int port; 25158c2ecf20Sopenharmony_ci int err = 0; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci switch (op) { 25188c2ecf20Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 25198c2ecf20Sopenharmony_ci port = !in_port ? get_param_l(out_param) : in_port; 25208c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port( 25218c2ecf20Sopenharmony_ci dev, slave, port); 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci if (port < 0) 25248c2ecf20Sopenharmony_ci return -EINVAL; 25258c2ecf20Sopenharmony_ci mac_del_from_slave(dev, slave, in_param, port); 25268c2ecf20Sopenharmony_ci __mlx4_unregister_mac(dev, port, in_param); 25278c2ecf20Sopenharmony_ci break; 25288c2ecf20Sopenharmony_ci default: 25298c2ecf20Sopenharmony_ci err = -EINVAL; 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci return err; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci} 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_cistatic int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 25388c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param, int port) 25398c2ecf20Sopenharmony_ci{ 25408c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 25418c2ecf20Sopenharmony_ci struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 25428c2ecf20Sopenharmony_ci int err = 0; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port( 25458c2ecf20Sopenharmony_ci dev, slave, port); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci if (port < 0) 25488c2ecf20Sopenharmony_ci return -EINVAL; 25498c2ecf20Sopenharmony_ci switch (op) { 25508c2ecf20Sopenharmony_ci case RES_OP_RESERVE_AND_MAP: 25518c2ecf20Sopenharmony_ci if (slave_state[slave].old_vlan_api) 25528c2ecf20Sopenharmony_ci return 0; 25538c2ecf20Sopenharmony_ci if (!port) 25548c2ecf20Sopenharmony_ci return -EINVAL; 25558c2ecf20Sopenharmony_ci vlan_del_from_slave(dev, slave, in_param, port); 25568c2ecf20Sopenharmony_ci __mlx4_unregister_vlan(dev, port, in_param); 25578c2ecf20Sopenharmony_ci break; 25588c2ecf20Sopenharmony_ci default: 25598c2ecf20Sopenharmony_ci err = -EINVAL; 25608c2ecf20Sopenharmony_ci break; 25618c2ecf20Sopenharmony_ci } 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci return err; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_cistatic int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 25678c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 25688c2ecf20Sopenharmony_ci{ 25698c2ecf20Sopenharmony_ci int index; 25708c2ecf20Sopenharmony_ci int err; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE) 25738c2ecf20Sopenharmony_ci return -EINVAL; 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci index = get_param_l(&in_param); 25768c2ecf20Sopenharmony_ci if (index == MLX4_SINK_COUNTER_INDEX(dev)) 25778c2ecf20Sopenharmony_ci return 0; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0); 25808c2ecf20Sopenharmony_ci if (err) 25818c2ecf20Sopenharmony_ci return err; 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci __mlx4_counter_free(dev, index); 25848c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci return err; 25878c2ecf20Sopenharmony_ci} 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_cistatic int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 25908c2ecf20Sopenharmony_ci u64 in_param, u64 *out_param) 25918c2ecf20Sopenharmony_ci{ 25928c2ecf20Sopenharmony_ci int xrcdn; 25938c2ecf20Sopenharmony_ci int err; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci if (op != RES_OP_RESERVE) 25968c2ecf20Sopenharmony_ci return -EINVAL; 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci xrcdn = get_param_l(&in_param); 25998c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 26008c2ecf20Sopenharmony_ci if (err) 26018c2ecf20Sopenharmony_ci return err; 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci return err; 26068c2ecf20Sopenharmony_ci} 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ciint mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, 26098c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 26108c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 26118c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 26128c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 26138c2ecf20Sopenharmony_ci{ 26148c2ecf20Sopenharmony_ci int err = -EINVAL; 26158c2ecf20Sopenharmony_ci int alop = vhcr->op_modifier; 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci switch (vhcr->in_modifier & 0xFF) { 26188c2ecf20Sopenharmony_ci case RES_QP: 26198c2ecf20Sopenharmony_ci err = qp_free_res(dev, slave, vhcr->op_modifier, alop, 26208c2ecf20Sopenharmony_ci vhcr->in_param); 26218c2ecf20Sopenharmony_ci break; 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci case RES_MTT: 26248c2ecf20Sopenharmony_ci err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, 26258c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 26268c2ecf20Sopenharmony_ci break; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci case RES_MPT: 26298c2ecf20Sopenharmony_ci err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, 26308c2ecf20Sopenharmony_ci vhcr->in_param); 26318c2ecf20Sopenharmony_ci break; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci case RES_CQ: 26348c2ecf20Sopenharmony_ci err = cq_free_res(dev, slave, vhcr->op_modifier, alop, 26358c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 26368c2ecf20Sopenharmony_ci break; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci case RES_SRQ: 26398c2ecf20Sopenharmony_ci err = srq_free_res(dev, slave, vhcr->op_modifier, alop, 26408c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 26418c2ecf20Sopenharmony_ci break; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci case RES_MAC: 26448c2ecf20Sopenharmony_ci err = mac_free_res(dev, slave, vhcr->op_modifier, alop, 26458c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 26468c2ecf20Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 26478c2ecf20Sopenharmony_ci break; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci case RES_VLAN: 26508c2ecf20Sopenharmony_ci err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, 26518c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param, 26528c2ecf20Sopenharmony_ci (vhcr->in_modifier >> 8) & 0xFF); 26538c2ecf20Sopenharmony_ci break; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci case RES_COUNTER: 26568c2ecf20Sopenharmony_ci err = counter_free_res(dev, slave, vhcr->op_modifier, alop, 26578c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 26588c2ecf20Sopenharmony_ci break; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci case RES_XRCD: 26618c2ecf20Sopenharmony_ci err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, 26628c2ecf20Sopenharmony_ci vhcr->in_param, &vhcr->out_param); 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci default: 26658c2ecf20Sopenharmony_ci break; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci return err; 26688c2ecf20Sopenharmony_ci} 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci/* ugly but other choices are uglier */ 26718c2ecf20Sopenharmony_cistatic int mr_phys_mpt(struct mlx4_mpt_entry *mpt) 26728c2ecf20Sopenharmony_ci{ 26738c2ecf20Sopenharmony_ci return (be32_to_cpu(mpt->flags) >> 9) & 1; 26748c2ecf20Sopenharmony_ci} 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_cistatic int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) 26778c2ecf20Sopenharmony_ci{ 26788c2ecf20Sopenharmony_ci return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; 26798c2ecf20Sopenharmony_ci} 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_cistatic int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) 26828c2ecf20Sopenharmony_ci{ 26838c2ecf20Sopenharmony_ci return be32_to_cpu(mpt->mtt_sz); 26848c2ecf20Sopenharmony_ci} 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_cistatic u32 mr_get_pd(struct mlx4_mpt_entry *mpt) 26878c2ecf20Sopenharmony_ci{ 26888c2ecf20Sopenharmony_ci return be32_to_cpu(mpt->pd_flags) & 0x00ffffff; 26898c2ecf20Sopenharmony_ci} 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_cistatic int mr_is_fmr(struct mlx4_mpt_entry *mpt) 26928c2ecf20Sopenharmony_ci{ 26938c2ecf20Sopenharmony_ci return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG; 26948c2ecf20Sopenharmony_ci} 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_cistatic int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt) 26978c2ecf20Sopenharmony_ci{ 26988c2ecf20Sopenharmony_ci return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE; 26998c2ecf20Sopenharmony_ci} 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_cistatic int mr_is_region(struct mlx4_mpt_entry *mpt) 27028c2ecf20Sopenharmony_ci{ 27038c2ecf20Sopenharmony_ci return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION; 27048c2ecf20Sopenharmony_ci} 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_cistatic int qp_get_mtt_addr(struct mlx4_qp_context *qpc) 27078c2ecf20Sopenharmony_ci{ 27088c2ecf20Sopenharmony_ci return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_cistatic int srq_get_mtt_addr(struct mlx4_srq_context *srqc) 27128c2ecf20Sopenharmony_ci{ 27138c2ecf20Sopenharmony_ci return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cistatic int qp_get_mtt_size(struct mlx4_qp_context *qpc) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci int page_shift = (qpc->log_page_size & 0x3f) + 12; 27198c2ecf20Sopenharmony_ci int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; 27208c2ecf20Sopenharmony_ci int log_sq_sride = qpc->sq_size_stride & 7; 27218c2ecf20Sopenharmony_ci int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; 27228c2ecf20Sopenharmony_ci int log_rq_stride = qpc->rq_size_stride & 7; 27238c2ecf20Sopenharmony_ci int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; 27248c2ecf20Sopenharmony_ci int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; 27258c2ecf20Sopenharmony_ci u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 27268c2ecf20Sopenharmony_ci int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0; 27278c2ecf20Sopenharmony_ci int sq_size; 27288c2ecf20Sopenharmony_ci int rq_size; 27298c2ecf20Sopenharmony_ci int total_pages; 27308c2ecf20Sopenharmony_ci int total_mem; 27318c2ecf20Sopenharmony_ci int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; 27328c2ecf20Sopenharmony_ci int tot; 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci sq_size = 1 << (log_sq_size + log_sq_sride + 4); 27358c2ecf20Sopenharmony_ci rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); 27368c2ecf20Sopenharmony_ci total_mem = sq_size + rq_size; 27378c2ecf20Sopenharmony_ci tot = (total_mem + (page_offset << 6)) >> page_shift; 27388c2ecf20Sopenharmony_ci total_pages = !tot ? 1 : roundup_pow_of_two(tot); 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci return total_pages; 27418c2ecf20Sopenharmony_ci} 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_cistatic int check_mtt_range(struct mlx4_dev *dev, int slave, int start, 27448c2ecf20Sopenharmony_ci int size, struct res_mtt *mtt) 27458c2ecf20Sopenharmony_ci{ 27468c2ecf20Sopenharmony_ci int res_start = mtt->com.res_id; 27478c2ecf20Sopenharmony_ci int res_size = (1 << mtt->order); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci if (start < res_start || start + size > res_start + res_size) 27508c2ecf20Sopenharmony_ci return -EPERM; 27518c2ecf20Sopenharmony_ci return 0; 27528c2ecf20Sopenharmony_ci} 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ciint mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, 27558c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 27568c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 27578c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 27588c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 27598c2ecf20Sopenharmony_ci{ 27608c2ecf20Sopenharmony_ci int err; 27618c2ecf20Sopenharmony_ci int index = vhcr->in_modifier; 27628c2ecf20Sopenharmony_ci struct res_mtt *mtt; 27638c2ecf20Sopenharmony_ci struct res_mpt *mpt = NULL; 27648c2ecf20Sopenharmony_ci int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; 27658c2ecf20Sopenharmony_ci int phys; 27668c2ecf20Sopenharmony_ci int id; 27678c2ecf20Sopenharmony_ci u32 pd; 27688c2ecf20Sopenharmony_ci int pd_slave; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 27718c2ecf20Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); 27728c2ecf20Sopenharmony_ci if (err) 27738c2ecf20Sopenharmony_ci return err; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* Disable memory windows for VFs. */ 27768c2ecf20Sopenharmony_ci if (!mr_is_region(inbox->buf)) { 27778c2ecf20Sopenharmony_ci err = -EPERM; 27788c2ecf20Sopenharmony_ci goto ex_abort; 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci /* Make sure that the PD bits related to the slave id are zeros. */ 27828c2ecf20Sopenharmony_ci pd = mr_get_pd(inbox->buf); 27838c2ecf20Sopenharmony_ci pd_slave = (pd >> 17) & 0x7f; 27848c2ecf20Sopenharmony_ci if (pd_slave != 0 && --pd_slave != slave) { 27858c2ecf20Sopenharmony_ci err = -EPERM; 27868c2ecf20Sopenharmony_ci goto ex_abort; 27878c2ecf20Sopenharmony_ci } 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci if (mr_is_fmr(inbox->buf)) { 27908c2ecf20Sopenharmony_ci /* FMR and Bind Enable are forbidden in slave devices. */ 27918c2ecf20Sopenharmony_ci if (mr_is_bind_enabled(inbox->buf)) { 27928c2ecf20Sopenharmony_ci err = -EPERM; 27938c2ecf20Sopenharmony_ci goto ex_abort; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci /* FMR and Memory Windows are also forbidden. */ 27968c2ecf20Sopenharmony_ci if (!mr_is_region(inbox->buf)) { 27978c2ecf20Sopenharmony_ci err = -EPERM; 27988c2ecf20Sopenharmony_ci goto ex_abort; 27998c2ecf20Sopenharmony_ci } 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci phys = mr_phys_mpt(inbox->buf); 28038c2ecf20Sopenharmony_ci if (!phys) { 28048c2ecf20Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 28058c2ecf20Sopenharmony_ci if (err) 28068c2ecf20Sopenharmony_ci goto ex_abort; 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, 28098c2ecf20Sopenharmony_ci mr_get_mtt_size(inbox->buf), mtt); 28108c2ecf20Sopenharmony_ci if (err) 28118c2ecf20Sopenharmony_ci goto ex_put; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci mpt->mtt = mtt; 28148c2ecf20Sopenharmony_ci } 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 28178c2ecf20Sopenharmony_ci if (err) 28188c2ecf20Sopenharmony_ci goto ex_put; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci if (!phys) { 28218c2ecf20Sopenharmony_ci atomic_inc(&mtt->ref_count); 28228c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 28268c2ecf20Sopenharmony_ci return 0; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ciex_put: 28298c2ecf20Sopenharmony_ci if (!phys) 28308c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 28318c2ecf20Sopenharmony_ciex_abort: 28328c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_MPT, id); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci return err; 28358c2ecf20Sopenharmony_ci} 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ciint mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, 28388c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 28398c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 28408c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 28418c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 28428c2ecf20Sopenharmony_ci{ 28438c2ecf20Sopenharmony_ci int err; 28448c2ecf20Sopenharmony_ci int index = vhcr->in_modifier; 28458c2ecf20Sopenharmony_ci struct res_mpt *mpt; 28468c2ecf20Sopenharmony_ci int id; 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 28498c2ecf20Sopenharmony_ci err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); 28508c2ecf20Sopenharmony_ci if (err) 28518c2ecf20Sopenharmony_ci return err; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 28548c2ecf20Sopenharmony_ci if (err) 28558c2ecf20Sopenharmony_ci goto ex_abort; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci if (mpt->mtt) 28588c2ecf20Sopenharmony_ci atomic_dec(&mpt->mtt->ref_count); 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_MPT, id); 28618c2ecf20Sopenharmony_ci return 0; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ciex_abort: 28648c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_MPT, id); 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci return err; 28678c2ecf20Sopenharmony_ci} 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ciint mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, 28708c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 28718c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 28728c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 28738c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 28748c2ecf20Sopenharmony_ci{ 28758c2ecf20Sopenharmony_ci int err; 28768c2ecf20Sopenharmony_ci int index = vhcr->in_modifier; 28778c2ecf20Sopenharmony_ci struct res_mpt *mpt; 28788c2ecf20Sopenharmony_ci int id; 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci id = index & mpt_mask(dev); 28818c2ecf20Sopenharmony_ci err = get_res(dev, slave, id, RES_MPT, &mpt); 28828c2ecf20Sopenharmony_ci if (err) 28838c2ecf20Sopenharmony_ci return err; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci if (mpt->com.from_state == RES_MPT_MAPPED) { 28868c2ecf20Sopenharmony_ci /* In order to allow rereg in SRIOV, we need to alter the MPT entry. To do 28878c2ecf20Sopenharmony_ci * that, the VF must read the MPT. But since the MPT entry memory is not 28888c2ecf20Sopenharmony_ci * in the VF's virtual memory space, it must use QUERY_MPT to obtain the 28898c2ecf20Sopenharmony_ci * entry contents. To guarantee that the MPT cannot be changed, the driver 28908c2ecf20Sopenharmony_ci * must perform HW2SW_MPT before this query and return the MPT entry to HW 28918c2ecf20Sopenharmony_ci * ownership fofollowing the change. The change here allows the VF to 28928c2ecf20Sopenharmony_ci * perform QUERY_MPT also when the entry is in SW ownership. 28938c2ecf20Sopenharmony_ci */ 28948c2ecf20Sopenharmony_ci struct mlx4_mpt_entry *mpt_entry = mlx4_table_find( 28958c2ecf20Sopenharmony_ci &mlx4_priv(dev)->mr_table.dmpt_table, 28968c2ecf20Sopenharmony_ci mpt->key, NULL); 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci if (NULL == mpt_entry || NULL == outbox->buf) { 28998c2ecf20Sopenharmony_ci err = -EINVAL; 29008c2ecf20Sopenharmony_ci goto out; 29018c2ecf20Sopenharmony_ci } 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci memcpy(outbox->buf, mpt_entry, sizeof(*mpt_entry)); 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci err = 0; 29068c2ecf20Sopenharmony_ci } else if (mpt->com.from_state == RES_MPT_HW) { 29078c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 29088c2ecf20Sopenharmony_ci } else { 29098c2ecf20Sopenharmony_ci err = -EBUSY; 29108c2ecf20Sopenharmony_ci goto out; 29118c2ecf20Sopenharmony_ci } 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ciout: 29158c2ecf20Sopenharmony_ci put_res(dev, slave, id, RES_MPT); 29168c2ecf20Sopenharmony_ci return err; 29178c2ecf20Sopenharmony_ci} 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_cistatic int qp_get_rcqn(struct mlx4_qp_context *qpc) 29208c2ecf20Sopenharmony_ci{ 29218c2ecf20Sopenharmony_ci return be32_to_cpu(qpc->cqn_recv) & 0xffffff; 29228c2ecf20Sopenharmony_ci} 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_cistatic int qp_get_scqn(struct mlx4_qp_context *qpc) 29258c2ecf20Sopenharmony_ci{ 29268c2ecf20Sopenharmony_ci return be32_to_cpu(qpc->cqn_send) & 0xffffff; 29278c2ecf20Sopenharmony_ci} 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_cistatic u32 qp_get_srqn(struct mlx4_qp_context *qpc) 29308c2ecf20Sopenharmony_ci{ 29318c2ecf20Sopenharmony_ci return be32_to_cpu(qpc->srqn) & 0x1ffffff; 29328c2ecf20Sopenharmony_ci} 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_cistatic void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, 29358c2ecf20Sopenharmony_ci struct mlx4_qp_context *context) 29368c2ecf20Sopenharmony_ci{ 29378c2ecf20Sopenharmony_ci u32 qpn = vhcr->in_modifier & 0xffffff; 29388c2ecf20Sopenharmony_ci u32 qkey = 0; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci if (mlx4_get_parav_qkey(dev, qpn, &qkey)) 29418c2ecf20Sopenharmony_ci return; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci /* adjust qkey in qp context */ 29448c2ecf20Sopenharmony_ci context->qkey = cpu_to_be32(qkey); 29458c2ecf20Sopenharmony_ci} 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_cistatic int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave, 29488c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc, 29498c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox); 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ciint mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 29528c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 29538c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 29548c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 29558c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 29568c2ecf20Sopenharmony_ci{ 29578c2ecf20Sopenharmony_ci int err; 29588c2ecf20Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 29598c2ecf20Sopenharmony_ci struct res_mtt *mtt; 29608c2ecf20Sopenharmony_ci struct res_qp *qp; 29618c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc = inbox->buf + 8; 29628c2ecf20Sopenharmony_ci int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; 29638c2ecf20Sopenharmony_ci int mtt_size = qp_get_mtt_size(qpc); 29648c2ecf20Sopenharmony_ci struct res_cq *rcq; 29658c2ecf20Sopenharmony_ci struct res_cq *scq; 29668c2ecf20Sopenharmony_ci int rcqn = qp_get_rcqn(qpc); 29678c2ecf20Sopenharmony_ci int scqn = qp_get_scqn(qpc); 29688c2ecf20Sopenharmony_ci u32 srqn = qp_get_srqn(qpc) & 0xffffff; 29698c2ecf20Sopenharmony_ci int use_srq = (qp_get_srqn(qpc) >> 24) & 1; 29708c2ecf20Sopenharmony_ci struct res_srq *srq; 29718c2ecf20Sopenharmony_ci int local_qpn = vhcr->in_modifier & 0xffffff; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, qpc, inbox); 29748c2ecf20Sopenharmony_ci if (err) 29758c2ecf20Sopenharmony_ci return err; 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); 29788c2ecf20Sopenharmony_ci if (err) 29798c2ecf20Sopenharmony_ci return err; 29808c2ecf20Sopenharmony_ci qp->local_qpn = local_qpn; 29818c2ecf20Sopenharmony_ci qp->sched_queue = 0; 29828c2ecf20Sopenharmony_ci qp->param3 = 0; 29838c2ecf20Sopenharmony_ci qp->vlan_control = 0; 29848c2ecf20Sopenharmony_ci qp->fvl_rx = 0; 29858c2ecf20Sopenharmony_ci qp->pri_path_fl = 0; 29868c2ecf20Sopenharmony_ci qp->vlan_index = 0; 29878c2ecf20Sopenharmony_ci qp->feup = 0; 29888c2ecf20Sopenharmony_ci qp->qpc_flags = be32_to_cpu(qpc->flags); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 29918c2ecf20Sopenharmony_ci if (err) 29928c2ecf20Sopenharmony_ci goto ex_abort; 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 29958c2ecf20Sopenharmony_ci if (err) 29968c2ecf20Sopenharmony_ci goto ex_put_mtt; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci err = get_res(dev, slave, rcqn, RES_CQ, &rcq); 29998c2ecf20Sopenharmony_ci if (err) 30008c2ecf20Sopenharmony_ci goto ex_put_mtt; 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci if (scqn != rcqn) { 30038c2ecf20Sopenharmony_ci err = get_res(dev, slave, scqn, RES_CQ, &scq); 30048c2ecf20Sopenharmony_ci if (err) 30058c2ecf20Sopenharmony_ci goto ex_put_rcq; 30068c2ecf20Sopenharmony_ci } else 30078c2ecf20Sopenharmony_ci scq = rcq; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci if (use_srq) { 30108c2ecf20Sopenharmony_ci err = get_res(dev, slave, srqn, RES_SRQ, &srq); 30118c2ecf20Sopenharmony_ci if (err) 30128c2ecf20Sopenharmony_ci goto ex_put_scq; 30138c2ecf20Sopenharmony_ci } 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, qpc); 30168c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 30178c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 30188c2ecf20Sopenharmony_ci if (err) 30198c2ecf20Sopenharmony_ci goto ex_put_srq; 30208c2ecf20Sopenharmony_ci atomic_inc(&mtt->ref_count); 30218c2ecf20Sopenharmony_ci qp->mtt = mtt; 30228c2ecf20Sopenharmony_ci atomic_inc(&rcq->ref_count); 30238c2ecf20Sopenharmony_ci qp->rcq = rcq; 30248c2ecf20Sopenharmony_ci atomic_inc(&scq->ref_count); 30258c2ecf20Sopenharmony_ci qp->scq = scq; 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci if (scqn != rcqn) 30288c2ecf20Sopenharmony_ci put_res(dev, slave, scqn, RES_CQ); 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci if (use_srq) { 30318c2ecf20Sopenharmony_ci atomic_inc(&srq->ref_count); 30328c2ecf20Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 30338c2ecf20Sopenharmony_ci qp->srq = srq; 30348c2ecf20Sopenharmony_ci } 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci /* Save param3 for dynamic changes from VST back to VGT */ 30378c2ecf20Sopenharmony_ci qp->param3 = qpc->param3; 30388c2ecf20Sopenharmony_ci put_res(dev, slave, rcqn, RES_CQ); 30398c2ecf20Sopenharmony_ci put_res(dev, slave, mtt_base, RES_MTT); 30408c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci return 0; 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ciex_put_srq: 30458c2ecf20Sopenharmony_ci if (use_srq) 30468c2ecf20Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 30478c2ecf20Sopenharmony_ciex_put_scq: 30488c2ecf20Sopenharmony_ci if (scqn != rcqn) 30498c2ecf20Sopenharmony_ci put_res(dev, slave, scqn, RES_CQ); 30508c2ecf20Sopenharmony_ciex_put_rcq: 30518c2ecf20Sopenharmony_ci put_res(dev, slave, rcqn, RES_CQ); 30528c2ecf20Sopenharmony_ciex_put_mtt: 30538c2ecf20Sopenharmony_ci put_res(dev, slave, mtt_base, RES_MTT); 30548c2ecf20Sopenharmony_ciex_abort: 30558c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_QP, qpn); 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci return err; 30588c2ecf20Sopenharmony_ci} 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_cistatic int eq_get_mtt_addr(struct mlx4_eq_context *eqc) 30618c2ecf20Sopenharmony_ci{ 30628c2ecf20Sopenharmony_ci return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; 30638c2ecf20Sopenharmony_ci} 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_cistatic int eq_get_mtt_size(struct mlx4_eq_context *eqc) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci int log_eq_size = eqc->log_eq_size & 0x1f; 30688c2ecf20Sopenharmony_ci int page_shift = (eqc->log_page_size & 0x3f) + 12; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci if (log_eq_size + 5 < page_shift) 30718c2ecf20Sopenharmony_ci return 1; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci return 1 << (log_eq_size + 5 - page_shift); 30748c2ecf20Sopenharmony_ci} 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_cistatic int cq_get_mtt_addr(struct mlx4_cq_context *cqc) 30778c2ecf20Sopenharmony_ci{ 30788c2ecf20Sopenharmony_ci return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; 30798c2ecf20Sopenharmony_ci} 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_cistatic int cq_get_mtt_size(struct mlx4_cq_context *cqc) 30828c2ecf20Sopenharmony_ci{ 30838c2ecf20Sopenharmony_ci int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; 30848c2ecf20Sopenharmony_ci int page_shift = (cqc->log_page_size & 0x3f) + 12; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci if (log_cq_size + 5 < page_shift) 30878c2ecf20Sopenharmony_ci return 1; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci return 1 << (log_cq_size + 5 - page_shift); 30908c2ecf20Sopenharmony_ci} 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ciint mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, 30938c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 30948c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 30958c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 30968c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 30978c2ecf20Sopenharmony_ci{ 30988c2ecf20Sopenharmony_ci int err; 30998c2ecf20Sopenharmony_ci int eqn = vhcr->in_modifier; 31008c2ecf20Sopenharmony_ci int res_id = (slave << 10) | eqn; 31018c2ecf20Sopenharmony_ci struct mlx4_eq_context *eqc = inbox->buf; 31028c2ecf20Sopenharmony_ci int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; 31038c2ecf20Sopenharmony_ci int mtt_size = eq_get_mtt_size(eqc); 31048c2ecf20Sopenharmony_ci struct res_eq *eq; 31058c2ecf20Sopenharmony_ci struct res_mtt *mtt; 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); 31088c2ecf20Sopenharmony_ci if (err) 31098c2ecf20Sopenharmony_ci return err; 31108c2ecf20Sopenharmony_ci err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); 31118c2ecf20Sopenharmony_ci if (err) 31128c2ecf20Sopenharmony_ci goto out_add; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 31158c2ecf20Sopenharmony_ci if (err) 31168c2ecf20Sopenharmony_ci goto out_move; 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 31198c2ecf20Sopenharmony_ci if (err) 31208c2ecf20Sopenharmony_ci goto out_put; 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 31238c2ecf20Sopenharmony_ci if (err) 31248c2ecf20Sopenharmony_ci goto out_put; 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci atomic_inc(&mtt->ref_count); 31278c2ecf20Sopenharmony_ci eq->mtt = mtt; 31288c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 31298c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_EQ, res_id); 31308c2ecf20Sopenharmony_ci return 0; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ciout_put: 31338c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 31348c2ecf20Sopenharmony_ciout_move: 31358c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_EQ, res_id); 31368c2ecf20Sopenharmony_ciout_add: 31378c2ecf20Sopenharmony_ci rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 31388c2ecf20Sopenharmony_ci return err; 31398c2ecf20Sopenharmony_ci} 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ciint mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave, 31428c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 31438c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 31448c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 31458c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 31468c2ecf20Sopenharmony_ci{ 31478c2ecf20Sopenharmony_ci int err; 31488c2ecf20Sopenharmony_ci u8 get = vhcr->op_modifier; 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci if (get != 1) 31518c2ecf20Sopenharmony_ci return -EPERM; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci return err; 31568c2ecf20Sopenharmony_ci} 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_cistatic int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, 31598c2ecf20Sopenharmony_ci int len, struct res_mtt **res) 31608c2ecf20Sopenharmony_ci{ 31618c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 31628c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 31638c2ecf20Sopenharmony_ci struct res_mtt *mtt; 31648c2ecf20Sopenharmony_ci int err = -EINVAL; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 31678c2ecf20Sopenharmony_ci list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], 31688c2ecf20Sopenharmony_ci com.list) { 31698c2ecf20Sopenharmony_ci if (!check_mtt_range(dev, slave, start, len, mtt)) { 31708c2ecf20Sopenharmony_ci *res = mtt; 31718c2ecf20Sopenharmony_ci mtt->com.from_state = mtt->com.state; 31728c2ecf20Sopenharmony_ci mtt->com.state = RES_MTT_BUSY; 31738c2ecf20Sopenharmony_ci err = 0; 31748c2ecf20Sopenharmony_ci break; 31758c2ecf20Sopenharmony_ci } 31768c2ecf20Sopenharmony_ci } 31778c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci return err; 31808c2ecf20Sopenharmony_ci} 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_cistatic int verify_qp_parameters(struct mlx4_dev *dev, 31838c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 31848c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 31858c2ecf20Sopenharmony_ci enum qp_transition transition, u8 slave) 31868c2ecf20Sopenharmony_ci{ 31878c2ecf20Sopenharmony_ci u32 qp_type; 31888c2ecf20Sopenharmony_ci u32 qpn; 31898c2ecf20Sopenharmony_ci struct mlx4_qp_context *qp_ctx; 31908c2ecf20Sopenharmony_ci enum mlx4_qp_optpar optpar; 31918c2ecf20Sopenharmony_ci int port; 31928c2ecf20Sopenharmony_ci int num_gids; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci qp_ctx = inbox->buf + 8; 31958c2ecf20Sopenharmony_ci qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 31968c2ecf20Sopenharmony_ci optpar = be32_to_cpu(*(__be32 *) inbox->buf); 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci if (slave != mlx4_master_func_num(dev)) { 31998c2ecf20Sopenharmony_ci qp_ctx->params2 &= ~cpu_to_be32(MLX4_QP_BIT_FPP); 32008c2ecf20Sopenharmony_ci /* setting QP rate-limit is disallowed for VFs */ 32018c2ecf20Sopenharmony_ci if (qp_ctx->rate_limit_params) 32028c2ecf20Sopenharmony_ci return -EPERM; 32038c2ecf20Sopenharmony_ci } 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci switch (qp_type) { 32068c2ecf20Sopenharmony_ci case MLX4_QP_ST_RC: 32078c2ecf20Sopenharmony_ci case MLX4_QP_ST_XRC: 32088c2ecf20Sopenharmony_ci case MLX4_QP_ST_UC: 32098c2ecf20Sopenharmony_ci switch (transition) { 32108c2ecf20Sopenharmony_ci case QP_TRANS_INIT2RTR: 32118c2ecf20Sopenharmony_ci case QP_TRANS_RTR2RTS: 32128c2ecf20Sopenharmony_ci case QP_TRANS_RTS2RTS: 32138c2ecf20Sopenharmony_ci case QP_TRANS_SQD2SQD: 32148c2ecf20Sopenharmony_ci case QP_TRANS_SQD2RTS: 32158c2ecf20Sopenharmony_ci if (slave != mlx4_master_func_num(dev)) { 32168c2ecf20Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 32178c2ecf20Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 32188c2ecf20Sopenharmony_ci if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 32198c2ecf20Sopenharmony_ci num_gids = mlx4_get_slave_num_gids(dev, slave, port); 32208c2ecf20Sopenharmony_ci else 32218c2ecf20Sopenharmony_ci num_gids = 1; 32228c2ecf20Sopenharmony_ci if (qp_ctx->pri_path.mgid_index >= num_gids) 32238c2ecf20Sopenharmony_ci return -EINVAL; 32248c2ecf20Sopenharmony_ci } 32258c2ecf20Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 32268c2ecf20Sopenharmony_ci port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 32278c2ecf20Sopenharmony_ci if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 32288c2ecf20Sopenharmony_ci num_gids = mlx4_get_slave_num_gids(dev, slave, port); 32298c2ecf20Sopenharmony_ci else 32308c2ecf20Sopenharmony_ci num_gids = 1; 32318c2ecf20Sopenharmony_ci if (qp_ctx->alt_path.mgid_index >= num_gids) 32328c2ecf20Sopenharmony_ci return -EINVAL; 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci } 32358c2ecf20Sopenharmony_ci break; 32368c2ecf20Sopenharmony_ci default: 32378c2ecf20Sopenharmony_ci break; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci break; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci case MLX4_QP_ST_MLX: 32428c2ecf20Sopenharmony_ci qpn = vhcr->in_modifier & 0x7fffff; 32438c2ecf20Sopenharmony_ci port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 32448c2ecf20Sopenharmony_ci if (transition == QP_TRANS_INIT2RTR && 32458c2ecf20Sopenharmony_ci slave != mlx4_master_func_num(dev) && 32468c2ecf20Sopenharmony_ci mlx4_is_qp_reserved(dev, qpn) && 32478c2ecf20Sopenharmony_ci !mlx4_vf_smi_enabled(dev, slave, port)) { 32488c2ecf20Sopenharmony_ci /* only enabled VFs may create MLX proxy QPs */ 32498c2ecf20Sopenharmony_ci mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n", 32508c2ecf20Sopenharmony_ci __func__, slave, port); 32518c2ecf20Sopenharmony_ci return -EPERM; 32528c2ecf20Sopenharmony_ci } 32538c2ecf20Sopenharmony_ci break; 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci default: 32568c2ecf20Sopenharmony_ci break; 32578c2ecf20Sopenharmony_ci } 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci return 0; 32608c2ecf20Sopenharmony_ci} 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ciint mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, 32638c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 32648c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 32658c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 32668c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 32678c2ecf20Sopenharmony_ci{ 32688c2ecf20Sopenharmony_ci struct mlx4_mtt mtt; 32698c2ecf20Sopenharmony_ci __be64 *page_list = inbox->buf; 32708c2ecf20Sopenharmony_ci u64 *pg_list = (u64 *)page_list; 32718c2ecf20Sopenharmony_ci int i; 32728c2ecf20Sopenharmony_ci struct res_mtt *rmtt = NULL; 32738c2ecf20Sopenharmony_ci int start = be64_to_cpu(page_list[0]); 32748c2ecf20Sopenharmony_ci int npages = vhcr->in_modifier; 32758c2ecf20Sopenharmony_ci int err; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci err = get_containing_mtt(dev, slave, start, npages, &rmtt); 32788c2ecf20Sopenharmony_ci if (err) 32798c2ecf20Sopenharmony_ci return err; 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_ci /* Call the SW implementation of write_mtt: 32828c2ecf20Sopenharmony_ci * - Prepare a dummy mtt struct 32838c2ecf20Sopenharmony_ci * - Translate inbox contents to simple addresses in host endianness */ 32848c2ecf20Sopenharmony_ci mtt.offset = 0; /* TBD this is broken but I don't handle it since 32858c2ecf20Sopenharmony_ci we don't really use it */ 32868c2ecf20Sopenharmony_ci mtt.order = 0; 32878c2ecf20Sopenharmony_ci mtt.page_shift = 0; 32888c2ecf20Sopenharmony_ci for (i = 0; i < npages; ++i) 32898c2ecf20Sopenharmony_ci pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, 32928c2ecf20Sopenharmony_ci ((u64 *)page_list + 2)); 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci if (rmtt) 32958c2ecf20Sopenharmony_ci put_res(dev, slave, rmtt->com.res_id, RES_MTT); 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci return err; 32988c2ecf20Sopenharmony_ci} 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ciint mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, 33018c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 33028c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 33038c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 33048c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 33058c2ecf20Sopenharmony_ci{ 33068c2ecf20Sopenharmony_ci int eqn = vhcr->in_modifier; 33078c2ecf20Sopenharmony_ci int res_id = eqn | (slave << 10); 33088c2ecf20Sopenharmony_ci struct res_eq *eq; 33098c2ecf20Sopenharmony_ci int err; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); 33128c2ecf20Sopenharmony_ci if (err) 33138c2ecf20Sopenharmony_ci return err; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); 33168c2ecf20Sopenharmony_ci if (err) 33178c2ecf20Sopenharmony_ci goto ex_abort; 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 33208c2ecf20Sopenharmony_ci if (err) 33218c2ecf20Sopenharmony_ci goto ex_put; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci atomic_dec(&eq->mtt->ref_count); 33248c2ecf20Sopenharmony_ci put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 33258c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_EQ, res_id); 33268c2ecf20Sopenharmony_ci rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci return 0; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ciex_put: 33318c2ecf20Sopenharmony_ci put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 33328c2ecf20Sopenharmony_ciex_abort: 33338c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_EQ, res_id); 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci return err; 33368c2ecf20Sopenharmony_ci} 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ciint mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) 33398c2ecf20Sopenharmony_ci{ 33408c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 33418c2ecf20Sopenharmony_ci struct mlx4_slave_event_eq_info *event_eq; 33428c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 33438c2ecf20Sopenharmony_ci u32 in_modifier = 0; 33448c2ecf20Sopenharmony_ci int err; 33458c2ecf20Sopenharmony_ci int res_id; 33468c2ecf20Sopenharmony_ci struct res_eq *req; 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci if (!priv->mfunc.master.slave_state) 33498c2ecf20Sopenharmony_ci return -EINVAL; 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci /* check for slave valid, slave not PF, and slave active */ 33528c2ecf20Sopenharmony_ci if (slave < 0 || slave > dev->persist->num_vfs || 33538c2ecf20Sopenharmony_ci slave == dev->caps.function || 33548c2ecf20Sopenharmony_ci !priv->mfunc.master.slave_state[slave].active) 33558c2ecf20Sopenharmony_ci return 0; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci /* Create the event only if the slave is registered */ 33608c2ecf20Sopenharmony_ci if (event_eq->eqn < 0) 33618c2ecf20Sopenharmony_ci return 0; 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); 33648c2ecf20Sopenharmony_ci res_id = (slave << 10) | event_eq->eqn; 33658c2ecf20Sopenharmony_ci err = get_res(dev, slave, res_id, RES_EQ, &req); 33668c2ecf20Sopenharmony_ci if (err) 33678c2ecf20Sopenharmony_ci goto unlock; 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci if (req->com.from_state != RES_EQ_HW) { 33708c2ecf20Sopenharmony_ci err = -EINVAL; 33718c2ecf20Sopenharmony_ci goto put; 33728c2ecf20Sopenharmony_ci } 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 33758c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) { 33768c2ecf20Sopenharmony_ci err = PTR_ERR(mailbox); 33778c2ecf20Sopenharmony_ci goto put; 33788c2ecf20Sopenharmony_ci } 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci if (eqe->type == MLX4_EVENT_TYPE_CMD) { 33818c2ecf20Sopenharmony_ci ++event_eq->token; 33828c2ecf20Sopenharmony_ci eqe->event.cmd.token = cpu_to_be16(event_eq->token); 33838c2ecf20Sopenharmony_ci } 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci memcpy(mailbox->buf, (u8 *) eqe, 28); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16); 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, 33908c2ecf20Sopenharmony_ci MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, 33918c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci put_res(dev, slave, res_id, RES_EQ); 33948c2ecf20Sopenharmony_ci mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 33958c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 33968c2ecf20Sopenharmony_ci return err; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ciput: 33998c2ecf20Sopenharmony_ci put_res(dev, slave, res_id, RES_EQ); 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ciunlock: 34028c2ecf20Sopenharmony_ci mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 34038c2ecf20Sopenharmony_ci return err; 34048c2ecf20Sopenharmony_ci} 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ciint mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, 34078c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 34088c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 34098c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 34108c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 34118c2ecf20Sopenharmony_ci{ 34128c2ecf20Sopenharmony_ci int eqn = vhcr->in_modifier; 34138c2ecf20Sopenharmony_ci int res_id = eqn | (slave << 10); 34148c2ecf20Sopenharmony_ci struct res_eq *eq; 34158c2ecf20Sopenharmony_ci int err; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci err = get_res(dev, slave, res_id, RES_EQ, &eq); 34188c2ecf20Sopenharmony_ci if (err) 34198c2ecf20Sopenharmony_ci return err; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci if (eq->com.from_state != RES_EQ_HW) { 34228c2ecf20Sopenharmony_ci err = -EINVAL; 34238c2ecf20Sopenharmony_ci goto ex_put; 34248c2ecf20Sopenharmony_ci } 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ciex_put: 34298c2ecf20Sopenharmony_ci put_res(dev, slave, res_id, RES_EQ); 34308c2ecf20Sopenharmony_ci return err; 34318c2ecf20Sopenharmony_ci} 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ciint mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, 34348c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 34358c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 34368c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 34378c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 34388c2ecf20Sopenharmony_ci{ 34398c2ecf20Sopenharmony_ci int err; 34408c2ecf20Sopenharmony_ci int cqn = vhcr->in_modifier; 34418c2ecf20Sopenharmony_ci struct mlx4_cq_context *cqc = inbox->buf; 34428c2ecf20Sopenharmony_ci int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 34438c2ecf20Sopenharmony_ci struct res_cq *cq = NULL; 34448c2ecf20Sopenharmony_ci struct res_mtt *mtt; 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); 34478c2ecf20Sopenharmony_ci if (err) 34488c2ecf20Sopenharmony_ci return err; 34498c2ecf20Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 34508c2ecf20Sopenharmony_ci if (err) 34518c2ecf20Sopenharmony_ci goto out_move; 34528c2ecf20Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 34538c2ecf20Sopenharmony_ci if (err) 34548c2ecf20Sopenharmony_ci goto out_put; 34558c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 34568c2ecf20Sopenharmony_ci if (err) 34578c2ecf20Sopenharmony_ci goto out_put; 34588c2ecf20Sopenharmony_ci atomic_inc(&mtt->ref_count); 34598c2ecf20Sopenharmony_ci cq->mtt = mtt; 34608c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 34618c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_CQ, cqn); 34628c2ecf20Sopenharmony_ci return 0; 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ciout_put: 34658c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 34668c2ecf20Sopenharmony_ciout_move: 34678c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_CQ, cqn); 34688c2ecf20Sopenharmony_ci return err; 34698c2ecf20Sopenharmony_ci} 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ciint mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, 34728c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 34738c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 34748c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 34758c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 34768c2ecf20Sopenharmony_ci{ 34778c2ecf20Sopenharmony_ci int err; 34788c2ecf20Sopenharmony_ci int cqn = vhcr->in_modifier; 34798c2ecf20Sopenharmony_ci struct res_cq *cq = NULL; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); 34828c2ecf20Sopenharmony_ci if (err) 34838c2ecf20Sopenharmony_ci return err; 34848c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 34858c2ecf20Sopenharmony_ci if (err) 34868c2ecf20Sopenharmony_ci goto out_move; 34878c2ecf20Sopenharmony_ci atomic_dec(&cq->mtt->ref_count); 34888c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_CQ, cqn); 34898c2ecf20Sopenharmony_ci return 0; 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ciout_move: 34928c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_CQ, cqn); 34938c2ecf20Sopenharmony_ci return err; 34948c2ecf20Sopenharmony_ci} 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ciint mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, 34978c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 34988c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 34998c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 35008c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 35018c2ecf20Sopenharmony_ci{ 35028c2ecf20Sopenharmony_ci int cqn = vhcr->in_modifier; 35038c2ecf20Sopenharmony_ci struct res_cq *cq; 35048c2ecf20Sopenharmony_ci int err; 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci err = get_res(dev, slave, cqn, RES_CQ, &cq); 35078c2ecf20Sopenharmony_ci if (err) 35088c2ecf20Sopenharmony_ci return err; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci if (cq->com.from_state != RES_CQ_HW) 35118c2ecf20Sopenharmony_ci goto ex_put; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 35148c2ecf20Sopenharmony_ciex_put: 35158c2ecf20Sopenharmony_ci put_res(dev, slave, cqn, RES_CQ); 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci return err; 35188c2ecf20Sopenharmony_ci} 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_cistatic int handle_resize(struct mlx4_dev *dev, int slave, 35218c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 35228c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 35238c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 35248c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd, 35258c2ecf20Sopenharmony_ci struct res_cq *cq) 35268c2ecf20Sopenharmony_ci{ 35278c2ecf20Sopenharmony_ci int err; 35288c2ecf20Sopenharmony_ci struct res_mtt *orig_mtt; 35298c2ecf20Sopenharmony_ci struct res_mtt *mtt; 35308c2ecf20Sopenharmony_ci struct mlx4_cq_context *cqc = inbox->buf; 35318c2ecf20Sopenharmony_ci int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); 35348c2ecf20Sopenharmony_ci if (err) 35358c2ecf20Sopenharmony_ci return err; 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci if (orig_mtt != cq->mtt) { 35388c2ecf20Sopenharmony_ci err = -EINVAL; 35398c2ecf20Sopenharmony_ci goto ex_put; 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 35438c2ecf20Sopenharmony_ci if (err) 35448c2ecf20Sopenharmony_ci goto ex_put; 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 35478c2ecf20Sopenharmony_ci if (err) 35488c2ecf20Sopenharmony_ci goto ex_put1; 35498c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 35508c2ecf20Sopenharmony_ci if (err) 35518c2ecf20Sopenharmony_ci goto ex_put1; 35528c2ecf20Sopenharmony_ci atomic_dec(&orig_mtt->ref_count); 35538c2ecf20Sopenharmony_ci put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 35548c2ecf20Sopenharmony_ci atomic_inc(&mtt->ref_count); 35558c2ecf20Sopenharmony_ci cq->mtt = mtt; 35568c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 35578c2ecf20Sopenharmony_ci return 0; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ciex_put1: 35608c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 35618c2ecf20Sopenharmony_ciex_put: 35628c2ecf20Sopenharmony_ci put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci return err; 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_ci} 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ciint mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, 35698c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 35708c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 35718c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 35728c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 35738c2ecf20Sopenharmony_ci{ 35748c2ecf20Sopenharmony_ci int cqn = vhcr->in_modifier; 35758c2ecf20Sopenharmony_ci struct res_cq *cq; 35768c2ecf20Sopenharmony_ci int err; 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci err = get_res(dev, slave, cqn, RES_CQ, &cq); 35798c2ecf20Sopenharmony_ci if (err) 35808c2ecf20Sopenharmony_ci return err; 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci if (cq->com.from_state != RES_CQ_HW) 35838c2ecf20Sopenharmony_ci goto ex_put; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci if (vhcr->op_modifier == 0) { 35868c2ecf20Sopenharmony_ci err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); 35878c2ecf20Sopenharmony_ci goto ex_put; 35888c2ecf20Sopenharmony_ci } 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 35918c2ecf20Sopenharmony_ciex_put: 35928c2ecf20Sopenharmony_ci put_res(dev, slave, cqn, RES_CQ); 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci return err; 35958c2ecf20Sopenharmony_ci} 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_cistatic int srq_get_mtt_size(struct mlx4_srq_context *srqc) 35988c2ecf20Sopenharmony_ci{ 35998c2ecf20Sopenharmony_ci int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; 36008c2ecf20Sopenharmony_ci int log_rq_stride = srqc->logstride & 7; 36018c2ecf20Sopenharmony_ci int page_shift = (srqc->log_page_size & 0x3f) + 12; 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci if (log_srq_size + log_rq_stride + 4 < page_shift) 36048c2ecf20Sopenharmony_ci return 1; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); 36078c2ecf20Sopenharmony_ci} 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ciint mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 36108c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 36118c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 36128c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 36138c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 36148c2ecf20Sopenharmony_ci{ 36158c2ecf20Sopenharmony_ci int err; 36168c2ecf20Sopenharmony_ci int srqn = vhcr->in_modifier; 36178c2ecf20Sopenharmony_ci struct res_mtt *mtt; 36188c2ecf20Sopenharmony_ci struct res_srq *srq = NULL; 36198c2ecf20Sopenharmony_ci struct mlx4_srq_context *srqc = inbox->buf; 36208c2ecf20Sopenharmony_ci int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) 36238c2ecf20Sopenharmony_ci return -EINVAL; 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); 36268c2ecf20Sopenharmony_ci if (err) 36278c2ecf20Sopenharmony_ci return err; 36288c2ecf20Sopenharmony_ci err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 36298c2ecf20Sopenharmony_ci if (err) 36308c2ecf20Sopenharmony_ci goto ex_abort; 36318c2ecf20Sopenharmony_ci err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), 36328c2ecf20Sopenharmony_ci mtt); 36338c2ecf20Sopenharmony_ci if (err) 36348c2ecf20Sopenharmony_ci goto ex_put_mtt; 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 36378c2ecf20Sopenharmony_ci if (err) 36388c2ecf20Sopenharmony_ci goto ex_put_mtt; 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci atomic_inc(&mtt->ref_count); 36418c2ecf20Sopenharmony_ci srq->mtt = mtt; 36428c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 36438c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_SRQ, srqn); 36448c2ecf20Sopenharmony_ci return 0; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ciex_put_mtt: 36478c2ecf20Sopenharmony_ci put_res(dev, slave, mtt->com.res_id, RES_MTT); 36488c2ecf20Sopenharmony_ciex_abort: 36498c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_SRQ, srqn); 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci return err; 36528c2ecf20Sopenharmony_ci} 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ciint mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 36558c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 36568c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 36578c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 36588c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 36598c2ecf20Sopenharmony_ci{ 36608c2ecf20Sopenharmony_ci int err; 36618c2ecf20Sopenharmony_ci int srqn = vhcr->in_modifier; 36628c2ecf20Sopenharmony_ci struct res_srq *srq = NULL; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); 36658c2ecf20Sopenharmony_ci if (err) 36668c2ecf20Sopenharmony_ci return err; 36678c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 36688c2ecf20Sopenharmony_ci if (err) 36698c2ecf20Sopenharmony_ci goto ex_abort; 36708c2ecf20Sopenharmony_ci atomic_dec(&srq->mtt->ref_count); 36718c2ecf20Sopenharmony_ci if (srq->cq) 36728c2ecf20Sopenharmony_ci atomic_dec(&srq->cq->ref_count); 36738c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_SRQ, srqn); 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci return 0; 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ciex_abort: 36788c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_SRQ, srqn); 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci return err; 36818c2ecf20Sopenharmony_ci} 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ciint mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, 36848c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 36858c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 36868c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 36878c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 36888c2ecf20Sopenharmony_ci{ 36898c2ecf20Sopenharmony_ci int err; 36908c2ecf20Sopenharmony_ci int srqn = vhcr->in_modifier; 36918c2ecf20Sopenharmony_ci struct res_srq *srq; 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci err = get_res(dev, slave, srqn, RES_SRQ, &srq); 36948c2ecf20Sopenharmony_ci if (err) 36958c2ecf20Sopenharmony_ci return err; 36968c2ecf20Sopenharmony_ci if (srq->com.from_state != RES_SRQ_HW) { 36978c2ecf20Sopenharmony_ci err = -EBUSY; 36988c2ecf20Sopenharmony_ci goto out; 36998c2ecf20Sopenharmony_ci } 37008c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 37018c2ecf20Sopenharmony_ciout: 37028c2ecf20Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 37038c2ecf20Sopenharmony_ci return err; 37048c2ecf20Sopenharmony_ci} 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ciint mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, 37078c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 37088c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 37098c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 37108c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 37118c2ecf20Sopenharmony_ci{ 37128c2ecf20Sopenharmony_ci int err; 37138c2ecf20Sopenharmony_ci int srqn = vhcr->in_modifier; 37148c2ecf20Sopenharmony_ci struct res_srq *srq; 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci err = get_res(dev, slave, srqn, RES_SRQ, &srq); 37178c2ecf20Sopenharmony_ci if (err) 37188c2ecf20Sopenharmony_ci return err; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci if (srq->com.from_state != RES_SRQ_HW) { 37218c2ecf20Sopenharmony_ci err = -EBUSY; 37228c2ecf20Sopenharmony_ci goto out; 37238c2ecf20Sopenharmony_ci } 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 37268c2ecf20Sopenharmony_ciout: 37278c2ecf20Sopenharmony_ci put_res(dev, slave, srqn, RES_SRQ); 37288c2ecf20Sopenharmony_ci return err; 37298c2ecf20Sopenharmony_ci} 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ciint mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, 37328c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 37338c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 37348c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 37358c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 37368c2ecf20Sopenharmony_ci{ 37378c2ecf20Sopenharmony_ci int err; 37388c2ecf20Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 37398c2ecf20Sopenharmony_ci struct res_qp *qp; 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &qp); 37428c2ecf20Sopenharmony_ci if (err) 37438c2ecf20Sopenharmony_ci return err; 37448c2ecf20Sopenharmony_ci if (qp->com.from_state != RES_QP_HW) { 37458c2ecf20Sopenharmony_ci err = -EBUSY; 37468c2ecf20Sopenharmony_ci goto out; 37478c2ecf20Sopenharmony_ci } 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 37508c2ecf20Sopenharmony_ciout: 37518c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 37528c2ecf20Sopenharmony_ci return err; 37538c2ecf20Sopenharmony_ci} 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_ciint mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 37568c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 37578c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 37588c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 37598c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 37608c2ecf20Sopenharmony_ci{ 37618c2ecf20Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 37628c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 37638c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 37648c2ecf20Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 37658c2ecf20Sopenharmony_ci} 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_cistatic int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave, 37688c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc, 37698c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox) 37708c2ecf20Sopenharmony_ci{ 37718c2ecf20Sopenharmony_ci enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf); 37728c2ecf20Sopenharmony_ci u8 pri_sched_queue; 37738c2ecf20Sopenharmony_ci int port = mlx4_slave_convert_port( 37748c2ecf20Sopenharmony_ci dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1; 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci if (port < 0) 37778c2ecf20Sopenharmony_ci return -EINVAL; 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) | 37808c2ecf20Sopenharmony_ci ((port & 1) << 6); 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci if (optpar & (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | MLX4_QP_OPTPAR_SCHED_QUEUE) || 37838c2ecf20Sopenharmony_ci qpc->pri_path.sched_queue || mlx4_is_eth(dev, port + 1)) { 37848c2ecf20Sopenharmony_ci qpc->pri_path.sched_queue = pri_sched_queue; 37858c2ecf20Sopenharmony_ci } 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_ci if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 37888c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port( 37898c2ecf20Sopenharmony_ci dev, slave, (qpc->alt_path.sched_queue >> 6 & 1) 37908c2ecf20Sopenharmony_ci + 1) - 1; 37918c2ecf20Sopenharmony_ci if (port < 0) 37928c2ecf20Sopenharmony_ci return -EINVAL; 37938c2ecf20Sopenharmony_ci qpc->alt_path.sched_queue = 37948c2ecf20Sopenharmony_ci (qpc->alt_path.sched_queue & ~(1 << 6)) | 37958c2ecf20Sopenharmony_ci (port & 1) << 6; 37968c2ecf20Sopenharmony_ci } 37978c2ecf20Sopenharmony_ci return 0; 37988c2ecf20Sopenharmony_ci} 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_cistatic int roce_verify_mac(struct mlx4_dev *dev, int slave, 38018c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc, 38028c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox) 38038c2ecf20Sopenharmony_ci{ 38048c2ecf20Sopenharmony_ci u64 mac; 38058c2ecf20Sopenharmony_ci int port; 38068c2ecf20Sopenharmony_ci u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 38078c2ecf20Sopenharmony_ci u8 sched = *(u8 *)(inbox->buf + 64); 38088c2ecf20Sopenharmony_ci u8 smac_ix; 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci port = (sched >> 6 & 1) + 1; 38118c2ecf20Sopenharmony_ci if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { 38128c2ecf20Sopenharmony_ci smac_ix = qpc->pri_path.grh_mylmc & 0x7f; 38138c2ecf20Sopenharmony_ci if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) 38148c2ecf20Sopenharmony_ci return -ENOENT; 38158c2ecf20Sopenharmony_ci } 38168c2ecf20Sopenharmony_ci return 0; 38178c2ecf20Sopenharmony_ci} 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ciint mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, 38208c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 38218c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 38228c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 38238c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 38248c2ecf20Sopenharmony_ci{ 38258c2ecf20Sopenharmony_ci int err; 38268c2ecf20Sopenharmony_ci struct mlx4_qp_context *qpc = inbox->buf + 8; 38278c2ecf20Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 38288c2ecf20Sopenharmony_ci struct res_qp *qp; 38298c2ecf20Sopenharmony_ci u8 orig_sched_queue; 38308c2ecf20Sopenharmony_ci u8 orig_vlan_control = qpc->pri_path.vlan_control; 38318c2ecf20Sopenharmony_ci u8 orig_fvl_rx = qpc->pri_path.fvl_rx; 38328c2ecf20Sopenharmony_ci u8 orig_pri_path_fl = qpc->pri_path.fl; 38338c2ecf20Sopenharmony_ci u8 orig_vlan_index = qpc->pri_path.vlan_index; 38348c2ecf20Sopenharmony_ci u8 orig_feup = qpc->pri_path.feup; 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, qpc, inbox); 38378c2ecf20Sopenharmony_ci if (err) 38388c2ecf20Sopenharmony_ci return err; 38398c2ecf20Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave); 38408c2ecf20Sopenharmony_ci if (err) 38418c2ecf20Sopenharmony_ci return err; 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci if (roce_verify_mac(dev, slave, qpc, inbox)) 38448c2ecf20Sopenharmony_ci return -EINVAL; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 38478c2ecf20Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 38488c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, qpc); 38498c2ecf20Sopenharmony_ci orig_sched_queue = qpc->pri_path.sched_queue; 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &qp); 38528c2ecf20Sopenharmony_ci if (err) 38538c2ecf20Sopenharmony_ci return err; 38548c2ecf20Sopenharmony_ci if (qp->com.from_state != RES_QP_HW) { 38558c2ecf20Sopenharmony_ci err = -EBUSY; 38568c2ecf20Sopenharmony_ci goto out; 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci err = update_vport_qp_param(dev, inbox, slave, qpn); 38608c2ecf20Sopenharmony_ci if (err) 38618c2ecf20Sopenharmony_ci goto out; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 38648c2ecf20Sopenharmony_ciout: 38658c2ecf20Sopenharmony_ci /* if no error, save sched queue value passed in by VF. This is 38668c2ecf20Sopenharmony_ci * essentially the QOS value provided by the VF. This will be useful 38678c2ecf20Sopenharmony_ci * if we allow dynamic changes from VST back to VGT 38688c2ecf20Sopenharmony_ci */ 38698c2ecf20Sopenharmony_ci if (!err) { 38708c2ecf20Sopenharmony_ci qp->sched_queue = orig_sched_queue; 38718c2ecf20Sopenharmony_ci qp->vlan_control = orig_vlan_control; 38728c2ecf20Sopenharmony_ci qp->fvl_rx = orig_fvl_rx; 38738c2ecf20Sopenharmony_ci qp->pri_path_fl = orig_pri_path_fl; 38748c2ecf20Sopenharmony_ci qp->vlan_index = orig_vlan_index; 38758c2ecf20Sopenharmony_ci qp->feup = orig_feup; 38768c2ecf20Sopenharmony_ci } 38778c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 38788c2ecf20Sopenharmony_ci return err; 38798c2ecf20Sopenharmony_ci} 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ciint mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 38828c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 38838c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 38848c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 38858c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 38868c2ecf20Sopenharmony_ci{ 38878c2ecf20Sopenharmony_ci int err; 38888c2ecf20Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 38918c2ecf20Sopenharmony_ci if (err) 38928c2ecf20Sopenharmony_ci return err; 38938c2ecf20Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave); 38948c2ecf20Sopenharmony_ci if (err) 38958c2ecf20Sopenharmony_ci return err; 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 38988c2ecf20Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 38998c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 39008c2ecf20Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 39018c2ecf20Sopenharmony_ci} 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ciint mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 39048c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 39058c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 39068c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 39078c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 39088c2ecf20Sopenharmony_ci{ 39098c2ecf20Sopenharmony_ci int err; 39108c2ecf20Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 39138c2ecf20Sopenharmony_ci if (err) 39148c2ecf20Sopenharmony_ci return err; 39158c2ecf20Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave); 39168c2ecf20Sopenharmony_ci if (err) 39178c2ecf20Sopenharmony_ci return err; 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 39208c2ecf20Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 39218c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 39228c2ecf20Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 39238c2ecf20Sopenharmony_ci} 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ciint mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 39278c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 39288c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 39298c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 39308c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 39318c2ecf20Sopenharmony_ci{ 39328c2ecf20Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 39338c2ecf20Sopenharmony_ci int err = adjust_qp_sched_queue(dev, slave, context, inbox); 39348c2ecf20Sopenharmony_ci if (err) 39358c2ecf20Sopenharmony_ci return err; 39368c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 39378c2ecf20Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 39388c2ecf20Sopenharmony_ci} 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ciint mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, 39418c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 39428c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 39438c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 39448c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 39458c2ecf20Sopenharmony_ci{ 39468c2ecf20Sopenharmony_ci int err; 39478c2ecf20Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 39508c2ecf20Sopenharmony_ci if (err) 39518c2ecf20Sopenharmony_ci return err; 39528c2ecf20Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave); 39538c2ecf20Sopenharmony_ci if (err) 39548c2ecf20Sopenharmony_ci return err; 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 39578c2ecf20Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 39588c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 39598c2ecf20Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 39608c2ecf20Sopenharmony_ci} 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ciint mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 39638c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 39648c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 39658c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 39668c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 39678c2ecf20Sopenharmony_ci{ 39688c2ecf20Sopenharmony_ci int err; 39698c2ecf20Sopenharmony_ci struct mlx4_qp_context *context = inbox->buf + 8; 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci err = adjust_qp_sched_queue(dev, slave, context, inbox); 39728c2ecf20Sopenharmony_ci if (err) 39738c2ecf20Sopenharmony_ci return err; 39748c2ecf20Sopenharmony_ci err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave); 39758c2ecf20Sopenharmony_ci if (err) 39768c2ecf20Sopenharmony_ci return err; 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci adjust_proxy_tun_qkey(dev, vhcr, context); 39798c2ecf20Sopenharmony_ci update_gid(dev, inbox, (u8)slave); 39808c2ecf20Sopenharmony_ci update_pkey_index(dev, slave, inbox); 39818c2ecf20Sopenharmony_ci return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 39828c2ecf20Sopenharmony_ci} 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ciint mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, 39858c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 39868c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 39878c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 39888c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 39898c2ecf20Sopenharmony_ci{ 39908c2ecf20Sopenharmony_ci int err; 39918c2ecf20Sopenharmony_ci int qpn = vhcr->in_modifier & 0x7fffff; 39928c2ecf20Sopenharmony_ci struct res_qp *qp; 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); 39958c2ecf20Sopenharmony_ci if (err) 39968c2ecf20Sopenharmony_ci return err; 39978c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 39988c2ecf20Sopenharmony_ci if (err) 39998c2ecf20Sopenharmony_ci goto ex_abort; 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci atomic_dec(&qp->mtt->ref_count); 40028c2ecf20Sopenharmony_ci atomic_dec(&qp->rcq->ref_count); 40038c2ecf20Sopenharmony_ci atomic_dec(&qp->scq->ref_count); 40048c2ecf20Sopenharmony_ci if (qp->srq) 40058c2ecf20Sopenharmony_ci atomic_dec(&qp->srq->ref_count); 40068c2ecf20Sopenharmony_ci res_end_move(dev, slave, RES_QP, qpn); 40078c2ecf20Sopenharmony_ci return 0; 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ciex_abort: 40108c2ecf20Sopenharmony_ci res_abort_move(dev, slave, RES_QP, qpn); 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci return err; 40138c2ecf20Sopenharmony_ci} 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_cistatic struct res_gid *find_gid(struct mlx4_dev *dev, int slave, 40168c2ecf20Sopenharmony_ci struct res_qp *rqp, u8 *gid) 40178c2ecf20Sopenharmony_ci{ 40188c2ecf20Sopenharmony_ci struct res_gid *res; 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci list_for_each_entry(res, &rqp->mcg_list, list) { 40218c2ecf20Sopenharmony_ci if (!memcmp(res->gid, gid, 16)) 40228c2ecf20Sopenharmony_ci return res; 40238c2ecf20Sopenharmony_ci } 40248c2ecf20Sopenharmony_ci return NULL; 40258c2ecf20Sopenharmony_ci} 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_cistatic int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 40288c2ecf20Sopenharmony_ci u8 *gid, enum mlx4_protocol prot, 40298c2ecf20Sopenharmony_ci enum mlx4_steer_type steer, u64 reg_id) 40308c2ecf20Sopenharmony_ci{ 40318c2ecf20Sopenharmony_ci struct res_gid *res; 40328c2ecf20Sopenharmony_ci int err; 40338c2ecf20Sopenharmony_ci 40348c2ecf20Sopenharmony_ci res = kzalloc(sizeof(*res), GFP_KERNEL); 40358c2ecf20Sopenharmony_ci if (!res) 40368c2ecf20Sopenharmony_ci return -ENOMEM; 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci spin_lock_irq(&rqp->mcg_spl); 40398c2ecf20Sopenharmony_ci if (find_gid(dev, slave, rqp, gid)) { 40408c2ecf20Sopenharmony_ci kfree(res); 40418c2ecf20Sopenharmony_ci err = -EEXIST; 40428c2ecf20Sopenharmony_ci } else { 40438c2ecf20Sopenharmony_ci memcpy(res->gid, gid, 16); 40448c2ecf20Sopenharmony_ci res->prot = prot; 40458c2ecf20Sopenharmony_ci res->steer = steer; 40468c2ecf20Sopenharmony_ci res->reg_id = reg_id; 40478c2ecf20Sopenharmony_ci list_add_tail(&res->list, &rqp->mcg_list); 40488c2ecf20Sopenharmony_ci err = 0; 40498c2ecf20Sopenharmony_ci } 40508c2ecf20Sopenharmony_ci spin_unlock_irq(&rqp->mcg_spl); 40518c2ecf20Sopenharmony_ci 40528c2ecf20Sopenharmony_ci return err; 40538c2ecf20Sopenharmony_ci} 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_cistatic int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 40568c2ecf20Sopenharmony_ci u8 *gid, enum mlx4_protocol prot, 40578c2ecf20Sopenharmony_ci enum mlx4_steer_type steer, u64 *reg_id) 40588c2ecf20Sopenharmony_ci{ 40598c2ecf20Sopenharmony_ci struct res_gid *res; 40608c2ecf20Sopenharmony_ci int err; 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci spin_lock_irq(&rqp->mcg_spl); 40638c2ecf20Sopenharmony_ci res = find_gid(dev, slave, rqp, gid); 40648c2ecf20Sopenharmony_ci if (!res || res->prot != prot || res->steer != steer) 40658c2ecf20Sopenharmony_ci err = -EINVAL; 40668c2ecf20Sopenharmony_ci else { 40678c2ecf20Sopenharmony_ci *reg_id = res->reg_id; 40688c2ecf20Sopenharmony_ci list_del(&res->list); 40698c2ecf20Sopenharmony_ci kfree(res); 40708c2ecf20Sopenharmony_ci err = 0; 40718c2ecf20Sopenharmony_ci } 40728c2ecf20Sopenharmony_ci spin_unlock_irq(&rqp->mcg_spl); 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_ci return err; 40758c2ecf20Sopenharmony_ci} 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_cistatic int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp, 40788c2ecf20Sopenharmony_ci u8 gid[16], int block_loopback, enum mlx4_protocol prot, 40798c2ecf20Sopenharmony_ci enum mlx4_steer_type type, u64 *reg_id) 40808c2ecf20Sopenharmony_ci{ 40818c2ecf20Sopenharmony_ci switch (dev->caps.steering_mode) { 40828c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: { 40838c2ecf20Sopenharmony_ci int port = mlx4_slave_convert_port(dev, slave, gid[5]); 40848c2ecf20Sopenharmony_ci if (port < 0) 40858c2ecf20Sopenharmony_ci return port; 40868c2ecf20Sopenharmony_ci return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, 40878c2ecf20Sopenharmony_ci block_loopback, prot, 40888c2ecf20Sopenharmony_ci reg_id); 40898c2ecf20Sopenharmony_ci } 40908c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 40918c2ecf20Sopenharmony_ci if (prot == MLX4_PROT_ETH) { 40928c2ecf20Sopenharmony_ci int port = mlx4_slave_convert_port(dev, slave, gid[5]); 40938c2ecf20Sopenharmony_ci if (port < 0) 40948c2ecf20Sopenharmony_ci return port; 40958c2ecf20Sopenharmony_ci gid[5] = port; 40968c2ecf20Sopenharmony_ci } 40978c2ecf20Sopenharmony_ci return mlx4_qp_attach_common(dev, qp, gid, 40988c2ecf20Sopenharmony_ci block_loopback, prot, type); 40998c2ecf20Sopenharmony_ci default: 41008c2ecf20Sopenharmony_ci return -EINVAL; 41018c2ecf20Sopenharmony_ci } 41028c2ecf20Sopenharmony_ci} 41038c2ecf20Sopenharmony_ci 41048c2ecf20Sopenharmony_cistatic int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, 41058c2ecf20Sopenharmony_ci u8 gid[16], enum mlx4_protocol prot, 41068c2ecf20Sopenharmony_ci enum mlx4_steer_type type, u64 reg_id) 41078c2ecf20Sopenharmony_ci{ 41088c2ecf20Sopenharmony_ci switch (dev->caps.steering_mode) { 41098c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 41108c2ecf20Sopenharmony_ci return mlx4_flow_detach(dev, reg_id); 41118c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 41128c2ecf20Sopenharmony_ci return mlx4_qp_detach_common(dev, qp, gid, prot, type); 41138c2ecf20Sopenharmony_ci default: 41148c2ecf20Sopenharmony_ci return -EINVAL; 41158c2ecf20Sopenharmony_ci } 41168c2ecf20Sopenharmony_ci} 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_cistatic int mlx4_adjust_port(struct mlx4_dev *dev, int slave, 41198c2ecf20Sopenharmony_ci u8 *gid, enum mlx4_protocol prot) 41208c2ecf20Sopenharmony_ci{ 41218c2ecf20Sopenharmony_ci int real_port; 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_ci if (prot != MLX4_PROT_ETH) 41248c2ecf20Sopenharmony_ci return 0; 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 || 41278c2ecf20Sopenharmony_ci dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { 41288c2ecf20Sopenharmony_ci real_port = mlx4_slave_convert_port(dev, slave, gid[5]); 41298c2ecf20Sopenharmony_ci if (real_port < 0) 41308c2ecf20Sopenharmony_ci return -EINVAL; 41318c2ecf20Sopenharmony_ci gid[5] = real_port; 41328c2ecf20Sopenharmony_ci } 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci return 0; 41358c2ecf20Sopenharmony_ci} 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ciint mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 41388c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 41398c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 41408c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 41418c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 41428c2ecf20Sopenharmony_ci{ 41438c2ecf20Sopenharmony_ci struct mlx4_qp qp; /* dummy for calling attach/detach */ 41448c2ecf20Sopenharmony_ci u8 *gid = inbox->buf; 41458c2ecf20Sopenharmony_ci enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; 41468c2ecf20Sopenharmony_ci int err; 41478c2ecf20Sopenharmony_ci int qpn; 41488c2ecf20Sopenharmony_ci struct res_qp *rqp; 41498c2ecf20Sopenharmony_ci u64 reg_id = 0; 41508c2ecf20Sopenharmony_ci int attach = vhcr->op_modifier; 41518c2ecf20Sopenharmony_ci int block_loopback = vhcr->in_modifier >> 31; 41528c2ecf20Sopenharmony_ci u8 steer_type_mask = 2; 41538c2ecf20Sopenharmony_ci enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci qpn = vhcr->in_modifier & 0xffffff; 41568c2ecf20Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 41578c2ecf20Sopenharmony_ci if (err) 41588c2ecf20Sopenharmony_ci return err; 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci qp.qpn = qpn; 41618c2ecf20Sopenharmony_ci if (attach) { 41628c2ecf20Sopenharmony_ci err = qp_attach(dev, slave, &qp, gid, block_loopback, prot, 41638c2ecf20Sopenharmony_ci type, ®_id); 41648c2ecf20Sopenharmony_ci if (err) { 41658c2ecf20Sopenharmony_ci pr_err("Fail to attach rule to qp 0x%x\n", qpn); 41668c2ecf20Sopenharmony_ci goto ex_put; 41678c2ecf20Sopenharmony_ci } 41688c2ecf20Sopenharmony_ci err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id); 41698c2ecf20Sopenharmony_ci if (err) 41708c2ecf20Sopenharmony_ci goto ex_detach; 41718c2ecf20Sopenharmony_ci } else { 41728c2ecf20Sopenharmony_ci err = mlx4_adjust_port(dev, slave, gid, prot); 41738c2ecf20Sopenharmony_ci if (err) 41748c2ecf20Sopenharmony_ci goto ex_put; 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id); 41778c2ecf20Sopenharmony_ci if (err) 41788c2ecf20Sopenharmony_ci goto ex_put; 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci err = qp_detach(dev, &qp, gid, prot, type, reg_id); 41818c2ecf20Sopenharmony_ci if (err) 41828c2ecf20Sopenharmony_ci pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n", 41838c2ecf20Sopenharmony_ci qpn, reg_id); 41848c2ecf20Sopenharmony_ci } 41858c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 41868c2ecf20Sopenharmony_ci return err; 41878c2ecf20Sopenharmony_ci 41888c2ecf20Sopenharmony_ciex_detach: 41898c2ecf20Sopenharmony_ci qp_detach(dev, &qp, gid, prot, type, reg_id); 41908c2ecf20Sopenharmony_ciex_put: 41918c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 41928c2ecf20Sopenharmony_ci return err; 41938c2ecf20Sopenharmony_ci} 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ci/* 41968c2ecf20Sopenharmony_ci * MAC validation for Flow Steering rules. 41978c2ecf20Sopenharmony_ci * VF can attach rules only with a mac address which is assigned to it. 41988c2ecf20Sopenharmony_ci */ 41998c2ecf20Sopenharmony_cistatic int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, 42008c2ecf20Sopenharmony_ci struct list_head *rlist) 42018c2ecf20Sopenharmony_ci{ 42028c2ecf20Sopenharmony_ci struct mac_res *res, *tmp; 42038c2ecf20Sopenharmony_ci __be64 be_mac; 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_ci /* make sure it isn't multicast or broadcast mac*/ 42068c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && 42078c2ecf20Sopenharmony_ci !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { 42088c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, rlist, list) { 42098c2ecf20Sopenharmony_ci be_mac = cpu_to_be64(res->mac << 16); 42108c2ecf20Sopenharmony_ci if (ether_addr_equal((u8 *)&be_mac, eth_header->eth.dst_mac)) 42118c2ecf20Sopenharmony_ci return 0; 42128c2ecf20Sopenharmony_ci } 42138c2ecf20Sopenharmony_ci pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", 42148c2ecf20Sopenharmony_ci eth_header->eth.dst_mac, slave); 42158c2ecf20Sopenharmony_ci return -EINVAL; 42168c2ecf20Sopenharmony_ci } 42178c2ecf20Sopenharmony_ci return 0; 42188c2ecf20Sopenharmony_ci} 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci/* 42218c2ecf20Sopenharmony_ci * In case of missing eth header, append eth header with a MAC address 42228c2ecf20Sopenharmony_ci * assigned to the VF. 42238c2ecf20Sopenharmony_ci */ 42248c2ecf20Sopenharmony_cistatic int add_eth_header(struct mlx4_dev *dev, int slave, 42258c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 42268c2ecf20Sopenharmony_ci struct list_head *rlist, int header_id) 42278c2ecf20Sopenharmony_ci{ 42288c2ecf20Sopenharmony_ci struct mac_res *res, *tmp; 42298c2ecf20Sopenharmony_ci u8 port; 42308c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule_hw_ctrl *ctrl; 42318c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule_hw_eth *eth_header; 42328c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule_hw_ipv4 *ip_header; 42338c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; 42348c2ecf20Sopenharmony_ci __be64 be_mac = 0; 42358c2ecf20Sopenharmony_ci __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 42388c2ecf20Sopenharmony_ci port = ctrl->port; 42398c2ecf20Sopenharmony_ci eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci /* Clear a space in the inbox for eth header */ 42428c2ecf20Sopenharmony_ci switch (header_id) { 42438c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_IPV4: 42448c2ecf20Sopenharmony_ci ip_header = 42458c2ecf20Sopenharmony_ci (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); 42468c2ecf20Sopenharmony_ci memmove(ip_header, eth_header, 42478c2ecf20Sopenharmony_ci sizeof(*ip_header) + sizeof(*l4_header)); 42488c2ecf20Sopenharmony_ci break; 42498c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_TCP: 42508c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_UDP: 42518c2ecf20Sopenharmony_ci l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) 42528c2ecf20Sopenharmony_ci (eth_header + 1); 42538c2ecf20Sopenharmony_ci memmove(l4_header, eth_header, sizeof(*l4_header)); 42548c2ecf20Sopenharmony_ci break; 42558c2ecf20Sopenharmony_ci default: 42568c2ecf20Sopenharmony_ci return -EINVAL; 42578c2ecf20Sopenharmony_ci } 42588c2ecf20Sopenharmony_ci list_for_each_entry_safe(res, tmp, rlist, list) { 42598c2ecf20Sopenharmony_ci if (port == res->port) { 42608c2ecf20Sopenharmony_ci be_mac = cpu_to_be64(res->mac << 16); 42618c2ecf20Sopenharmony_ci break; 42628c2ecf20Sopenharmony_ci } 42638c2ecf20Sopenharmony_ci } 42648c2ecf20Sopenharmony_ci if (!be_mac) { 42658c2ecf20Sopenharmony_ci pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d\n", 42668c2ecf20Sopenharmony_ci port); 42678c2ecf20Sopenharmony_ci return -EINVAL; 42688c2ecf20Sopenharmony_ci } 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ci memset(eth_header, 0, sizeof(*eth_header)); 42718c2ecf20Sopenharmony_ci eth_header->size = sizeof(*eth_header) >> 2; 42728c2ecf20Sopenharmony_ci eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); 42738c2ecf20Sopenharmony_ci memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); 42748c2ecf20Sopenharmony_ci memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); 42758c2ecf20Sopenharmony_ci 42768c2ecf20Sopenharmony_ci return 0; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci} 42798c2ecf20Sopenharmony_ci 42808c2ecf20Sopenharmony_ci#define MLX4_UPD_QP_PATH_MASK_SUPPORTED ( \ 42818c2ecf20Sopenharmony_ci 1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX |\ 42828c2ecf20Sopenharmony_ci 1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB) 42838c2ecf20Sopenharmony_ciint mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, 42848c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 42858c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 42868c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 42878c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd_info) 42888c2ecf20Sopenharmony_ci{ 42898c2ecf20Sopenharmony_ci int err; 42908c2ecf20Sopenharmony_ci u32 qpn = vhcr->in_modifier & 0xffffff; 42918c2ecf20Sopenharmony_ci struct res_qp *rqp; 42928c2ecf20Sopenharmony_ci u64 mac; 42938c2ecf20Sopenharmony_ci unsigned port; 42948c2ecf20Sopenharmony_ci u64 pri_addr_path_mask; 42958c2ecf20Sopenharmony_ci struct mlx4_update_qp_context *cmd; 42968c2ecf20Sopenharmony_ci int smac_index; 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci cmd = (struct mlx4_update_qp_context *)inbox->buf; 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci pri_addr_path_mask = be64_to_cpu(cmd->primary_addr_path_mask); 43018c2ecf20Sopenharmony_ci if (cmd->qp_mask || cmd->secondary_addr_path_mask || 43028c2ecf20Sopenharmony_ci (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED)) 43038c2ecf20Sopenharmony_ci return -EPERM; 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci if ((pri_addr_path_mask & 43068c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) && 43078c2ecf20Sopenharmony_ci !(dev->caps.flags2 & 43088c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) { 43098c2ecf20Sopenharmony_ci mlx4_warn(dev, "Src check LB for slave %d isn't supported\n", 43108c2ecf20Sopenharmony_ci slave); 43118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 43128c2ecf20Sopenharmony_ci } 43138c2ecf20Sopenharmony_ci 43148c2ecf20Sopenharmony_ci /* Just change the smac for the QP */ 43158c2ecf20Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 43168c2ecf20Sopenharmony_ci if (err) { 43178c2ecf20Sopenharmony_ci mlx4_err(dev, "Updating qpn 0x%x for slave %d rejected\n", qpn, slave); 43188c2ecf20Sopenharmony_ci return err; 43198c2ecf20Sopenharmony_ci } 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ci port = (rqp->sched_queue >> 6 & 1) + 1; 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_ci if (pri_addr_path_mask & (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)) { 43248c2ecf20Sopenharmony_ci smac_index = cmd->qp_context.pri_path.grh_mylmc; 43258c2ecf20Sopenharmony_ci err = mac_find_smac_ix_in_slave(dev, slave, port, 43268c2ecf20Sopenharmony_ci smac_index, &mac); 43278c2ecf20Sopenharmony_ci 43288c2ecf20Sopenharmony_ci if (err) { 43298c2ecf20Sopenharmony_ci mlx4_err(dev, "Failed to update qpn 0x%x, MAC is invalid. smac_ix: %d\n", 43308c2ecf20Sopenharmony_ci qpn, smac_index); 43318c2ecf20Sopenharmony_ci goto err_mac; 43328c2ecf20Sopenharmony_ci } 43338c2ecf20Sopenharmony_ci } 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, inbox->dma, 43368c2ecf20Sopenharmony_ci vhcr->in_modifier, 0, 43378c2ecf20Sopenharmony_ci MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A, 43388c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 43398c2ecf20Sopenharmony_ci if (err) { 43408c2ecf20Sopenharmony_ci mlx4_err(dev, "Failed to update qpn on qpn 0x%x, command failed\n", qpn); 43418c2ecf20Sopenharmony_ci goto err_mac; 43428c2ecf20Sopenharmony_ci } 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_cierr_mac: 43458c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 43468c2ecf20Sopenharmony_ci return err; 43478c2ecf20Sopenharmony_ci} 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_cistatic u32 qp_attach_mbox_size(void *mbox) 43508c2ecf20Sopenharmony_ci{ 43518c2ecf20Sopenharmony_ci u32 size = sizeof(struct mlx4_net_trans_rule_hw_ctrl); 43528c2ecf20Sopenharmony_ci struct _rule_hw *rule_header; 43538c2ecf20Sopenharmony_ci 43548c2ecf20Sopenharmony_ci rule_header = (struct _rule_hw *)(mbox + size); 43558c2ecf20Sopenharmony_ci 43568c2ecf20Sopenharmony_ci while (rule_header->size) { 43578c2ecf20Sopenharmony_ci size += rule_header->size * sizeof(u32); 43588c2ecf20Sopenharmony_ci rule_header += 1; 43598c2ecf20Sopenharmony_ci } 43608c2ecf20Sopenharmony_ci return size; 43618c2ecf20Sopenharmony_ci} 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_cistatic int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule); 43648c2ecf20Sopenharmony_ci 43658c2ecf20Sopenharmony_ciint mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 43668c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 43678c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 43688c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 43698c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 43708c2ecf20Sopenharmony_ci{ 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 43738c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 43748c2ecf20Sopenharmony_ci struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; 43758c2ecf20Sopenharmony_ci int err; 43768c2ecf20Sopenharmony_ci int qpn; 43778c2ecf20Sopenharmony_ci struct res_qp *rqp; 43788c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule_hw_ctrl *ctrl; 43798c2ecf20Sopenharmony_ci struct _rule_hw *rule_header; 43808c2ecf20Sopenharmony_ci int header_id; 43818c2ecf20Sopenharmony_ci struct res_fs_rule *rrule; 43828c2ecf20Sopenharmony_ci u32 mbox_size; 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci if (dev->caps.steering_mode != 43858c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) 43868c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 43898c2ecf20Sopenharmony_ci err = mlx4_slave_convert_port(dev, slave, ctrl->port); 43908c2ecf20Sopenharmony_ci if (err <= 0) 43918c2ecf20Sopenharmony_ci return -EINVAL; 43928c2ecf20Sopenharmony_ci ctrl->port = err; 43938c2ecf20Sopenharmony_ci qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; 43948c2ecf20Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 43958c2ecf20Sopenharmony_ci if (err) { 43968c2ecf20Sopenharmony_ci pr_err("Steering rule with qpn 0x%x rejected\n", qpn); 43978c2ecf20Sopenharmony_ci return err; 43988c2ecf20Sopenharmony_ci } 43998c2ecf20Sopenharmony_ci rule_header = (struct _rule_hw *)(ctrl + 1); 44008c2ecf20Sopenharmony_ci header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_ci if (header_id == MLX4_NET_TRANS_RULE_ID_ETH) 44038c2ecf20Sopenharmony_ci mlx4_handle_eth_header_mcast_prio(ctrl, rule_header); 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ci switch (header_id) { 44068c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_ETH: 44078c2ecf20Sopenharmony_ci if (validate_eth_header_mac(slave, rule_header, rlist)) { 44088c2ecf20Sopenharmony_ci err = -EINVAL; 44098c2ecf20Sopenharmony_ci goto err_put_qp; 44108c2ecf20Sopenharmony_ci } 44118c2ecf20Sopenharmony_ci break; 44128c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_IB: 44138c2ecf20Sopenharmony_ci break; 44148c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_IPV4: 44158c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_TCP: 44168c2ecf20Sopenharmony_ci case MLX4_NET_TRANS_RULE_ID_UDP: 44178c2ecf20Sopenharmony_ci pr_warn("Can't attach FS rule without L2 headers, adding L2 header\n"); 44188c2ecf20Sopenharmony_ci if (add_eth_header(dev, slave, inbox, rlist, header_id)) { 44198c2ecf20Sopenharmony_ci err = -EINVAL; 44208c2ecf20Sopenharmony_ci goto err_put_qp; 44218c2ecf20Sopenharmony_ci } 44228c2ecf20Sopenharmony_ci vhcr->in_modifier += 44238c2ecf20Sopenharmony_ci sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; 44248c2ecf20Sopenharmony_ci break; 44258c2ecf20Sopenharmony_ci default: 44268c2ecf20Sopenharmony_ci pr_err("Corrupted mailbox\n"); 44278c2ecf20Sopenharmony_ci err = -EINVAL; 44288c2ecf20Sopenharmony_ci goto err_put_qp; 44298c2ecf20Sopenharmony_ci } 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_ci err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, 44328c2ecf20Sopenharmony_ci vhcr->in_modifier, 0, 44338c2ecf20Sopenharmony_ci MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 44348c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 44358c2ecf20Sopenharmony_ci if (err) 44368c2ecf20Sopenharmony_ci goto err_put_qp; 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ci err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); 44408c2ecf20Sopenharmony_ci if (err) { 44418c2ecf20Sopenharmony_ci mlx4_err(dev, "Fail to add flow steering resources\n"); 44428c2ecf20Sopenharmony_ci goto err_detach; 44438c2ecf20Sopenharmony_ci } 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci err = get_res(dev, slave, vhcr->out_param, RES_FS_RULE, &rrule); 44468c2ecf20Sopenharmony_ci if (err) 44478c2ecf20Sopenharmony_ci goto err_detach; 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci mbox_size = qp_attach_mbox_size(inbox->buf); 44508c2ecf20Sopenharmony_ci rrule->mirr_mbox = kmalloc(mbox_size, GFP_KERNEL); 44518c2ecf20Sopenharmony_ci if (!rrule->mirr_mbox) { 44528c2ecf20Sopenharmony_ci err = -ENOMEM; 44538c2ecf20Sopenharmony_ci goto err_put_rule; 44548c2ecf20Sopenharmony_ci } 44558c2ecf20Sopenharmony_ci rrule->mirr_mbox_size = mbox_size; 44568c2ecf20Sopenharmony_ci rrule->mirr_rule_id = 0; 44578c2ecf20Sopenharmony_ci memcpy(rrule->mirr_mbox, inbox->buf, mbox_size); 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_ci /* set different port */ 44608c2ecf20Sopenharmony_ci ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)rrule->mirr_mbox; 44618c2ecf20Sopenharmony_ci if (ctrl->port == 1) 44628c2ecf20Sopenharmony_ci ctrl->port = 2; 44638c2ecf20Sopenharmony_ci else 44648c2ecf20Sopenharmony_ci ctrl->port = 1; 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci if (mlx4_is_bonded(dev)) 44678c2ecf20Sopenharmony_ci mlx4_do_mirror_rule(dev, rrule); 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_ci atomic_inc(&rqp->ref_count); 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_cierr_put_rule: 44728c2ecf20Sopenharmony_ci put_res(dev, slave, vhcr->out_param, RES_FS_RULE); 44738c2ecf20Sopenharmony_cierr_detach: 44748c2ecf20Sopenharmony_ci /* detach rule on error */ 44758c2ecf20Sopenharmony_ci if (err) 44768c2ecf20Sopenharmony_ci mlx4_cmd(dev, vhcr->out_param, 0, 0, 44778c2ecf20Sopenharmony_ci MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 44788c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 44798c2ecf20Sopenharmony_cierr_put_qp: 44808c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 44818c2ecf20Sopenharmony_ci return err; 44828c2ecf20Sopenharmony_ci} 44838c2ecf20Sopenharmony_ci 44848c2ecf20Sopenharmony_cistatic int mlx4_undo_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule) 44858c2ecf20Sopenharmony_ci{ 44868c2ecf20Sopenharmony_ci int err; 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci err = rem_res_range(dev, fs_rule->com.owner, fs_rule->com.res_id, 1, RES_FS_RULE, 0); 44898c2ecf20Sopenharmony_ci if (err) { 44908c2ecf20Sopenharmony_ci mlx4_err(dev, "Fail to remove flow steering resources\n"); 44918c2ecf20Sopenharmony_ci return err; 44928c2ecf20Sopenharmony_ci } 44938c2ecf20Sopenharmony_ci 44948c2ecf20Sopenharmony_ci mlx4_cmd(dev, fs_rule->com.res_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, 44958c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 44968c2ecf20Sopenharmony_ci return 0; 44978c2ecf20Sopenharmony_ci} 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ciint mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, 45008c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 45018c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 45028c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 45038c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 45048c2ecf20Sopenharmony_ci{ 45058c2ecf20Sopenharmony_ci int err; 45068c2ecf20Sopenharmony_ci struct res_qp *rqp; 45078c2ecf20Sopenharmony_ci struct res_fs_rule *rrule; 45088c2ecf20Sopenharmony_ci u64 mirr_reg_id; 45098c2ecf20Sopenharmony_ci int qpn; 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci if (dev->caps.steering_mode != 45128c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) 45138c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 45148c2ecf20Sopenharmony_ci 45158c2ecf20Sopenharmony_ci err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); 45168c2ecf20Sopenharmony_ci if (err) 45178c2ecf20Sopenharmony_ci return err; 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci if (!rrule->mirr_mbox) { 45208c2ecf20Sopenharmony_ci mlx4_err(dev, "Mirror rules cannot be removed explicitly\n"); 45218c2ecf20Sopenharmony_ci put_res(dev, slave, vhcr->in_param, RES_FS_RULE); 45228c2ecf20Sopenharmony_ci return -EINVAL; 45238c2ecf20Sopenharmony_ci } 45248c2ecf20Sopenharmony_ci mirr_reg_id = rrule->mirr_rule_id; 45258c2ecf20Sopenharmony_ci kfree(rrule->mirr_mbox); 45268c2ecf20Sopenharmony_ci qpn = rrule->qpn; 45278c2ecf20Sopenharmony_ci 45288c2ecf20Sopenharmony_ci /* Release the rule form busy state before removal */ 45298c2ecf20Sopenharmony_ci put_res(dev, slave, vhcr->in_param, RES_FS_RULE); 45308c2ecf20Sopenharmony_ci err = get_res(dev, slave, qpn, RES_QP, &rqp); 45318c2ecf20Sopenharmony_ci if (err) 45328c2ecf20Sopenharmony_ci return err; 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci if (mirr_reg_id && mlx4_is_bonded(dev)) { 45358c2ecf20Sopenharmony_ci err = get_res(dev, slave, mirr_reg_id, RES_FS_RULE, &rrule); 45368c2ecf20Sopenharmony_ci if (err) { 45378c2ecf20Sopenharmony_ci mlx4_err(dev, "Fail to get resource of mirror rule\n"); 45388c2ecf20Sopenharmony_ci } else { 45398c2ecf20Sopenharmony_ci put_res(dev, slave, mirr_reg_id, RES_FS_RULE); 45408c2ecf20Sopenharmony_ci mlx4_undo_mirror_rule(dev, rrule); 45418c2ecf20Sopenharmony_ci } 45428c2ecf20Sopenharmony_ci } 45438c2ecf20Sopenharmony_ci err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0); 45448c2ecf20Sopenharmony_ci if (err) { 45458c2ecf20Sopenharmony_ci mlx4_err(dev, "Fail to remove flow steering resources\n"); 45468c2ecf20Sopenharmony_ci goto out; 45478c2ecf20Sopenharmony_ci } 45488c2ecf20Sopenharmony_ci 45498c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, vhcr->in_param, 0, 0, 45508c2ecf20Sopenharmony_ci MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 45518c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 45528c2ecf20Sopenharmony_ci if (!err) 45538c2ecf20Sopenharmony_ci atomic_dec(&rqp->ref_count); 45548c2ecf20Sopenharmony_ciout: 45558c2ecf20Sopenharmony_ci put_res(dev, slave, qpn, RES_QP); 45568c2ecf20Sopenharmony_ci return err; 45578c2ecf20Sopenharmony_ci} 45588c2ecf20Sopenharmony_ci 45598c2ecf20Sopenharmony_cienum { 45608c2ecf20Sopenharmony_ci BUSY_MAX_RETRIES = 10 45618c2ecf20Sopenharmony_ci}; 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ciint mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, 45648c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 45658c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 45668c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 45678c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 45688c2ecf20Sopenharmony_ci{ 45698c2ecf20Sopenharmony_ci int err; 45708c2ecf20Sopenharmony_ci int index = vhcr->in_modifier & 0xffff; 45718c2ecf20Sopenharmony_ci 45728c2ecf20Sopenharmony_ci err = get_res(dev, slave, index, RES_COUNTER, NULL); 45738c2ecf20Sopenharmony_ci if (err) 45748c2ecf20Sopenharmony_ci return err; 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 45778c2ecf20Sopenharmony_ci put_res(dev, slave, index, RES_COUNTER); 45788c2ecf20Sopenharmony_ci return err; 45798c2ecf20Sopenharmony_ci} 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_cistatic void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) 45828c2ecf20Sopenharmony_ci{ 45838c2ecf20Sopenharmony_ci struct res_gid *rgid; 45848c2ecf20Sopenharmony_ci struct res_gid *tmp; 45858c2ecf20Sopenharmony_ci struct mlx4_qp qp; /* dummy for calling attach/detach */ 45868c2ecf20Sopenharmony_ci 45878c2ecf20Sopenharmony_ci list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { 45888c2ecf20Sopenharmony_ci switch (dev->caps.steering_mode) { 45898c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 45908c2ecf20Sopenharmony_ci mlx4_flow_detach(dev, rgid->reg_id); 45918c2ecf20Sopenharmony_ci break; 45928c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 45938c2ecf20Sopenharmony_ci qp.qpn = rqp->local_qpn; 45948c2ecf20Sopenharmony_ci (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, 45958c2ecf20Sopenharmony_ci rgid->prot, rgid->steer); 45968c2ecf20Sopenharmony_ci break; 45978c2ecf20Sopenharmony_ci } 45988c2ecf20Sopenharmony_ci list_del(&rgid->list); 45998c2ecf20Sopenharmony_ci kfree(rgid); 46008c2ecf20Sopenharmony_ci } 46018c2ecf20Sopenharmony_ci} 46028c2ecf20Sopenharmony_ci 46038c2ecf20Sopenharmony_cistatic int _move_all_busy(struct mlx4_dev *dev, int slave, 46048c2ecf20Sopenharmony_ci enum mlx4_resource type, int print) 46058c2ecf20Sopenharmony_ci{ 46068c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 46078c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = 46088c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker; 46098c2ecf20Sopenharmony_ci struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; 46108c2ecf20Sopenharmony_ci struct res_common *r; 46118c2ecf20Sopenharmony_ci struct res_common *tmp; 46128c2ecf20Sopenharmony_ci int busy; 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci busy = 0; 46158c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 46168c2ecf20Sopenharmony_ci list_for_each_entry_safe(r, tmp, rlist, list) { 46178c2ecf20Sopenharmony_ci if (r->owner == slave) { 46188c2ecf20Sopenharmony_ci if (!r->removing) { 46198c2ecf20Sopenharmony_ci if (r->state == RES_ANY_BUSY) { 46208c2ecf20Sopenharmony_ci if (print) 46218c2ecf20Sopenharmony_ci mlx4_dbg(dev, 46228c2ecf20Sopenharmony_ci "%s id 0x%llx is busy\n", 46238c2ecf20Sopenharmony_ci resource_str(type), 46248c2ecf20Sopenharmony_ci r->res_id); 46258c2ecf20Sopenharmony_ci ++busy; 46268c2ecf20Sopenharmony_ci } else { 46278c2ecf20Sopenharmony_ci r->from_state = r->state; 46288c2ecf20Sopenharmony_ci r->state = RES_ANY_BUSY; 46298c2ecf20Sopenharmony_ci r->removing = 1; 46308c2ecf20Sopenharmony_ci } 46318c2ecf20Sopenharmony_ci } 46328c2ecf20Sopenharmony_ci } 46338c2ecf20Sopenharmony_ci } 46348c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 46358c2ecf20Sopenharmony_ci 46368c2ecf20Sopenharmony_ci return busy; 46378c2ecf20Sopenharmony_ci} 46388c2ecf20Sopenharmony_ci 46398c2ecf20Sopenharmony_cistatic int move_all_busy(struct mlx4_dev *dev, int slave, 46408c2ecf20Sopenharmony_ci enum mlx4_resource type) 46418c2ecf20Sopenharmony_ci{ 46428c2ecf20Sopenharmony_ci unsigned long begin; 46438c2ecf20Sopenharmony_ci int busy; 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_ci begin = jiffies; 46468c2ecf20Sopenharmony_ci do { 46478c2ecf20Sopenharmony_ci busy = _move_all_busy(dev, slave, type, 0); 46488c2ecf20Sopenharmony_ci if (time_after(jiffies, begin + 5 * HZ)) 46498c2ecf20Sopenharmony_ci break; 46508c2ecf20Sopenharmony_ci if (busy) 46518c2ecf20Sopenharmony_ci cond_resched(); 46528c2ecf20Sopenharmony_ci } while (busy); 46538c2ecf20Sopenharmony_ci 46548c2ecf20Sopenharmony_ci if (busy) 46558c2ecf20Sopenharmony_ci busy = _move_all_busy(dev, slave, type, 1); 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ci return busy; 46588c2ecf20Sopenharmony_ci} 46598c2ecf20Sopenharmony_cistatic void rem_slave_qps(struct mlx4_dev *dev, int slave) 46608c2ecf20Sopenharmony_ci{ 46618c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 46628c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 46638c2ecf20Sopenharmony_ci struct list_head *qp_list = 46648c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_QP]; 46658c2ecf20Sopenharmony_ci struct res_qp *qp; 46668c2ecf20Sopenharmony_ci struct res_qp *tmp; 46678c2ecf20Sopenharmony_ci int state; 46688c2ecf20Sopenharmony_ci u64 in_param; 46698c2ecf20Sopenharmony_ci int qpn; 46708c2ecf20Sopenharmony_ci int err; 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_QP); 46738c2ecf20Sopenharmony_ci if (err) 46748c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy for slave %d\n", 46758c2ecf20Sopenharmony_ci slave); 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 46788c2ecf20Sopenharmony_ci list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 46798c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 46808c2ecf20Sopenharmony_ci if (qp->com.owner == slave) { 46818c2ecf20Sopenharmony_ci qpn = qp->com.res_id; 46828c2ecf20Sopenharmony_ci detach_qp(dev, slave, qp); 46838c2ecf20Sopenharmony_ci state = qp->com.from_state; 46848c2ecf20Sopenharmony_ci while (state != 0) { 46858c2ecf20Sopenharmony_ci switch (state) { 46868c2ecf20Sopenharmony_ci case RES_QP_RESERVED: 46878c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 46888c2ecf20Sopenharmony_ci rb_erase(&qp->com.node, 46898c2ecf20Sopenharmony_ci &tracker->res_tree[RES_QP]); 46908c2ecf20Sopenharmony_ci list_del(&qp->com.list); 46918c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 46928c2ecf20Sopenharmony_ci if (!valid_reserved(dev, slave, qpn)) { 46938c2ecf20Sopenharmony_ci __mlx4_qp_release_range(dev, qpn, 1); 46948c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, 46958c2ecf20Sopenharmony_ci RES_QP, 1, 0); 46968c2ecf20Sopenharmony_ci } 46978c2ecf20Sopenharmony_ci kfree(qp); 46988c2ecf20Sopenharmony_ci state = 0; 46998c2ecf20Sopenharmony_ci break; 47008c2ecf20Sopenharmony_ci case RES_QP_MAPPED: 47018c2ecf20Sopenharmony_ci if (!valid_reserved(dev, slave, qpn)) 47028c2ecf20Sopenharmony_ci __mlx4_qp_free_icm(dev, qpn); 47038c2ecf20Sopenharmony_ci state = RES_QP_RESERVED; 47048c2ecf20Sopenharmony_ci break; 47058c2ecf20Sopenharmony_ci case RES_QP_HW: 47068c2ecf20Sopenharmony_ci in_param = slave; 47078c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, in_param, 47088c2ecf20Sopenharmony_ci qp->local_qpn, 2, 47098c2ecf20Sopenharmony_ci MLX4_CMD_2RST_QP, 47108c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 47118c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 47128c2ecf20Sopenharmony_ci if (err) 47138c2ecf20Sopenharmony_ci mlx4_dbg(dev, "rem_slave_qps: failed to move slave %d qpn %d to reset\n", 47148c2ecf20Sopenharmony_ci slave, qp->local_qpn); 47158c2ecf20Sopenharmony_ci atomic_dec(&qp->rcq->ref_count); 47168c2ecf20Sopenharmony_ci atomic_dec(&qp->scq->ref_count); 47178c2ecf20Sopenharmony_ci atomic_dec(&qp->mtt->ref_count); 47188c2ecf20Sopenharmony_ci if (qp->srq) 47198c2ecf20Sopenharmony_ci atomic_dec(&qp->srq->ref_count); 47208c2ecf20Sopenharmony_ci state = RES_QP_MAPPED; 47218c2ecf20Sopenharmony_ci break; 47228c2ecf20Sopenharmony_ci default: 47238c2ecf20Sopenharmony_ci state = 0; 47248c2ecf20Sopenharmony_ci } 47258c2ecf20Sopenharmony_ci } 47268c2ecf20Sopenharmony_ci } 47278c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 47288c2ecf20Sopenharmony_ci } 47298c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 47308c2ecf20Sopenharmony_ci} 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_cistatic void rem_slave_srqs(struct mlx4_dev *dev, int slave) 47338c2ecf20Sopenharmony_ci{ 47348c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 47358c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 47368c2ecf20Sopenharmony_ci struct list_head *srq_list = 47378c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_SRQ]; 47388c2ecf20Sopenharmony_ci struct res_srq *srq; 47398c2ecf20Sopenharmony_ci struct res_srq *tmp; 47408c2ecf20Sopenharmony_ci int state; 47418c2ecf20Sopenharmony_ci u64 in_param; 47428c2ecf20Sopenharmony_ci int srqn; 47438c2ecf20Sopenharmony_ci int err; 47448c2ecf20Sopenharmony_ci 47458c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_SRQ); 47468c2ecf20Sopenharmony_ci if (err) 47478c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs - too busy for slave %d\n", 47488c2ecf20Sopenharmony_ci slave); 47498c2ecf20Sopenharmony_ci 47508c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 47518c2ecf20Sopenharmony_ci list_for_each_entry_safe(srq, tmp, srq_list, com.list) { 47528c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 47538c2ecf20Sopenharmony_ci if (srq->com.owner == slave) { 47548c2ecf20Sopenharmony_ci srqn = srq->com.res_id; 47558c2ecf20Sopenharmony_ci state = srq->com.from_state; 47568c2ecf20Sopenharmony_ci while (state != 0) { 47578c2ecf20Sopenharmony_ci switch (state) { 47588c2ecf20Sopenharmony_ci case RES_SRQ_ALLOCATED: 47598c2ecf20Sopenharmony_ci __mlx4_srq_free_icm(dev, srqn); 47608c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 47618c2ecf20Sopenharmony_ci rb_erase(&srq->com.node, 47628c2ecf20Sopenharmony_ci &tracker->res_tree[RES_SRQ]); 47638c2ecf20Sopenharmony_ci list_del(&srq->com.list); 47648c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 47658c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, 47668c2ecf20Sopenharmony_ci RES_SRQ, 1, 0); 47678c2ecf20Sopenharmony_ci kfree(srq); 47688c2ecf20Sopenharmony_ci state = 0; 47698c2ecf20Sopenharmony_ci break; 47708c2ecf20Sopenharmony_ci 47718c2ecf20Sopenharmony_ci case RES_SRQ_HW: 47728c2ecf20Sopenharmony_ci in_param = slave; 47738c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, in_param, srqn, 1, 47748c2ecf20Sopenharmony_ci MLX4_CMD_HW2SW_SRQ, 47758c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 47768c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 47778c2ecf20Sopenharmony_ci if (err) 47788c2ecf20Sopenharmony_ci mlx4_dbg(dev, "rem_slave_srqs: failed to move slave %d srq %d to SW ownership\n", 47798c2ecf20Sopenharmony_ci slave, srqn); 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci atomic_dec(&srq->mtt->ref_count); 47828c2ecf20Sopenharmony_ci if (srq->cq) 47838c2ecf20Sopenharmony_ci atomic_dec(&srq->cq->ref_count); 47848c2ecf20Sopenharmony_ci state = RES_SRQ_ALLOCATED; 47858c2ecf20Sopenharmony_ci break; 47868c2ecf20Sopenharmony_ci 47878c2ecf20Sopenharmony_ci default: 47888c2ecf20Sopenharmony_ci state = 0; 47898c2ecf20Sopenharmony_ci } 47908c2ecf20Sopenharmony_ci } 47918c2ecf20Sopenharmony_ci } 47928c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 47938c2ecf20Sopenharmony_ci } 47948c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 47958c2ecf20Sopenharmony_ci} 47968c2ecf20Sopenharmony_ci 47978c2ecf20Sopenharmony_cistatic void rem_slave_cqs(struct mlx4_dev *dev, int slave) 47988c2ecf20Sopenharmony_ci{ 47998c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 48008c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 48018c2ecf20Sopenharmony_ci struct list_head *cq_list = 48028c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_CQ]; 48038c2ecf20Sopenharmony_ci struct res_cq *cq; 48048c2ecf20Sopenharmony_ci struct res_cq *tmp; 48058c2ecf20Sopenharmony_ci int state; 48068c2ecf20Sopenharmony_ci u64 in_param; 48078c2ecf20Sopenharmony_ci int cqn; 48088c2ecf20Sopenharmony_ci int err; 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_CQ); 48118c2ecf20Sopenharmony_ci if (err) 48128c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs - too busy for slave %d\n", 48138c2ecf20Sopenharmony_ci slave); 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 48168c2ecf20Sopenharmony_ci list_for_each_entry_safe(cq, tmp, cq_list, com.list) { 48178c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 48188c2ecf20Sopenharmony_ci if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { 48198c2ecf20Sopenharmony_ci cqn = cq->com.res_id; 48208c2ecf20Sopenharmony_ci state = cq->com.from_state; 48218c2ecf20Sopenharmony_ci while (state != 0) { 48228c2ecf20Sopenharmony_ci switch (state) { 48238c2ecf20Sopenharmony_ci case RES_CQ_ALLOCATED: 48248c2ecf20Sopenharmony_ci __mlx4_cq_free_icm(dev, cqn); 48258c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 48268c2ecf20Sopenharmony_ci rb_erase(&cq->com.node, 48278c2ecf20Sopenharmony_ci &tracker->res_tree[RES_CQ]); 48288c2ecf20Sopenharmony_ci list_del(&cq->com.list); 48298c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 48308c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, 48318c2ecf20Sopenharmony_ci RES_CQ, 1, 0); 48328c2ecf20Sopenharmony_ci kfree(cq); 48338c2ecf20Sopenharmony_ci state = 0; 48348c2ecf20Sopenharmony_ci break; 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_ci case RES_CQ_HW: 48378c2ecf20Sopenharmony_ci in_param = slave; 48388c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, in_param, cqn, 1, 48398c2ecf20Sopenharmony_ci MLX4_CMD_HW2SW_CQ, 48408c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 48418c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 48428c2ecf20Sopenharmony_ci if (err) 48438c2ecf20Sopenharmony_ci mlx4_dbg(dev, "rem_slave_cqs: failed to move slave %d cq %d to SW ownership\n", 48448c2ecf20Sopenharmony_ci slave, cqn); 48458c2ecf20Sopenharmony_ci atomic_dec(&cq->mtt->ref_count); 48468c2ecf20Sopenharmony_ci state = RES_CQ_ALLOCATED; 48478c2ecf20Sopenharmony_ci break; 48488c2ecf20Sopenharmony_ci 48498c2ecf20Sopenharmony_ci default: 48508c2ecf20Sopenharmony_ci state = 0; 48518c2ecf20Sopenharmony_ci } 48528c2ecf20Sopenharmony_ci } 48538c2ecf20Sopenharmony_ci } 48548c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 48558c2ecf20Sopenharmony_ci } 48568c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 48578c2ecf20Sopenharmony_ci} 48588c2ecf20Sopenharmony_ci 48598c2ecf20Sopenharmony_cistatic void rem_slave_mrs(struct mlx4_dev *dev, int slave) 48608c2ecf20Sopenharmony_ci{ 48618c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 48628c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 48638c2ecf20Sopenharmony_ci struct list_head *mpt_list = 48648c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MPT]; 48658c2ecf20Sopenharmony_ci struct res_mpt *mpt; 48668c2ecf20Sopenharmony_ci struct res_mpt *tmp; 48678c2ecf20Sopenharmony_ci int state; 48688c2ecf20Sopenharmony_ci u64 in_param; 48698c2ecf20Sopenharmony_ci int mptn; 48708c2ecf20Sopenharmony_ci int err; 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_MPT); 48738c2ecf20Sopenharmony_ci if (err) 48748c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts - too busy for slave %d\n", 48758c2ecf20Sopenharmony_ci slave); 48768c2ecf20Sopenharmony_ci 48778c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 48788c2ecf20Sopenharmony_ci list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { 48798c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 48808c2ecf20Sopenharmony_ci if (mpt->com.owner == slave) { 48818c2ecf20Sopenharmony_ci mptn = mpt->com.res_id; 48828c2ecf20Sopenharmony_ci state = mpt->com.from_state; 48838c2ecf20Sopenharmony_ci while (state != 0) { 48848c2ecf20Sopenharmony_ci switch (state) { 48858c2ecf20Sopenharmony_ci case RES_MPT_RESERVED: 48868c2ecf20Sopenharmony_ci __mlx4_mpt_release(dev, mpt->key); 48878c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 48888c2ecf20Sopenharmony_ci rb_erase(&mpt->com.node, 48898c2ecf20Sopenharmony_ci &tracker->res_tree[RES_MPT]); 48908c2ecf20Sopenharmony_ci list_del(&mpt->com.list); 48918c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 48928c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, 48938c2ecf20Sopenharmony_ci RES_MPT, 1, 0); 48948c2ecf20Sopenharmony_ci kfree(mpt); 48958c2ecf20Sopenharmony_ci state = 0; 48968c2ecf20Sopenharmony_ci break; 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci case RES_MPT_MAPPED: 48998c2ecf20Sopenharmony_ci __mlx4_mpt_free_icm(dev, mpt->key); 49008c2ecf20Sopenharmony_ci state = RES_MPT_RESERVED; 49018c2ecf20Sopenharmony_ci break; 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_ci case RES_MPT_HW: 49048c2ecf20Sopenharmony_ci in_param = slave; 49058c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, in_param, mptn, 0, 49068c2ecf20Sopenharmony_ci MLX4_CMD_HW2SW_MPT, 49078c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 49088c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 49098c2ecf20Sopenharmony_ci if (err) 49108c2ecf20Sopenharmony_ci mlx4_dbg(dev, "rem_slave_mrs: failed to move slave %d mpt %d to SW ownership\n", 49118c2ecf20Sopenharmony_ci slave, mptn); 49128c2ecf20Sopenharmony_ci if (mpt->mtt) 49138c2ecf20Sopenharmony_ci atomic_dec(&mpt->mtt->ref_count); 49148c2ecf20Sopenharmony_ci state = RES_MPT_MAPPED; 49158c2ecf20Sopenharmony_ci break; 49168c2ecf20Sopenharmony_ci default: 49178c2ecf20Sopenharmony_ci state = 0; 49188c2ecf20Sopenharmony_ci } 49198c2ecf20Sopenharmony_ci } 49208c2ecf20Sopenharmony_ci } 49218c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 49228c2ecf20Sopenharmony_ci } 49238c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 49248c2ecf20Sopenharmony_ci} 49258c2ecf20Sopenharmony_ci 49268c2ecf20Sopenharmony_cistatic void rem_slave_mtts(struct mlx4_dev *dev, int slave) 49278c2ecf20Sopenharmony_ci{ 49288c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 49298c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = 49308c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker; 49318c2ecf20Sopenharmony_ci struct list_head *mtt_list = 49328c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_MTT]; 49338c2ecf20Sopenharmony_ci struct res_mtt *mtt; 49348c2ecf20Sopenharmony_ci struct res_mtt *tmp; 49358c2ecf20Sopenharmony_ci int state; 49368c2ecf20Sopenharmony_ci int base; 49378c2ecf20Sopenharmony_ci int err; 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_MTT); 49408c2ecf20Sopenharmony_ci if (err) 49418c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts - too busy for slave %d\n", 49428c2ecf20Sopenharmony_ci slave); 49438c2ecf20Sopenharmony_ci 49448c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 49458c2ecf20Sopenharmony_ci list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { 49468c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 49478c2ecf20Sopenharmony_ci if (mtt->com.owner == slave) { 49488c2ecf20Sopenharmony_ci base = mtt->com.res_id; 49498c2ecf20Sopenharmony_ci state = mtt->com.from_state; 49508c2ecf20Sopenharmony_ci while (state != 0) { 49518c2ecf20Sopenharmony_ci switch (state) { 49528c2ecf20Sopenharmony_ci case RES_MTT_ALLOCATED: 49538c2ecf20Sopenharmony_ci __mlx4_free_mtt_range(dev, base, 49548c2ecf20Sopenharmony_ci mtt->order); 49558c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 49568c2ecf20Sopenharmony_ci rb_erase(&mtt->com.node, 49578c2ecf20Sopenharmony_ci &tracker->res_tree[RES_MTT]); 49588c2ecf20Sopenharmony_ci list_del(&mtt->com.list); 49598c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 49608c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_MTT, 49618c2ecf20Sopenharmony_ci 1 << mtt->order, 0); 49628c2ecf20Sopenharmony_ci kfree(mtt); 49638c2ecf20Sopenharmony_ci state = 0; 49648c2ecf20Sopenharmony_ci break; 49658c2ecf20Sopenharmony_ci 49668c2ecf20Sopenharmony_ci default: 49678c2ecf20Sopenharmony_ci state = 0; 49688c2ecf20Sopenharmony_ci } 49698c2ecf20Sopenharmony_ci } 49708c2ecf20Sopenharmony_ci } 49718c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 49728c2ecf20Sopenharmony_ci } 49738c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 49748c2ecf20Sopenharmony_ci} 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_cistatic int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule) 49778c2ecf20Sopenharmony_ci{ 49788c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 49798c2ecf20Sopenharmony_ci int err; 49808c2ecf20Sopenharmony_ci struct res_fs_rule *mirr_rule; 49818c2ecf20Sopenharmony_ci u64 reg_id; 49828c2ecf20Sopenharmony_ci 49838c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 49848c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) 49858c2ecf20Sopenharmony_ci return PTR_ERR(mailbox); 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci if (!fs_rule->mirr_mbox) { 49888c2ecf20Sopenharmony_ci mlx4_err(dev, "rule mirroring mailbox is null\n"); 49898c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 49908c2ecf20Sopenharmony_ci return -EINVAL; 49918c2ecf20Sopenharmony_ci } 49928c2ecf20Sopenharmony_ci memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size); 49938c2ecf20Sopenharmony_ci err = mlx4_cmd_imm(dev, mailbox->dma, ®_id, fs_rule->mirr_mbox_size >> 2, 0, 49948c2ecf20Sopenharmony_ci MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 49958c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 49968c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_ci if (err) 49998c2ecf20Sopenharmony_ci goto err; 50008c2ecf20Sopenharmony_ci 50018c2ecf20Sopenharmony_ci err = add_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, fs_rule->qpn); 50028c2ecf20Sopenharmony_ci if (err) 50038c2ecf20Sopenharmony_ci goto err_detach; 50048c2ecf20Sopenharmony_ci 50058c2ecf20Sopenharmony_ci err = get_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE, &mirr_rule); 50068c2ecf20Sopenharmony_ci if (err) 50078c2ecf20Sopenharmony_ci goto err_rem; 50088c2ecf20Sopenharmony_ci 50098c2ecf20Sopenharmony_ci fs_rule->mirr_rule_id = reg_id; 50108c2ecf20Sopenharmony_ci mirr_rule->mirr_rule_id = 0; 50118c2ecf20Sopenharmony_ci mirr_rule->mirr_mbox_size = 0; 50128c2ecf20Sopenharmony_ci mirr_rule->mirr_mbox = NULL; 50138c2ecf20Sopenharmony_ci put_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE); 50148c2ecf20Sopenharmony_ci 50158c2ecf20Sopenharmony_ci return 0; 50168c2ecf20Sopenharmony_cierr_rem: 50178c2ecf20Sopenharmony_ci rem_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, 0); 50188c2ecf20Sopenharmony_cierr_detach: 50198c2ecf20Sopenharmony_ci mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, 50208c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 50218c2ecf20Sopenharmony_cierr: 50228c2ecf20Sopenharmony_ci return err; 50238c2ecf20Sopenharmony_ci} 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_cistatic int mlx4_mirror_fs_rules(struct mlx4_dev *dev, bool bond) 50268c2ecf20Sopenharmony_ci{ 50278c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 50288c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = 50298c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker; 50308c2ecf20Sopenharmony_ci struct rb_root *root = &tracker->res_tree[RES_FS_RULE]; 50318c2ecf20Sopenharmony_ci struct rb_node *p; 50328c2ecf20Sopenharmony_ci struct res_fs_rule *fs_rule; 50338c2ecf20Sopenharmony_ci int err = 0; 50348c2ecf20Sopenharmony_ci LIST_HEAD(mirr_list); 50358c2ecf20Sopenharmony_ci 50368c2ecf20Sopenharmony_ci for (p = rb_first(root); p; p = rb_next(p)) { 50378c2ecf20Sopenharmony_ci fs_rule = rb_entry(p, struct res_fs_rule, com.node); 50388c2ecf20Sopenharmony_ci if ((bond && fs_rule->mirr_mbox_size) || 50398c2ecf20Sopenharmony_ci (!bond && !fs_rule->mirr_mbox_size)) 50408c2ecf20Sopenharmony_ci list_add_tail(&fs_rule->mirr_list, &mirr_list); 50418c2ecf20Sopenharmony_ci } 50428c2ecf20Sopenharmony_ci 50438c2ecf20Sopenharmony_ci list_for_each_entry(fs_rule, &mirr_list, mirr_list) { 50448c2ecf20Sopenharmony_ci if (bond) 50458c2ecf20Sopenharmony_ci err += mlx4_do_mirror_rule(dev, fs_rule); 50468c2ecf20Sopenharmony_ci else 50478c2ecf20Sopenharmony_ci err += mlx4_undo_mirror_rule(dev, fs_rule); 50488c2ecf20Sopenharmony_ci } 50498c2ecf20Sopenharmony_ci return err; 50508c2ecf20Sopenharmony_ci} 50518c2ecf20Sopenharmony_ci 50528c2ecf20Sopenharmony_ciint mlx4_bond_fs_rules(struct mlx4_dev *dev) 50538c2ecf20Sopenharmony_ci{ 50548c2ecf20Sopenharmony_ci return mlx4_mirror_fs_rules(dev, true); 50558c2ecf20Sopenharmony_ci} 50568c2ecf20Sopenharmony_ci 50578c2ecf20Sopenharmony_ciint mlx4_unbond_fs_rules(struct mlx4_dev *dev) 50588c2ecf20Sopenharmony_ci{ 50598c2ecf20Sopenharmony_ci return mlx4_mirror_fs_rules(dev, false); 50608c2ecf20Sopenharmony_ci} 50618c2ecf20Sopenharmony_ci 50628c2ecf20Sopenharmony_cistatic void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) 50638c2ecf20Sopenharmony_ci{ 50648c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 50658c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = 50668c2ecf20Sopenharmony_ci &priv->mfunc.master.res_tracker; 50678c2ecf20Sopenharmony_ci struct list_head *fs_rule_list = 50688c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_FS_RULE]; 50698c2ecf20Sopenharmony_ci struct res_fs_rule *fs_rule; 50708c2ecf20Sopenharmony_ci struct res_fs_rule *tmp; 50718c2ecf20Sopenharmony_ci int state; 50728c2ecf20Sopenharmony_ci u64 base; 50738c2ecf20Sopenharmony_ci int err; 50748c2ecf20Sopenharmony_ci 50758c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_FS_RULE); 50768c2ecf20Sopenharmony_ci if (err) 50778c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", 50788c2ecf20Sopenharmony_ci slave); 50798c2ecf20Sopenharmony_ci 50808c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 50818c2ecf20Sopenharmony_ci list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { 50828c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 50838c2ecf20Sopenharmony_ci if (fs_rule->com.owner == slave) { 50848c2ecf20Sopenharmony_ci base = fs_rule->com.res_id; 50858c2ecf20Sopenharmony_ci state = fs_rule->com.from_state; 50868c2ecf20Sopenharmony_ci while (state != 0) { 50878c2ecf20Sopenharmony_ci switch (state) { 50888c2ecf20Sopenharmony_ci case RES_FS_RULE_ALLOCATED: 50898c2ecf20Sopenharmony_ci /* detach rule */ 50908c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, base, 0, 0, 50918c2ecf20Sopenharmony_ci MLX4_QP_FLOW_STEERING_DETACH, 50928c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 50938c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 50948c2ecf20Sopenharmony_ci 50958c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 50968c2ecf20Sopenharmony_ci rb_erase(&fs_rule->com.node, 50978c2ecf20Sopenharmony_ci &tracker->res_tree[RES_FS_RULE]); 50988c2ecf20Sopenharmony_ci list_del(&fs_rule->com.list); 50998c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 51008c2ecf20Sopenharmony_ci kfree(fs_rule->mirr_mbox); 51018c2ecf20Sopenharmony_ci kfree(fs_rule); 51028c2ecf20Sopenharmony_ci state = 0; 51038c2ecf20Sopenharmony_ci break; 51048c2ecf20Sopenharmony_ci 51058c2ecf20Sopenharmony_ci default: 51068c2ecf20Sopenharmony_ci state = 0; 51078c2ecf20Sopenharmony_ci } 51088c2ecf20Sopenharmony_ci } 51098c2ecf20Sopenharmony_ci } 51108c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 51118c2ecf20Sopenharmony_ci } 51128c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 51138c2ecf20Sopenharmony_ci} 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_cistatic void rem_slave_eqs(struct mlx4_dev *dev, int slave) 51168c2ecf20Sopenharmony_ci{ 51178c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 51188c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 51198c2ecf20Sopenharmony_ci struct list_head *eq_list = 51208c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_EQ]; 51218c2ecf20Sopenharmony_ci struct res_eq *eq; 51228c2ecf20Sopenharmony_ci struct res_eq *tmp; 51238c2ecf20Sopenharmony_ci int err; 51248c2ecf20Sopenharmony_ci int state; 51258c2ecf20Sopenharmony_ci int eqn; 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_EQ); 51288c2ecf20Sopenharmony_ci if (err) 51298c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs - too busy for slave %d\n", 51308c2ecf20Sopenharmony_ci slave); 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 51338c2ecf20Sopenharmony_ci list_for_each_entry_safe(eq, tmp, eq_list, com.list) { 51348c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 51358c2ecf20Sopenharmony_ci if (eq->com.owner == slave) { 51368c2ecf20Sopenharmony_ci eqn = eq->com.res_id; 51378c2ecf20Sopenharmony_ci state = eq->com.from_state; 51388c2ecf20Sopenharmony_ci while (state != 0) { 51398c2ecf20Sopenharmony_ci switch (state) { 51408c2ecf20Sopenharmony_ci case RES_EQ_RESERVED: 51418c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 51428c2ecf20Sopenharmony_ci rb_erase(&eq->com.node, 51438c2ecf20Sopenharmony_ci &tracker->res_tree[RES_EQ]); 51448c2ecf20Sopenharmony_ci list_del(&eq->com.list); 51458c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 51468c2ecf20Sopenharmony_ci kfree(eq); 51478c2ecf20Sopenharmony_ci state = 0; 51488c2ecf20Sopenharmony_ci break; 51498c2ecf20Sopenharmony_ci 51508c2ecf20Sopenharmony_ci case RES_EQ_HW: 51518c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, slave, eqn & 0x3ff, 51528c2ecf20Sopenharmony_ci 1, MLX4_CMD_HW2SW_EQ, 51538c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 51548c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 51558c2ecf20Sopenharmony_ci if (err) 51568c2ecf20Sopenharmony_ci mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n", 51578c2ecf20Sopenharmony_ci slave, eqn & 0x3ff); 51588c2ecf20Sopenharmony_ci atomic_dec(&eq->mtt->ref_count); 51598c2ecf20Sopenharmony_ci state = RES_EQ_RESERVED; 51608c2ecf20Sopenharmony_ci break; 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_ci default: 51638c2ecf20Sopenharmony_ci state = 0; 51648c2ecf20Sopenharmony_ci } 51658c2ecf20Sopenharmony_ci } 51668c2ecf20Sopenharmony_ci } 51678c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 51688c2ecf20Sopenharmony_ci } 51698c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 51708c2ecf20Sopenharmony_ci} 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_cistatic void rem_slave_counters(struct mlx4_dev *dev, int slave) 51738c2ecf20Sopenharmony_ci{ 51748c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 51758c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 51768c2ecf20Sopenharmony_ci struct list_head *counter_list = 51778c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_COUNTER]; 51788c2ecf20Sopenharmony_ci struct res_counter *counter; 51798c2ecf20Sopenharmony_ci struct res_counter *tmp; 51808c2ecf20Sopenharmony_ci int err; 51818c2ecf20Sopenharmony_ci int *counters_arr = NULL; 51828c2ecf20Sopenharmony_ci int i, j; 51838c2ecf20Sopenharmony_ci 51848c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_COUNTER); 51858c2ecf20Sopenharmony_ci if (err) 51868c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n", 51878c2ecf20Sopenharmony_ci slave); 51888c2ecf20Sopenharmony_ci 51898c2ecf20Sopenharmony_ci counters_arr = kmalloc_array(dev->caps.max_counters, 51908c2ecf20Sopenharmony_ci sizeof(*counters_arr), GFP_KERNEL); 51918c2ecf20Sopenharmony_ci if (!counters_arr) 51928c2ecf20Sopenharmony_ci return; 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci do { 51958c2ecf20Sopenharmony_ci i = 0; 51968c2ecf20Sopenharmony_ci j = 0; 51978c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 51988c2ecf20Sopenharmony_ci list_for_each_entry_safe(counter, tmp, counter_list, com.list) { 51998c2ecf20Sopenharmony_ci if (counter->com.owner == slave) { 52008c2ecf20Sopenharmony_ci counters_arr[i++] = counter->com.res_id; 52018c2ecf20Sopenharmony_ci rb_erase(&counter->com.node, 52028c2ecf20Sopenharmony_ci &tracker->res_tree[RES_COUNTER]); 52038c2ecf20Sopenharmony_ci list_del(&counter->com.list); 52048c2ecf20Sopenharmony_ci kfree(counter); 52058c2ecf20Sopenharmony_ci } 52068c2ecf20Sopenharmony_ci } 52078c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci while (j < i) { 52108c2ecf20Sopenharmony_ci __mlx4_counter_free(dev, counters_arr[j++]); 52118c2ecf20Sopenharmony_ci mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 52128c2ecf20Sopenharmony_ci } 52138c2ecf20Sopenharmony_ci } while (i); 52148c2ecf20Sopenharmony_ci 52158c2ecf20Sopenharmony_ci kfree(counters_arr); 52168c2ecf20Sopenharmony_ci} 52178c2ecf20Sopenharmony_ci 52188c2ecf20Sopenharmony_cistatic void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) 52198c2ecf20Sopenharmony_ci{ 52208c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 52218c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 52228c2ecf20Sopenharmony_ci struct list_head *xrcdn_list = 52238c2ecf20Sopenharmony_ci &tracker->slave_list[slave].res_list[RES_XRCD]; 52248c2ecf20Sopenharmony_ci struct res_xrcdn *xrcd; 52258c2ecf20Sopenharmony_ci struct res_xrcdn *tmp; 52268c2ecf20Sopenharmony_ci int err; 52278c2ecf20Sopenharmony_ci int xrcdn; 52288c2ecf20Sopenharmony_ci 52298c2ecf20Sopenharmony_ci err = move_all_busy(dev, slave, RES_XRCD); 52308c2ecf20Sopenharmony_ci if (err) 52318c2ecf20Sopenharmony_ci mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns - too busy for slave %d\n", 52328c2ecf20Sopenharmony_ci slave); 52338c2ecf20Sopenharmony_ci 52348c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 52358c2ecf20Sopenharmony_ci list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { 52368c2ecf20Sopenharmony_ci if (xrcd->com.owner == slave) { 52378c2ecf20Sopenharmony_ci xrcdn = xrcd->com.res_id; 52388c2ecf20Sopenharmony_ci rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); 52398c2ecf20Sopenharmony_ci list_del(&xrcd->com.list); 52408c2ecf20Sopenharmony_ci kfree(xrcd); 52418c2ecf20Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 52428c2ecf20Sopenharmony_ci } 52438c2ecf20Sopenharmony_ci } 52448c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 52458c2ecf20Sopenharmony_ci} 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_civoid mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) 52488c2ecf20Sopenharmony_ci{ 52498c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 52508c2ecf20Sopenharmony_ci mlx4_reset_roce_gids(dev, slave); 52518c2ecf20Sopenharmony_ci mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 52528c2ecf20Sopenharmony_ci rem_slave_vlans(dev, slave); 52538c2ecf20Sopenharmony_ci rem_slave_macs(dev, slave); 52548c2ecf20Sopenharmony_ci rem_slave_fs_rule(dev, slave); 52558c2ecf20Sopenharmony_ci rem_slave_qps(dev, slave); 52568c2ecf20Sopenharmony_ci rem_slave_srqs(dev, slave); 52578c2ecf20Sopenharmony_ci rem_slave_cqs(dev, slave); 52588c2ecf20Sopenharmony_ci rem_slave_mrs(dev, slave); 52598c2ecf20Sopenharmony_ci rem_slave_eqs(dev, slave); 52608c2ecf20Sopenharmony_ci rem_slave_mtts(dev, slave); 52618c2ecf20Sopenharmony_ci rem_slave_counters(dev, slave); 52628c2ecf20Sopenharmony_ci rem_slave_xrcdns(dev, slave); 52638c2ecf20Sopenharmony_ci mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 52648c2ecf20Sopenharmony_ci} 52658c2ecf20Sopenharmony_ci 52668c2ecf20Sopenharmony_cistatic void update_qos_vpp(struct mlx4_update_qp_context *ctx, 52678c2ecf20Sopenharmony_ci struct mlx4_vf_immed_vlan_work *work) 52688c2ecf20Sopenharmony_ci{ 52698c2ecf20Sopenharmony_ci ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP); 52708c2ecf20Sopenharmony_ci ctx->qp_context.qos_vport = work->qos_vport; 52718c2ecf20Sopenharmony_ci} 52728c2ecf20Sopenharmony_ci 52738c2ecf20Sopenharmony_civoid mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) 52748c2ecf20Sopenharmony_ci{ 52758c2ecf20Sopenharmony_ci struct mlx4_vf_immed_vlan_work *work = 52768c2ecf20Sopenharmony_ci container_of(_work, struct mlx4_vf_immed_vlan_work, work); 52778c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 52788c2ecf20Sopenharmony_ci struct mlx4_update_qp_context *upd_context; 52798c2ecf20Sopenharmony_ci struct mlx4_dev *dev = &work->priv->dev; 52808c2ecf20Sopenharmony_ci struct mlx4_resource_tracker *tracker = 52818c2ecf20Sopenharmony_ci &work->priv->mfunc.master.res_tracker; 52828c2ecf20Sopenharmony_ci struct list_head *qp_list = 52838c2ecf20Sopenharmony_ci &tracker->slave_list[work->slave].res_list[RES_QP]; 52848c2ecf20Sopenharmony_ci struct res_qp *qp; 52858c2ecf20Sopenharmony_ci struct res_qp *tmp; 52868c2ecf20Sopenharmony_ci u64 qp_path_mask_vlan_ctrl = 52878c2ecf20Sopenharmony_ci ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | 52888c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | 52898c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | 52908c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | 52918c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | 52928c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED)); 52938c2ecf20Sopenharmony_ci 52948c2ecf20Sopenharmony_ci u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | 52958c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) | 52968c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_CV) | 52978c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_SV) | 52988c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) | 52998c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) | 53008c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) | 53018c2ecf20Sopenharmony_ci (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); 53028c2ecf20Sopenharmony_ci 53038c2ecf20Sopenharmony_ci int err; 53048c2ecf20Sopenharmony_ci int port, errors = 0; 53058c2ecf20Sopenharmony_ci u8 vlan_control; 53068c2ecf20Sopenharmony_ci 53078c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev)) { 53088c2ecf20Sopenharmony_ci mlx4_warn(dev, "Trying to update-qp in slave %d\n", 53098c2ecf20Sopenharmony_ci work->slave); 53108c2ecf20Sopenharmony_ci goto out; 53118c2ecf20Sopenharmony_ci } 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 53148c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) 53158c2ecf20Sopenharmony_ci goto out; 53168c2ecf20Sopenharmony_ci if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE) /* block all */ 53178c2ecf20Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 53188c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 53198c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED | 53208c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 53218c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED | 53228c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 53238c2ecf20Sopenharmony_ci else if (!work->vlan_id) 53248c2ecf20Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 53258c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 53268c2ecf20Sopenharmony_ci else if (work->vlan_proto == htons(ETH_P_8021AD)) 53278c2ecf20Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED | 53288c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 53298c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 53308c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 53318c2ecf20Sopenharmony_ci else /* vst 802.1Q */ 53328c2ecf20Sopenharmony_ci vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 53338c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 53348c2ecf20Sopenharmony_ci MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci upd_context = mailbox->buf; 53378c2ecf20Sopenharmony_ci upd_context->qp_mask = cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_VSD); 53388c2ecf20Sopenharmony_ci 53398c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 53408c2ecf20Sopenharmony_ci list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 53418c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 53428c2ecf20Sopenharmony_ci if (qp->com.owner == work->slave) { 53438c2ecf20Sopenharmony_ci if (qp->com.from_state != RES_QP_HW || 53448c2ecf20Sopenharmony_ci !qp->sched_queue || /* no INIT2RTR trans yet */ 53458c2ecf20Sopenharmony_ci mlx4_is_qp_reserved(dev, qp->local_qpn) || 53468c2ecf20Sopenharmony_ci qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { 53478c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 53488c2ecf20Sopenharmony_ci continue; 53498c2ecf20Sopenharmony_ci } 53508c2ecf20Sopenharmony_ci port = (qp->sched_queue >> 6 & 1) + 1; 53518c2ecf20Sopenharmony_ci if (port != work->port) { 53528c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 53538c2ecf20Sopenharmony_ci continue; 53548c2ecf20Sopenharmony_ci } 53558c2ecf20Sopenharmony_ci if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff)) 53568c2ecf20Sopenharmony_ci upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask); 53578c2ecf20Sopenharmony_ci else 53588c2ecf20Sopenharmony_ci upd_context->primary_addr_path_mask = 53598c2ecf20Sopenharmony_ci cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl); 53608c2ecf20Sopenharmony_ci if (work->vlan_id == MLX4_VGT) { 53618c2ecf20Sopenharmony_ci upd_context->qp_context.param3 = qp->param3; 53628c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.vlan_control = qp->vlan_control; 53638c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx; 53648c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.vlan_index = qp->vlan_index; 53658c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.fl = qp->pri_path_fl; 53668c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.feup = qp->feup; 53678c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.sched_queue = 53688c2ecf20Sopenharmony_ci qp->sched_queue; 53698c2ecf20Sopenharmony_ci } else { 53708c2ecf20Sopenharmony_ci upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN); 53718c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.vlan_control = vlan_control; 53728c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; 53738c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.fvl_rx = 53748c2ecf20Sopenharmony_ci qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN; 53758c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.fl = 53768c2ecf20Sopenharmony_ci qp->pri_path_fl | MLX4_FL_ETH_HIDE_CQE_VLAN; 53778c2ecf20Sopenharmony_ci if (work->vlan_proto == htons(ETH_P_8021AD)) 53788c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.fl |= MLX4_FL_SV; 53798c2ecf20Sopenharmony_ci else 53808c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.fl |= MLX4_FL_CV; 53818c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.feup = 53828c2ecf20Sopenharmony_ci qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 53838c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.sched_queue = 53848c2ecf20Sopenharmony_ci qp->sched_queue & 0xC7; 53858c2ecf20Sopenharmony_ci upd_context->qp_context.pri_path.sched_queue |= 53868c2ecf20Sopenharmony_ci ((work->qos & 0x7) << 3); 53878c2ecf20Sopenharmony_ci 53888c2ecf20Sopenharmony_ci if (dev->caps.flags2 & 53898c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG2_QOS_VPP) 53908c2ecf20Sopenharmony_ci update_qos_vpp(upd_context, work); 53918c2ecf20Sopenharmony_ci } 53928c2ecf20Sopenharmony_ci 53938c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, mailbox->dma, 53948c2ecf20Sopenharmony_ci qp->local_qpn & 0xffffff, 53958c2ecf20Sopenharmony_ci 0, MLX4_CMD_UPDATE_QP, 53968c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 53978c2ecf20Sopenharmony_ci if (err) { 53988c2ecf20Sopenharmony_ci mlx4_info(dev, "UPDATE_QP failed for slave %d, port %d, qpn %d (%d)\n", 53998c2ecf20Sopenharmony_ci work->slave, port, qp->local_qpn, err); 54008c2ecf20Sopenharmony_ci errors++; 54018c2ecf20Sopenharmony_ci } 54028c2ecf20Sopenharmony_ci } 54038c2ecf20Sopenharmony_ci spin_lock_irq(mlx4_tlock(dev)); 54048c2ecf20Sopenharmony_ci } 54058c2ecf20Sopenharmony_ci spin_unlock_irq(mlx4_tlock(dev)); 54068c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 54078c2ecf20Sopenharmony_ci 54088c2ecf20Sopenharmony_ci if (errors) 54098c2ecf20Sopenharmony_ci mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", 54108c2ecf20Sopenharmony_ci errors, work->slave, work->port); 54118c2ecf20Sopenharmony_ci 54128c2ecf20Sopenharmony_ci /* unregister previous vlan_id if needed and we had no errors 54138c2ecf20Sopenharmony_ci * while updating the QPs 54148c2ecf20Sopenharmony_ci */ 54158c2ecf20Sopenharmony_ci if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && 54168c2ecf20Sopenharmony_ci NO_INDX != work->orig_vlan_ix) 54178c2ecf20Sopenharmony_ci __mlx4_unregister_vlan(&work->priv->dev, work->port, 54188c2ecf20Sopenharmony_ci work->orig_vlan_id); 54198c2ecf20Sopenharmony_ciout: 54208c2ecf20Sopenharmony_ci kfree(work); 54218c2ecf20Sopenharmony_ci return; 54228c2ecf20Sopenharmony_ci} 5423