mlx4_resource_tracker.c revision 255932
1255932Salfred/* 2255932Salfred * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3255932Salfred * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. 4255932Salfred * All rights reserved. 5255932Salfred * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 6255932Salfred * 7255932Salfred * This software is available to you under a choice of one of two 8255932Salfred * licenses. You may choose to be licensed under the terms of the GNU 9255932Salfred * General Public License (GPL) Version 2, available from the file 10255932Salfred * COPYING in the main directory of this source tree, or the 11255932Salfred * OpenIB.org BSD license below: 12255932Salfred * 13255932Salfred * Redistribution and use in source and binary forms, with or 14255932Salfred * without modification, are permitted provided that the following 15255932Salfred * conditions are met: 16255932Salfred * 17255932Salfred * - Redistributions of source code must retain the above 18255932Salfred * copyright notice, this list of conditions and the following 19255932Salfred * disclaimer. 20255932Salfred * 21255932Salfred * - Redistributions in binary form must reproduce the above 22255932Salfred * copyright notice, this list of conditions and the following 23255932Salfred * disclaimer in the documentation and/or other materials 24255932Salfred * provided with the distribution. 25255932Salfred * 26255932Salfred * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27255932Salfred * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28255932Salfred * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29255932Salfred * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30255932Salfred * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31255932Salfred * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32255932Salfred * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33255932Salfred * SOFTWARE. 34255932Salfred */ 35255932Salfred 36255932Salfred#include <linux/sched.h> 37255932Salfred#include <linux/pci.h> 38255932Salfred#include <linux/errno.h> 39255932Salfred#include <linux/kernel.h> 40255932Salfred#include <linux/io.h> 41255932Salfred#include <linux/slab.h> 42255932Salfred#include <linux/mlx4/cmd.h> 43255932Salfred#include <linux/mlx4/qp.h> 44255932Salfred#include <linux/if_ether.h> 45255932Salfred#include <linux/compat.h> 46255932Salfred 47255932Salfred#include "mlx4.h" 48255932Salfred#include "fw.h" 49255932Salfred 50255932Salfred#define MLX4_MAC_VALID (1ull << 63) 51255932Salfred 52255932Salfredstruct mac_res { 53255932Salfred struct list_head list; 54255932Salfred u64 mac; 55255932Salfred int ref_count; 56255932Salfred u8 smac_index; 57255932Salfred u8 port; 58255932Salfred}; 59255932Salfred 60255932Salfredstruct vlan_res { 61255932Salfred struct list_head list; 62255932Salfred u16 vlan; 63255932Salfred int ref_count; 64255932Salfred int vlan_index; 65255932Salfred u8 port; 66255932Salfred}; 67255932Salfred 68255932Salfredstruct res_common { 69255932Salfred struct list_head list; 70255932Salfred struct rb_node node; 71255932Salfred u64 res_id; 72255932Salfred int owner; 73255932Salfred int state; 74255932Salfred int from_state; 75255932Salfred int to_state; 76255932Salfred int removing; 77255932Salfred}; 78255932Salfred 79255932Salfredenum { 80255932Salfred RES_ANY_BUSY = 1 81255932Salfred}; 82255932Salfred 83255932Salfredstruct res_gid { 84255932Salfred struct list_head list; 85255932Salfred u8 gid[16]; 86255932Salfred enum mlx4_protocol prot; 87255932Salfred enum mlx4_steer_type steer; 88255932Salfred}; 89255932Salfred 90255932Salfredenum res_qp_states { 91255932Salfred RES_QP_BUSY = RES_ANY_BUSY, 92255932Salfred 93255932Salfred /* QP number was allocated */ 94255932Salfred RES_QP_RESERVED, 95255932Salfred 96255932Salfred /* ICM memory for QP context was mapped */ 97255932Salfred RES_QP_MAPPED, 98255932Salfred 99255932Salfred /* QP is in hw ownership */ 100255932Salfred RES_QP_HW 101255932Salfred}; 102255932Salfred 103255932Salfredstruct res_qp { 104255932Salfred struct res_common com; 105255932Salfred struct res_mtt *mtt; 106255932Salfred struct res_cq *rcq; 107255932Salfred struct res_cq *scq; 108255932Salfred struct res_srq *srq; 109255932Salfred struct list_head mcg_list; 110255932Salfred spinlock_t mcg_spl; 111255932Salfred int local_qpn; 112255932Salfred}; 113255932Salfred 114255932Salfredenum res_mtt_states { 115255932Salfred RES_MTT_BUSY = RES_ANY_BUSY, 116255932Salfred RES_MTT_ALLOCATED, 117255932Salfred}; 118255932Salfred 119255932Salfredstatic inline const char *mtt_states_str(enum res_mtt_states state) 120255932Salfred{ 121255932Salfred switch (state) { 122255932Salfred case RES_MTT_BUSY: return "RES_MTT_BUSY"; 123255932Salfred case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED"; 124255932Salfred default: return "Unknown"; 125255932Salfred } 126255932Salfred} 127255932Salfred 128255932Salfredstruct res_mtt { 129255932Salfred struct res_common com; 130255932Salfred int order; 131255932Salfred atomic_t ref_count; 132255932Salfred}; 133255932Salfred 134255932Salfredenum res_mpt_states { 135255932Salfred RES_MPT_BUSY = RES_ANY_BUSY, 136255932Salfred RES_MPT_RESERVED, 137255932Salfred RES_MPT_MAPPED, 138255932Salfred RES_MPT_HW, 139255932Salfred}; 140255932Salfred 141255932Salfredstruct res_mpt { 142255932Salfred struct res_common com; 143255932Salfred struct res_mtt *mtt; 144255932Salfred int key; 145255932Salfred}; 146255932Salfred 147255932Salfredenum res_eq_states { 148255932Salfred RES_EQ_BUSY = RES_ANY_BUSY, 149255932Salfred RES_EQ_RESERVED, 150255932Salfred RES_EQ_HW, 151255932Salfred}; 152255932Salfred 153255932Salfredstruct res_eq { 154255932Salfred struct res_common com; 155255932Salfred struct res_mtt *mtt; 156255932Salfred}; 157255932Salfred 158255932Salfredenum res_cq_states { 159255932Salfred RES_CQ_BUSY = RES_ANY_BUSY, 160255932Salfred RES_CQ_ALLOCATED, 161255932Salfred RES_CQ_HW, 162255932Salfred}; 163255932Salfred 164255932Salfredstruct res_cq { 165255932Salfred struct res_common com; 166255932Salfred struct res_mtt *mtt; 167255932Salfred atomic_t ref_count; 168255932Salfred}; 169255932Salfred 170255932Salfredenum res_srq_states { 171255932Salfred RES_SRQ_BUSY = RES_ANY_BUSY, 172255932Salfred RES_SRQ_ALLOCATED, 173255932Salfred RES_SRQ_HW, 174255932Salfred}; 175255932Salfred 176255932Salfredstruct res_srq { 177255932Salfred struct res_common com; 178255932Salfred struct res_mtt *mtt; 179255932Salfred struct res_cq *cq; 180255932Salfred atomic_t ref_count; 181255932Salfred}; 182255932Salfred 183255932Salfredenum res_counter_states { 184255932Salfred RES_COUNTER_BUSY = RES_ANY_BUSY, 185255932Salfred RES_COUNTER_ALLOCATED, 186255932Salfred}; 187255932Salfred 188255932Salfredstruct res_counter { 189255932Salfred struct res_common com; 190255932Salfred int port; 191255932Salfred}; 192255932Salfred 193255932Salfredenum res_xrcdn_states { 194255932Salfred RES_XRCD_BUSY = RES_ANY_BUSY, 195255932Salfred RES_XRCD_ALLOCATED, 196255932Salfred}; 197255932Salfred 198255932Salfredstruct res_xrcdn { 199255932Salfred struct res_common com; 200255932Salfred int port; 201255932Salfred}; 202255932Salfred 203255932Salfredenum res_fs_rule_states { 204255932Salfred RES_FS_RULE_BUSY = RES_ANY_BUSY, 205255932Salfred RES_FS_RULE_ALLOCATED, 206255932Salfred}; 207255932Salfred 208255932Salfredstruct res_fs_rule { 209255932Salfred struct res_common com; 210255932Salfred}; 211255932Salfred 212255932Salfredstatic int mlx4_is_eth(struct mlx4_dev *dev, int port) 213255932Salfred{ 214255932Salfred return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; 215255932Salfred} 216255932Salfred 217255932Salfredstatic void *res_tracker_lookup(struct rb_root *root, u64 res_id) 218255932Salfred{ 219255932Salfred struct rb_node *node = root->rb_node; 220255932Salfred 221255932Salfred while (node) { 222255932Salfred struct res_common *res = container_of(node, struct res_common, 223255932Salfred node); 224255932Salfred 225255932Salfred if (res_id < res->res_id) 226255932Salfred node = node->rb_left; 227255932Salfred else if (res_id > res->res_id) 228255932Salfred node = node->rb_right; 229255932Salfred else 230255932Salfred return res; 231255932Salfred } 232255932Salfred return NULL; 233255932Salfred} 234255932Salfred 235255932Salfredstatic int res_tracker_insert(struct rb_root *root, struct res_common *res) 236255932Salfred{ 237255932Salfred struct rb_node **new = &(root->rb_node), *parent = NULL; 238255932Salfred 239255932Salfred /* Figure out where to put new node */ 240255932Salfred while (*new) { 241255932Salfred struct res_common *this = container_of(*new, struct res_common, 242255932Salfred node); 243255932Salfred 244255932Salfred parent = *new; 245255932Salfred if (res->res_id < this->res_id) 246255932Salfred new = &((*new)->rb_left); 247255932Salfred else if (res->res_id > this->res_id) 248255932Salfred new = &((*new)->rb_right); 249255932Salfred else 250255932Salfred return -EEXIST; 251255932Salfred } 252255932Salfred 253255932Salfred /* Add new node and rebalance tree. */ 254255932Salfred rb_link_node(&res->node, parent, new); 255255932Salfred rb_insert_color(&res->node, root); 256255932Salfred 257255932Salfred return 0; 258255932Salfred} 259255932Salfred 260255932Salfredenum qp_transition { 261255932Salfred QP_TRANS_INIT2RTR, 262255932Salfred QP_TRANS_RTR2RTS, 263255932Salfred QP_TRANS_RTS2RTS, 264255932Salfred QP_TRANS_SQERR2RTS, 265255932Salfred QP_TRANS_SQD2SQD, 266255932Salfred QP_TRANS_SQD2RTS 267255932Salfred}; 268255932Salfred 269255932Salfred/* For Debug uses */ 270255932Salfredstatic const char *ResourceType(enum mlx4_resource rt) 271255932Salfred{ 272255932Salfred switch (rt) { 273255932Salfred case RES_QP: return "RES_QP"; 274255932Salfred case RES_CQ: return "RES_CQ"; 275255932Salfred case RES_SRQ: return "RES_SRQ"; 276255932Salfred case RES_MPT: return "RES_MPT"; 277255932Salfred case RES_MTT: return "RES_MTT"; 278255932Salfred case RES_MAC: return "RES_MAC"; 279255932Salfred case RES_VLAN: return "RES_VLAN"; 280255932Salfred case RES_EQ: return "RES_EQ"; 281255932Salfred case RES_COUNTER: return "RES_COUNTER"; 282255932Salfred case RES_FS_RULE: return "RES_FS_RULE"; 283255932Salfred case RES_XRCD: return "RES_XRCD"; 284255932Salfred default: return "Unknown resource type !!!"; 285255932Salfred }; 286255932Salfred} 287255932Salfred 288255932Salfredstatic void rem_slave_vlans(struct mlx4_dev *dev, int slave); 289255932Salfredstatic inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, 290255932Salfred enum mlx4_resource res_type, int count, 291255932Salfred int port) 292255932Salfred{ 293255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 294255932Salfred struct resource_allocator *res_alloc = 295255932Salfred &priv->mfunc.master.res_tracker.res_alloc[res_type]; 296255932Salfred int err = -EINVAL; 297255932Salfred int allocated, free, reserved, guaranteed, from_free; 298255932Salfred 299255932Salfred spin_lock(&res_alloc->alloc_lock); 300255932Salfred allocated = (port > 0) ? 301255932Salfred res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : 302255932Salfred res_alloc->allocated[slave]; 303255932Salfred free = (port > 0) ? res_alloc->res_port_free[port - 1] : 304255932Salfred res_alloc->res_free; 305255932Salfred reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] : 306255932Salfred res_alloc->res_reserved; 307255932Salfred guaranteed = res_alloc->guaranteed[slave]; 308255932Salfred 309255932Salfred if (allocated + count > res_alloc->quota[slave]) 310255932Salfred goto out; 311255932Salfred 312255932Salfred if (allocated + count <= guaranteed) { 313255932Salfred err = 0; 314255932Salfred } else { 315255932Salfred /* portion may need to be obtained from free area */ 316255932Salfred if (guaranteed - allocated > 0) 317255932Salfred from_free = count - (guaranteed - allocated); 318255932Salfred else 319255932Salfred from_free = count; 320255932Salfred 321255932Salfred if (free - from_free > reserved) 322255932Salfred err = 0; 323255932Salfred } 324255932Salfred 325255932Salfred if (!err) { 326255932Salfred /* grant the request */ 327255932Salfred if (port > 0) { 328255932Salfred res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count; 329255932Salfred res_alloc->res_port_free[port - 1] -= count; 330255932Salfred } else { 331255932Salfred res_alloc->allocated[slave] += count; 332255932Salfred res_alloc->res_free -= count; 333255932Salfred } 334255932Salfred } 335255932Salfred 336255932Salfredout: 337255932Salfred spin_unlock(&res_alloc->alloc_lock); 338255932Salfred return err; 339255932Salfred 340255932Salfred} 341255932Salfred 342255932Salfredstatic inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, 343255932Salfred enum mlx4_resource res_type, int count, 344255932Salfred int port) 345255932Salfred{ 346255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 347255932Salfred struct resource_allocator *res_alloc = 348255932Salfred &priv->mfunc.master.res_tracker.res_alloc[res_type]; 349255932Salfred 350255932Salfred spin_lock(&res_alloc->alloc_lock); 351255932Salfred if (port > 0) { 352255932Salfred res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count; 353255932Salfred res_alloc->res_port_free[port - 1] += count; 354255932Salfred } else { 355255932Salfred res_alloc->allocated[slave] -= count; 356255932Salfred res_alloc->res_free += count; 357255932Salfred } 358255932Salfred 359255932Salfred spin_unlock(&res_alloc->alloc_lock); 360255932Salfred return; 361255932Salfred} 362255932Salfred 363255932Salfredstatic inline void initialize_res_quotas(struct mlx4_dev *dev, 364255932Salfred struct resource_allocator *res_alloc, 365255932Salfred enum mlx4_resource res_type, 366255932Salfred int vf, int num_instances) 367255932Salfred{ 368255932Salfred res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1)); 369255932Salfred res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; 370255932Salfred if (vf == mlx4_master_func_num(dev)) { 371255932Salfred res_alloc->res_free = num_instances; 372255932Salfred if (res_type == RES_MTT) { 373255932Salfred /* reserved mtts will be taken out of the PF allocation */ 374255932Salfred res_alloc->res_free += dev->caps.reserved_mtts; 375255932Salfred res_alloc->guaranteed[vf] += dev->caps.reserved_mtts; 376255932Salfred res_alloc->quota[vf] += dev->caps.reserved_mtts; 377255932Salfred } 378255932Salfred } 379255932Salfred} 380255932Salfred 381255932Salfredvoid mlx4_init_quotas(struct mlx4_dev *dev) 382255932Salfred{ 383255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 384255932Salfred int pf; 385255932Salfred 386255932Salfred /* quotas for VFs are initialized in mlx4_slave_cap */ 387255932Salfred if (mlx4_is_slave(dev)) 388255932Salfred return; 389255932Salfred 390255932Salfred if (!mlx4_is_mfunc(dev)) { 391255932Salfred dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps - 392255932Salfred mlx4_num_reserved_sqps(dev); 393255932Salfred dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs; 394255932Salfred dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs; 395255932Salfred dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts; 396255932Salfred dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws; 397255932Salfred return; 398255932Salfred } 399255932Salfred 400255932Salfred pf = mlx4_master_func_num(dev); 401255932Salfred dev->quotas.qp = 402255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf]; 403255932Salfred dev->quotas.cq = 404255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf]; 405255932Salfred dev->quotas.srq = 406255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf]; 407255932Salfred dev->quotas.mtt = 408255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf]; 409255932Salfred dev->quotas.mpt = 410255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; 411255932Salfred} 412255932Salfredint mlx4_init_resource_tracker(struct mlx4_dev *dev) 413255932Salfred{ 414255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 415255932Salfred int i, j; 416255932Salfred int t; 417255932Salfred 418255932Salfred priv->mfunc.master.res_tracker.slave_list = 419255932Salfred kzalloc(dev->num_slaves * sizeof(struct slave_list), 420255932Salfred GFP_KERNEL); 421255932Salfred if (!priv->mfunc.master.res_tracker.slave_list) 422255932Salfred return -ENOMEM; 423255932Salfred 424255932Salfred for (i = 0 ; i < dev->num_slaves; i++) { 425255932Salfred for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t) 426255932Salfred INIT_LIST_HEAD(&priv->mfunc.master.res_tracker. 427255932Salfred slave_list[i].res_list[t]); 428255932Salfred mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 429255932Salfred } 430255932Salfred 431255932Salfred mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n", 432255932Salfred dev->num_slaves); 433255932Salfred for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) 434255932Salfred priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT; 435255932Salfred 436255932Salfred for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 437255932Salfred struct resource_allocator *res_alloc = 438255932Salfred &priv->mfunc.master.res_tracker.res_alloc[i]; 439255932Salfred res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); 440255932Salfred res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); 441255932Salfred if (i == RES_MAC || i == RES_VLAN) 442255932Salfred res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * 443255932Salfred (dev->num_vfs + 1) * sizeof(int), 444255932Salfred GFP_KERNEL); 445255932Salfred else 446255932Salfred res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); 447255932Salfred 448255932Salfred if (!res_alloc->quota || !res_alloc->guaranteed || 449255932Salfred !res_alloc->allocated) 450255932Salfred goto no_mem_err; 451255932Salfred 452255932Salfred spin_lock_init(&res_alloc->alloc_lock); 453255932Salfred for (t = 0; t < dev->num_vfs + 1; t++) { 454255932Salfred switch (i) { 455255932Salfred case RES_QP: 456255932Salfred initialize_res_quotas(dev, res_alloc, RES_QP, 457255932Salfred t, dev->caps.num_qps - 458255932Salfred dev->caps.reserved_qps - 459255932Salfred mlx4_num_reserved_sqps(dev)); 460255932Salfred break; 461255932Salfred case RES_CQ: 462255932Salfred initialize_res_quotas(dev, res_alloc, RES_CQ, 463255932Salfred t, dev->caps.num_cqs - 464255932Salfred dev->caps.reserved_cqs); 465255932Salfred break; 466255932Salfred case RES_SRQ: 467255932Salfred initialize_res_quotas(dev, res_alloc, RES_SRQ, 468255932Salfred t, dev->caps.num_srqs - 469255932Salfred dev->caps.reserved_srqs); 470255932Salfred break; 471255932Salfred case RES_MPT: 472255932Salfred initialize_res_quotas(dev, res_alloc, RES_MPT, 473255932Salfred t, dev->caps.num_mpts - 474255932Salfred dev->caps.reserved_mrws); 475255932Salfred break; 476255932Salfred case RES_MTT: 477255932Salfred initialize_res_quotas(dev, res_alloc, RES_MTT, 478255932Salfred t, dev->caps.num_mtts - 479255932Salfred dev->caps.reserved_mtts); 480255932Salfred break; 481255932Salfred case RES_MAC: 482255932Salfred if (t == mlx4_master_func_num(dev)) { 483255932Salfred res_alloc->quota[t] = 484255932Salfred MLX4_MAX_MAC_NUM - 2 * dev->num_vfs; 485255932Salfred res_alloc->guaranteed[t] = res_alloc->quota[t]; 486255932Salfred for (j = 0; j < MLX4_MAX_PORTS; j++) 487255932Salfred res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM; 488255932Salfred } else { 489255932Salfred res_alloc->quota[t] = 2; 490255932Salfred res_alloc->guaranteed[t] = 2; 491255932Salfred } 492255932Salfred break; 493255932Salfred case RES_VLAN: 494255932Salfred if (t == mlx4_master_func_num(dev)) { 495255932Salfred res_alloc->quota[t] = MLX4_MAX_VLAN_NUM; 496255932Salfred res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2; 497255932Salfred for (j = 0; j < MLX4_MAX_PORTS; j++) 498255932Salfred res_alloc->res_port_free[j] = 499255932Salfred res_alloc->quota[t]; 500255932Salfred } else { 501255932Salfred res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2; 502255932Salfred res_alloc->guaranteed[t] = 0; 503255932Salfred } 504255932Salfred break; 505255932Salfred case RES_COUNTER: 506255932Salfred res_alloc->quota[t] = dev->caps.max_counters; 507255932Salfred res_alloc->guaranteed[t] = 0; 508255932Salfred if (t == mlx4_master_func_num(dev)) 509255932Salfred res_alloc->res_free = res_alloc->quota[t]; 510255932Salfred break; 511255932Salfred default: 512255932Salfred break; 513255932Salfred } 514255932Salfred if (i == RES_MAC || i == RES_VLAN) { 515255932Salfred for (j = 0; j < MLX4_MAX_PORTS; j++) 516255932Salfred res_alloc->res_port_rsvd[j] += 517255932Salfred res_alloc->guaranteed[t]; 518255932Salfred } else { 519255932Salfred res_alloc->res_reserved += res_alloc->guaranteed[t]; 520255932Salfred } 521255932Salfred } 522255932Salfred } 523255932Salfred spin_lock_init(&priv->mfunc.master.res_tracker.lock); 524255932Salfred return 0; 525255932Salfred 526255932Salfredno_mem_err: 527255932Salfred for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 528255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 529255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 530255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 531255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 532255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 533255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 534255932Salfred } 535255932Salfred return -ENOMEM; 536255932Salfred} 537255932Salfred 538255932Salfredvoid mlx4_free_resource_tracker(struct mlx4_dev *dev, 539255932Salfred enum mlx4_res_tracker_free_type type) 540255932Salfred{ 541255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 542255932Salfred int i; 543255932Salfred 544255932Salfred if (priv->mfunc.master.res_tracker.slave_list) { 545255932Salfred if (type != RES_TR_FREE_STRUCTS_ONLY) { 546255932Salfred for (i = 0; i < dev->num_slaves; i++) { 547255932Salfred if (type == RES_TR_FREE_ALL || 548255932Salfred dev->caps.function != i) 549255932Salfred mlx4_delete_all_resources_for_slave(dev, i); 550255932Salfred } 551255932Salfred /* free master's vlans */ 552255932Salfred i = dev->caps.function; 553255932Salfred mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 554255932Salfred rem_slave_vlans(dev, i); 555255932Salfred mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 556255932Salfred } 557255932Salfred 558255932Salfred if (type != RES_TR_FREE_SLAVES_ONLY) { 559255932Salfred for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 560255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 561255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 562255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 563255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 564255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 565255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 566255932Salfred } 567255932Salfred kfree(priv->mfunc.master.res_tracker.slave_list); 568255932Salfred priv->mfunc.master.res_tracker.slave_list = NULL; 569255932Salfred } 570255932Salfred } 571255932Salfred} 572255932Salfred 573255932Salfredstatic void update_pkey_index(struct mlx4_dev *dev, int slave, 574255932Salfred struct mlx4_cmd_mailbox *inbox) 575255932Salfred{ 576255932Salfred u8 sched = *(u8 *)(inbox->buf + 64); 577255932Salfred u8 orig_index = *(u8 *)(inbox->buf + 35); 578255932Salfred u8 new_index; 579255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 580255932Salfred int port; 581255932Salfred 582255932Salfred port = (sched >> 6 & 1) + 1; 583255932Salfred 584255932Salfred new_index = priv->virt2phys_pkey[slave][port - 1][orig_index]; 585255932Salfred *(u8 *)(inbox->buf + 35) = new_index; 586255932Salfred} 587255932Salfred 588255932Salfredstatic void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, 589255932Salfred u8 slave) 590255932Salfred{ 591255932Salfred struct mlx4_qp_context *qp_ctx = inbox->buf + 8; 592255932Salfred enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); 593255932Salfred u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 594255932Salfred int port; 595255932Salfred 596255932Salfred if (MLX4_QP_ST_UD == ts) { 597255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 598255932Salfred if (mlx4_is_eth(dev, port)) 599255932Salfred qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80; 600255932Salfred else 601255932Salfred qp_ctx->pri_path.mgid_index = 0x80 | slave; 602255932Salfred 603255932Salfred } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) { 604255932Salfred if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 605255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 606255932Salfred if (mlx4_is_eth(dev, port)) { 607255932Salfred qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); 608255932Salfred qp_ctx->pri_path.mgid_index &= 0x7f; 609255932Salfred } else { 610255932Salfred qp_ctx->pri_path.mgid_index = slave & 0x7F; 611255932Salfred } 612255932Salfred } 613255932Salfred if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 614255932Salfred port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 615255932Salfred if (mlx4_is_eth(dev, port)) { 616255932Salfred qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); 617255932Salfred qp_ctx->alt_path.mgid_index &= 0x7f; 618255932Salfred } else { 619255932Salfred qp_ctx->alt_path.mgid_index = slave & 0x7F; 620255932Salfred } 621255932Salfred } 622255932Salfred } 623255932Salfred} 624255932Salfred 625255932Salfredstatic int update_vport_qp_param(struct mlx4_dev *dev, 626255932Salfred struct mlx4_cmd_mailbox *inbox, 627255932Salfred u8 slave) 628255932Salfred{ 629255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 630255932Salfred struct mlx4_vport_oper_state *vp_oper; 631255932Salfred struct mlx4_priv *priv; 632255932Salfred u32 qp_type; 633255932Salfred int port; 634255932Salfred 635255932Salfred port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; 636255932Salfred priv = mlx4_priv(dev); 637255932Salfred vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 638255932Salfred 639255932Salfred if (MLX4_VGT != vp_oper->state.default_vlan) { 640255932Salfred qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 641255932Salfred if (MLX4_QP_ST_RC == qp_type) 642255932Salfred return -EINVAL; 643255932Salfred 644255932Salfred qpc->srqn |= cpu_to_be32(1 << 25); /*set cqe vlan mask */ 645255932Salfred qpc->pri_path.vlan_index = vp_oper->vlan_idx; 646255932Salfred qpc->pri_path.fl = 1 << 6; /* set cv bit*/ 647255932Salfred qpc->pri_path.feup |= 1 << 3; /* set fvl bit */ 648255932Salfred qpc->pri_path.sched_queue &= 0xC7; 649255932Salfred qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; 650255932Salfred mlx4_dbg(dev, "qp %d port %d Q 0x%x set vlan to %d vidx %d feup %x fl %x\n", 651255932Salfred be32_to_cpu(qpc->local_qpn) & 0xffffff, port, 652255932Salfred (int)(qpc->pri_path.sched_queue), vp_oper->state.default_vlan, 653255932Salfred vp_oper->vlan_idx, (int)(qpc->pri_path.feup), 654255932Salfred (int)(qpc->pri_path.fl)); 655255932Salfred } 656255932Salfred if (vp_oper->state.spoofchk) { 657255932Salfred qpc->pri_path.feup |= 1 << 5; /* set fsm bit */; 658255932Salfred qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx; 659255932Salfred mlx4_dbg(dev, "spoof qp %d port %d feup 0x%x, myLmc 0x%x mindx %d\n", 660255932Salfred be32_to_cpu(qpc->local_qpn) & 0xffffff, port, 661255932Salfred (int)qpc->pri_path.feup, (int)qpc->pri_path.grh_mylmc, 662255932Salfred vp_oper->mac_idx); 663255932Salfred } 664255932Salfred return 0; 665255932Salfred} 666255932Salfred 667255932Salfredstatic int mpt_mask(struct mlx4_dev *dev) 668255932Salfred{ 669255932Salfred return dev->caps.num_mpts - 1; 670255932Salfred} 671255932Salfred 672255932Salfredstatic void *find_res(struct mlx4_dev *dev, int res_id, 673255932Salfred enum mlx4_resource type) 674255932Salfred{ 675255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 676255932Salfred 677255932Salfred return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type], 678255932Salfred res_id); 679255932Salfred} 680255932Salfred 681255932Salfredstatic int get_res(struct mlx4_dev *dev, int slave, u64 res_id, 682255932Salfred enum mlx4_resource type, 683255932Salfred void *res) 684255932Salfred{ 685255932Salfred struct res_common *r; 686255932Salfred int err = 0; 687255932Salfred 688255932Salfred spin_lock_irq(mlx4_tlock(dev)); 689255932Salfred r = find_res(dev, res_id, type); 690255932Salfred if (!r) { 691255932Salfred err = -ENOENT; 692255932Salfred goto exit; 693255932Salfred } 694255932Salfred 695255932Salfred if (r->state == RES_ANY_BUSY) { 696255932Salfred err = -EBUSY; 697255932Salfred goto exit; 698255932Salfred } 699255932Salfred 700255932Salfred if (r->owner != slave) { 701255932Salfred err = -EPERM; 702255932Salfred goto exit; 703255932Salfred } 704255932Salfred 705255932Salfred r->from_state = r->state; 706255932Salfred r->state = RES_ANY_BUSY; 707255932Salfred 708255932Salfred if (res) 709255932Salfred *((struct res_common **)res) = r; 710255932Salfred 711255932Salfredexit: 712255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 713255932Salfred return err; 714255932Salfred} 715255932Salfred 716255932Salfredint mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, 717255932Salfred enum mlx4_resource type, 718255932Salfred u64 res_id, int *slave) 719255932Salfred{ 720255932Salfred 721255932Salfred struct res_common *r; 722255932Salfred int err = -ENOENT; 723255932Salfred int id = res_id; 724255932Salfred 725255932Salfred if (type == RES_QP) 726255932Salfred id &= 0x7fffff; 727255932Salfred spin_lock(mlx4_tlock(dev)); 728255932Salfred 729255932Salfred r = find_res(dev, id, type); 730255932Salfred if (r) { 731255932Salfred *slave = r->owner; 732255932Salfred err = 0; 733255932Salfred } 734255932Salfred spin_unlock(mlx4_tlock(dev)); 735255932Salfred 736255932Salfred return err; 737255932Salfred} 738255932Salfred 739255932Salfredstatic void put_res(struct mlx4_dev *dev, int slave, u64 res_id, 740255932Salfred enum mlx4_resource type) 741255932Salfred{ 742255932Salfred struct res_common *r; 743255932Salfred 744255932Salfred spin_lock_irq(mlx4_tlock(dev)); 745255932Salfred r = find_res(dev, res_id, type); 746255932Salfred if (r) 747255932Salfred r->state = r->from_state; 748255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 749255932Salfred} 750255932Salfred 751255932Salfredstatic struct res_common *alloc_qp_tr(int id) 752255932Salfred{ 753255932Salfred struct res_qp *ret; 754255932Salfred 755255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 756255932Salfred if (!ret) 757255932Salfred return NULL; 758255932Salfred 759255932Salfred ret->com.res_id = id; 760255932Salfred ret->com.state = RES_QP_RESERVED; 761255932Salfred ret->local_qpn = id; 762255932Salfred INIT_LIST_HEAD(&ret->mcg_list); 763255932Salfred spin_lock_init(&ret->mcg_spl); 764255932Salfred 765255932Salfred return &ret->com; 766255932Salfred} 767255932Salfred 768255932Salfredstatic struct res_common *alloc_mtt_tr(int id, int order) 769255932Salfred{ 770255932Salfred struct res_mtt *ret; 771255932Salfred 772255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 773255932Salfred if (!ret) 774255932Salfred return NULL; 775255932Salfred 776255932Salfred ret->com.res_id = id; 777255932Salfred ret->order = order; 778255932Salfred ret->com.state = RES_MTT_ALLOCATED; 779255932Salfred atomic_set(&ret->ref_count, 0); 780255932Salfred 781255932Salfred return &ret->com; 782255932Salfred} 783255932Salfred 784255932Salfredstatic struct res_common *alloc_mpt_tr(int id, int key) 785255932Salfred{ 786255932Salfred struct res_mpt *ret; 787255932Salfred 788255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 789255932Salfred if (!ret) 790255932Salfred return NULL; 791255932Salfred 792255932Salfred ret->com.res_id = id; 793255932Salfred ret->com.state = RES_MPT_RESERVED; 794255932Salfred ret->key = key; 795255932Salfred 796255932Salfred return &ret->com; 797255932Salfred} 798255932Salfred 799255932Salfredstatic struct res_common *alloc_eq_tr(int id) 800255932Salfred{ 801255932Salfred struct res_eq *ret; 802255932Salfred 803255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 804255932Salfred if (!ret) 805255932Salfred return NULL; 806255932Salfred 807255932Salfred ret->com.res_id = id; 808255932Salfred ret->com.state = RES_EQ_RESERVED; 809255932Salfred 810255932Salfred return &ret->com; 811255932Salfred} 812255932Salfred 813255932Salfredstatic struct res_common *alloc_cq_tr(int id) 814255932Salfred{ 815255932Salfred struct res_cq *ret; 816255932Salfred 817255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 818255932Salfred if (!ret) 819255932Salfred return NULL; 820255932Salfred 821255932Salfred ret->com.res_id = id; 822255932Salfred ret->com.state = RES_CQ_ALLOCATED; 823255932Salfred atomic_set(&ret->ref_count, 0); 824255932Salfred 825255932Salfred return &ret->com; 826255932Salfred} 827255932Salfred 828255932Salfredstatic struct res_common *alloc_srq_tr(int id) 829255932Salfred{ 830255932Salfred struct res_srq *ret; 831255932Salfred 832255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 833255932Salfred if (!ret) 834255932Salfred return NULL; 835255932Salfred 836255932Salfred ret->com.res_id = id; 837255932Salfred ret->com.state = RES_SRQ_ALLOCATED; 838255932Salfred atomic_set(&ret->ref_count, 0); 839255932Salfred 840255932Salfred return &ret->com; 841255932Salfred} 842255932Salfred 843255932Salfredstatic struct res_common *alloc_counter_tr(int id) 844255932Salfred{ 845255932Salfred struct res_counter *ret; 846255932Salfred 847255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 848255932Salfred if (!ret) 849255932Salfred return NULL; 850255932Salfred 851255932Salfred ret->com.res_id = id; 852255932Salfred ret->com.state = RES_COUNTER_ALLOCATED; 853255932Salfred 854255932Salfred return &ret->com; 855255932Salfred} 856255932Salfred 857255932Salfredstatic struct res_common *alloc_xrcdn_tr(int id) 858255932Salfred{ 859255932Salfred struct res_xrcdn *ret; 860255932Salfred 861255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 862255932Salfred if (!ret) 863255932Salfred return NULL; 864255932Salfred 865255932Salfred ret->com.res_id = id; 866255932Salfred ret->com.state = RES_XRCD_ALLOCATED; 867255932Salfred 868255932Salfred return &ret->com; 869255932Salfred} 870255932Salfred 871255932Salfredstatic struct res_common *alloc_fs_rule_tr(u64 id) 872255932Salfred{ 873255932Salfred struct res_fs_rule *ret; 874255932Salfred 875255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 876255932Salfred if (!ret) 877255932Salfred return NULL; 878255932Salfred 879255932Salfred ret->com.res_id = id; 880255932Salfred ret->com.state = RES_FS_RULE_ALLOCATED; 881255932Salfred 882255932Salfred return &ret->com; 883255932Salfred} 884255932Salfred 885255932Salfredstatic struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, 886255932Salfred int extra) 887255932Salfred{ 888255932Salfred struct res_common *ret; 889255932Salfred 890255932Salfred switch (type) { 891255932Salfred case RES_QP: 892255932Salfred ret = alloc_qp_tr(id); 893255932Salfred break; 894255932Salfred case RES_MPT: 895255932Salfred ret = alloc_mpt_tr(id, extra); 896255932Salfred break; 897255932Salfred case RES_MTT: 898255932Salfred ret = alloc_mtt_tr(id, extra); 899255932Salfred break; 900255932Salfred case RES_EQ: 901255932Salfred ret = alloc_eq_tr(id); 902255932Salfred break; 903255932Salfred case RES_CQ: 904255932Salfred ret = alloc_cq_tr(id); 905255932Salfred break; 906255932Salfred case RES_SRQ: 907255932Salfred ret = alloc_srq_tr(id); 908255932Salfred break; 909255932Salfred case RES_MAC: 910255932Salfred printk(KERN_ERR "implementation missing\n"); 911255932Salfred return NULL; 912255932Salfred case RES_COUNTER: 913255932Salfred ret = alloc_counter_tr(id); 914255932Salfred break; 915255932Salfred case RES_XRCD: 916255932Salfred ret = alloc_xrcdn_tr(id); 917255932Salfred break; 918255932Salfred case RES_FS_RULE: 919255932Salfred ret = alloc_fs_rule_tr(id); 920255932Salfred break; 921255932Salfred default: 922255932Salfred return NULL; 923255932Salfred } 924255932Salfred if (ret) 925255932Salfred ret->owner = slave; 926255932Salfred 927255932Salfred return ret; 928255932Salfred} 929255932Salfred 930255932Salfredstatic int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 931255932Salfred enum mlx4_resource type, int extra) 932255932Salfred{ 933255932Salfred int i; 934255932Salfred int err; 935255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 936255932Salfred struct res_common **res_arr; 937255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 938255932Salfred struct rb_root *root = &tracker->res_tree[type]; 939255932Salfred 940255932Salfred res_arr = kzalloc(count * sizeof *res_arr, GFP_KERNEL); 941255932Salfred if (!res_arr) 942255932Salfred return -ENOMEM; 943255932Salfred 944255932Salfred for (i = 0; i < count; ++i) { 945255932Salfred res_arr[i] = alloc_tr(base + i, type, slave, extra); 946255932Salfred if (!res_arr[i]) { 947255932Salfred for (--i; i >= 0; --i) 948255932Salfred kfree(res_arr[i]); 949255932Salfred 950255932Salfred kfree(res_arr); 951255932Salfred return -ENOMEM; 952255932Salfred } 953255932Salfred } 954255932Salfred 955255932Salfred spin_lock_irq(mlx4_tlock(dev)); 956255932Salfred for (i = 0; i < count; ++i) { 957255932Salfred if (find_res(dev, base + i, type)) { 958255932Salfred err = -EEXIST; 959255932Salfred goto undo; 960255932Salfred } 961255932Salfred err = res_tracker_insert(root, res_arr[i]); 962255932Salfred if (err) 963255932Salfred goto undo; 964255932Salfred list_add_tail(&res_arr[i]->list, 965255932Salfred &tracker->slave_list[slave].res_list[type]); 966255932Salfred } 967255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 968255932Salfred kfree(res_arr); 969255932Salfred 970255932Salfred return 0; 971255932Salfred 972255932Salfredundo: 973255932Salfred for (--i; i >= base; --i) 974255932Salfred rb_erase(&res_arr[i]->node, root); 975255932Salfred 976255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 977255932Salfred 978255932Salfred for (i = 0; i < count; ++i) 979255932Salfred kfree(res_arr[i]); 980255932Salfred 981255932Salfred kfree(res_arr); 982255932Salfred 983255932Salfred return err; 984255932Salfred} 985255932Salfred 986255932Salfredstatic int remove_qp_ok(struct res_qp *res) 987255932Salfred{ 988255932Salfred if (res->com.state == RES_QP_BUSY) 989255932Salfred return -EBUSY; 990255932Salfred else if (res->com.state != RES_QP_RESERVED) 991255932Salfred return -EPERM; 992255932Salfred 993255932Salfred return 0; 994255932Salfred} 995255932Salfred 996255932Salfredstatic int remove_mtt_ok(struct res_mtt *res, int order) 997255932Salfred{ 998255932Salfred if (res->com.state == RES_MTT_BUSY || 999255932Salfred atomic_read(&res->ref_count)) { 1000255932Salfred printk(KERN_DEBUG "%s-%d: state %s, ref_count %d\n", 1001255932Salfred __func__, __LINE__, 1002255932Salfred mtt_states_str(res->com.state), 1003255932Salfred atomic_read(&res->ref_count)); 1004255932Salfred return -EBUSY; 1005255932Salfred } else if (res->com.state != RES_MTT_ALLOCATED) 1006255932Salfred return -EPERM; 1007255932Salfred else if (res->order != order) 1008255932Salfred return -EINVAL; 1009255932Salfred 1010255932Salfred return 0; 1011255932Salfred} 1012255932Salfred 1013255932Salfredstatic int remove_mpt_ok(struct res_mpt *res) 1014255932Salfred{ 1015255932Salfred if (res->com.state == RES_MPT_BUSY) 1016255932Salfred return -EBUSY; 1017255932Salfred else if (res->com.state != RES_MPT_RESERVED) 1018255932Salfred return -EPERM; 1019255932Salfred 1020255932Salfred return 0; 1021255932Salfred} 1022255932Salfred 1023255932Salfredstatic int remove_eq_ok(struct res_eq *res) 1024255932Salfred{ 1025255932Salfred if (res->com.state == RES_MPT_BUSY) 1026255932Salfred return -EBUSY; 1027255932Salfred else if (res->com.state != RES_MPT_RESERVED) 1028255932Salfred return -EPERM; 1029255932Salfred 1030255932Salfred return 0; 1031255932Salfred} 1032255932Salfred 1033255932Salfredstatic int remove_counter_ok(struct res_counter *res) 1034255932Salfred{ 1035255932Salfred if (res->com.state == RES_COUNTER_BUSY) 1036255932Salfred return -EBUSY; 1037255932Salfred else if (res->com.state != RES_COUNTER_ALLOCATED) 1038255932Salfred return -EPERM; 1039255932Salfred 1040255932Salfred return 0; 1041255932Salfred} 1042255932Salfred 1043255932Salfredstatic int remove_xrcdn_ok(struct res_xrcdn *res) 1044255932Salfred{ 1045255932Salfred if (res->com.state == RES_XRCD_BUSY) 1046255932Salfred return -EBUSY; 1047255932Salfred else if (res->com.state != RES_XRCD_ALLOCATED) 1048255932Salfred return -EPERM; 1049255932Salfred 1050255932Salfred return 0; 1051255932Salfred} 1052255932Salfred 1053255932Salfredstatic int remove_fs_rule_ok(struct res_fs_rule *res) 1054255932Salfred{ 1055255932Salfred if (res->com.state == RES_FS_RULE_BUSY) 1056255932Salfred return -EBUSY; 1057255932Salfred else if (res->com.state != RES_FS_RULE_ALLOCATED) 1058255932Salfred return -EPERM; 1059255932Salfred 1060255932Salfred return 0; 1061255932Salfred} 1062255932Salfred 1063255932Salfredstatic int remove_cq_ok(struct res_cq *res) 1064255932Salfred{ 1065255932Salfred if (res->com.state == RES_CQ_BUSY) 1066255932Salfred return -EBUSY; 1067255932Salfred else if (res->com.state != RES_CQ_ALLOCATED) 1068255932Salfred return -EPERM; 1069255932Salfred 1070255932Salfred return 0; 1071255932Salfred} 1072255932Salfred 1073255932Salfredstatic int remove_srq_ok(struct res_srq *res) 1074255932Salfred{ 1075255932Salfred if (res->com.state == RES_SRQ_BUSY) 1076255932Salfred return -EBUSY; 1077255932Salfred else if (res->com.state != RES_SRQ_ALLOCATED) 1078255932Salfred return -EPERM; 1079255932Salfred 1080255932Salfred return 0; 1081255932Salfred} 1082255932Salfred 1083255932Salfredstatic int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) 1084255932Salfred{ 1085255932Salfred switch (type) { 1086255932Salfred case RES_QP: 1087255932Salfred return remove_qp_ok((struct res_qp *)res); 1088255932Salfred case RES_CQ: 1089255932Salfred return remove_cq_ok((struct res_cq *)res); 1090255932Salfred case RES_SRQ: 1091255932Salfred return remove_srq_ok((struct res_srq *)res); 1092255932Salfred case RES_MPT: 1093255932Salfred return remove_mpt_ok((struct res_mpt *)res); 1094255932Salfred case RES_MTT: 1095255932Salfred return remove_mtt_ok((struct res_mtt *)res, extra); 1096255932Salfred case RES_MAC: 1097255932Salfred return -ENOSYS; 1098255932Salfred case RES_EQ: 1099255932Salfred return remove_eq_ok((struct res_eq *)res); 1100255932Salfred case RES_COUNTER: 1101255932Salfred return remove_counter_ok((struct res_counter *)res); 1102255932Salfred case RES_XRCD: 1103255932Salfred return remove_xrcdn_ok((struct res_xrcdn *)res); 1104255932Salfred case RES_FS_RULE: 1105255932Salfred return remove_fs_rule_ok((struct res_fs_rule *)res); 1106255932Salfred default: 1107255932Salfred return -EINVAL; 1108255932Salfred } 1109255932Salfred} 1110255932Salfred 1111255932Salfredstatic int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 1112255932Salfred enum mlx4_resource type, int extra) 1113255932Salfred{ 1114255932Salfred u64 i; 1115255932Salfred int err; 1116255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1117255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1118255932Salfred struct res_common *r; 1119255932Salfred 1120255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1121255932Salfred for (i = base; i < base + count; ++i) { 1122255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], i); 1123255932Salfred if (!r) { 1124255932Salfred err = -ENOENT; 1125255932Salfred goto out; 1126255932Salfred } 1127255932Salfred if (r->owner != slave) { 1128255932Salfred err = -EPERM; 1129255932Salfred goto out; 1130255932Salfred } 1131255932Salfred err = remove_ok(r, type, extra); 1132255932Salfred if (err) 1133255932Salfred goto out; 1134255932Salfred } 1135255932Salfred 1136255932Salfred for (i = base; i < base + count; ++i) { 1137255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], i); 1138255932Salfred rb_erase(&r->node, &tracker->res_tree[type]); 1139255932Salfred list_del(&r->list); 1140255932Salfred kfree(r); 1141255932Salfred } 1142255932Salfred err = 0; 1143255932Salfred 1144255932Salfredout: 1145255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1146255932Salfred 1147255932Salfred return err; 1148255932Salfred} 1149255932Salfred 1150255932Salfredstatic int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn, 1151255932Salfred enum res_qp_states state, struct res_qp **qp, 1152255932Salfred int alloc) 1153255932Salfred{ 1154255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1155255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1156255932Salfred struct res_qp *r; 1157255932Salfred int err = 0; 1158255932Salfred 1159255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1160255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn); 1161255932Salfred if (!r) 1162255932Salfred err = -ENOENT; 1163255932Salfred else if (r->com.owner != slave) 1164255932Salfred err = -EPERM; 1165255932Salfred else { 1166255932Salfred switch (state) { 1167255932Salfred case RES_QP_BUSY: 1168255932Salfred mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n", 1169255932Salfred __func__, r->com.res_id); 1170255932Salfred err = -EBUSY; 1171255932Salfred break; 1172255932Salfred 1173255932Salfred case RES_QP_RESERVED: 1174255932Salfred if (r->com.state == RES_QP_MAPPED && !alloc) 1175255932Salfred break; 1176255932Salfred 1177255932Salfred mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id); 1178255932Salfred err = -EINVAL; 1179255932Salfred break; 1180255932Salfred 1181255932Salfred case RES_QP_MAPPED: 1182255932Salfred if ((r->com.state == RES_QP_RESERVED && alloc) || 1183255932Salfred r->com.state == RES_QP_HW) 1184255932Salfred break; 1185255932Salfred else { 1186255932Salfred mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", 1187255932Salfred r->com.res_id); 1188255932Salfred err = -EINVAL; 1189255932Salfred } 1190255932Salfred 1191255932Salfred break; 1192255932Salfred 1193255932Salfred case RES_QP_HW: 1194255932Salfred if (r->com.state != RES_QP_MAPPED) 1195255932Salfred err = -EINVAL; 1196255932Salfred break; 1197255932Salfred default: 1198255932Salfred err = -EINVAL; 1199255932Salfred } 1200255932Salfred 1201255932Salfred if (!err) { 1202255932Salfred r->com.from_state = r->com.state; 1203255932Salfred r->com.to_state = state; 1204255932Salfred r->com.state = RES_QP_BUSY; 1205255932Salfred if (qp) 1206255932Salfred *qp = r; 1207255932Salfred } 1208255932Salfred } 1209255932Salfred 1210255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1211255932Salfred 1212255932Salfred return err; 1213255932Salfred} 1214255932Salfred 1215255932Salfredstatic int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 1216255932Salfred enum res_mpt_states state, struct res_mpt **mpt) 1217255932Salfred{ 1218255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1219255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1220255932Salfred struct res_mpt *r; 1221255932Salfred int err = 0; 1222255932Salfred 1223255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1224255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index); 1225255932Salfred if (!r) 1226255932Salfred err = -ENOENT; 1227255932Salfred else if (r->com.owner != slave) 1228255932Salfred err = -EPERM; 1229255932Salfred else { 1230255932Salfred switch (state) { 1231255932Salfred case RES_MPT_BUSY: 1232255932Salfred err = -EINVAL; 1233255932Salfred break; 1234255932Salfred 1235255932Salfred case RES_MPT_RESERVED: 1236255932Salfred if (r->com.state != RES_MPT_MAPPED) 1237255932Salfred err = -EINVAL; 1238255932Salfred break; 1239255932Salfred 1240255932Salfred case RES_MPT_MAPPED: 1241255932Salfred if (r->com.state != RES_MPT_RESERVED && 1242255932Salfred r->com.state != RES_MPT_HW) 1243255932Salfred err = -EINVAL; 1244255932Salfred break; 1245255932Salfred 1246255932Salfred case RES_MPT_HW: 1247255932Salfred if (r->com.state != RES_MPT_MAPPED) 1248255932Salfred err = -EINVAL; 1249255932Salfred break; 1250255932Salfred default: 1251255932Salfred err = -EINVAL; 1252255932Salfred } 1253255932Salfred 1254255932Salfred if (!err) { 1255255932Salfred r->com.from_state = r->com.state; 1256255932Salfred r->com.to_state = state; 1257255932Salfred r->com.state = RES_MPT_BUSY; 1258255932Salfred if (mpt) 1259255932Salfred *mpt = r; 1260255932Salfred } 1261255932Salfred } 1262255932Salfred 1263255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1264255932Salfred 1265255932Salfred return err; 1266255932Salfred} 1267255932Salfred 1268255932Salfredstatic int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 1269255932Salfred enum res_eq_states state, struct res_eq **eq) 1270255932Salfred{ 1271255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1272255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1273255932Salfred struct res_eq *r; 1274255932Salfred int err = 0; 1275255932Salfred 1276255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1277255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index); 1278255932Salfred if (!r) 1279255932Salfred err = -ENOENT; 1280255932Salfred else if (r->com.owner != slave) 1281255932Salfred err = -EPERM; 1282255932Salfred else { 1283255932Salfred switch (state) { 1284255932Salfred case RES_EQ_BUSY: 1285255932Salfred err = -EINVAL; 1286255932Salfred break; 1287255932Salfred 1288255932Salfred case RES_EQ_RESERVED: 1289255932Salfred if (r->com.state != RES_EQ_HW) 1290255932Salfred err = -EINVAL; 1291255932Salfred break; 1292255932Salfred 1293255932Salfred case RES_EQ_HW: 1294255932Salfred if (r->com.state != RES_EQ_RESERVED) 1295255932Salfred err = -EINVAL; 1296255932Salfred break; 1297255932Salfred 1298255932Salfred default: 1299255932Salfred err = -EINVAL; 1300255932Salfred } 1301255932Salfred 1302255932Salfred if (!err) { 1303255932Salfred r->com.from_state = r->com.state; 1304255932Salfred r->com.to_state = state; 1305255932Salfred r->com.state = RES_EQ_BUSY; 1306255932Salfred if (eq) 1307255932Salfred *eq = r; 1308255932Salfred } 1309255932Salfred } 1310255932Salfred 1311255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1312255932Salfred 1313255932Salfred return err; 1314255932Salfred} 1315255932Salfred 1316255932Salfredstatic int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn, 1317255932Salfred enum res_cq_states state, struct res_cq **cq) 1318255932Salfred{ 1319255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1320255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1321255932Salfred struct res_cq *r; 1322255932Salfred int err; 1323255932Salfred 1324255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1325255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn); 1326255932Salfred if (!r) 1327255932Salfred err = -ENOENT; 1328255932Salfred else if (r->com.owner != slave) 1329255932Salfred err = -EPERM; 1330255932Salfred else { 1331255932Salfred switch (state) { 1332255932Salfred case RES_CQ_BUSY: 1333255932Salfred err = -EBUSY; 1334255932Salfred break; 1335255932Salfred 1336255932Salfred case RES_CQ_ALLOCATED: 1337255932Salfred if (r->com.state != RES_CQ_HW) 1338255932Salfred err = -EINVAL; 1339255932Salfred else if (atomic_read(&r->ref_count)) 1340255932Salfred err = -EBUSY; 1341255932Salfred else 1342255932Salfred err = 0; 1343255932Salfred break; 1344255932Salfred 1345255932Salfred case RES_CQ_HW: 1346255932Salfred if (r->com.state != RES_CQ_ALLOCATED) 1347255932Salfred err = -EINVAL; 1348255932Salfred else 1349255932Salfred err = 0; 1350255932Salfred break; 1351255932Salfred 1352255932Salfred default: 1353255932Salfred err = -EINVAL; 1354255932Salfred } 1355255932Salfred 1356255932Salfred if (!err) { 1357255932Salfred r->com.from_state = r->com.state; 1358255932Salfred r->com.to_state = state; 1359255932Salfred r->com.state = RES_CQ_BUSY; 1360255932Salfred if (cq) 1361255932Salfred *cq = r; 1362255932Salfred } 1363255932Salfred } 1364255932Salfred 1365255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1366255932Salfred 1367255932Salfred return err; 1368255932Salfred} 1369255932Salfred 1370255932Salfredstatic int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 1371255932Salfred enum res_srq_states state, struct res_srq **srq) 1372255932Salfred{ 1373255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1374255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1375255932Salfred struct res_srq *r; 1376255932Salfred int err = 0; 1377255932Salfred 1378255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1379255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index); 1380255932Salfred if (!r) 1381255932Salfred err = -ENOENT; 1382255932Salfred else if (r->com.owner != slave) 1383255932Salfred err = -EPERM; 1384255932Salfred else { 1385255932Salfred switch (state) { 1386255932Salfred case RES_SRQ_BUSY: 1387255932Salfred err = -EINVAL; 1388255932Salfred break; 1389255932Salfred 1390255932Salfred case RES_SRQ_ALLOCATED: 1391255932Salfred if (r->com.state != RES_SRQ_HW) 1392255932Salfred err = -EINVAL; 1393255932Salfred else if (atomic_read(&r->ref_count)) 1394255932Salfred err = -EBUSY; 1395255932Salfred break; 1396255932Salfred 1397255932Salfred case RES_SRQ_HW: 1398255932Salfred if (r->com.state != RES_SRQ_ALLOCATED) 1399255932Salfred err = -EINVAL; 1400255932Salfred break; 1401255932Salfred 1402255932Salfred default: 1403255932Salfred err = -EINVAL; 1404255932Salfred } 1405255932Salfred 1406255932Salfred if (!err) { 1407255932Salfred r->com.from_state = r->com.state; 1408255932Salfred r->com.to_state = state; 1409255932Salfred r->com.state = RES_SRQ_BUSY; 1410255932Salfred if (srq) 1411255932Salfred *srq = r; 1412255932Salfred } 1413255932Salfred } 1414255932Salfred 1415255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1416255932Salfred 1417255932Salfred return err; 1418255932Salfred} 1419255932Salfred 1420255932Salfredstatic void res_abort_move(struct mlx4_dev *dev, int slave, 1421255932Salfred enum mlx4_resource type, int id) 1422255932Salfred{ 1423255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1424255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1425255932Salfred struct res_common *r; 1426255932Salfred 1427255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1428255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], id); 1429255932Salfred if (r && (r->owner == slave)) 1430255932Salfred r->state = r->from_state; 1431255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1432255932Salfred} 1433255932Salfred 1434255932Salfredstatic void res_end_move(struct mlx4_dev *dev, int slave, 1435255932Salfred enum mlx4_resource type, int id) 1436255932Salfred{ 1437255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1438255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1439255932Salfred struct res_common *r; 1440255932Salfred 1441255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1442255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], id); 1443255932Salfred if (r && (r->owner == slave)) 1444255932Salfred r->state = r->to_state; 1445255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1446255932Salfred} 1447255932Salfred 1448255932Salfredstatic int valid_reserved(struct mlx4_dev *dev, int slave, int qpn) 1449255932Salfred{ 1450255932Salfred return mlx4_is_qp_reserved(dev, qpn) && 1451255932Salfred (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn)); 1452255932Salfred} 1453255932Salfred 1454255932Salfredstatic int fw_reserved(struct mlx4_dev *dev, int qpn) 1455255932Salfred{ 1456255932Salfred return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; 1457255932Salfred} 1458255932Salfred 1459255932Salfredstatic int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1460255932Salfred u64 in_param, u64 *out_param) 1461255932Salfred{ 1462255932Salfred int err; 1463255932Salfred int count; 1464255932Salfred int align; 1465255932Salfred int base; 1466255932Salfred int qpn; 1467255932Salfred u8 bf_qp; 1468255932Salfred 1469255932Salfred switch (op) { 1470255932Salfred case RES_OP_RESERVE: 1471255932Salfred count = get_param_l(&in_param) & 0xffffff; 1472255932Salfred bf_qp = get_param_l(&in_param) >> 31; 1473255932Salfred align = get_param_h(&in_param); 1474255932Salfred err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); 1475255932Salfred if (err) 1476255932Salfred return err; 1477255932Salfred 1478255932Salfred err = __mlx4_qp_reserve_range(dev, count, align, &base, bf_qp); 1479255932Salfred if (err) { 1480255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 1481255932Salfred return err; 1482255932Salfred } 1483255932Salfred 1484255932Salfred err = add_res_range(dev, slave, base, count, RES_QP, 0); 1485255932Salfred if (err) { 1486255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 1487255932Salfred __mlx4_qp_release_range(dev, base, count); 1488255932Salfred return err; 1489255932Salfred } 1490255932Salfred set_param_l(out_param, base); 1491255932Salfred break; 1492255932Salfred case RES_OP_MAP_ICM: 1493255932Salfred qpn = get_param_l(&in_param) & 0x7fffff; 1494255932Salfred if (valid_reserved(dev, slave, qpn)) { 1495255932Salfred err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); 1496255932Salfred if (err) 1497255932Salfred return err; 1498255932Salfred } 1499255932Salfred 1500255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, 1501255932Salfred NULL, 1); 1502255932Salfred if (err) 1503255932Salfred return err; 1504255932Salfred 1505255932Salfred if (!fw_reserved(dev, qpn)) { 1506255932Salfred err = __mlx4_qp_alloc_icm(dev, qpn); 1507255932Salfred if (err) { 1508255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 1509255932Salfred return err; 1510255932Salfred } 1511255932Salfred } 1512255932Salfred 1513255932Salfred res_end_move(dev, slave, RES_QP, qpn); 1514255932Salfred break; 1515255932Salfred 1516255932Salfred default: 1517255932Salfred err = -EINVAL; 1518255932Salfred break; 1519255932Salfred } 1520255932Salfred return err; 1521255932Salfred} 1522255932Salfred 1523255932Salfredstatic int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1524255932Salfred u64 in_param, u64 *out_param) 1525255932Salfred{ 1526255932Salfred int err = -EINVAL; 1527255932Salfred int base; 1528255932Salfred int order; 1529255932Salfred 1530255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1531255932Salfred return err; 1532255932Salfred 1533255932Salfred order = get_param_l(&in_param); 1534255932Salfred 1535255932Salfred err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); 1536255932Salfred if (err) 1537255932Salfred return err; 1538255932Salfred 1539255932Salfred base = __mlx4_alloc_mtt_range(dev, order); 1540255932Salfred if (base == -1) { 1541255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 1542255932Salfred return -ENOMEM; 1543255932Salfred } 1544255932Salfred 1545255932Salfred err = add_res_range(dev, slave, base, 1, RES_MTT, order); 1546255932Salfred if (err) { 1547255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 1548255932Salfred __mlx4_free_mtt_range(dev, base, order); 1549255932Salfred } else 1550255932Salfred set_param_l(out_param, base); 1551255932Salfred 1552255932Salfred return err; 1553255932Salfred} 1554255932Salfred 1555255932Salfredstatic int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1556255932Salfred u64 in_param, u64 *out_param) 1557255932Salfred{ 1558255932Salfred int err = -EINVAL; 1559255932Salfred int index; 1560255932Salfred int id; 1561255932Salfred struct res_mpt *mpt; 1562255932Salfred 1563255932Salfred switch (op) { 1564255932Salfred case RES_OP_RESERVE: 1565255932Salfred err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); 1566255932Salfred if (err) 1567255932Salfred break; 1568255932Salfred 1569255932Salfred index = __mlx4_mr_reserve(dev); 1570255932Salfred if (index == -1) { 1571255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 1572255932Salfred break; 1573255932Salfred } 1574255932Salfred id = index & mpt_mask(dev); 1575255932Salfred 1576255932Salfred err = add_res_range(dev, slave, id, 1, RES_MPT, index); 1577255932Salfred if (err) { 1578255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 1579255932Salfred __mlx4_mr_release(dev, index); 1580255932Salfred break; 1581255932Salfred } 1582255932Salfred set_param_l(out_param, index); 1583255932Salfred break; 1584255932Salfred case RES_OP_MAP_ICM: 1585255932Salfred index = get_param_l(&in_param); 1586255932Salfred id = index & mpt_mask(dev); 1587255932Salfred err = mr_res_start_move_to(dev, slave, id, 1588255932Salfred RES_MPT_MAPPED, &mpt); 1589255932Salfred if (err) 1590255932Salfred return err; 1591255932Salfred 1592255932Salfred err = __mlx4_mr_alloc_icm(dev, mpt->key); 1593255932Salfred if (err) { 1594255932Salfred res_abort_move(dev, slave, RES_MPT, id); 1595255932Salfred return err; 1596255932Salfred } 1597255932Salfred 1598255932Salfred res_end_move(dev, slave, RES_MPT, id); 1599255932Salfred break; 1600255932Salfred } 1601255932Salfred return err; 1602255932Salfred} 1603255932Salfred 1604255932Salfredstatic int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1605255932Salfred u64 in_param, u64 *out_param) 1606255932Salfred{ 1607255932Salfred int cqn; 1608255932Salfred int err; 1609255932Salfred 1610255932Salfred switch (op) { 1611255932Salfred case RES_OP_RESERVE_AND_MAP: 1612255932Salfred err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); 1613255932Salfred if (err) 1614255932Salfred break; 1615255932Salfred 1616255932Salfred err = __mlx4_cq_alloc_icm(dev, &cqn); 1617255932Salfred if (err) { 1618255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 1619255932Salfred break; 1620255932Salfred } 1621255932Salfred 1622255932Salfred err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); 1623255932Salfred if (err) { 1624255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 1625255932Salfred __mlx4_cq_free_icm(dev, cqn); 1626255932Salfred break; 1627255932Salfred } 1628255932Salfred 1629255932Salfred set_param_l(out_param, cqn); 1630255932Salfred break; 1631255932Salfred 1632255932Salfred default: 1633255932Salfred err = -EINVAL; 1634255932Salfred } 1635255932Salfred 1636255932Salfred return err; 1637255932Salfred} 1638255932Salfred 1639255932Salfredstatic int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1640255932Salfred u64 in_param, u64 *out_param) 1641255932Salfred{ 1642255932Salfred int srqn; 1643255932Salfred int err; 1644255932Salfred 1645255932Salfred switch (op) { 1646255932Salfred case RES_OP_RESERVE_AND_MAP: 1647255932Salfred err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); 1648255932Salfred if (err) 1649255932Salfred break; 1650255932Salfred 1651255932Salfred err = __mlx4_srq_alloc_icm(dev, &srqn); 1652255932Salfred if (err) { 1653255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 1654255932Salfred break; 1655255932Salfred } 1656255932Salfred 1657255932Salfred err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 1658255932Salfred if (err) { 1659255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 1660255932Salfred __mlx4_srq_free_icm(dev, srqn); 1661255932Salfred break; 1662255932Salfred } 1663255932Salfred 1664255932Salfred set_param_l(out_param, srqn); 1665255932Salfred break; 1666255932Salfred 1667255932Salfred default: 1668255932Salfred err = -EINVAL; 1669255932Salfred } 1670255932Salfred 1671255932Salfred return err; 1672255932Salfred} 1673255932Salfred 1674255932Salfredstatic int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, 1675255932Salfred u8 smac_index, u64 *mac) 1676255932Salfred{ 1677255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1678255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1679255932Salfred struct list_head *mac_list = 1680255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1681255932Salfred struct mac_res *res, *tmp; 1682255932Salfred 1683255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1684255932Salfred if (res->smac_index == smac_index && res->port == (u8) port) { 1685255932Salfred *mac = res->mac; 1686255932Salfred return 0; 1687255932Salfred } 1688255932Salfred } 1689255932Salfred return -ENOENT; 1690255932Salfred} 1691255932Salfred 1692255932Salfredstatic int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) 1693255932Salfred{ 1694255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1695255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1696255932Salfred struct list_head *mac_list = 1697255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1698255932Salfred struct mac_res *res, *tmp; 1699255932Salfred 1700255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1701255932Salfred if (res->mac == mac && res->port == (u8) port) { 1702255932Salfred /* mac found. update ref count */ 1703255932Salfred ++res->ref_count; 1704255932Salfred return 0; 1705255932Salfred } 1706255932Salfred } 1707255932Salfred 1708255932Salfred if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) 1709255932Salfred return -EINVAL; 1710255932Salfred res = kzalloc(sizeof *res, GFP_KERNEL); 1711255932Salfred if (!res) { 1712255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, port); 1713255932Salfred return -ENOMEM; 1714255932Salfred } 1715255932Salfred res->mac = mac; 1716255932Salfred res->port = (u8) port; 1717255932Salfred res->smac_index = smac_index; 1718255932Salfred res->ref_count = 1; 1719255932Salfred list_add_tail(&res->list, 1720255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]); 1721255932Salfred return 0; 1722255932Salfred} 1723255932Salfred 1724255932Salfred 1725255932Salfredstatic void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, 1726255932Salfred int port) 1727255932Salfred{ 1728255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1729255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1730255932Salfred struct list_head *mac_list = 1731255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1732255932Salfred struct mac_res *res, *tmp; 1733255932Salfred 1734255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1735255932Salfred if (res->mac == mac && res->port == (u8) port) { 1736255932Salfred if (!--res->ref_count) { 1737255932Salfred list_del(&res->list); 1738255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, port); 1739255932Salfred kfree(res); 1740255932Salfred } 1741255932Salfred break; 1742255932Salfred } 1743255932Salfred } 1744255932Salfred} 1745255932Salfred 1746255932Salfredstatic void rem_slave_macs(struct mlx4_dev *dev, int slave) 1747255932Salfred{ 1748255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1749255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1750255932Salfred struct list_head *mac_list = 1751255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1752255932Salfred struct mac_res *res, *tmp; 1753255932Salfred int i; 1754255932Salfred 1755255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1756255932Salfred list_del(&res->list); 1757255932Salfred /* dereference the mac the num times the slave referenced it */ 1758255932Salfred for (i = 0; i < res->ref_count; i++) 1759255932Salfred __mlx4_unregister_mac(dev, res->port, res->mac); 1760255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); 1761255932Salfred kfree(res); 1762255932Salfred } 1763255932Salfred} 1764255932Salfred 1765255932Salfredstatic int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1766255932Salfred u64 in_param, u64 *out_param, int in_port) 1767255932Salfred{ 1768255932Salfred int err = -EINVAL; 1769255932Salfred int port; 1770255932Salfred u64 mac; 1771255932Salfred u8 smac_index = 0; 1772255932Salfred 1773255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1774255932Salfred return err; 1775255932Salfred 1776255932Salfred port = !in_port ? get_param_l(out_param) : in_port; 1777255932Salfred mac = in_param; 1778255932Salfred 1779255932Salfred err = __mlx4_register_mac(dev, port, mac); 1780255932Salfred if (err >= 0) { 1781255932Salfred smac_index = err; 1782255932Salfred set_param_l(out_param, err); 1783255932Salfred err = 0; 1784255932Salfred } 1785255932Salfred 1786255932Salfred if (!err) { 1787255932Salfred err = mac_add_to_slave(dev, slave, mac, port, smac_index); 1788255932Salfred if (err) 1789255932Salfred __mlx4_unregister_mac(dev, port, mac); 1790255932Salfred } 1791255932Salfred return err; 1792255932Salfred} 1793255932Salfred 1794255932Salfredstatic int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, 1795255932Salfred int port, int vlan_index) 1796255932Salfred{ 1797255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1798255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1799255932Salfred struct list_head *vlan_list = 1800255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1801255932Salfred struct vlan_res *res, *tmp; 1802255932Salfred 1803255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1804255932Salfred if (res->vlan == vlan && res->port == (u8) port) { 1805255932Salfred /* vlan found. update ref count */ 1806255932Salfred ++res->ref_count; 1807255932Salfred return 0; 1808255932Salfred } 1809255932Salfred } 1810255932Salfred 1811255932Salfred if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) 1812255932Salfred return -EINVAL; 1813255932Salfred res = kzalloc(sizeof(*res), GFP_KERNEL); 1814255932Salfred if (!res) { 1815255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1, port); 1816255932Salfred return -ENOMEM; 1817255932Salfred } 1818255932Salfred res->vlan = vlan; 1819255932Salfred res->port = (u8) port; 1820255932Salfred res->vlan_index = vlan_index; 1821255932Salfred res->ref_count = 1; 1822255932Salfred list_add_tail(&res->list, 1823255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]); 1824255932Salfred return 0; 1825255932Salfred} 1826255932Salfred 1827255932Salfred 1828255932Salfredstatic void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, 1829255932Salfred int port) 1830255932Salfred{ 1831255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1832255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1833255932Salfred struct list_head *vlan_list = 1834255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1835255932Salfred struct vlan_res *res, *tmp; 1836255932Salfred 1837255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1838255932Salfred if (res->vlan == vlan && res->port == (u8) port) { 1839255932Salfred if (!--res->ref_count) { 1840255932Salfred list_del(&res->list); 1841255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1842255932Salfred 1, port); 1843255932Salfred kfree(res); 1844255932Salfred } 1845255932Salfred break; 1846255932Salfred } 1847255932Salfred } 1848255932Salfred} 1849255932Salfred 1850255932Salfredstatic void rem_slave_vlans(struct mlx4_dev *dev, int slave) 1851255932Salfred{ 1852255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1853255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1854255932Salfred struct list_head *vlan_list = 1855255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1856255932Salfred struct vlan_res *res, *tmp; 1857255932Salfred int i; 1858255932Salfred 1859255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1860255932Salfred list_del(&res->list); 1861255932Salfred /* dereference the vlan the num times the slave referenced it */ 1862255932Salfred for (i = 0; i < res->ref_count; i++) 1863255932Salfred __mlx4_unregister_vlan(dev, res->port, res->vlan); 1864255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); 1865255932Salfred kfree(res); 1866255932Salfred } 1867255932Salfred} 1868255932Salfred 1869255932Salfredstatic int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1870255932Salfred u64 in_param, u64 *out_param, int port) 1871255932Salfred{ 1872255932Salfred int err = -EINVAL; 1873255932Salfred u16 vlan; 1874255932Salfred int vlan_index; 1875255932Salfred 1876255932Salfred if (!port) 1877255932Salfred return err; 1878255932Salfred 1879255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1880255932Salfred return err; 1881255932Salfred 1882255932Salfred vlan = (u16) in_param; 1883255932Salfred 1884255932Salfred err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); 1885255932Salfred if (!err) { 1886255932Salfred set_param_l(out_param, (u32) vlan_index); 1887255932Salfred err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); 1888255932Salfred if (err) 1889255932Salfred __mlx4_unregister_vlan(dev, port, vlan); 1890255932Salfred } 1891255932Salfred return err; 1892255932Salfred} 1893255932Salfred 1894255932Salfredstatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1895255932Salfred u64 in_param, u64 *out_param) 1896255932Salfred{ 1897255932Salfred u32 index; 1898255932Salfred int err; 1899255932Salfred 1900255932Salfred if (op != RES_OP_RESERVE) 1901255932Salfred return -EINVAL; 1902255932Salfred 1903255932Salfred err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0); 1904255932Salfred if (err) 1905255932Salfred return err; 1906255932Salfred 1907255932Salfred err = __mlx4_counter_alloc(dev, &index); 1908255932Salfred if (err) { 1909255932Salfred mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 1910255932Salfred return err; 1911255932Salfred } 1912255932Salfred 1913255932Salfred err = add_res_range(dev, slave, index, 1, RES_COUNTER, 0); 1914255932Salfred if (err) { 1915255932Salfred __mlx4_counter_free(dev, index); 1916255932Salfred mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 1917255932Salfred } else { 1918255932Salfred set_param_l(out_param, index); 1919255932Salfred } 1920255932Salfred 1921255932Salfred return err; 1922255932Salfred} 1923255932Salfred 1924255932Salfredstatic int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1925255932Salfred u64 in_param, u64 *out_param) 1926255932Salfred{ 1927255932Salfred u32 xrcdn; 1928255932Salfred int err; 1929255932Salfred 1930255932Salfred if (op != RES_OP_RESERVE) 1931255932Salfred return -EINVAL; 1932255932Salfred 1933255932Salfred err = __mlx4_xrcd_alloc(dev, &xrcdn); 1934255932Salfred if (err) 1935255932Salfred return err; 1936255932Salfred 1937255932Salfred err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 1938255932Salfred if (err) 1939255932Salfred __mlx4_xrcd_free(dev, xrcdn); 1940255932Salfred else 1941255932Salfred set_param_l(out_param, xrcdn); 1942255932Salfred 1943255932Salfred return err; 1944255932Salfred} 1945255932Salfred 1946255932Salfredint mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, 1947255932Salfred struct mlx4_vhcr *vhcr, 1948255932Salfred struct mlx4_cmd_mailbox *inbox, 1949255932Salfred struct mlx4_cmd_mailbox *outbox, 1950255932Salfred struct mlx4_cmd_info *cmd) 1951255932Salfred{ 1952255932Salfred int err; 1953255932Salfred int alop = vhcr->op_modifier; 1954255932Salfred 1955255932Salfred switch (vhcr->in_modifier & 0xFF) { 1956255932Salfred case RES_QP: 1957255932Salfred err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, 1958255932Salfred vhcr->in_param, &vhcr->out_param); 1959255932Salfred break; 1960255932Salfred 1961255932Salfred case RES_MTT: 1962255932Salfred err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, 1963255932Salfred vhcr->in_param, &vhcr->out_param); 1964255932Salfred break; 1965255932Salfred 1966255932Salfred case RES_MPT: 1967255932Salfred err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, 1968255932Salfred vhcr->in_param, &vhcr->out_param); 1969255932Salfred break; 1970255932Salfred 1971255932Salfred case RES_CQ: 1972255932Salfred err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, 1973255932Salfred vhcr->in_param, &vhcr->out_param); 1974255932Salfred break; 1975255932Salfred 1976255932Salfred case RES_SRQ: 1977255932Salfred err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, 1978255932Salfred vhcr->in_param, &vhcr->out_param); 1979255932Salfred break; 1980255932Salfred 1981255932Salfred case RES_MAC: 1982255932Salfred err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, 1983255932Salfred vhcr->in_param, &vhcr->out_param, 1984255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 1985255932Salfred break; 1986255932Salfred 1987255932Salfred case RES_VLAN: 1988255932Salfred err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, 1989255932Salfred vhcr->in_param, &vhcr->out_param, 1990255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 1991255932Salfred break; 1992255932Salfred 1993255932Salfred case RES_COUNTER: 1994255932Salfred err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, 1995255932Salfred vhcr->in_param, &vhcr->out_param); 1996255932Salfred break; 1997255932Salfred 1998255932Salfred case RES_XRCD: 1999255932Salfred err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, 2000255932Salfred vhcr->in_param, &vhcr->out_param); 2001255932Salfred break; 2002255932Salfred 2003255932Salfred default: 2004255932Salfred err = -EINVAL; 2005255932Salfred break; 2006255932Salfred } 2007255932Salfred 2008255932Salfred return err; 2009255932Salfred} 2010255932Salfred 2011255932Salfredstatic int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2012255932Salfred u64 in_param) 2013255932Salfred{ 2014255932Salfred int err; 2015255932Salfred int count; 2016255932Salfred int base; 2017255932Salfred int qpn; 2018255932Salfred 2019255932Salfred switch (op) { 2020255932Salfred case RES_OP_RESERVE: 2021255932Salfred base = get_param_l(&in_param) & 0x7fffff; 2022255932Salfred count = get_param_h(&in_param); 2023255932Salfred err = rem_res_range(dev, slave, base, count, RES_QP, 0); 2024255932Salfred if (err) 2025255932Salfred break; 2026255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 2027255932Salfred __mlx4_qp_release_range(dev, base, count); 2028255932Salfred break; 2029255932Salfred case RES_OP_MAP_ICM: 2030255932Salfred qpn = get_param_l(&in_param) & 0x7fffff; 2031255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, 2032255932Salfred NULL, 0); 2033255932Salfred if (err) 2034255932Salfred return err; 2035255932Salfred 2036255932Salfred if (!fw_reserved(dev, qpn)) 2037255932Salfred __mlx4_qp_free_icm(dev, qpn); 2038255932Salfred 2039255932Salfred res_end_move(dev, slave, RES_QP, qpn); 2040255932Salfred 2041255932Salfred if (valid_reserved(dev, slave, qpn)) 2042255932Salfred err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); 2043255932Salfred break; 2044255932Salfred default: 2045255932Salfred err = -EINVAL; 2046255932Salfred break; 2047255932Salfred } 2048255932Salfred return err; 2049255932Salfred} 2050255932Salfred 2051255932Salfredstatic int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2052255932Salfred u64 in_param, u64 *out_param) 2053255932Salfred{ 2054255932Salfred int err = -EINVAL; 2055255932Salfred int base; 2056255932Salfred int order; 2057255932Salfred 2058255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 2059255932Salfred return err; 2060255932Salfred 2061255932Salfred base = get_param_l(&in_param); 2062255932Salfred order = get_param_h(&in_param); 2063255932Salfred err = rem_res_range(dev, slave, base, 1, RES_MTT, order); 2064255932Salfred if (!err) { 2065255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 2066255932Salfred __mlx4_free_mtt_range(dev, base, order); 2067255932Salfred } 2068255932Salfred return err; 2069255932Salfred} 2070255932Salfred 2071255932Salfredstatic int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2072255932Salfred u64 in_param) 2073255932Salfred{ 2074255932Salfred int err = -EINVAL; 2075255932Salfred int index; 2076255932Salfred int id; 2077255932Salfred struct res_mpt *mpt; 2078255932Salfred 2079255932Salfred switch (op) { 2080255932Salfred case RES_OP_RESERVE: 2081255932Salfred index = get_param_l(&in_param); 2082255932Salfred id = index & mpt_mask(dev); 2083255932Salfred err = get_res(dev, slave, id, RES_MPT, &mpt); 2084255932Salfred if (err) 2085255932Salfred break; 2086255932Salfred index = mpt->key; 2087255932Salfred put_res(dev, slave, id, RES_MPT); 2088255932Salfred 2089255932Salfred err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); 2090255932Salfred if (err) 2091255932Salfred break; 2092255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 2093255932Salfred __mlx4_mr_release(dev, index); 2094255932Salfred break; 2095255932Salfred case RES_OP_MAP_ICM: 2096255932Salfred index = get_param_l(&in_param); 2097255932Salfred id = index & mpt_mask(dev); 2098255932Salfred err = mr_res_start_move_to(dev, slave, id, 2099255932Salfred RES_MPT_RESERVED, &mpt); 2100255932Salfred if (err) 2101255932Salfred return err; 2102255932Salfred 2103255932Salfred __mlx4_mr_free_icm(dev, mpt->key); 2104255932Salfred res_end_move(dev, slave, RES_MPT, id); 2105255932Salfred return err; 2106255932Salfred break; 2107255932Salfred default: 2108255932Salfred err = -EINVAL; 2109255932Salfred break; 2110255932Salfred } 2111255932Salfred return err; 2112255932Salfred} 2113255932Salfred 2114255932Salfredstatic int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2115255932Salfred u64 in_param, u64 *out_param) 2116255932Salfred{ 2117255932Salfred int cqn; 2118255932Salfred int err; 2119255932Salfred 2120255932Salfred switch (op) { 2121255932Salfred case RES_OP_RESERVE_AND_MAP: 2122255932Salfred cqn = get_param_l(&in_param); 2123255932Salfred err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); 2124255932Salfred if (err) 2125255932Salfred break; 2126255932Salfred 2127255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 2128255932Salfred __mlx4_cq_free_icm(dev, cqn); 2129255932Salfred break; 2130255932Salfred 2131255932Salfred default: 2132255932Salfred err = -EINVAL; 2133255932Salfred break; 2134255932Salfred } 2135255932Salfred 2136255932Salfred return err; 2137255932Salfred} 2138255932Salfred 2139255932Salfredstatic int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2140255932Salfred u64 in_param, u64 *out_param) 2141255932Salfred{ 2142255932Salfred int srqn; 2143255932Salfred int err; 2144255932Salfred 2145255932Salfred switch (op) { 2146255932Salfred case RES_OP_RESERVE_AND_MAP: 2147255932Salfred srqn = get_param_l(&in_param); 2148255932Salfred err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 2149255932Salfred if (err) 2150255932Salfred break; 2151255932Salfred 2152255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 2153255932Salfred __mlx4_srq_free_icm(dev, srqn); 2154255932Salfred break; 2155255932Salfred 2156255932Salfred default: 2157255932Salfred err = -EINVAL; 2158255932Salfred break; 2159255932Salfred } 2160255932Salfred 2161255932Salfred return err; 2162255932Salfred} 2163255932Salfred 2164255932Salfredstatic int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2165255932Salfred u64 in_param, u64 *out_param, int in_port) 2166255932Salfred{ 2167255932Salfred int port; 2168255932Salfred int err = 0; 2169255932Salfred 2170255932Salfred switch (op) { 2171255932Salfred case RES_OP_RESERVE_AND_MAP: 2172255932Salfred port = !in_port ? get_param_l(out_param) : in_port; 2173255932Salfred mac_del_from_slave(dev, slave, in_param, port); 2174255932Salfred __mlx4_unregister_mac(dev, port, in_param); 2175255932Salfred break; 2176255932Salfred default: 2177255932Salfred err = -EINVAL; 2178255932Salfred break; 2179255932Salfred } 2180255932Salfred 2181255932Salfred return err; 2182255932Salfred 2183255932Salfred} 2184255932Salfred 2185255932Salfredstatic int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2186255932Salfred u64 in_param, u64 *out_param, int port) 2187255932Salfred{ 2188255932Salfred int err = 0; 2189255932Salfred 2190255932Salfred switch (op) { 2191255932Salfred case RES_OP_RESERVE_AND_MAP: 2192255932Salfred if (!port) 2193255932Salfred return -EINVAL; 2194255932Salfred vlan_del_from_slave(dev, slave, in_param, port); 2195255932Salfred __mlx4_unregister_vlan(dev, port, in_param); 2196255932Salfred break; 2197255932Salfred default: 2198255932Salfred err = -EINVAL; 2199255932Salfred break; 2200255932Salfred } 2201255932Salfred 2202255932Salfred return err; 2203255932Salfred} 2204255932Salfred 2205255932Salfredstatic int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2206255932Salfred u64 in_param, u64 *out_param) 2207255932Salfred{ 2208255932Salfred int index; 2209255932Salfred int err; 2210255932Salfred 2211255932Salfred if (op != RES_OP_RESERVE) 2212255932Salfred return -EINVAL; 2213255932Salfred 2214255932Salfred index = get_param_l(&in_param); 2215255932Salfred err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0); 2216255932Salfred if (err) 2217255932Salfred return err; 2218255932Salfred 2219255932Salfred __mlx4_counter_free(dev, index); 2220255932Salfred mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); 2221255932Salfred 2222255932Salfred return err; 2223255932Salfred} 2224255932Salfred 2225255932Salfredstatic int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2226255932Salfred u64 in_param, u64 *out_param) 2227255932Salfred{ 2228255932Salfred int xrcdn; 2229255932Salfred int err; 2230255932Salfred 2231255932Salfred if (op != RES_OP_RESERVE) 2232255932Salfred return -EINVAL; 2233255932Salfred 2234255932Salfred xrcdn = get_param_l(&in_param); 2235255932Salfred err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 2236255932Salfred if (err) 2237255932Salfred return err; 2238255932Salfred 2239255932Salfred __mlx4_xrcd_free(dev, xrcdn); 2240255932Salfred 2241255932Salfred return err; 2242255932Salfred} 2243255932Salfred 2244255932Salfredint mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, 2245255932Salfred struct mlx4_vhcr *vhcr, 2246255932Salfred struct mlx4_cmd_mailbox *inbox, 2247255932Salfred struct mlx4_cmd_mailbox *outbox, 2248255932Salfred struct mlx4_cmd_info *cmd) 2249255932Salfred{ 2250255932Salfred int err = -EINVAL; 2251255932Salfred int alop = vhcr->op_modifier; 2252255932Salfred 2253255932Salfred switch (vhcr->in_modifier & 0xFF) { 2254255932Salfred case RES_QP: 2255255932Salfred err = qp_free_res(dev, slave, vhcr->op_modifier, alop, 2256255932Salfred vhcr->in_param); 2257255932Salfred break; 2258255932Salfred 2259255932Salfred case RES_MTT: 2260255932Salfred err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, 2261255932Salfred vhcr->in_param, &vhcr->out_param); 2262255932Salfred break; 2263255932Salfred 2264255932Salfred case RES_MPT: 2265255932Salfred err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, 2266255932Salfred vhcr->in_param); 2267255932Salfred break; 2268255932Salfred 2269255932Salfred case RES_CQ: 2270255932Salfred err = cq_free_res(dev, slave, vhcr->op_modifier, alop, 2271255932Salfred vhcr->in_param, &vhcr->out_param); 2272255932Salfred break; 2273255932Salfred 2274255932Salfred case RES_SRQ: 2275255932Salfred err = srq_free_res(dev, slave, vhcr->op_modifier, alop, 2276255932Salfred vhcr->in_param, &vhcr->out_param); 2277255932Salfred break; 2278255932Salfred 2279255932Salfred case RES_MAC: 2280255932Salfred err = mac_free_res(dev, slave, vhcr->op_modifier, alop, 2281255932Salfred vhcr->in_param, &vhcr->out_param, 2282255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2283255932Salfred break; 2284255932Salfred 2285255932Salfred case RES_VLAN: 2286255932Salfred err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, 2287255932Salfred vhcr->in_param, &vhcr->out_param, 2288255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2289255932Salfred break; 2290255932Salfred 2291255932Salfred case RES_COUNTER: 2292255932Salfred err = counter_free_res(dev, slave, vhcr->op_modifier, alop, 2293255932Salfred vhcr->in_param, &vhcr->out_param); 2294255932Salfred break; 2295255932Salfred 2296255932Salfred case RES_XRCD: 2297255932Salfred err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, 2298255932Salfred vhcr->in_param, &vhcr->out_param); 2299255932Salfred 2300255932Salfred default: 2301255932Salfred break; 2302255932Salfred } 2303255932Salfred return err; 2304255932Salfred} 2305255932Salfred 2306255932Salfred/* ugly but other choices are uglier */ 2307255932Salfredstatic int mr_phys_mpt(struct mlx4_mpt_entry *mpt) 2308255932Salfred{ 2309255932Salfred return (be32_to_cpu(mpt->flags) >> 9) & 1; 2310255932Salfred} 2311255932Salfred 2312255932Salfredstatic int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) 2313255932Salfred{ 2314255932Salfred return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; 2315255932Salfred} 2316255932Salfred 2317255932Salfredstatic int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) 2318255932Salfred{ 2319255932Salfred return be32_to_cpu(mpt->mtt_sz); 2320255932Salfred} 2321255932Salfred 2322255932Salfredstatic int qp_get_mtt_addr(struct mlx4_qp_context *qpc) 2323255932Salfred{ 2324255932Salfred return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; 2325255932Salfred} 2326255932Salfred 2327255932Salfredstatic int srq_get_mtt_addr(struct mlx4_srq_context *srqc) 2328255932Salfred{ 2329255932Salfred return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; 2330255932Salfred} 2331255932Salfred 2332255932Salfredstatic int qp_get_mtt_size(struct mlx4_qp_context *qpc) 2333255932Salfred{ 2334255932Salfred int page_shift = (qpc->log_page_size & 0x3f) + 12; 2335255932Salfred int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; 2336255932Salfred int log_sq_sride = qpc->sq_size_stride & 7; 2337255932Salfred int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; 2338255932Salfred int log_rq_stride = qpc->rq_size_stride & 7; 2339255932Salfred int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; 2340255932Salfred int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; 2341255932Salfred int xrc = (be32_to_cpu(qpc->local_qpn) >> 23) & 1; 2342255932Salfred int sq_size; 2343255932Salfred int rq_size; 2344255932Salfred int total_pages; 2345255932Salfred int total_mem; 2346255932Salfred int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; 2347255932Salfred 2348255932Salfred sq_size = 1 << (log_sq_size + log_sq_sride + 4); 2349255932Salfred rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); 2350255932Salfred total_mem = sq_size + rq_size; 2351255932Salfred total_pages = 2352255932Salfred roundup_pow_of_two((total_mem + (page_offset << 6)) >> 2353255932Salfred page_shift); 2354255932Salfred 2355255932Salfred return total_pages; 2356255932Salfred} 2357255932Salfred 2358255932Salfredstatic int check_mtt_range(struct mlx4_dev *dev, int slave, int start, 2359255932Salfred int size, struct res_mtt *mtt) 2360255932Salfred{ 2361255932Salfred int res_start = mtt->com.res_id; 2362255932Salfred int res_size = (1 << mtt->order); 2363255932Salfred 2364255932Salfred if (start < res_start || start + size > res_start + res_size) 2365255932Salfred return -EPERM; 2366255932Salfred return 0; 2367255932Salfred} 2368255932Salfred 2369255932Salfredint mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, 2370255932Salfred struct mlx4_vhcr *vhcr, 2371255932Salfred struct mlx4_cmd_mailbox *inbox, 2372255932Salfred struct mlx4_cmd_mailbox *outbox, 2373255932Salfred struct mlx4_cmd_info *cmd) 2374255932Salfred{ 2375255932Salfred int err; 2376255932Salfred int index = vhcr->in_modifier; 2377255932Salfred struct res_mtt *mtt; 2378255932Salfred struct res_mpt *mpt; 2379255932Salfred int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; 2380255932Salfred int phys; 2381255932Salfred int id; 2382255932Salfred 2383255932Salfred id = index & mpt_mask(dev); 2384255932Salfred err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); 2385255932Salfred if (err) 2386255932Salfred return err; 2387255932Salfred 2388255932Salfred phys = mr_phys_mpt(inbox->buf); 2389255932Salfred if (!phys) { 2390255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2391255932Salfred if (err) 2392255932Salfred goto ex_abort; 2393255932Salfred 2394255932Salfred err = check_mtt_range(dev, slave, mtt_base, 2395255932Salfred mr_get_mtt_size(inbox->buf), mtt); 2396255932Salfred if (err) 2397255932Salfred goto ex_put; 2398255932Salfred 2399255932Salfred mpt->mtt = mtt; 2400255932Salfred } 2401255932Salfred 2402255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2403255932Salfred if (err) 2404255932Salfred goto ex_put; 2405255932Salfred 2406255932Salfred if (!phys) { 2407255932Salfred atomic_inc(&mtt->ref_count); 2408255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2409255932Salfred } 2410255932Salfred 2411255932Salfred res_end_move(dev, slave, RES_MPT, id); 2412255932Salfred return 0; 2413255932Salfred 2414255932Salfredex_put: 2415255932Salfred if (!phys) 2416255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2417255932Salfredex_abort: 2418255932Salfred res_abort_move(dev, slave, RES_MPT, id); 2419255932Salfred 2420255932Salfred return err; 2421255932Salfred} 2422255932Salfred 2423255932Salfredint mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, 2424255932Salfred struct mlx4_vhcr *vhcr, 2425255932Salfred struct mlx4_cmd_mailbox *inbox, 2426255932Salfred struct mlx4_cmd_mailbox *outbox, 2427255932Salfred struct mlx4_cmd_info *cmd) 2428255932Salfred{ 2429255932Salfred int err; 2430255932Salfred int index = vhcr->in_modifier; 2431255932Salfred struct res_mpt *mpt; 2432255932Salfred int id; 2433255932Salfred 2434255932Salfred id = index & mpt_mask(dev); 2435255932Salfred err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); 2436255932Salfred if (err) 2437255932Salfred return err; 2438255932Salfred 2439255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2440255932Salfred if (err) 2441255932Salfred goto ex_abort; 2442255932Salfred 2443255932Salfred if (mpt->mtt) 2444255932Salfred atomic_dec(&mpt->mtt->ref_count); 2445255932Salfred 2446255932Salfred res_end_move(dev, slave, RES_MPT, id); 2447255932Salfred return 0; 2448255932Salfred 2449255932Salfredex_abort: 2450255932Salfred res_abort_move(dev, slave, RES_MPT, id); 2451255932Salfred 2452255932Salfred return err; 2453255932Salfred} 2454255932Salfred 2455255932Salfredint mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, 2456255932Salfred struct mlx4_vhcr *vhcr, 2457255932Salfred struct mlx4_cmd_mailbox *inbox, 2458255932Salfred struct mlx4_cmd_mailbox *outbox, 2459255932Salfred struct mlx4_cmd_info *cmd) 2460255932Salfred{ 2461255932Salfred int err; 2462255932Salfred int index = vhcr->in_modifier; 2463255932Salfred struct res_mpt *mpt; 2464255932Salfred int id; 2465255932Salfred 2466255932Salfred id = index & mpt_mask(dev); 2467255932Salfred err = get_res(dev, slave, id, RES_MPT, &mpt); 2468255932Salfred if (err) 2469255932Salfred return err; 2470255932Salfred 2471255932Salfred if (mpt->com.from_state != RES_MPT_HW) { 2472255932Salfred err = -EBUSY; 2473255932Salfred goto out; 2474255932Salfred } 2475255932Salfred 2476255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2477255932Salfred 2478255932Salfredout: 2479255932Salfred put_res(dev, slave, id, RES_MPT); 2480255932Salfred return err; 2481255932Salfred} 2482255932Salfred 2483255932Salfredstatic int qp_get_rcqn(struct mlx4_qp_context *qpc) 2484255932Salfred{ 2485255932Salfred return be32_to_cpu(qpc->cqn_recv) & 0xffffff; 2486255932Salfred} 2487255932Salfred 2488255932Salfredstatic int qp_get_scqn(struct mlx4_qp_context *qpc) 2489255932Salfred{ 2490255932Salfred return be32_to_cpu(qpc->cqn_send) & 0xffffff; 2491255932Salfred} 2492255932Salfred 2493255932Salfredstatic u32 qp_get_srqn(struct mlx4_qp_context *qpc) 2494255932Salfred{ 2495255932Salfred return be32_to_cpu(qpc->srqn) & 0x1ffffff; 2496255932Salfred} 2497255932Salfred 2498255932Salfredstatic void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, 2499255932Salfred struct mlx4_qp_context *context) 2500255932Salfred{ 2501255932Salfred u32 qpn = vhcr->in_modifier & 0xffffff; 2502255932Salfred u32 qkey = 0; 2503255932Salfred 2504255932Salfred if (mlx4_get_parav_qkey(dev, qpn, &qkey)) 2505255932Salfred return; 2506255932Salfred 2507255932Salfred /* adjust qkey in qp context */ 2508255932Salfred context->qkey = cpu_to_be32(qkey); 2509255932Salfred} 2510255932Salfred 2511255932Salfredint mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 2512255932Salfred struct mlx4_vhcr *vhcr, 2513255932Salfred struct mlx4_cmd_mailbox *inbox, 2514255932Salfred struct mlx4_cmd_mailbox *outbox, 2515255932Salfred struct mlx4_cmd_info *cmd) 2516255932Salfred{ 2517255932Salfred int err; 2518255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 2519255932Salfred struct res_mtt *mtt; 2520255932Salfred struct res_qp *qp; 2521255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 2522255932Salfred int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; 2523255932Salfred int mtt_size = qp_get_mtt_size(qpc); 2524255932Salfred struct res_cq *rcq; 2525255932Salfred struct res_cq *scq; 2526255932Salfred int rcqn = qp_get_rcqn(qpc); 2527255932Salfred int scqn = qp_get_scqn(qpc); 2528255932Salfred u32 srqn = qp_get_srqn(qpc) & 0xffffff; 2529255932Salfred int use_srq = (qp_get_srqn(qpc) >> 24) & 1; 2530255932Salfred struct res_srq *srq; 2531255932Salfred int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; 2532255932Salfred 2533255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); 2534255932Salfred if (err) 2535255932Salfred return err; 2536255932Salfred qp->local_qpn = local_qpn; 2537255932Salfred 2538255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2539255932Salfred if (err) 2540255932Salfred goto ex_abort; 2541255932Salfred 2542255932Salfred err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 2543255932Salfred if (err) 2544255932Salfred goto ex_put_mtt; 2545255932Salfred 2546255932Salfred err = get_res(dev, slave, rcqn, RES_CQ, &rcq); 2547255932Salfred if (err) 2548255932Salfred goto ex_put_mtt; 2549255932Salfred 2550255932Salfred if (scqn != rcqn) { 2551255932Salfred err = get_res(dev, slave, scqn, RES_CQ, &scq); 2552255932Salfred if (err) 2553255932Salfred goto ex_put_rcq; 2554255932Salfred } else 2555255932Salfred scq = rcq; 2556255932Salfred 2557255932Salfred if (use_srq) { 2558255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 2559255932Salfred if (err) 2560255932Salfred goto ex_put_scq; 2561255932Salfred } 2562255932Salfred 2563255932Salfred adjust_proxy_tun_qkey(dev, vhcr, qpc); 2564255932Salfred update_pkey_index(dev, slave, inbox); 2565255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2566255932Salfred if (err) 2567255932Salfred goto ex_put_srq; 2568255932Salfred atomic_inc(&mtt->ref_count); 2569255932Salfred qp->mtt = mtt; 2570255932Salfred atomic_inc(&rcq->ref_count); 2571255932Salfred qp->rcq = rcq; 2572255932Salfred atomic_inc(&scq->ref_count); 2573255932Salfred qp->scq = scq; 2574255932Salfred 2575255932Salfred if (scqn != rcqn) 2576255932Salfred put_res(dev, slave, scqn, RES_CQ); 2577255932Salfred 2578255932Salfred if (use_srq) { 2579255932Salfred atomic_inc(&srq->ref_count); 2580255932Salfred put_res(dev, slave, srqn, RES_SRQ); 2581255932Salfred qp->srq = srq; 2582255932Salfred } 2583255932Salfred put_res(dev, slave, rcqn, RES_CQ); 2584255932Salfred put_res(dev, slave, mtt_base, RES_MTT); 2585255932Salfred res_end_move(dev, slave, RES_QP, qpn); 2586255932Salfred 2587255932Salfred return 0; 2588255932Salfred 2589255932Salfredex_put_srq: 2590255932Salfred if (use_srq) 2591255932Salfred put_res(dev, slave, srqn, RES_SRQ); 2592255932Salfredex_put_scq: 2593255932Salfred if (scqn != rcqn) 2594255932Salfred put_res(dev, slave, scqn, RES_CQ); 2595255932Salfredex_put_rcq: 2596255932Salfred put_res(dev, slave, rcqn, RES_CQ); 2597255932Salfredex_put_mtt: 2598255932Salfred put_res(dev, slave, mtt_base, RES_MTT); 2599255932Salfredex_abort: 2600255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 2601255932Salfred 2602255932Salfred return err; 2603255932Salfred} 2604255932Salfred 2605255932Salfredstatic int eq_get_mtt_addr(struct mlx4_eq_context *eqc) 2606255932Salfred{ 2607255932Salfred return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; 2608255932Salfred} 2609255932Salfred 2610255932Salfredstatic int eq_get_mtt_size(struct mlx4_eq_context *eqc) 2611255932Salfred{ 2612255932Salfred int log_eq_size = eqc->log_eq_size & 0x1f; 2613255932Salfred int page_shift = (eqc->log_page_size & 0x3f) + 12; 2614255932Salfred 2615255932Salfred if (log_eq_size + 5 < page_shift) 2616255932Salfred return 1; 2617255932Salfred 2618255932Salfred return 1 << (log_eq_size + 5 - page_shift); 2619255932Salfred} 2620255932Salfred 2621255932Salfredstatic int cq_get_mtt_addr(struct mlx4_cq_context *cqc) 2622255932Salfred{ 2623255932Salfred return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; 2624255932Salfred} 2625255932Salfred 2626255932Salfredstatic int cq_get_mtt_size(struct mlx4_cq_context *cqc) 2627255932Salfred{ 2628255932Salfred int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; 2629255932Salfred int page_shift = (cqc->log_page_size & 0x3f) + 12; 2630255932Salfred 2631255932Salfred if (log_cq_size + 5 < page_shift) 2632255932Salfred return 1; 2633255932Salfred 2634255932Salfred return 1 << (log_cq_size + 5 - page_shift); 2635255932Salfred} 2636255932Salfred 2637255932Salfredint mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, 2638255932Salfred struct mlx4_vhcr *vhcr, 2639255932Salfred struct mlx4_cmd_mailbox *inbox, 2640255932Salfred struct mlx4_cmd_mailbox *outbox, 2641255932Salfred struct mlx4_cmd_info *cmd) 2642255932Salfred{ 2643255932Salfred int err; 2644255932Salfred int eqn = vhcr->in_modifier; 2645255932Salfred int res_id = (slave << 8) | eqn; 2646255932Salfred struct mlx4_eq_context *eqc = inbox->buf; 2647255932Salfred int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; 2648255932Salfred int mtt_size = eq_get_mtt_size(eqc); 2649255932Salfred struct res_eq *eq; 2650255932Salfred struct res_mtt *mtt; 2651255932Salfred 2652255932Salfred err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2653255932Salfred if (err) 2654255932Salfred return err; 2655255932Salfred err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); 2656255932Salfred if (err) 2657255932Salfred goto out_add; 2658255932Salfred 2659255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2660255932Salfred if (err) 2661255932Salfred goto out_move; 2662255932Salfred 2663255932Salfred err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 2664255932Salfred if (err) 2665255932Salfred goto out_put; 2666255932Salfred 2667255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2668255932Salfred if (err) 2669255932Salfred goto out_put; 2670255932Salfred 2671255932Salfred atomic_inc(&mtt->ref_count); 2672255932Salfred eq->mtt = mtt; 2673255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2674255932Salfred res_end_move(dev, slave, RES_EQ, res_id); 2675255932Salfred return 0; 2676255932Salfred 2677255932Salfredout_put: 2678255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2679255932Salfredout_move: 2680255932Salfred res_abort_move(dev, slave, RES_EQ, res_id); 2681255932Salfredout_add: 2682255932Salfred rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2683255932Salfred return err; 2684255932Salfred} 2685255932Salfred 2686255932Salfredstatic int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, 2687255932Salfred int len, struct res_mtt **res) 2688255932Salfred{ 2689255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2690255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 2691255932Salfred struct res_mtt *mtt; 2692255932Salfred int err = -EINVAL; 2693255932Salfred 2694255932Salfred spin_lock_irq(mlx4_tlock(dev)); 2695255932Salfred list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], 2696255932Salfred com.list) { 2697255932Salfred if (!check_mtt_range(dev, slave, start, len, mtt)) { 2698255932Salfred *res = mtt; 2699255932Salfred mtt->com.from_state = mtt->com.state; 2700255932Salfred mtt->com.state = RES_MTT_BUSY; 2701255932Salfred err = 0; 2702255932Salfred break; 2703255932Salfred } 2704255932Salfred } 2705255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 2706255932Salfred 2707255932Salfred return err; 2708255932Salfred} 2709255932Salfred 2710255932Salfredstatic int verify_qp_parameters(struct mlx4_dev *dev, 2711255932Salfred struct mlx4_cmd_mailbox *inbox, 2712255932Salfred enum qp_transition transition, u8 slave) 2713255932Salfred{ 2714255932Salfred u32 qp_type; 2715255932Salfred struct mlx4_qp_context *qp_ctx; 2716255932Salfred enum mlx4_qp_optpar optpar; 2717255932Salfred int port; 2718255932Salfred int num_gids; 2719255932Salfred 2720255932Salfred qp_ctx = inbox->buf + 8; 2721255932Salfred qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 2722255932Salfred optpar = be32_to_cpu(*(__be32 *) inbox->buf); 2723255932Salfred 2724255932Salfred switch (qp_type) { 2725255932Salfred case MLX4_QP_ST_RC: 2726255932Salfred case MLX4_QP_ST_UC: 2727255932Salfred switch (transition) { 2728255932Salfred case QP_TRANS_INIT2RTR: 2729255932Salfred case QP_TRANS_RTR2RTS: 2730255932Salfred case QP_TRANS_RTS2RTS: 2731255932Salfred case QP_TRANS_SQD2SQD: 2732255932Salfred case QP_TRANS_SQD2RTS: 2733255932Salfred if (slave != mlx4_master_func_num(dev)) 2734255932Salfred if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 2735255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 2736255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 2737255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 2738255932Salfred else 2739255932Salfred num_gids = 1; 2740255932Salfred if (qp_ctx->pri_path.mgid_index >= num_gids) 2741255932Salfred return -EINVAL; 2742255932Salfred } 2743255932Salfred if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 2744255932Salfred port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 2745255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 2746255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 2747255932Salfred else 2748255932Salfred num_gids = 1; 2749255932Salfred if (qp_ctx->alt_path.mgid_index >= num_gids) 2750255932Salfred return -EINVAL; 2751255932Salfred } 2752255932Salfred break; 2753255932Salfred default: 2754255932Salfred break; 2755255932Salfred } 2756255932Salfred 2757255932Salfred break; 2758255932Salfred default: 2759255932Salfred break; 2760255932Salfred } 2761255932Salfred 2762255932Salfred return 0; 2763255932Salfred} 2764255932Salfred 2765255932Salfredint mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, 2766255932Salfred struct mlx4_vhcr *vhcr, 2767255932Salfred struct mlx4_cmd_mailbox *inbox, 2768255932Salfred struct mlx4_cmd_mailbox *outbox, 2769255932Salfred struct mlx4_cmd_info *cmd) 2770255932Salfred{ 2771255932Salfred struct mlx4_mtt mtt; 2772255932Salfred __be64 *page_list = inbox->buf; 2773255932Salfred u64 *pg_list = (u64 *)page_list; 2774255932Salfred int i; 2775255932Salfred struct res_mtt *rmtt = NULL; 2776255932Salfred int start = be64_to_cpu(page_list[0]); 2777255932Salfred int npages = vhcr->in_modifier; 2778255932Salfred int err; 2779255932Salfred 2780255932Salfred err = get_containing_mtt(dev, slave, start, npages, &rmtt); 2781255932Salfred if (err) 2782255932Salfred return err; 2783255932Salfred 2784255932Salfred /* Call the SW implementation of write_mtt: 2785255932Salfred * - Prepare a dummy mtt struct 2786255932Salfred * - Translate inbox contents to simple addresses in host endianess */ 2787255932Salfred mtt.offset = 0; /* TBD this is broken but I don't handle it since 2788255932Salfred we don't really use it */ 2789255932Salfred mtt.order = 0; 2790255932Salfred mtt.page_shift = 0; 2791255932Salfred for (i = 0; i < npages; ++i) 2792255932Salfred pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); 2793255932Salfred 2794255932Salfred err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, 2795255932Salfred ((u64 *)page_list + 2)); 2796255932Salfred 2797255932Salfred if (rmtt) 2798255932Salfred put_res(dev, slave, rmtt->com.res_id, RES_MTT); 2799255932Salfred 2800255932Salfred return err; 2801255932Salfred} 2802255932Salfred 2803255932Salfredint mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, 2804255932Salfred struct mlx4_vhcr *vhcr, 2805255932Salfred struct mlx4_cmd_mailbox *inbox, 2806255932Salfred struct mlx4_cmd_mailbox *outbox, 2807255932Salfred struct mlx4_cmd_info *cmd) 2808255932Salfred{ 2809255932Salfred int eqn = vhcr->in_modifier; 2810255932Salfred int res_id = eqn | (slave << 8); 2811255932Salfred struct res_eq *eq; 2812255932Salfred int err; 2813255932Salfred 2814255932Salfred err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); 2815255932Salfred if (err) 2816255932Salfred return err; 2817255932Salfred 2818255932Salfred err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); 2819255932Salfred if (err) 2820255932Salfred goto ex_abort; 2821255932Salfred 2822255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2823255932Salfred if (err) 2824255932Salfred goto ex_put; 2825255932Salfred 2826255932Salfred atomic_dec(&eq->mtt->ref_count); 2827255932Salfred put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 2828255932Salfred res_end_move(dev, slave, RES_EQ, res_id); 2829255932Salfred rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2830255932Salfred 2831255932Salfred return 0; 2832255932Salfred 2833255932Salfredex_put: 2834255932Salfred put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 2835255932Salfredex_abort: 2836255932Salfred res_abort_move(dev, slave, RES_EQ, res_id); 2837255932Salfred 2838255932Salfred return err; 2839255932Salfred} 2840255932Salfred 2841255932Salfredint mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) 2842255932Salfred{ 2843255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2844255932Salfred struct mlx4_slave_event_eq_info *event_eq; 2845255932Salfred struct mlx4_cmd_mailbox *mailbox; 2846255932Salfred u32 in_modifier = 0; 2847255932Salfred int err; 2848255932Salfred int res_id; 2849255932Salfred struct res_eq *req; 2850255932Salfred 2851255932Salfred if (!priv->mfunc.master.slave_state) 2852255932Salfred return -EINVAL; 2853255932Salfred 2854255932Salfred event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; 2855255932Salfred 2856255932Salfred /* Create the event only if the slave is registered */ 2857255932Salfred if (event_eq->eqn < 0) 2858255932Salfred return 0; 2859255932Salfred 2860255932Salfred mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); 2861255932Salfred res_id = (slave << 8) | event_eq->eqn; 2862255932Salfred err = get_res(dev, slave, res_id, RES_EQ, &req); 2863255932Salfred if (err) 2864255932Salfred goto unlock; 2865255932Salfred 2866255932Salfred if (req->com.from_state != RES_EQ_HW) { 2867255932Salfred err = -EINVAL; 2868255932Salfred goto put; 2869255932Salfred } 2870255932Salfred 2871255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 2872255932Salfred if (IS_ERR(mailbox)) { 2873255932Salfred err = PTR_ERR(mailbox); 2874255932Salfred goto put; 2875255932Salfred } 2876255932Salfred 2877255932Salfred if (eqe->type == MLX4_EVENT_TYPE_CMD) { 2878255932Salfred ++event_eq->token; 2879255932Salfred eqe->event.cmd.token = cpu_to_be16(event_eq->token); 2880255932Salfred } 2881255932Salfred 2882255932Salfred memcpy(mailbox->buf, (u8 *) eqe, 28); 2883255932Salfred 2884255932Salfred in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); 2885255932Salfred 2886255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, 2887255932Salfred MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, 2888255932Salfred MLX4_CMD_NATIVE); 2889255932Salfred 2890255932Salfred put_res(dev, slave, res_id, RES_EQ); 2891255932Salfred mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 2892255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 2893255932Salfred return err; 2894255932Salfred 2895255932Salfredput: 2896255932Salfred put_res(dev, slave, res_id, RES_EQ); 2897255932Salfred 2898255932Salfredunlock: 2899255932Salfred mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 2900255932Salfred return err; 2901255932Salfred} 2902255932Salfred 2903255932Salfredint mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, 2904255932Salfred struct mlx4_vhcr *vhcr, 2905255932Salfred struct mlx4_cmd_mailbox *inbox, 2906255932Salfred struct mlx4_cmd_mailbox *outbox, 2907255932Salfred struct mlx4_cmd_info *cmd) 2908255932Salfred{ 2909255932Salfred int eqn = vhcr->in_modifier; 2910255932Salfred int res_id = eqn | (slave << 8); 2911255932Salfred struct res_eq *eq; 2912255932Salfred int err; 2913255932Salfred 2914255932Salfred err = get_res(dev, slave, res_id, RES_EQ, &eq); 2915255932Salfred if (err) 2916255932Salfred return err; 2917255932Salfred 2918255932Salfred if (eq->com.from_state != RES_EQ_HW) { 2919255932Salfred err = -EINVAL; 2920255932Salfred goto ex_put; 2921255932Salfred } 2922255932Salfred 2923255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2924255932Salfred 2925255932Salfredex_put: 2926255932Salfred put_res(dev, slave, res_id, RES_EQ); 2927255932Salfred return err; 2928255932Salfred} 2929255932Salfred 2930255932Salfredint mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, 2931255932Salfred struct mlx4_vhcr *vhcr, 2932255932Salfred struct mlx4_cmd_mailbox *inbox, 2933255932Salfred struct mlx4_cmd_mailbox *outbox, 2934255932Salfred struct mlx4_cmd_info *cmd) 2935255932Salfred{ 2936255932Salfred int err; 2937255932Salfred int cqn = vhcr->in_modifier; 2938255932Salfred struct mlx4_cq_context *cqc = inbox->buf; 2939255932Salfred int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 2940255932Salfred struct res_cq *cq; 2941255932Salfred struct res_mtt *mtt; 2942255932Salfred 2943255932Salfred err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); 2944255932Salfred if (err) 2945255932Salfred return err; 2946255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2947255932Salfred if (err) 2948255932Salfred goto out_move; 2949255932Salfred err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 2950255932Salfred if (err) 2951255932Salfred goto out_put; 2952255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2953255932Salfred if (err) 2954255932Salfred goto out_put; 2955255932Salfred atomic_inc(&mtt->ref_count); 2956255932Salfred cq->mtt = mtt; 2957255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2958255932Salfred res_end_move(dev, slave, RES_CQ, cqn); 2959255932Salfred return 0; 2960255932Salfred 2961255932Salfredout_put: 2962255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2963255932Salfredout_move: 2964255932Salfred res_abort_move(dev, slave, RES_CQ, cqn); 2965255932Salfred return err; 2966255932Salfred} 2967255932Salfred 2968255932Salfredint mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, 2969255932Salfred struct mlx4_vhcr *vhcr, 2970255932Salfred struct mlx4_cmd_mailbox *inbox, 2971255932Salfred struct mlx4_cmd_mailbox *outbox, 2972255932Salfred struct mlx4_cmd_info *cmd) 2973255932Salfred{ 2974255932Salfred int err; 2975255932Salfred int cqn = vhcr->in_modifier; 2976255932Salfred struct res_cq *cq; 2977255932Salfred 2978255932Salfred err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); 2979255932Salfred if (err) 2980255932Salfred return err; 2981255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2982255932Salfred if (err) 2983255932Salfred goto out_move; 2984255932Salfred atomic_dec(&cq->mtt->ref_count); 2985255932Salfred res_end_move(dev, slave, RES_CQ, cqn); 2986255932Salfred return 0; 2987255932Salfred 2988255932Salfredout_move: 2989255932Salfred res_abort_move(dev, slave, RES_CQ, cqn); 2990255932Salfred return err; 2991255932Salfred} 2992255932Salfred 2993255932Salfredint mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, 2994255932Salfred struct mlx4_vhcr *vhcr, 2995255932Salfred struct mlx4_cmd_mailbox *inbox, 2996255932Salfred struct mlx4_cmd_mailbox *outbox, 2997255932Salfred struct mlx4_cmd_info *cmd) 2998255932Salfred{ 2999255932Salfred int cqn = vhcr->in_modifier; 3000255932Salfred struct res_cq *cq; 3001255932Salfred int err; 3002255932Salfred 3003255932Salfred err = get_res(dev, slave, cqn, RES_CQ, &cq); 3004255932Salfred if (err) 3005255932Salfred return err; 3006255932Salfred 3007255932Salfred if (cq->com.from_state != RES_CQ_HW) 3008255932Salfred goto ex_put; 3009255932Salfred 3010255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3011255932Salfredex_put: 3012255932Salfred put_res(dev, slave, cqn, RES_CQ); 3013255932Salfred 3014255932Salfred return err; 3015255932Salfred} 3016255932Salfred 3017255932Salfredstatic int handle_resize(struct mlx4_dev *dev, int slave, 3018255932Salfred struct mlx4_vhcr *vhcr, 3019255932Salfred struct mlx4_cmd_mailbox *inbox, 3020255932Salfred struct mlx4_cmd_mailbox *outbox, 3021255932Salfred struct mlx4_cmd_info *cmd, 3022255932Salfred struct res_cq *cq) 3023255932Salfred{ 3024255932Salfred int err; 3025255932Salfred struct res_mtt *orig_mtt; 3026255932Salfred struct res_mtt *mtt; 3027255932Salfred struct mlx4_cq_context *cqc = inbox->buf; 3028255932Salfred int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 3029255932Salfred 3030255932Salfred err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); 3031255932Salfred if (err) 3032255932Salfred return err; 3033255932Salfred 3034255932Salfred if (orig_mtt != cq->mtt) { 3035255932Salfred err = -EINVAL; 3036255932Salfred goto ex_put; 3037255932Salfred } 3038255932Salfred 3039255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3040255932Salfred if (err) 3041255932Salfred goto ex_put; 3042255932Salfred 3043255932Salfred err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 3044255932Salfred if (err) 3045255932Salfred goto ex_put1; 3046255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3047255932Salfred if (err) 3048255932Salfred goto ex_put1; 3049255932Salfred atomic_dec(&orig_mtt->ref_count); 3050255932Salfred put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 3051255932Salfred atomic_inc(&mtt->ref_count); 3052255932Salfred cq->mtt = mtt; 3053255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3054255932Salfred return 0; 3055255932Salfred 3056255932Salfredex_put1: 3057255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3058255932Salfredex_put: 3059255932Salfred put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 3060255932Salfred 3061255932Salfred return err; 3062255932Salfred 3063255932Salfred} 3064255932Salfred 3065255932Salfredint mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, 3066255932Salfred struct mlx4_vhcr *vhcr, 3067255932Salfred struct mlx4_cmd_mailbox *inbox, 3068255932Salfred struct mlx4_cmd_mailbox *outbox, 3069255932Salfred struct mlx4_cmd_info *cmd) 3070255932Salfred{ 3071255932Salfred int cqn = vhcr->in_modifier; 3072255932Salfred struct res_cq *cq; 3073255932Salfred int err; 3074255932Salfred 3075255932Salfred err = get_res(dev, slave, cqn, RES_CQ, &cq); 3076255932Salfred if (err) 3077255932Salfred return err; 3078255932Salfred 3079255932Salfred if (cq->com.from_state != RES_CQ_HW) 3080255932Salfred goto ex_put; 3081255932Salfred 3082255932Salfred if (vhcr->op_modifier == 0) { 3083255932Salfred err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); 3084255932Salfred goto ex_put; 3085255932Salfred } 3086255932Salfred 3087255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3088255932Salfredex_put: 3089255932Salfred put_res(dev, slave, cqn, RES_CQ); 3090255932Salfred 3091255932Salfred return err; 3092255932Salfred} 3093255932Salfred 3094255932Salfredstatic int srq_get_mtt_size(struct mlx4_srq_context *srqc) 3095255932Salfred{ 3096255932Salfred int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; 3097255932Salfred int log_rq_stride = srqc->logstride & 7; 3098255932Salfred int page_shift = (srqc->log_page_size & 0x3f) + 12; 3099255932Salfred 3100255932Salfred if (log_srq_size + log_rq_stride + 4 < page_shift) 3101255932Salfred return 1; 3102255932Salfred 3103255932Salfred return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); 3104255932Salfred} 3105255932Salfred 3106255932Salfredint mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3107255932Salfred struct mlx4_vhcr *vhcr, 3108255932Salfred struct mlx4_cmd_mailbox *inbox, 3109255932Salfred struct mlx4_cmd_mailbox *outbox, 3110255932Salfred struct mlx4_cmd_info *cmd) 3111255932Salfred{ 3112255932Salfred int err; 3113255932Salfred int srqn = vhcr->in_modifier; 3114255932Salfred struct res_mtt *mtt; 3115255932Salfred struct res_srq *srq; 3116255932Salfred struct mlx4_srq_context *srqc = inbox->buf; 3117255932Salfred int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; 3118255932Salfred 3119255932Salfred if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) 3120255932Salfred return -EINVAL; 3121255932Salfred 3122255932Salfred err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); 3123255932Salfred if (err) 3124255932Salfred return err; 3125255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3126255932Salfred if (err) 3127255932Salfred goto ex_abort; 3128255932Salfred err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), 3129255932Salfred mtt); 3130255932Salfred if (err) 3131255932Salfred goto ex_put_mtt; 3132255932Salfred 3133255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3134255932Salfred if (err) 3135255932Salfred goto ex_put_mtt; 3136255932Salfred 3137255932Salfred atomic_inc(&mtt->ref_count); 3138255932Salfred srq->mtt = mtt; 3139255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3140255932Salfred res_end_move(dev, slave, RES_SRQ, srqn); 3141255932Salfred return 0; 3142255932Salfred 3143255932Salfredex_put_mtt: 3144255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3145255932Salfredex_abort: 3146255932Salfred res_abort_move(dev, slave, RES_SRQ, srqn); 3147255932Salfred 3148255932Salfred return err; 3149255932Salfred} 3150255932Salfred 3151255932Salfredint mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3152255932Salfred struct mlx4_vhcr *vhcr, 3153255932Salfred struct mlx4_cmd_mailbox *inbox, 3154255932Salfred struct mlx4_cmd_mailbox *outbox, 3155255932Salfred struct mlx4_cmd_info *cmd) 3156255932Salfred{ 3157255932Salfred int err; 3158255932Salfred int srqn = vhcr->in_modifier; 3159255932Salfred struct res_srq *srq; 3160255932Salfred 3161255932Salfred err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); 3162255932Salfred if (err) 3163255932Salfred return err; 3164255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3165255932Salfred if (err) 3166255932Salfred goto ex_abort; 3167255932Salfred atomic_dec(&srq->mtt->ref_count); 3168255932Salfred if (srq->cq) 3169255932Salfred atomic_dec(&srq->cq->ref_count); 3170255932Salfred res_end_move(dev, slave, RES_SRQ, srqn); 3171255932Salfred 3172255932Salfred return 0; 3173255932Salfred 3174255932Salfredex_abort: 3175255932Salfred res_abort_move(dev, slave, RES_SRQ, srqn); 3176255932Salfred 3177255932Salfred return err; 3178255932Salfred} 3179255932Salfred 3180255932Salfredint mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3181255932Salfred struct mlx4_vhcr *vhcr, 3182255932Salfred struct mlx4_cmd_mailbox *inbox, 3183255932Salfred struct mlx4_cmd_mailbox *outbox, 3184255932Salfred struct mlx4_cmd_info *cmd) 3185255932Salfred{ 3186255932Salfred int err; 3187255932Salfred int srqn = vhcr->in_modifier; 3188255932Salfred struct res_srq *srq; 3189255932Salfred 3190255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 3191255932Salfred if (err) 3192255932Salfred return err; 3193255932Salfred if (srq->com.from_state != RES_SRQ_HW) { 3194255932Salfred err = -EBUSY; 3195255932Salfred goto out; 3196255932Salfred } 3197255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3198255932Salfredout: 3199255932Salfred put_res(dev, slave, srqn, RES_SRQ); 3200255932Salfred return err; 3201255932Salfred} 3202255932Salfred 3203255932Salfredint mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3204255932Salfred struct mlx4_vhcr *vhcr, 3205255932Salfred struct mlx4_cmd_mailbox *inbox, 3206255932Salfred struct mlx4_cmd_mailbox *outbox, 3207255932Salfred struct mlx4_cmd_info *cmd) 3208255932Salfred{ 3209255932Salfred int err; 3210255932Salfred int srqn = vhcr->in_modifier; 3211255932Salfred struct res_srq *srq; 3212255932Salfred 3213255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 3214255932Salfred if (err) 3215255932Salfred return err; 3216255932Salfred 3217255932Salfred if (srq->com.from_state != RES_SRQ_HW) { 3218255932Salfred err = -EBUSY; 3219255932Salfred goto out; 3220255932Salfred } 3221255932Salfred 3222255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3223255932Salfredout: 3224255932Salfred put_res(dev, slave, srqn, RES_SRQ); 3225255932Salfred return err; 3226255932Salfred} 3227255932Salfred 3228255932Salfredint mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, 3229255932Salfred struct mlx4_vhcr *vhcr, 3230255932Salfred struct mlx4_cmd_mailbox *inbox, 3231255932Salfred struct mlx4_cmd_mailbox *outbox, 3232255932Salfred struct mlx4_cmd_info *cmd) 3233255932Salfred{ 3234255932Salfred int err; 3235255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 3236255932Salfred struct res_qp *qp; 3237255932Salfred 3238255932Salfred err = get_res(dev, slave, qpn, RES_QP, &qp); 3239255932Salfred if (err) 3240255932Salfred return err; 3241255932Salfred if (qp->com.from_state != RES_QP_HW) { 3242255932Salfred err = -EBUSY; 3243255932Salfred goto out; 3244255932Salfred } 3245255932Salfred 3246255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3247255932Salfredout: 3248255932Salfred put_res(dev, slave, qpn, RES_QP); 3249255932Salfred return err; 3250255932Salfred} 3251255932Salfred 3252255932Salfredint mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 3253255932Salfred struct mlx4_vhcr *vhcr, 3254255932Salfred struct mlx4_cmd_mailbox *inbox, 3255255932Salfred struct mlx4_cmd_mailbox *outbox, 3256255932Salfred struct mlx4_cmd_info *cmd) 3257255932Salfred{ 3258255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3259255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3260255932Salfred update_pkey_index(dev, slave, inbox); 3261255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3262255932Salfred} 3263255932Salfred 3264255932Salfredstatic int roce_verify_mac(struct mlx4_dev *dev, int slave, 3265255932Salfred struct mlx4_qp_context *qpc, 3266255932Salfred struct mlx4_cmd_mailbox *inbox) 3267255932Salfred{ 3268255932Salfred u64 mac; 3269255932Salfred int port; 3270255932Salfred u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 3271255932Salfred u8 sched = *(u8 *)(inbox->buf + 64); 3272255932Salfred u8 smac_ix; 3273255932Salfred 3274255932Salfred port = (sched >> 6 & 1) + 1; 3275255932Salfred if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { 3276255932Salfred smac_ix = qpc->pri_path.grh_mylmc & 0x7f; 3277255932Salfred if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) 3278255932Salfred return -ENOENT; 3279255932Salfred } 3280255932Salfred return 0; 3281255932Salfred} 3282255932Salfred 3283255932Salfredint mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, 3284255932Salfred struct mlx4_vhcr *vhcr, 3285255932Salfred struct mlx4_cmd_mailbox *inbox, 3286255932Salfred struct mlx4_cmd_mailbox *outbox, 3287255932Salfred struct mlx4_cmd_info *cmd) 3288255932Salfred{ 3289255932Salfred int err; 3290255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 3291255932Salfred 3292255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); 3293255932Salfred if (err) 3294255932Salfred return err; 3295255932Salfred 3296255932Salfred if (roce_verify_mac(dev, slave, qpc, inbox)) 3297255932Salfred return -EINVAL; 3298255932Salfred 3299255932Salfred update_pkey_index(dev, slave, inbox); 3300255932Salfred update_gid(dev, inbox, (u8)slave); 3301255932Salfred adjust_proxy_tun_qkey(dev, vhcr, qpc); 3302255932Salfred err = update_vport_qp_param(dev, inbox, slave); 3303255932Salfred if (err) 3304255932Salfred return err; 3305255932Salfred 3306255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3307255932Salfred} 3308255932Salfred 3309255932Salfredint mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3310255932Salfred struct mlx4_vhcr *vhcr, 3311255932Salfred struct mlx4_cmd_mailbox *inbox, 3312255932Salfred struct mlx4_cmd_mailbox *outbox, 3313255932Salfred struct mlx4_cmd_info *cmd) 3314255932Salfred{ 3315255932Salfred int err; 3316255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3317255932Salfred 3318255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave); 3319255932Salfred if (err) 3320255932Salfred return err; 3321255932Salfred 3322255932Salfred update_pkey_index(dev, slave, inbox); 3323255932Salfred update_gid(dev, inbox, (u8)slave); 3324255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3325255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3326255932Salfred} 3327255932Salfred 3328255932Salfredint mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3329255932Salfred struct mlx4_vhcr *vhcr, 3330255932Salfred struct mlx4_cmd_mailbox *inbox, 3331255932Salfred struct mlx4_cmd_mailbox *outbox, 3332255932Salfred struct mlx4_cmd_info *cmd) 3333255932Salfred{ 3334255932Salfred int err; 3335255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3336255932Salfred 3337255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave); 3338255932Salfred if (err) 3339255932Salfred return err; 3340255932Salfred 3341255932Salfred update_pkey_index(dev, slave, inbox); 3342255932Salfred update_gid(dev, inbox, (u8)slave); 3343255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3344255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3345255932Salfred} 3346255932Salfred 3347255932Salfred 3348255932Salfredint mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3349255932Salfred struct mlx4_vhcr *vhcr, 3350255932Salfred struct mlx4_cmd_mailbox *inbox, 3351255932Salfred struct mlx4_cmd_mailbox *outbox, 3352255932Salfred struct mlx4_cmd_info *cmd) 3353255932Salfred{ 3354255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3355255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3356255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3357255932Salfred} 3358255932Salfred 3359255932Salfredint mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, 3360255932Salfred struct mlx4_vhcr *vhcr, 3361255932Salfred struct mlx4_cmd_mailbox *inbox, 3362255932Salfred struct mlx4_cmd_mailbox *outbox, 3363255932Salfred struct mlx4_cmd_info *cmd) 3364255932Salfred{ 3365255932Salfred int err; 3366255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3367255932Salfred 3368255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave); 3369255932Salfred if (err) 3370255932Salfred return err; 3371255932Salfred 3372255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3373255932Salfred update_gid(dev, inbox, (u8)slave); 3374255932Salfred update_pkey_index(dev, slave, inbox); 3375255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3376255932Salfred} 3377255932Salfred 3378255932Salfredint mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3379255932Salfred struct mlx4_vhcr *vhcr, 3380255932Salfred struct mlx4_cmd_mailbox *inbox, 3381255932Salfred struct mlx4_cmd_mailbox *outbox, 3382255932Salfred struct mlx4_cmd_info *cmd) 3383255932Salfred{ 3384255932Salfred int err; 3385255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3386255932Salfred 3387255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave); 3388255932Salfred if (err) 3389255932Salfred return err; 3390255932Salfred 3391255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3392255932Salfred update_gid(dev, inbox, (u8)slave); 3393255932Salfred update_pkey_index(dev, slave, inbox); 3394255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3395255932Salfred} 3396255932Salfred 3397255932Salfredint mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, 3398255932Salfred struct mlx4_vhcr *vhcr, 3399255932Salfred struct mlx4_cmd_mailbox *inbox, 3400255932Salfred struct mlx4_cmd_mailbox *outbox, 3401255932Salfred struct mlx4_cmd_info *cmd) 3402255932Salfred{ 3403255932Salfred int err; 3404255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 3405255932Salfred struct res_qp *qp; 3406255932Salfred 3407255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); 3408255932Salfred if (err) 3409255932Salfred return err; 3410255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3411255932Salfred if (err) 3412255932Salfred goto ex_abort; 3413255932Salfred 3414255932Salfred atomic_dec(&qp->mtt->ref_count); 3415255932Salfred atomic_dec(&qp->rcq->ref_count); 3416255932Salfred atomic_dec(&qp->scq->ref_count); 3417255932Salfred if (qp->srq) 3418255932Salfred atomic_dec(&qp->srq->ref_count); 3419255932Salfred res_end_move(dev, slave, RES_QP, qpn); 3420255932Salfred return 0; 3421255932Salfred 3422255932Salfredex_abort: 3423255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 3424255932Salfred 3425255932Salfred return err; 3426255932Salfred} 3427255932Salfred 3428255932Salfredstatic struct res_gid *find_gid(struct mlx4_dev *dev, int slave, 3429255932Salfred struct res_qp *rqp, u8 *gid) 3430255932Salfred{ 3431255932Salfred struct res_gid *res; 3432255932Salfred 3433255932Salfred list_for_each_entry(res, &rqp->mcg_list, list) { 3434255932Salfred if (!memcmp(res->gid, gid, 16)) 3435255932Salfred return res; 3436255932Salfred } 3437255932Salfred return NULL; 3438255932Salfred} 3439255932Salfred 3440255932Salfredstatic int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 3441255932Salfred u8 *gid, enum mlx4_protocol prot, 3442255932Salfred enum mlx4_steer_type steer) 3443255932Salfred{ 3444255932Salfred struct res_gid *res; 3445255932Salfred int err; 3446255932Salfred 3447255932Salfred res = kzalloc(sizeof *res, GFP_KERNEL); 3448255932Salfred if (!res) 3449255932Salfred return -ENOMEM; 3450255932Salfred 3451255932Salfred spin_lock_irq(&rqp->mcg_spl); 3452255932Salfred if (find_gid(dev, slave, rqp, gid)) { 3453255932Salfred kfree(res); 3454255932Salfred err = -EEXIST; 3455255932Salfred } else { 3456255932Salfred memcpy(res->gid, gid, 16); 3457255932Salfred res->prot = prot; 3458255932Salfred res->steer = steer; 3459255932Salfred list_add_tail(&res->list, &rqp->mcg_list); 3460255932Salfred err = 0; 3461255932Salfred } 3462255932Salfred spin_unlock_irq(&rqp->mcg_spl); 3463255932Salfred 3464255932Salfred return err; 3465255932Salfred} 3466255932Salfred 3467255932Salfredstatic int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 3468255932Salfred u8 *gid, enum mlx4_protocol prot, 3469255932Salfred enum mlx4_steer_type steer) 3470255932Salfred{ 3471255932Salfred struct res_gid *res; 3472255932Salfred int err; 3473255932Salfred 3474255932Salfred spin_lock_irq(&rqp->mcg_spl); 3475255932Salfred res = find_gid(dev, slave, rqp, gid); 3476255932Salfred if (!res || res->prot != prot || res->steer != steer) 3477255932Salfred err = -EINVAL; 3478255932Salfred else { 3479255932Salfred list_del(&res->list); 3480255932Salfred kfree(res); 3481255932Salfred err = 0; 3482255932Salfred } 3483255932Salfred spin_unlock_irq(&rqp->mcg_spl); 3484255932Salfred 3485255932Salfred return err; 3486255932Salfred} 3487255932Salfred 3488255932Salfredint mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 3489255932Salfred struct mlx4_vhcr *vhcr, 3490255932Salfred struct mlx4_cmd_mailbox *inbox, 3491255932Salfred struct mlx4_cmd_mailbox *outbox, 3492255932Salfred struct mlx4_cmd_info *cmd) 3493255932Salfred{ 3494255932Salfred struct mlx4_qp qp; /* dummy for calling attach/detach */ 3495255932Salfred u8 *gid = inbox->buf; 3496255932Salfred enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; 3497255932Salfred int err; 3498255932Salfred int qpn; 3499255932Salfred struct res_qp *rqp; 3500255932Salfred int attach = vhcr->op_modifier; 3501255932Salfred int block_loopback = vhcr->in_modifier >> 31; 3502255932Salfred u8 steer_type_mask = 2; 3503255932Salfred enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; 3504255932Salfred 3505255932Salfred qpn = vhcr->in_modifier & 0xffffff; 3506255932Salfred err = get_res(dev, slave, qpn, RES_QP, &rqp); 3507255932Salfred if (err) 3508255932Salfred return err; 3509255932Salfred 3510255932Salfred qp.qpn = qpn; 3511255932Salfred if (attach) { 3512255932Salfred err = add_mcg_res(dev, slave, rqp, gid, prot, type); 3513255932Salfred if (err) 3514255932Salfred goto ex_put; 3515255932Salfred 3516255932Salfred err = mlx4_qp_attach_common(dev, &qp, gid, 3517255932Salfred block_loopback, prot, type); 3518255932Salfred if (err) 3519255932Salfred goto ex_rem; 3520255932Salfred } else { 3521255932Salfred err = rem_mcg_res(dev, slave, rqp, gid, prot, type); 3522255932Salfred if (err) 3523255932Salfred goto ex_put; 3524255932Salfred err = mlx4_qp_detach_common(dev, &qp, gid, prot, type); 3525255932Salfred } 3526255932Salfred 3527255932Salfred put_res(dev, slave, qpn, RES_QP); 3528255932Salfred return 0; 3529255932Salfred 3530255932Salfredex_rem: 3531255932Salfred /* ignore error return below, already in error */ 3532255932Salfred (void) rem_mcg_res(dev, slave, rqp, gid, prot, type); 3533255932Salfredex_put: 3534255932Salfred put_res(dev, slave, qpn, RES_QP); 3535255932Salfred 3536255932Salfred return err; 3537255932Salfred} 3538255932Salfred 3539255932Salfred/* 3540255932Salfred * MAC validation for Flow Steering rules. 3541255932Salfred * VF can attach rules only with a mac address which is assigned to it. 3542255932Salfred */ 3543255932Salfred 3544255932Salfredstatic int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, 3545255932Salfred struct list_head *rlist) 3546255932Salfred{ 3547255932Salfred struct mac_res *res, *tmp; 3548255932Salfred __be64 be_mac; 3549255932Salfred 3550255932Salfred /* make sure it isn't multicast or broadcast mac*/ 3551255932Salfred if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && 3552255932Salfred !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { 3553255932Salfred list_for_each_entry_safe(res, tmp, rlist, list) { 3554255932Salfred be_mac = cpu_to_be64(res->mac << 16); 3555255932Salfred if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN)) 3556255932Salfred return 0; 3557255932Salfred } 3558255932Salfred pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", 3559255932Salfred eth_header->eth.dst_mac, slave); 3560255932Salfred return -EINVAL; 3561255932Salfred } 3562255932Salfred return 0; 3563255932Salfred} 3564255932Salfred 3565255932Salfred/* 3566255932Salfred * In case of missing eth header, append eth header with a MAC address 3567255932Salfred * assigned to the VF. 3568255932Salfred */ 3569255932Salfredstatic int add_eth_header(struct mlx4_dev *dev, int slave, 3570255932Salfred struct mlx4_cmd_mailbox *inbox, 3571255932Salfred struct list_head *rlist, int header_id) 3572255932Salfred{ 3573255932Salfred struct mac_res *res, *tmp; 3574255932Salfred u8 port; 3575255932Salfred struct mlx4_net_trans_rule_hw_ctrl *ctrl; 3576255932Salfred struct mlx4_net_trans_rule_hw_eth *eth_header; 3577255932Salfred struct mlx4_net_trans_rule_hw_ipv4 *ip_header; 3578255932Salfred struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; 3579255932Salfred __be64 be_mac = 0; 3580255932Salfred __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); 3581255932Salfred 3582255932Salfred ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 3583255932Salfred port = ctrl->port; 3584255932Salfred eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); 3585255932Salfred 3586255932Salfred /* Clear a space in the inbox for eth header */ 3587255932Salfred switch (header_id) { 3588255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 3589255932Salfred ip_header = 3590255932Salfred (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); 3591255932Salfred memmove(ip_header, eth_header, 3592255932Salfred sizeof(*ip_header) + sizeof(*l4_header)); 3593255932Salfred break; 3594255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 3595255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 3596255932Salfred l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) 3597255932Salfred (eth_header + 1); 3598255932Salfred memmove(l4_header, eth_header, sizeof(*l4_header)); 3599255932Salfred break; 3600255932Salfred default: 3601255932Salfred return -EINVAL; 3602255932Salfred } 3603255932Salfred list_for_each_entry_safe(res, tmp, rlist, list) { 3604255932Salfred if (port == res->port) { 3605255932Salfred be_mac = cpu_to_be64(res->mac << 16); 3606255932Salfred break; 3607255932Salfred } 3608255932Salfred } 3609255932Salfred if (!be_mac) { 3610255932Salfred pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n", 3611255932Salfred port); 3612255932Salfred return -EINVAL; 3613255932Salfred } 3614255932Salfred 3615255932Salfred memset(eth_header, 0, sizeof(*eth_header)); 3616255932Salfred eth_header->size = sizeof(*eth_header) >> 2; 3617255932Salfred eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); 3618255932Salfred memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); 3619255932Salfred memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); 3620255932Salfred 3621255932Salfred return 0; 3622255932Salfred 3623255932Salfred} 3624255932Salfred 3625255932Salfredint mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 3626255932Salfred struct mlx4_vhcr *vhcr, 3627255932Salfred struct mlx4_cmd_mailbox *inbox, 3628255932Salfred struct mlx4_cmd_mailbox *outbox, 3629255932Salfred struct mlx4_cmd_info *cmd) 3630255932Salfred{ 3631255932Salfred 3632255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3633255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 3634255932Salfred struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; 3635255932Salfred int err; 3636255932Salfred struct mlx4_net_trans_rule_hw_ctrl *ctrl; 3637255932Salfred struct _rule_hw *rule_header; 3638255932Salfred int header_id; 3639255932Salfred 3640255932Salfred if (dev->caps.steering_mode != 3641255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 3642255932Salfred return -EOPNOTSUPP; 3643255932Salfred 3644255932Salfred ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 3645255932Salfred rule_header = (struct _rule_hw *)(ctrl + 1); 3646255932Salfred header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); 3647255932Salfred 3648255932Salfred switch (header_id) { 3649255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 3650255932Salfred if (validate_eth_header_mac(slave, rule_header, rlist)) 3651255932Salfred return -EINVAL; 3652255932Salfred break; 3653255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 3654255932Salfred break; 3655255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 3656255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 3657255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 3658255932Salfred pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n"); 3659255932Salfred if (add_eth_header(dev, slave, inbox, rlist, header_id)) 3660255932Salfred return -EINVAL; 3661255932Salfred vhcr->in_modifier += 3662255932Salfred sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; 3663255932Salfred break; 3664255932Salfred default: 3665255932Salfred pr_err("Corrupted mailbox.\n"); 3666255932Salfred return -EINVAL; 3667255932Salfred } 3668255932Salfred 3669255932Salfred err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, 3670255932Salfred vhcr->in_modifier, 0, 3671255932Salfred MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 3672255932Salfred MLX4_CMD_NATIVE); 3673255932Salfred if (err) 3674255932Salfred return err; 3675255932Salfred 3676255932Salfred err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0); 3677255932Salfred if (err) { 3678255932Salfred mlx4_err(dev, "Fail to add flow steering resources.\n "); 3679255932Salfred /* detach rule*/ 3680255932Salfred mlx4_cmd(dev, vhcr->out_param, 0, 0, 3681255932Salfred MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 3682255932Salfred MLX4_CMD_NATIVE); 3683255932Salfred } 3684255932Salfred return err; 3685255932Salfred} 3686255932Salfred 3687255932Salfredint mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, 3688255932Salfred struct mlx4_vhcr *vhcr, 3689255932Salfred struct mlx4_cmd_mailbox *inbox, 3690255932Salfred struct mlx4_cmd_mailbox *outbox, 3691255932Salfred struct mlx4_cmd_info *cmd) 3692255932Salfred{ 3693255932Salfred int err; 3694255932Salfred 3695255932Salfred if (dev->caps.steering_mode != 3696255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 3697255932Salfred return -EOPNOTSUPP; 3698255932Salfred 3699255932Salfred err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0); 3700255932Salfred if (err) { 3701255932Salfred mlx4_err(dev, "Fail to remove flow steering resources.\n "); 3702255932Salfred return err; 3703255932Salfred } 3704255932Salfred 3705255932Salfred err = mlx4_cmd(dev, vhcr->in_param, 0, 0, 3706255932Salfred MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 3707255932Salfred MLX4_CMD_NATIVE); 3708255932Salfred return err; 3709255932Salfred} 3710255932Salfred 3711255932Salfredenum { 3712255932Salfred BUSY_MAX_RETRIES = 10 3713255932Salfred}; 3714255932Salfred 3715255932Salfredint mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, 3716255932Salfred struct mlx4_vhcr *vhcr, 3717255932Salfred struct mlx4_cmd_mailbox *inbox, 3718255932Salfred struct mlx4_cmd_mailbox *outbox, 3719255932Salfred struct mlx4_cmd_info *cmd) 3720255932Salfred{ 3721255932Salfred int err; 3722255932Salfred int index = vhcr->in_modifier & 0xffff; 3723255932Salfred 3724255932Salfred err = get_res(dev, slave, index, RES_COUNTER, NULL); 3725255932Salfred if (err) 3726255932Salfred return err; 3727255932Salfred 3728255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3729255932Salfred put_res(dev, slave, index, RES_COUNTER); 3730255932Salfred return err; 3731255932Salfred} 3732255932Salfred 3733255932Salfredstatic void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) 3734255932Salfred{ 3735255932Salfred struct res_gid *rgid; 3736255932Salfred struct res_gid *tmp; 3737255932Salfred struct mlx4_qp qp; /* dummy for calling attach/detach */ 3738255932Salfred 3739255932Salfred list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { 3740255932Salfred qp.qpn = rqp->local_qpn; 3741255932Salfred (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, rgid->prot, 3742255932Salfred rgid->steer); 3743255932Salfred list_del(&rgid->list); 3744255932Salfred kfree(rgid); 3745255932Salfred } 3746255932Salfred} 3747255932Salfred 3748255932Salfredstatic int _move_all_busy(struct mlx4_dev *dev, int slave, 3749255932Salfred enum mlx4_resource type, int print) 3750255932Salfred{ 3751255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3752255932Salfred struct mlx4_resource_tracker *tracker = 3753255932Salfred &priv->mfunc.master.res_tracker; 3754255932Salfred struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; 3755255932Salfred struct res_common *r; 3756255932Salfred struct res_common *tmp; 3757255932Salfred int busy; 3758255932Salfred 3759255932Salfred busy = 0; 3760255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3761255932Salfred list_for_each_entry_safe(r, tmp, rlist, list) { 3762255932Salfred if (r->owner == slave) { 3763255932Salfred if (!r->removing) { 3764255932Salfred if (r->state == RES_ANY_BUSY) { 3765255932Salfred if (print) 3766255932Salfred mlx4_dbg(dev, 3767255932Salfred "%s id 0x%llx is busy\n", 3768255932Salfred ResourceType(type), 3769255932Salfred r->res_id); 3770255932Salfred ++busy; 3771255932Salfred } else { 3772255932Salfred r->from_state = r->state; 3773255932Salfred r->state = RES_ANY_BUSY; 3774255932Salfred r->removing = 1; 3775255932Salfred } 3776255932Salfred } 3777255932Salfred } 3778255932Salfred } 3779255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3780255932Salfred 3781255932Salfred return busy; 3782255932Salfred} 3783255932Salfred 3784255932Salfredstatic int move_all_busy(struct mlx4_dev *dev, int slave, 3785255932Salfred enum mlx4_resource type) 3786255932Salfred{ 3787255932Salfred unsigned long begin; 3788255932Salfred int busy; 3789255932Salfred 3790255932Salfred begin = jiffies; 3791255932Salfred do { 3792255932Salfred busy = _move_all_busy(dev, slave, type, 0); 3793255932Salfred if (time_after(jiffies, begin + 5 * HZ)) 3794255932Salfred break; 3795255932Salfred if (busy) 3796255932Salfred cond_resched(); 3797255932Salfred } while (busy); 3798255932Salfred 3799255932Salfred if (busy) 3800255932Salfred busy = _move_all_busy(dev, slave, type, 1); 3801255932Salfred 3802255932Salfred return busy; 3803255932Salfred} 3804255932Salfredstatic void rem_slave_qps(struct mlx4_dev *dev, int slave) 3805255932Salfred{ 3806255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3807255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 3808255932Salfred struct list_head *qp_list = 3809255932Salfred &tracker->slave_list[slave].res_list[RES_QP]; 3810255932Salfred struct res_qp *qp; 3811255932Salfred struct res_qp *tmp; 3812255932Salfred int state; 3813255932Salfred u64 in_param; 3814255932Salfred int qpn; 3815255932Salfred int err; 3816255932Salfred 3817255932Salfred err = move_all_busy(dev, slave, RES_QP); 3818255932Salfred if (err) 3819255932Salfred mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy" 3820255932Salfred "for slave %d\n", slave); 3821255932Salfred 3822255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3823255932Salfred list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 3824255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3825255932Salfred if (qp->com.owner == slave) { 3826255932Salfred qpn = qp->com.res_id; 3827255932Salfred detach_qp(dev, slave, qp); 3828255932Salfred state = qp->com.from_state; 3829255932Salfred while (state != 0) { 3830255932Salfred switch (state) { 3831255932Salfred case RES_QP_RESERVED: 3832255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3833255932Salfred rb_erase(&qp->com.node, 3834255932Salfred &tracker->res_tree[RES_QP]); 3835255932Salfred list_del(&qp->com.list); 3836255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3837255932Salfred kfree(qp); 3838255932Salfred state = 0; 3839255932Salfred break; 3840255932Salfred case RES_QP_MAPPED: 3841255932Salfred if (!valid_reserved(dev, slave, qpn)) 3842255932Salfred __mlx4_qp_free_icm(dev, qpn); 3843255932Salfred state = RES_QP_RESERVED; 3844255932Salfred break; 3845255932Salfred case RES_QP_HW: 3846255932Salfred in_param = slave; 3847255932Salfred err = mlx4_cmd(dev, in_param, 3848255932Salfred qp->local_qpn, 2, 3849255932Salfred MLX4_CMD_2RST_QP, 3850255932Salfred MLX4_CMD_TIME_CLASS_A, 3851255932Salfred MLX4_CMD_NATIVE); 3852255932Salfred if (err) 3853255932Salfred mlx4_dbg(dev, "rem_slave_qps: failed" 3854255932Salfred " to move slave %d qpn %d to" 3855255932Salfred " reset\n", slave, 3856255932Salfred qp->local_qpn); 3857255932Salfred atomic_dec(&qp->rcq->ref_count); 3858255932Salfred atomic_dec(&qp->scq->ref_count); 3859255932Salfred atomic_dec(&qp->mtt->ref_count); 3860255932Salfred if (qp->srq) 3861255932Salfred atomic_dec(&qp->srq->ref_count); 3862255932Salfred state = RES_QP_MAPPED; 3863255932Salfred break; 3864255932Salfred default: 3865255932Salfred state = 0; 3866255932Salfred } 3867255932Salfred } 3868255932Salfred } 3869255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3870255932Salfred } 3871255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3872255932Salfred} 3873255932Salfred 3874255932Salfredstatic void rem_slave_srqs(struct mlx4_dev *dev, int slave) 3875255932Salfred{ 3876255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3877255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 3878255932Salfred struct list_head *srq_list = 3879255932Salfred &tracker->slave_list[slave].res_list[RES_SRQ]; 3880255932Salfred struct res_srq *srq; 3881255932Salfred struct res_srq *tmp; 3882255932Salfred int state; 3883255932Salfred u64 in_param; 3884255932Salfred LIST_HEAD(tlist); 3885255932Salfred int srqn; 3886255932Salfred int err; 3887255932Salfred 3888255932Salfred err = move_all_busy(dev, slave, RES_SRQ); 3889255932Salfred if (err) 3890255932Salfred mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs to " 3891255932Salfred "busy for slave %d\n", slave); 3892255932Salfred 3893255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3894255932Salfred list_for_each_entry_safe(srq, tmp, srq_list, com.list) { 3895255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3896255932Salfred if (srq->com.owner == slave) { 3897255932Salfred srqn = srq->com.res_id; 3898255932Salfred state = srq->com.from_state; 3899255932Salfred while (state != 0) { 3900255932Salfred switch (state) { 3901255932Salfred case RES_SRQ_ALLOCATED: 3902255932Salfred __mlx4_srq_free_icm(dev, srqn); 3903255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3904255932Salfred rb_erase(&srq->com.node, 3905255932Salfred &tracker->res_tree[RES_SRQ]); 3906255932Salfred list_del(&srq->com.list); 3907255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3908255932Salfred kfree(srq); 3909255932Salfred state = 0; 3910255932Salfred break; 3911255932Salfred 3912255932Salfred case RES_SRQ_HW: 3913255932Salfred in_param = slave; 3914255932Salfred err = mlx4_cmd(dev, in_param, srqn, 1, 3915255932Salfred MLX4_CMD_HW2SW_SRQ, 3916255932Salfred MLX4_CMD_TIME_CLASS_A, 3917255932Salfred MLX4_CMD_NATIVE); 3918255932Salfred if (err) 3919255932Salfred mlx4_dbg(dev, "rem_slave_srqs: failed" 3920255932Salfred " to move slave %d srq %d to" 3921255932Salfred " SW ownership\n", 3922255932Salfred slave, srqn); 3923255932Salfred 3924255932Salfred atomic_dec(&srq->mtt->ref_count); 3925255932Salfred if (srq->cq) 3926255932Salfred atomic_dec(&srq->cq->ref_count); 3927255932Salfred state = RES_SRQ_ALLOCATED; 3928255932Salfred break; 3929255932Salfred 3930255932Salfred default: 3931255932Salfred state = 0; 3932255932Salfred } 3933255932Salfred } 3934255932Salfred } 3935255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3936255932Salfred } 3937255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3938255932Salfred} 3939255932Salfred 3940255932Salfredstatic void rem_slave_cqs(struct mlx4_dev *dev, int slave) 3941255932Salfred{ 3942255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3943255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 3944255932Salfred struct list_head *cq_list = 3945255932Salfred &tracker->slave_list[slave].res_list[RES_CQ]; 3946255932Salfred struct res_cq *cq; 3947255932Salfred struct res_cq *tmp; 3948255932Salfred int state; 3949255932Salfred u64 in_param; 3950255932Salfred LIST_HEAD(tlist); 3951255932Salfred int cqn; 3952255932Salfred int err; 3953255932Salfred 3954255932Salfred err = move_all_busy(dev, slave, RES_CQ); 3955255932Salfred if (err) 3956255932Salfred mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs to " 3957255932Salfred "busy for slave %d\n", slave); 3958255932Salfred 3959255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3960255932Salfred list_for_each_entry_safe(cq, tmp, cq_list, com.list) { 3961255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3962255932Salfred if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { 3963255932Salfred cqn = cq->com.res_id; 3964255932Salfred state = cq->com.from_state; 3965255932Salfred while (state != 0) { 3966255932Salfred switch (state) { 3967255932Salfred case RES_CQ_ALLOCATED: 3968255932Salfred __mlx4_cq_free_icm(dev, cqn); 3969255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3970255932Salfred rb_erase(&cq->com.node, 3971255932Salfred &tracker->res_tree[RES_CQ]); 3972255932Salfred list_del(&cq->com.list); 3973255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 3974255932Salfred kfree(cq); 3975255932Salfred state = 0; 3976255932Salfred break; 3977255932Salfred 3978255932Salfred case RES_CQ_HW: 3979255932Salfred in_param = slave; 3980255932Salfred err = mlx4_cmd(dev, in_param, cqn, 1, 3981255932Salfred MLX4_CMD_HW2SW_CQ, 3982255932Salfred MLX4_CMD_TIME_CLASS_A, 3983255932Salfred MLX4_CMD_NATIVE); 3984255932Salfred if (err) 3985255932Salfred mlx4_dbg(dev, "rem_slave_cqs: failed" 3986255932Salfred " to move slave %d cq %d to" 3987255932Salfred " SW ownership\n", 3988255932Salfred slave, cqn); 3989255932Salfred atomic_dec(&cq->mtt->ref_count); 3990255932Salfred state = RES_CQ_ALLOCATED; 3991255932Salfred break; 3992255932Salfred 3993255932Salfred default: 3994255932Salfred state = 0; 3995255932Salfred } 3996255932Salfred } 3997255932Salfred } 3998255932Salfred spin_lock_irq(mlx4_tlock(dev)); 3999255932Salfred } 4000255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4001255932Salfred} 4002255932Salfred 4003255932Salfredstatic void rem_slave_mrs(struct mlx4_dev *dev, int slave) 4004255932Salfred{ 4005255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4006255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4007255932Salfred struct list_head *mpt_list = 4008255932Salfred &tracker->slave_list[slave].res_list[RES_MPT]; 4009255932Salfred struct res_mpt *mpt; 4010255932Salfred struct res_mpt *tmp; 4011255932Salfred int state; 4012255932Salfred u64 in_param; 4013255932Salfred LIST_HEAD(tlist); 4014255932Salfred int mptn; 4015255932Salfred int err; 4016255932Salfred 4017255932Salfred err = move_all_busy(dev, slave, RES_MPT); 4018255932Salfred if (err) 4019255932Salfred mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts to " 4020255932Salfred "busy for slave %d\n", slave); 4021255932Salfred 4022255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4023255932Salfred list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { 4024255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4025255932Salfred if (mpt->com.owner == slave) { 4026255932Salfred mptn = mpt->com.res_id; 4027255932Salfred state = mpt->com.from_state; 4028255932Salfred while (state != 0) { 4029255932Salfred switch (state) { 4030255932Salfred case RES_MPT_RESERVED: 4031255932Salfred __mlx4_mr_release(dev, mpt->key); 4032255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4033255932Salfred rb_erase(&mpt->com.node, 4034255932Salfred &tracker->res_tree[RES_MPT]); 4035255932Salfred list_del(&mpt->com.list); 4036255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4037255932Salfred kfree(mpt); 4038255932Salfred state = 0; 4039255932Salfred break; 4040255932Salfred 4041255932Salfred case RES_MPT_MAPPED: 4042255932Salfred __mlx4_mr_free_icm(dev, mpt->key); 4043255932Salfred state = RES_MPT_RESERVED; 4044255932Salfred break; 4045255932Salfred 4046255932Salfred case RES_MPT_HW: 4047255932Salfred in_param = slave; 4048255932Salfred err = mlx4_cmd(dev, in_param, mptn, 0, 4049255932Salfred MLX4_CMD_HW2SW_MPT, 4050255932Salfred MLX4_CMD_TIME_CLASS_A, 4051255932Salfred MLX4_CMD_NATIVE); 4052255932Salfred if (err) 4053255932Salfred mlx4_dbg(dev, "rem_slave_mrs: failed" 4054255932Salfred " to move slave %d mpt %d to" 4055255932Salfred " SW ownership\n", 4056255932Salfred slave, mptn); 4057255932Salfred if (mpt->mtt) 4058255932Salfred atomic_dec(&mpt->mtt->ref_count); 4059255932Salfred state = RES_MPT_MAPPED; 4060255932Salfred break; 4061255932Salfred default: 4062255932Salfred state = 0; 4063255932Salfred } 4064255932Salfred } 4065255932Salfred } 4066255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4067255932Salfred } 4068255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4069255932Salfred} 4070255932Salfred 4071255932Salfredstatic void rem_slave_mtts(struct mlx4_dev *dev, int slave) 4072255932Salfred{ 4073255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4074255932Salfred struct mlx4_resource_tracker *tracker = 4075255932Salfred &priv->mfunc.master.res_tracker; 4076255932Salfred struct list_head *mtt_list = 4077255932Salfred &tracker->slave_list[slave].res_list[RES_MTT]; 4078255932Salfred struct res_mtt *mtt; 4079255932Salfred struct res_mtt *tmp; 4080255932Salfred int state; 4081255932Salfred LIST_HEAD(tlist); 4082255932Salfred int base; 4083255932Salfred int err; 4084255932Salfred 4085255932Salfred err = move_all_busy(dev, slave, RES_MTT); 4086255932Salfred if (err) 4087255932Salfred mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts to " 4088255932Salfred "busy for slave %d\n", slave); 4089255932Salfred 4090255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4091255932Salfred list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { 4092255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4093255932Salfred if (mtt->com.owner == slave) { 4094255932Salfred base = mtt->com.res_id; 4095255932Salfred state = mtt->com.from_state; 4096255932Salfred while (state != 0) { 4097255932Salfred switch (state) { 4098255932Salfred case RES_MTT_ALLOCATED: 4099255932Salfred __mlx4_free_mtt_range(dev, base, 4100255932Salfred mtt->order); 4101255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4102255932Salfred rb_erase(&mtt->com.node, 4103255932Salfred &tracker->res_tree[RES_MTT]); 4104255932Salfred list_del(&mtt->com.list); 4105255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4106255932Salfred kfree(mtt); 4107255932Salfred state = 0; 4108255932Salfred break; 4109255932Salfred 4110255932Salfred default: 4111255932Salfred state = 0; 4112255932Salfred } 4113255932Salfred } 4114255932Salfred } 4115255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4116255932Salfred } 4117255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4118255932Salfred} 4119255932Salfred 4120255932Salfredstatic void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) 4121255932Salfred{ 4122255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4123255932Salfred struct mlx4_resource_tracker *tracker = 4124255932Salfred &priv->mfunc.master.res_tracker; 4125255932Salfred struct list_head *fs_rule_list = 4126255932Salfred &tracker->slave_list[slave].res_list[RES_FS_RULE]; 4127255932Salfred struct res_fs_rule *fs_rule; 4128255932Salfred struct res_fs_rule *tmp; 4129255932Salfred int state; 4130255932Salfred u64 base; 4131255932Salfred int err; 4132255932Salfred 4133255932Salfred err = move_all_busy(dev, slave, RES_FS_RULE); 4134255932Salfred if (err) 4135255932Salfred mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", 4136255932Salfred slave); 4137255932Salfred 4138255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4139255932Salfred list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { 4140255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4141255932Salfred if (fs_rule->com.owner == slave) { 4142255932Salfred base = fs_rule->com.res_id; 4143255932Salfred state = fs_rule->com.from_state; 4144255932Salfred while (state != 0) { 4145255932Salfred switch (state) { 4146255932Salfred case RES_FS_RULE_ALLOCATED: 4147255932Salfred /* detach rule */ 4148255932Salfred err = mlx4_cmd(dev, base, 0, 0, 4149255932Salfred MLX4_QP_FLOW_STEERING_DETACH, 4150255932Salfred MLX4_CMD_TIME_CLASS_A, 4151255932Salfred MLX4_CMD_NATIVE); 4152255932Salfred 4153255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4154255932Salfred rb_erase(&fs_rule->com.node, 4155255932Salfred &tracker->res_tree[RES_FS_RULE]); 4156255932Salfred list_del(&fs_rule->com.list); 4157255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4158255932Salfred kfree(fs_rule); 4159255932Salfred state = 0; 4160255932Salfred break; 4161255932Salfred 4162255932Salfred default: 4163255932Salfred state = 0; 4164255932Salfred } 4165255932Salfred } 4166255932Salfred } 4167255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4168255932Salfred } 4169255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4170255932Salfred} 4171255932Salfred 4172255932Salfredstatic void rem_slave_eqs(struct mlx4_dev *dev, int slave) 4173255932Salfred{ 4174255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4175255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4176255932Salfred struct list_head *eq_list = 4177255932Salfred &tracker->slave_list[slave].res_list[RES_EQ]; 4178255932Salfred struct res_eq *eq; 4179255932Salfred struct res_eq *tmp; 4180255932Salfred int err; 4181255932Salfred int state; 4182255932Salfred LIST_HEAD(tlist); 4183255932Salfred int eqn; 4184255932Salfred struct mlx4_cmd_mailbox *mailbox; 4185255932Salfred 4186255932Salfred err = move_all_busy(dev, slave, RES_EQ); 4187255932Salfred if (err) 4188255932Salfred mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs to " 4189255932Salfred "busy for slave %d\n", slave); 4190255932Salfred 4191255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4192255932Salfred list_for_each_entry_safe(eq, tmp, eq_list, com.list) { 4193255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4194255932Salfred if (eq->com.owner == slave) { 4195255932Salfred eqn = eq->com.res_id; 4196255932Salfred state = eq->com.from_state; 4197255932Salfred while (state != 0) { 4198255932Salfred switch (state) { 4199255932Salfred case RES_EQ_RESERVED: 4200255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4201255932Salfred rb_erase(&eq->com.node, 4202255932Salfred &tracker->res_tree[RES_EQ]); 4203255932Salfred list_del(&eq->com.list); 4204255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4205255932Salfred kfree(eq); 4206255932Salfred state = 0; 4207255932Salfred break; 4208255932Salfred 4209255932Salfred case RES_EQ_HW: 4210255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 4211255932Salfred if (IS_ERR(mailbox)) { 4212255932Salfred cond_resched(); 4213255932Salfred continue; 4214255932Salfred } 4215255932Salfred err = mlx4_cmd_box(dev, slave, 0, 4216255932Salfred eqn & 0xff, 0, 4217255932Salfred MLX4_CMD_HW2SW_EQ, 4218255932Salfred MLX4_CMD_TIME_CLASS_A, 4219255932Salfred MLX4_CMD_NATIVE); 4220255932Salfred if (err) 4221255932Salfred mlx4_dbg(dev, "rem_slave_eqs: failed" 4222255932Salfred " to move slave %d eqs %d to" 4223255932Salfred " SW ownership\n", slave, eqn); 4224255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 4225255932Salfred atomic_dec(&eq->mtt->ref_count); 4226255932Salfred state = RES_EQ_RESERVED; 4227255932Salfred break; 4228255932Salfred 4229255932Salfred default: 4230255932Salfred state = 0; 4231255932Salfred } 4232255932Salfred } 4233255932Salfred } 4234255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4235255932Salfred } 4236255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4237255932Salfred} 4238255932Salfred 4239255932Salfredstatic void rem_slave_counters(struct mlx4_dev *dev, int slave) 4240255932Salfred{ 4241255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4242255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4243255932Salfred struct list_head *counter_list = 4244255932Salfred &tracker->slave_list[slave].res_list[RES_COUNTER]; 4245255932Salfred struct res_counter *counter; 4246255932Salfred struct res_counter *tmp; 4247255932Salfred int err; 4248255932Salfred int index; 4249255932Salfred 4250255932Salfred err = move_all_busy(dev, slave, RES_COUNTER); 4251255932Salfred if (err) 4252255932Salfred mlx4_warn(dev, "rem_slave_counters: Could not move all counters to " 4253255932Salfred "busy for slave %d\n", slave); 4254255932Salfred 4255255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4256255932Salfred list_for_each_entry_safe(counter, tmp, counter_list, com.list) { 4257255932Salfred if (counter->com.owner == slave) { 4258255932Salfred index = counter->com.res_id; 4259255932Salfred rb_erase(&counter->com.node, 4260255932Salfred &tracker->res_tree[RES_COUNTER]); 4261255932Salfred list_del(&counter->com.list); 4262255932Salfred kfree(counter); 4263255932Salfred __mlx4_counter_free(dev, index); 4264255932Salfred } 4265255932Salfred } 4266255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4267255932Salfred} 4268255932Salfred 4269255932Salfredstatic void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) 4270255932Salfred{ 4271255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4272255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4273255932Salfred struct list_head *xrcdn_list = 4274255932Salfred &tracker->slave_list[slave].res_list[RES_XRCD]; 4275255932Salfred struct res_xrcdn *xrcd; 4276255932Salfred struct res_xrcdn *tmp; 4277255932Salfred int err; 4278255932Salfred int xrcdn; 4279255932Salfred 4280255932Salfred err = move_all_busy(dev, slave, RES_XRCD); 4281255932Salfred if (err) 4282255932Salfred mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns to " 4283255932Salfred "busy for slave %d\n", slave); 4284255932Salfred 4285255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4286255932Salfred list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { 4287255932Salfred if (xrcd->com.owner == slave) { 4288255932Salfred xrcdn = xrcd->com.res_id; 4289255932Salfred rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); 4290255932Salfred list_del(&xrcd->com.list); 4291255932Salfred kfree(xrcd); 4292255932Salfred __mlx4_xrcd_free(dev, xrcdn); 4293255932Salfred } 4294255932Salfred } 4295255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4296255932Salfred} 4297255932Salfred 4298255932Salfredvoid mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) 4299255932Salfred{ 4300255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4301255932Salfred 4302255932Salfred mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 4303255932Salfred rem_slave_macs(dev, slave); 4304255932Salfred rem_slave_vlans(dev, slave); 4305255932Salfred rem_slave_qps(dev, slave); 4306255932Salfred rem_slave_srqs(dev, slave); 4307255932Salfred rem_slave_cqs(dev, slave); 4308255932Salfred rem_slave_mrs(dev, slave); 4309255932Salfred rem_slave_eqs(dev, slave); 4310255932Salfred rem_slave_mtts(dev, slave); 4311255932Salfred rem_slave_counters(dev, slave); 4312255932Salfred rem_slave_xrcdns(dev, slave); 4313255932Salfred rem_slave_fs_rule(dev, slave); 4314255932Salfred mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 4315255932Salfred} 4316