mlx4_resource_tracker.c revision 272060
1255932Salfred/* 2255932Salfred * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3272027Shselasky * Copyright (c) 2005, 2006, 2007, 2008, 2014 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> 45272027Shselasky#include <linux/etherdevice.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; 88272027Shselasky u64 reg_id; 89255932Salfred}; 90255932Salfred 91255932Salfredenum res_qp_states { 92255932Salfred RES_QP_BUSY = RES_ANY_BUSY, 93255932Salfred 94255932Salfred /* QP number was allocated */ 95255932Salfred RES_QP_RESERVED, 96255932Salfred 97255932Salfred /* ICM memory for QP context was mapped */ 98255932Salfred RES_QP_MAPPED, 99255932Salfred 100255932Salfred /* QP is in hw ownership */ 101255932Salfred RES_QP_HW 102255932Salfred}; 103255932Salfred 104255932Salfredstruct res_qp { 105255932Salfred struct res_common com; 106255932Salfred struct res_mtt *mtt; 107255932Salfred struct res_cq *rcq; 108255932Salfred struct res_cq *scq; 109255932Salfred struct res_srq *srq; 110255932Salfred struct list_head mcg_list; 111255932Salfred spinlock_t mcg_spl; 112255932Salfred int local_qpn; 113272027Shselasky atomic_t ref_count; 114272027Shselasky u32 qpc_flags; 115272027Shselasky /* saved qp params before VST enforcement in order to restore on VGT */ 116272027Shselasky u8 sched_queue; 117272027Shselasky __be32 param3; 118272027Shselasky u8 vlan_control; 119272027Shselasky u8 fvl_rx; 120272027Shselasky u8 pri_path_fl; 121272027Shselasky u8 vlan_index; 122272027Shselasky u8 feup; 123255932Salfred}; 124255932Salfred 125255932Salfredenum res_mtt_states { 126255932Salfred RES_MTT_BUSY = RES_ANY_BUSY, 127255932Salfred RES_MTT_ALLOCATED, 128255932Salfred}; 129255932Salfred 130255932Salfredstatic inline const char *mtt_states_str(enum res_mtt_states state) 131255932Salfred{ 132255932Salfred switch (state) { 133255932Salfred case RES_MTT_BUSY: return "RES_MTT_BUSY"; 134255932Salfred case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED"; 135255932Salfred default: return "Unknown"; 136255932Salfred } 137255932Salfred} 138255932Salfred 139255932Salfredstruct res_mtt { 140255932Salfred struct res_common com; 141255932Salfred int order; 142255932Salfred atomic_t ref_count; 143255932Salfred}; 144255932Salfred 145255932Salfredenum res_mpt_states { 146255932Salfred RES_MPT_BUSY = RES_ANY_BUSY, 147255932Salfred RES_MPT_RESERVED, 148255932Salfred RES_MPT_MAPPED, 149255932Salfred RES_MPT_HW, 150255932Salfred}; 151255932Salfred 152255932Salfredstruct res_mpt { 153255932Salfred struct res_common com; 154255932Salfred struct res_mtt *mtt; 155255932Salfred int key; 156255932Salfred}; 157255932Salfred 158255932Salfredenum res_eq_states { 159255932Salfred RES_EQ_BUSY = RES_ANY_BUSY, 160255932Salfred RES_EQ_RESERVED, 161255932Salfred RES_EQ_HW, 162255932Salfred}; 163255932Salfred 164255932Salfredstruct res_eq { 165255932Salfred struct res_common com; 166255932Salfred struct res_mtt *mtt; 167255932Salfred}; 168255932Salfred 169255932Salfredenum res_cq_states { 170255932Salfred RES_CQ_BUSY = RES_ANY_BUSY, 171255932Salfred RES_CQ_ALLOCATED, 172255932Salfred RES_CQ_HW, 173255932Salfred}; 174255932Salfred 175255932Salfredstruct res_cq { 176255932Salfred struct res_common com; 177255932Salfred struct res_mtt *mtt; 178255932Salfred atomic_t ref_count; 179255932Salfred}; 180255932Salfred 181255932Salfredenum res_srq_states { 182255932Salfred RES_SRQ_BUSY = RES_ANY_BUSY, 183255932Salfred RES_SRQ_ALLOCATED, 184255932Salfred RES_SRQ_HW, 185255932Salfred}; 186255932Salfred 187255932Salfredstruct res_srq { 188255932Salfred struct res_common com; 189255932Salfred struct res_mtt *mtt; 190255932Salfred struct res_cq *cq; 191255932Salfred atomic_t ref_count; 192255932Salfred}; 193255932Salfred 194255932Salfredenum res_counter_states { 195255932Salfred RES_COUNTER_BUSY = RES_ANY_BUSY, 196255932Salfred RES_COUNTER_ALLOCATED, 197255932Salfred}; 198255932Salfred 199255932Salfredstruct res_counter { 200255932Salfred struct res_common com; 201255932Salfred int port; 202255932Salfred}; 203255932Salfred 204255932Salfredenum res_xrcdn_states { 205255932Salfred RES_XRCD_BUSY = RES_ANY_BUSY, 206255932Salfred RES_XRCD_ALLOCATED, 207255932Salfred}; 208255932Salfred 209255932Salfredstruct res_xrcdn { 210255932Salfred struct res_common com; 211255932Salfred int port; 212255932Salfred}; 213255932Salfred 214255932Salfredenum res_fs_rule_states { 215255932Salfred RES_FS_RULE_BUSY = RES_ANY_BUSY, 216255932Salfred RES_FS_RULE_ALLOCATED, 217255932Salfred}; 218255932Salfred 219255932Salfredstruct res_fs_rule { 220255932Salfred struct res_common com; 221272027Shselasky int qpn; 222255932Salfred}; 223255932Salfred 224255932Salfredstatic int mlx4_is_eth(struct mlx4_dev *dev, int port) 225255932Salfred{ 226255932Salfred return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; 227255932Salfred} 228255932Salfred 229255932Salfredstatic void *res_tracker_lookup(struct rb_root *root, u64 res_id) 230255932Salfred{ 231255932Salfred struct rb_node *node = root->rb_node; 232255932Salfred 233255932Salfred while (node) { 234255932Salfred struct res_common *res = container_of(node, struct res_common, 235255932Salfred node); 236255932Salfred 237255932Salfred if (res_id < res->res_id) 238255932Salfred node = node->rb_left; 239255932Salfred else if (res_id > res->res_id) 240255932Salfred node = node->rb_right; 241255932Salfred else 242255932Salfred return res; 243255932Salfred } 244255932Salfred return NULL; 245255932Salfred} 246255932Salfred 247255932Salfredstatic int res_tracker_insert(struct rb_root *root, struct res_common *res) 248255932Salfred{ 249255932Salfred struct rb_node **new = &(root->rb_node), *parent = NULL; 250255932Salfred 251255932Salfred /* Figure out where to put new node */ 252255932Salfred while (*new) { 253255932Salfred struct res_common *this = container_of(*new, struct res_common, 254255932Salfred node); 255255932Salfred 256255932Salfred parent = *new; 257255932Salfred if (res->res_id < this->res_id) 258255932Salfred new = &((*new)->rb_left); 259255932Salfred else if (res->res_id > this->res_id) 260255932Salfred new = &((*new)->rb_right); 261255932Salfred else 262255932Salfred return -EEXIST; 263255932Salfred } 264255932Salfred 265255932Salfred /* Add new node and rebalance tree. */ 266255932Salfred rb_link_node(&res->node, parent, new); 267255932Salfred rb_insert_color(&res->node, root); 268255932Salfred 269255932Salfred return 0; 270255932Salfred} 271255932Salfred 272255932Salfredenum qp_transition { 273255932Salfred QP_TRANS_INIT2RTR, 274255932Salfred QP_TRANS_RTR2RTS, 275255932Salfred QP_TRANS_RTS2RTS, 276255932Salfred QP_TRANS_SQERR2RTS, 277255932Salfred QP_TRANS_SQD2SQD, 278255932Salfred QP_TRANS_SQD2RTS 279255932Salfred}; 280255932Salfred 281255932Salfred/* For Debug uses */ 282255932Salfredstatic const char *ResourceType(enum mlx4_resource rt) 283255932Salfred{ 284255932Salfred switch (rt) { 285255932Salfred case RES_QP: return "RES_QP"; 286255932Salfred case RES_CQ: return "RES_CQ"; 287255932Salfred case RES_SRQ: return "RES_SRQ"; 288255932Salfred case RES_MPT: return "RES_MPT"; 289255932Salfred case RES_MTT: return "RES_MTT"; 290255932Salfred case RES_MAC: return "RES_MAC"; 291255932Salfred case RES_VLAN: return "RES_VLAN"; 292255932Salfred case RES_EQ: return "RES_EQ"; 293255932Salfred case RES_COUNTER: return "RES_COUNTER"; 294255932Salfred case RES_FS_RULE: return "RES_FS_RULE"; 295255932Salfred case RES_XRCD: return "RES_XRCD"; 296255932Salfred default: return "Unknown resource type !!!"; 297255932Salfred }; 298255932Salfred} 299255932Salfred 300255932Salfredstatic void rem_slave_vlans(struct mlx4_dev *dev, int slave); 301255932Salfredstatic inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, 302255932Salfred enum mlx4_resource res_type, int count, 303255932Salfred int port) 304255932Salfred{ 305255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 306255932Salfred struct resource_allocator *res_alloc = 307255932Salfred &priv->mfunc.master.res_tracker.res_alloc[res_type]; 308255932Salfred int err = -EINVAL; 309255932Salfred int allocated, free, reserved, guaranteed, from_free; 310255932Salfred 311255932Salfred spin_lock(&res_alloc->alloc_lock); 312255932Salfred allocated = (port > 0) ? 313255932Salfred res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : 314255932Salfred res_alloc->allocated[slave]; 315255932Salfred free = (port > 0) ? res_alloc->res_port_free[port - 1] : 316255932Salfred res_alloc->res_free; 317255932Salfred reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] : 318255932Salfred res_alloc->res_reserved; 319255932Salfred guaranteed = res_alloc->guaranteed[slave]; 320255932Salfred 321255932Salfred if (allocated + count > res_alloc->quota[slave]) 322255932Salfred goto out; 323255932Salfred 324255932Salfred if (allocated + count <= guaranteed) { 325255932Salfred err = 0; 326255932Salfred } else { 327255932Salfred /* portion may need to be obtained from free area */ 328255932Salfred if (guaranteed - allocated > 0) 329255932Salfred from_free = count - (guaranteed - allocated); 330255932Salfred else 331255932Salfred from_free = count; 332255932Salfred 333255932Salfred if (free - from_free > reserved) 334255932Salfred err = 0; 335255932Salfred } 336255932Salfred 337255932Salfred if (!err) { 338255932Salfred /* grant the request */ 339255932Salfred if (port > 0) { 340255932Salfred res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count; 341255932Salfred res_alloc->res_port_free[port - 1] -= count; 342255932Salfred } else { 343255932Salfred res_alloc->allocated[slave] += count; 344255932Salfred res_alloc->res_free -= count; 345255932Salfred } 346255932Salfred } 347255932Salfred 348255932Salfredout: 349255932Salfred spin_unlock(&res_alloc->alloc_lock); 350255932Salfred return err; 351255932Salfred 352255932Salfred} 353255932Salfred 354255932Salfredstatic inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, 355255932Salfred enum mlx4_resource res_type, int count, 356255932Salfred int port) 357255932Salfred{ 358255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 359255932Salfred struct resource_allocator *res_alloc = 360255932Salfred &priv->mfunc.master.res_tracker.res_alloc[res_type]; 361255932Salfred 362255932Salfred spin_lock(&res_alloc->alloc_lock); 363255932Salfred if (port > 0) { 364255932Salfred res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count; 365255932Salfred res_alloc->res_port_free[port - 1] += count; 366255932Salfred } else { 367255932Salfred res_alloc->allocated[slave] -= count; 368255932Salfred res_alloc->res_free += count; 369255932Salfred } 370255932Salfred 371255932Salfred spin_unlock(&res_alloc->alloc_lock); 372255932Salfred return; 373255932Salfred} 374255932Salfred 375255932Salfredstatic inline void initialize_res_quotas(struct mlx4_dev *dev, 376255932Salfred struct resource_allocator *res_alloc, 377255932Salfred enum mlx4_resource res_type, 378255932Salfred int vf, int num_instances) 379255932Salfred{ 380255932Salfred res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1)); 381255932Salfred res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; 382255932Salfred if (vf == mlx4_master_func_num(dev)) { 383255932Salfred res_alloc->res_free = num_instances; 384255932Salfred if (res_type == RES_MTT) { 385255932Salfred /* reserved mtts will be taken out of the PF allocation */ 386255932Salfred res_alloc->res_free += dev->caps.reserved_mtts; 387255932Salfred res_alloc->guaranteed[vf] += dev->caps.reserved_mtts; 388255932Salfred res_alloc->quota[vf] += dev->caps.reserved_mtts; 389255932Salfred } 390255932Salfred } 391255932Salfred} 392255932Salfred 393255932Salfredvoid mlx4_init_quotas(struct mlx4_dev *dev) 394255932Salfred{ 395255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 396255932Salfred int pf; 397255932Salfred 398255932Salfred /* quotas for VFs are initialized in mlx4_slave_cap */ 399255932Salfred if (mlx4_is_slave(dev)) 400255932Salfred return; 401255932Salfred 402255932Salfred if (!mlx4_is_mfunc(dev)) { 403255932Salfred dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps - 404255932Salfred mlx4_num_reserved_sqps(dev); 405255932Salfred dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs; 406255932Salfred dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs; 407255932Salfred dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts; 408255932Salfred dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws; 409255932Salfred return; 410255932Salfred } 411255932Salfred 412255932Salfred pf = mlx4_master_func_num(dev); 413255932Salfred dev->quotas.qp = 414255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf]; 415255932Salfred dev->quotas.cq = 416255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf]; 417255932Salfred dev->quotas.srq = 418255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf]; 419255932Salfred dev->quotas.mtt = 420255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf]; 421255932Salfred dev->quotas.mpt = 422255932Salfred priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; 423255932Salfred} 424255932Salfredint mlx4_init_resource_tracker(struct mlx4_dev *dev) 425255932Salfred{ 426255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 427255932Salfred int i, j; 428255932Salfred int t; 429255932Salfred 430255932Salfred priv->mfunc.master.res_tracker.slave_list = 431255932Salfred kzalloc(dev->num_slaves * sizeof(struct slave_list), 432255932Salfred GFP_KERNEL); 433255932Salfred if (!priv->mfunc.master.res_tracker.slave_list) 434255932Salfred return -ENOMEM; 435255932Salfred 436255932Salfred for (i = 0 ; i < dev->num_slaves; i++) { 437255932Salfred for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t) 438255932Salfred INIT_LIST_HEAD(&priv->mfunc.master.res_tracker. 439255932Salfred slave_list[i].res_list[t]); 440255932Salfred mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 441255932Salfred } 442255932Salfred 443255932Salfred mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n", 444255932Salfred dev->num_slaves); 445255932Salfred for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) 446255932Salfred priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT; 447255932Salfred 448255932Salfred for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 449255932Salfred struct resource_allocator *res_alloc = 450255932Salfred &priv->mfunc.master.res_tracker.res_alloc[i]; 451255932Salfred res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); 452255932Salfred res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); 453255932Salfred if (i == RES_MAC || i == RES_VLAN) 454255932Salfred res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * 455255932Salfred (dev->num_vfs + 1) * sizeof(int), 456255932Salfred GFP_KERNEL); 457255932Salfred else 458255932Salfred res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); 459255932Salfred 460255932Salfred if (!res_alloc->quota || !res_alloc->guaranteed || 461255932Salfred !res_alloc->allocated) 462255932Salfred goto no_mem_err; 463255932Salfred 464255932Salfred spin_lock_init(&res_alloc->alloc_lock); 465255932Salfred for (t = 0; t < dev->num_vfs + 1; t++) { 466255932Salfred switch (i) { 467255932Salfred case RES_QP: 468255932Salfred initialize_res_quotas(dev, res_alloc, RES_QP, 469255932Salfred t, dev->caps.num_qps - 470255932Salfred dev->caps.reserved_qps - 471255932Salfred mlx4_num_reserved_sqps(dev)); 472255932Salfred break; 473255932Salfred case RES_CQ: 474255932Salfred initialize_res_quotas(dev, res_alloc, RES_CQ, 475255932Salfred t, dev->caps.num_cqs - 476255932Salfred dev->caps.reserved_cqs); 477255932Salfred break; 478255932Salfred case RES_SRQ: 479255932Salfred initialize_res_quotas(dev, res_alloc, RES_SRQ, 480255932Salfred t, dev->caps.num_srqs - 481255932Salfred dev->caps.reserved_srqs); 482255932Salfred break; 483255932Salfred case RES_MPT: 484255932Salfred initialize_res_quotas(dev, res_alloc, RES_MPT, 485255932Salfred t, dev->caps.num_mpts - 486255932Salfred dev->caps.reserved_mrws); 487255932Salfred break; 488255932Salfred case RES_MTT: 489255932Salfred initialize_res_quotas(dev, res_alloc, RES_MTT, 490255932Salfred t, dev->caps.num_mtts - 491255932Salfred dev->caps.reserved_mtts); 492255932Salfred break; 493255932Salfred case RES_MAC: 494255932Salfred if (t == mlx4_master_func_num(dev)) { 495255932Salfred res_alloc->quota[t] = 496255932Salfred MLX4_MAX_MAC_NUM - 2 * dev->num_vfs; 497255932Salfred res_alloc->guaranteed[t] = res_alloc->quota[t]; 498255932Salfred for (j = 0; j < MLX4_MAX_PORTS; j++) 499255932Salfred res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM; 500255932Salfred } else { 501255932Salfred res_alloc->quota[t] = 2; 502255932Salfred res_alloc->guaranteed[t] = 2; 503255932Salfred } 504255932Salfred break; 505255932Salfred case RES_VLAN: 506255932Salfred if (t == mlx4_master_func_num(dev)) { 507255932Salfred res_alloc->quota[t] = MLX4_MAX_VLAN_NUM; 508255932Salfred res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2; 509255932Salfred for (j = 0; j < MLX4_MAX_PORTS; j++) 510255932Salfred res_alloc->res_port_free[j] = 511255932Salfred res_alloc->quota[t]; 512255932Salfred } else { 513255932Salfred res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2; 514255932Salfred res_alloc->guaranteed[t] = 0; 515255932Salfred } 516255932Salfred break; 517255932Salfred case RES_COUNTER: 518255932Salfred res_alloc->quota[t] = dev->caps.max_counters; 519255932Salfred res_alloc->guaranteed[t] = 0; 520255932Salfred if (t == mlx4_master_func_num(dev)) 521255932Salfred res_alloc->res_free = res_alloc->quota[t]; 522255932Salfred break; 523255932Salfred default: 524255932Salfred break; 525255932Salfred } 526255932Salfred if (i == RES_MAC || i == RES_VLAN) { 527255932Salfred for (j = 0; j < MLX4_MAX_PORTS; j++) 528255932Salfred res_alloc->res_port_rsvd[j] += 529255932Salfred res_alloc->guaranteed[t]; 530255932Salfred } else { 531255932Salfred res_alloc->res_reserved += res_alloc->guaranteed[t]; 532255932Salfred } 533255932Salfred } 534255932Salfred } 535255932Salfred spin_lock_init(&priv->mfunc.master.res_tracker.lock); 536255932Salfred return 0; 537255932Salfred 538255932Salfredno_mem_err: 539255932Salfred for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 540255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 541255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 542255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 543255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 544255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 545255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 546255932Salfred } 547255932Salfred return -ENOMEM; 548255932Salfred} 549255932Salfred 550255932Salfredvoid mlx4_free_resource_tracker(struct mlx4_dev *dev, 551255932Salfred enum mlx4_res_tracker_free_type type) 552255932Salfred{ 553255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 554255932Salfred int i; 555255932Salfred 556255932Salfred if (priv->mfunc.master.res_tracker.slave_list) { 557255932Salfred if (type != RES_TR_FREE_STRUCTS_ONLY) { 558255932Salfred for (i = 0; i < dev->num_slaves; i++) { 559255932Salfred if (type == RES_TR_FREE_ALL || 560255932Salfred dev->caps.function != i) 561255932Salfred mlx4_delete_all_resources_for_slave(dev, i); 562255932Salfred } 563255932Salfred /* free master's vlans */ 564255932Salfred i = dev->caps.function; 565255932Salfred mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 566255932Salfred rem_slave_vlans(dev, i); 567255932Salfred mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); 568255932Salfred } 569255932Salfred 570255932Salfred if (type != RES_TR_FREE_SLAVES_ONLY) { 571255932Salfred for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { 572255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); 573255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; 574255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); 575255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; 576255932Salfred kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); 577255932Salfred priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; 578255932Salfred } 579255932Salfred kfree(priv->mfunc.master.res_tracker.slave_list); 580255932Salfred priv->mfunc.master.res_tracker.slave_list = NULL; 581255932Salfred } 582255932Salfred } 583255932Salfred} 584255932Salfred 585255932Salfredstatic void update_pkey_index(struct mlx4_dev *dev, int slave, 586255932Salfred struct mlx4_cmd_mailbox *inbox) 587255932Salfred{ 588255932Salfred u8 sched = *(u8 *)(inbox->buf + 64); 589255932Salfred u8 orig_index = *(u8 *)(inbox->buf + 35); 590255932Salfred u8 new_index; 591255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 592255932Salfred int port; 593255932Salfred 594255932Salfred port = (sched >> 6 & 1) + 1; 595255932Salfred 596255932Salfred new_index = priv->virt2phys_pkey[slave][port - 1][orig_index]; 597255932Salfred *(u8 *)(inbox->buf + 35) = new_index; 598255932Salfred} 599255932Salfred 600255932Salfredstatic void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, 601255932Salfred u8 slave) 602255932Salfred{ 603255932Salfred struct mlx4_qp_context *qp_ctx = inbox->buf + 8; 604255932Salfred enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); 605255932Salfred u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 606255932Salfred int port; 607255932Salfred 608255932Salfred if (MLX4_QP_ST_UD == ts) { 609255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 610255932Salfred if (mlx4_is_eth(dev, port)) 611255932Salfred qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80; 612255932Salfred else 613255932Salfred qp_ctx->pri_path.mgid_index = 0x80 | slave; 614255932Salfred 615255932Salfred } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) { 616255932Salfred if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 617255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 618255932Salfred if (mlx4_is_eth(dev, port)) { 619255932Salfred qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); 620255932Salfred qp_ctx->pri_path.mgid_index &= 0x7f; 621255932Salfred } else { 622255932Salfred qp_ctx->pri_path.mgid_index = slave & 0x7F; 623255932Salfred } 624255932Salfred } 625255932Salfred if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 626255932Salfred port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 627255932Salfred if (mlx4_is_eth(dev, port)) { 628255932Salfred qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); 629255932Salfred qp_ctx->alt_path.mgid_index &= 0x7f; 630255932Salfred } else { 631255932Salfred qp_ctx->alt_path.mgid_index = slave & 0x7F; 632255932Salfred } 633255932Salfred } 634255932Salfred } 635255932Salfred} 636255932Salfred 637272027Shselaskystatic int check_counter_index_validity(struct mlx4_dev *dev, int slave, int port, int idx) 638272027Shselasky{ 639272027Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 640272027Shselasky struct counter_index *counter, *tmp_counter; 641272027Shselasky 642272027Shselasky if (slave == 0) { 643272027Shselasky list_for_each_entry_safe(counter, tmp_counter, 644272027Shselasky &priv->counters_table.global_port_list[port - 1], 645272027Shselasky list) { 646272027Shselasky if (counter->index == idx) 647272027Shselasky return 0; 648272027Shselasky } 649272027Shselasky return -EINVAL; 650272027Shselasky } else { 651272027Shselasky list_for_each_entry_safe(counter, tmp_counter, 652272027Shselasky &priv->counters_table.vf_list[slave - 1][port - 1], 653272027Shselasky list) { 654272027Shselasky if (counter->index == idx) 655272027Shselasky return 0; 656272027Shselasky } 657272027Shselasky return -EINVAL; 658272027Shselasky } 659272027Shselasky} 660272027Shselasky 661255932Salfredstatic int update_vport_qp_param(struct mlx4_dev *dev, 662255932Salfred struct mlx4_cmd_mailbox *inbox, 663272027Shselasky u8 slave, u32 qpn) 664255932Salfred{ 665255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 666255932Salfred struct mlx4_vport_oper_state *vp_oper; 667255932Salfred struct mlx4_priv *priv; 668255932Salfred u32 qp_type; 669255932Salfred int port; 670255932Salfred 671255932Salfred port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; 672255932Salfred priv = mlx4_priv(dev); 673255932Salfred vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 674272027Shselasky qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 675255932Salfred 676272027Shselasky if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && 677272027Shselasky qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX) { 678272027Shselasky if (check_counter_index_validity(dev, slave, port, 679272027Shselasky qpc->pri_path.counter_index)) 680255932Salfred return -EINVAL; 681272027Shselasky } 682255932Salfred 683272027Shselasky mlx4_dbg(dev, "%s: QP counter_index %d for slave %d port %d\n", 684272027Shselasky __func__, qpc->pri_path.counter_index, slave, port); 685272027Shselasky 686272027Shselasky if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) && 687272027Shselasky dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && 688272027Shselasky !mlx4_is_qp_reserved(dev, qpn) && 689272027Shselasky qp_type == MLX4_QP_ST_MLX && 690272027Shselasky qpc->pri_path.counter_index != 0xFF) { 691272027Shselasky /* disable multicast loopback to qp with same counter */ 692272027Shselasky qpc->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB; 693272027Shselasky qpc->pri_path.vlan_control |= 694272027Shselasky MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; 695272027Shselasky } 696272027Shselasky 697272027Shselasky if (MLX4_VGT != vp_oper->state.default_vlan) { 698272027Shselasky /* the reserved QPs (special, proxy, tunnel) 699272027Shselasky * do not operate over vlans 700272027Shselasky */ 701272027Shselasky if (mlx4_is_qp_reserved(dev, qpn)) 702272027Shselasky return 0; 703272027Shselasky 704272027Shselasky /* force strip vlan by clear vsd */ 705272027Shselasky qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); 706272027Shselasky /* preserve IF_COUNTER flag */ 707272027Shselasky qpc->pri_path.vlan_control &= 708272027Shselasky MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; 709272027Shselasky if (MLX4_QP_ST_RC != qp_type) { 710272027Shselasky if (0 != vp_oper->state.default_vlan) { 711272027Shselasky qpc->pri_path.vlan_control |= 712272027Shselasky MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 713272027Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 714272027Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 715272027Shselasky } else { /* priority tagged */ 716272027Shselasky qpc->pri_path.vlan_control |= 717272027Shselasky MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 718272027Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 719272027Shselasky } 720272027Shselasky } 721272027Shselasky qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN; 722255932Salfred qpc->pri_path.vlan_index = vp_oper->vlan_idx; 723272027Shselasky qpc->pri_path.fl |= MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; 724272027Shselasky qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 725255932Salfred qpc->pri_path.sched_queue &= 0xC7; 726255932Salfred qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; 727255932Salfred } 728255932Salfred if (vp_oper->state.spoofchk) { 729272027Shselasky qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC; 730255932Salfred qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx; 731255932Salfred } 732255932Salfred return 0; 733255932Salfred} 734255932Salfred 735255932Salfredstatic int mpt_mask(struct mlx4_dev *dev) 736255932Salfred{ 737255932Salfred return dev->caps.num_mpts - 1; 738255932Salfred} 739255932Salfred 740272027Shselaskystatic void *find_res(struct mlx4_dev *dev, u64 res_id, 741255932Salfred enum mlx4_resource type) 742255932Salfred{ 743255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 744255932Salfred 745255932Salfred return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type], 746255932Salfred res_id); 747255932Salfred} 748255932Salfred 749255932Salfredstatic int get_res(struct mlx4_dev *dev, int slave, u64 res_id, 750255932Salfred enum mlx4_resource type, 751255932Salfred void *res) 752255932Salfred{ 753255932Salfred struct res_common *r; 754255932Salfred int err = 0; 755255932Salfred 756255932Salfred spin_lock_irq(mlx4_tlock(dev)); 757255932Salfred r = find_res(dev, res_id, type); 758255932Salfred if (!r) { 759272027Shselasky err = -ENONET; 760255932Salfred goto exit; 761255932Salfred } 762255932Salfred 763255932Salfred if (r->state == RES_ANY_BUSY) { 764255932Salfred err = -EBUSY; 765255932Salfred goto exit; 766255932Salfred } 767255932Salfred 768255932Salfred if (r->owner != slave) { 769255932Salfred err = -EPERM; 770255932Salfred goto exit; 771255932Salfred } 772255932Salfred 773255932Salfred r->from_state = r->state; 774255932Salfred r->state = RES_ANY_BUSY; 775255932Salfred 776255932Salfred if (res) 777255932Salfred *((struct res_common **)res) = r; 778255932Salfred 779255932Salfredexit: 780255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 781255932Salfred return err; 782255932Salfred} 783255932Salfred 784255932Salfredint mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, 785255932Salfred enum mlx4_resource type, 786255932Salfred u64 res_id, int *slave) 787255932Salfred{ 788255932Salfred 789255932Salfred struct res_common *r; 790255932Salfred int err = -ENOENT; 791255932Salfred int id = res_id; 792255932Salfred 793255932Salfred if (type == RES_QP) 794255932Salfred id &= 0x7fffff; 795255932Salfred spin_lock(mlx4_tlock(dev)); 796255932Salfred 797255932Salfred r = find_res(dev, id, type); 798255932Salfred if (r) { 799255932Salfred *slave = r->owner; 800255932Salfred err = 0; 801255932Salfred } 802255932Salfred spin_unlock(mlx4_tlock(dev)); 803255932Salfred 804255932Salfred return err; 805255932Salfred} 806255932Salfred 807255932Salfredstatic void put_res(struct mlx4_dev *dev, int slave, u64 res_id, 808255932Salfred enum mlx4_resource type) 809255932Salfred{ 810255932Salfred struct res_common *r; 811255932Salfred 812255932Salfred spin_lock_irq(mlx4_tlock(dev)); 813255932Salfred r = find_res(dev, res_id, type); 814255932Salfred if (r) 815255932Salfred r->state = r->from_state; 816255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 817255932Salfred} 818255932Salfred 819255932Salfredstatic struct res_common *alloc_qp_tr(int id) 820255932Salfred{ 821255932Salfred struct res_qp *ret; 822255932Salfred 823255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 824255932Salfred if (!ret) 825255932Salfred return NULL; 826255932Salfred 827255932Salfred ret->com.res_id = id; 828255932Salfred ret->com.state = RES_QP_RESERVED; 829255932Salfred ret->local_qpn = id; 830255932Salfred INIT_LIST_HEAD(&ret->mcg_list); 831255932Salfred spin_lock_init(&ret->mcg_spl); 832272027Shselasky atomic_set(&ret->ref_count, 0); 833255932Salfred 834255932Salfred return &ret->com; 835255932Salfred} 836255932Salfred 837255932Salfredstatic struct res_common *alloc_mtt_tr(int id, int order) 838255932Salfred{ 839255932Salfred struct res_mtt *ret; 840255932Salfred 841255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 842255932Salfred if (!ret) 843255932Salfred return NULL; 844255932Salfred 845255932Salfred ret->com.res_id = id; 846255932Salfred ret->order = order; 847255932Salfred ret->com.state = RES_MTT_ALLOCATED; 848255932Salfred atomic_set(&ret->ref_count, 0); 849255932Salfred 850255932Salfred return &ret->com; 851255932Salfred} 852255932Salfred 853255932Salfredstatic struct res_common *alloc_mpt_tr(int id, int key) 854255932Salfred{ 855255932Salfred struct res_mpt *ret; 856255932Salfred 857255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 858255932Salfred if (!ret) 859255932Salfred return NULL; 860255932Salfred 861255932Salfred ret->com.res_id = id; 862255932Salfred ret->com.state = RES_MPT_RESERVED; 863255932Salfred ret->key = key; 864255932Salfred 865255932Salfred return &ret->com; 866255932Salfred} 867255932Salfred 868255932Salfredstatic struct res_common *alloc_eq_tr(int id) 869255932Salfred{ 870255932Salfred struct res_eq *ret; 871255932Salfred 872255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 873255932Salfred if (!ret) 874255932Salfred return NULL; 875255932Salfred 876255932Salfred ret->com.res_id = id; 877255932Salfred ret->com.state = RES_EQ_RESERVED; 878255932Salfred 879255932Salfred return &ret->com; 880255932Salfred} 881255932Salfred 882255932Salfredstatic struct res_common *alloc_cq_tr(int id) 883255932Salfred{ 884255932Salfred struct res_cq *ret; 885255932Salfred 886255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 887255932Salfred if (!ret) 888255932Salfred return NULL; 889255932Salfred 890255932Salfred ret->com.res_id = id; 891255932Salfred ret->com.state = RES_CQ_ALLOCATED; 892255932Salfred atomic_set(&ret->ref_count, 0); 893255932Salfred 894255932Salfred return &ret->com; 895255932Salfred} 896255932Salfred 897255932Salfredstatic struct res_common *alloc_srq_tr(int id) 898255932Salfred{ 899255932Salfred struct res_srq *ret; 900255932Salfred 901255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 902255932Salfred if (!ret) 903255932Salfred return NULL; 904255932Salfred 905255932Salfred ret->com.res_id = id; 906255932Salfred ret->com.state = RES_SRQ_ALLOCATED; 907255932Salfred atomic_set(&ret->ref_count, 0); 908255932Salfred 909255932Salfred return &ret->com; 910255932Salfred} 911255932Salfred 912255932Salfredstatic struct res_common *alloc_counter_tr(int id) 913255932Salfred{ 914255932Salfred struct res_counter *ret; 915255932Salfred 916255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 917255932Salfred if (!ret) 918255932Salfred return NULL; 919255932Salfred 920255932Salfred ret->com.res_id = id; 921255932Salfred ret->com.state = RES_COUNTER_ALLOCATED; 922255932Salfred 923255932Salfred return &ret->com; 924255932Salfred} 925255932Salfred 926255932Salfredstatic struct res_common *alloc_xrcdn_tr(int id) 927255932Salfred{ 928255932Salfred struct res_xrcdn *ret; 929255932Salfred 930255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 931255932Salfred if (!ret) 932255932Salfred return NULL; 933255932Salfred 934255932Salfred ret->com.res_id = id; 935255932Salfred ret->com.state = RES_XRCD_ALLOCATED; 936255932Salfred 937255932Salfred return &ret->com; 938255932Salfred} 939255932Salfred 940272027Shselaskystatic struct res_common *alloc_fs_rule_tr(u64 id, int qpn) 941255932Salfred{ 942255932Salfred struct res_fs_rule *ret; 943255932Salfred 944255932Salfred ret = kzalloc(sizeof *ret, GFP_KERNEL); 945255932Salfred if (!ret) 946255932Salfred return NULL; 947255932Salfred 948255932Salfred ret->com.res_id = id; 949255932Salfred ret->com.state = RES_FS_RULE_ALLOCATED; 950272027Shselasky ret->qpn = qpn; 951255932Salfred return &ret->com; 952255932Salfred} 953255932Salfred 954255932Salfredstatic struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, 955255932Salfred int extra) 956255932Salfred{ 957255932Salfred struct res_common *ret; 958255932Salfred 959255932Salfred switch (type) { 960255932Salfred case RES_QP: 961255932Salfred ret = alloc_qp_tr(id); 962255932Salfred break; 963255932Salfred case RES_MPT: 964255932Salfred ret = alloc_mpt_tr(id, extra); 965255932Salfred break; 966255932Salfred case RES_MTT: 967255932Salfred ret = alloc_mtt_tr(id, extra); 968255932Salfred break; 969255932Salfred case RES_EQ: 970255932Salfred ret = alloc_eq_tr(id); 971255932Salfred break; 972255932Salfred case RES_CQ: 973255932Salfred ret = alloc_cq_tr(id); 974255932Salfred break; 975255932Salfred case RES_SRQ: 976255932Salfred ret = alloc_srq_tr(id); 977255932Salfred break; 978255932Salfred case RES_MAC: 979255932Salfred printk(KERN_ERR "implementation missing\n"); 980255932Salfred return NULL; 981255932Salfred case RES_COUNTER: 982255932Salfred ret = alloc_counter_tr(id); 983255932Salfred break; 984255932Salfred case RES_XRCD: 985255932Salfred ret = alloc_xrcdn_tr(id); 986255932Salfred break; 987255932Salfred case RES_FS_RULE: 988272027Shselasky ret = alloc_fs_rule_tr(id, extra); 989255932Salfred break; 990255932Salfred default: 991255932Salfred return NULL; 992255932Salfred } 993255932Salfred if (ret) 994255932Salfred ret->owner = slave; 995255932Salfred 996255932Salfred return ret; 997255932Salfred} 998255932Salfred 999255932Salfredstatic int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 1000255932Salfred enum mlx4_resource type, int extra) 1001255932Salfred{ 1002255932Salfred int i; 1003255932Salfred int err; 1004255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1005255932Salfred struct res_common **res_arr; 1006255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1007255932Salfred struct rb_root *root = &tracker->res_tree[type]; 1008255932Salfred 1009255932Salfred res_arr = kzalloc(count * sizeof *res_arr, GFP_KERNEL); 1010255932Salfred if (!res_arr) 1011255932Salfred return -ENOMEM; 1012255932Salfred 1013255932Salfred for (i = 0; i < count; ++i) { 1014255932Salfred res_arr[i] = alloc_tr(base + i, type, slave, extra); 1015255932Salfred if (!res_arr[i]) { 1016255932Salfred for (--i; i >= 0; --i) 1017255932Salfred kfree(res_arr[i]); 1018255932Salfred 1019255932Salfred kfree(res_arr); 1020255932Salfred return -ENOMEM; 1021255932Salfred } 1022255932Salfred } 1023255932Salfred 1024255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1025255932Salfred for (i = 0; i < count; ++i) { 1026255932Salfred if (find_res(dev, base + i, type)) { 1027255932Salfred err = -EEXIST; 1028255932Salfred goto undo; 1029255932Salfred } 1030255932Salfred err = res_tracker_insert(root, res_arr[i]); 1031255932Salfred if (err) 1032255932Salfred goto undo; 1033255932Salfred list_add_tail(&res_arr[i]->list, 1034255932Salfred &tracker->slave_list[slave].res_list[type]); 1035255932Salfred } 1036255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1037255932Salfred kfree(res_arr); 1038255932Salfred 1039255932Salfred return 0; 1040255932Salfred 1041255932Salfredundo: 1042272027Shselasky for (--i; i >= 0; --i) { 1043255932Salfred rb_erase(&res_arr[i]->node, root); 1044272027Shselasky list_del_init(&res_arr[i]->list); 1045272027Shselasky } 1046255932Salfred 1047255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1048255932Salfred 1049255932Salfred for (i = 0; i < count; ++i) 1050255932Salfred kfree(res_arr[i]); 1051255932Salfred 1052255932Salfred kfree(res_arr); 1053255932Salfred 1054255932Salfred return err; 1055255932Salfred} 1056255932Salfred 1057255932Salfredstatic int remove_qp_ok(struct res_qp *res) 1058255932Salfred{ 1059272027Shselasky if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || 1060272027Shselasky !list_empty(&res->mcg_list)) { 1061272027Shselasky pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", 1062272027Shselasky res->com.state, atomic_read(&res->ref_count)); 1063255932Salfred return -EBUSY; 1064272027Shselasky } else if (res->com.state != RES_QP_RESERVED) { 1065255932Salfred return -EPERM; 1066272027Shselasky } 1067255932Salfred 1068255932Salfred return 0; 1069255932Salfred} 1070255932Salfred 1071255932Salfredstatic int remove_mtt_ok(struct res_mtt *res, int order) 1072255932Salfred{ 1073255932Salfred if (res->com.state == RES_MTT_BUSY || 1074255932Salfred atomic_read(&res->ref_count)) { 1075255932Salfred printk(KERN_DEBUG "%s-%d: state %s, ref_count %d\n", 1076255932Salfred __func__, __LINE__, 1077255932Salfred mtt_states_str(res->com.state), 1078255932Salfred atomic_read(&res->ref_count)); 1079255932Salfred return -EBUSY; 1080255932Salfred } else if (res->com.state != RES_MTT_ALLOCATED) 1081255932Salfred return -EPERM; 1082255932Salfred else if (res->order != order) 1083255932Salfred return -EINVAL; 1084255932Salfred 1085255932Salfred return 0; 1086255932Salfred} 1087255932Salfred 1088255932Salfredstatic int remove_mpt_ok(struct res_mpt *res) 1089255932Salfred{ 1090255932Salfred if (res->com.state == RES_MPT_BUSY) 1091255932Salfred return -EBUSY; 1092255932Salfred else if (res->com.state != RES_MPT_RESERVED) 1093255932Salfred return -EPERM; 1094255932Salfred 1095255932Salfred return 0; 1096255932Salfred} 1097255932Salfred 1098255932Salfredstatic int remove_eq_ok(struct res_eq *res) 1099255932Salfred{ 1100255932Salfred if (res->com.state == RES_MPT_BUSY) 1101255932Salfred return -EBUSY; 1102255932Salfred else if (res->com.state != RES_MPT_RESERVED) 1103255932Salfred return -EPERM; 1104255932Salfred 1105255932Salfred return 0; 1106255932Salfred} 1107255932Salfred 1108255932Salfredstatic int remove_counter_ok(struct res_counter *res) 1109255932Salfred{ 1110255932Salfred if (res->com.state == RES_COUNTER_BUSY) 1111255932Salfred return -EBUSY; 1112255932Salfred else if (res->com.state != RES_COUNTER_ALLOCATED) 1113255932Salfred return -EPERM; 1114255932Salfred 1115255932Salfred return 0; 1116255932Salfred} 1117255932Salfred 1118255932Salfredstatic int remove_xrcdn_ok(struct res_xrcdn *res) 1119255932Salfred{ 1120255932Salfred if (res->com.state == RES_XRCD_BUSY) 1121255932Salfred return -EBUSY; 1122255932Salfred else if (res->com.state != RES_XRCD_ALLOCATED) 1123255932Salfred return -EPERM; 1124255932Salfred 1125255932Salfred return 0; 1126255932Salfred} 1127255932Salfred 1128255932Salfredstatic int remove_fs_rule_ok(struct res_fs_rule *res) 1129255932Salfred{ 1130255932Salfred if (res->com.state == RES_FS_RULE_BUSY) 1131255932Salfred return -EBUSY; 1132255932Salfred else if (res->com.state != RES_FS_RULE_ALLOCATED) 1133255932Salfred return -EPERM; 1134255932Salfred 1135255932Salfred return 0; 1136255932Salfred} 1137255932Salfred 1138255932Salfredstatic int remove_cq_ok(struct res_cq *res) 1139255932Salfred{ 1140255932Salfred if (res->com.state == RES_CQ_BUSY) 1141255932Salfred return -EBUSY; 1142255932Salfred else if (res->com.state != RES_CQ_ALLOCATED) 1143255932Salfred return -EPERM; 1144255932Salfred 1145255932Salfred return 0; 1146255932Salfred} 1147255932Salfred 1148255932Salfredstatic int remove_srq_ok(struct res_srq *res) 1149255932Salfred{ 1150255932Salfred if (res->com.state == RES_SRQ_BUSY) 1151255932Salfred return -EBUSY; 1152255932Salfred else if (res->com.state != RES_SRQ_ALLOCATED) 1153255932Salfred return -EPERM; 1154255932Salfred 1155255932Salfred return 0; 1156255932Salfred} 1157255932Salfred 1158255932Salfredstatic int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) 1159255932Salfred{ 1160255932Salfred switch (type) { 1161255932Salfred case RES_QP: 1162255932Salfred return remove_qp_ok((struct res_qp *)res); 1163255932Salfred case RES_CQ: 1164255932Salfred return remove_cq_ok((struct res_cq *)res); 1165255932Salfred case RES_SRQ: 1166255932Salfred return remove_srq_ok((struct res_srq *)res); 1167255932Salfred case RES_MPT: 1168255932Salfred return remove_mpt_ok((struct res_mpt *)res); 1169255932Salfred case RES_MTT: 1170255932Salfred return remove_mtt_ok((struct res_mtt *)res, extra); 1171255932Salfred case RES_MAC: 1172255932Salfred return -ENOSYS; 1173255932Salfred case RES_EQ: 1174255932Salfred return remove_eq_ok((struct res_eq *)res); 1175255932Salfred case RES_COUNTER: 1176255932Salfred return remove_counter_ok((struct res_counter *)res); 1177255932Salfred case RES_XRCD: 1178255932Salfred return remove_xrcdn_ok((struct res_xrcdn *)res); 1179255932Salfred case RES_FS_RULE: 1180255932Salfred return remove_fs_rule_ok((struct res_fs_rule *)res); 1181255932Salfred default: 1182255932Salfred return -EINVAL; 1183255932Salfred } 1184255932Salfred} 1185255932Salfred 1186255932Salfredstatic int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, 1187255932Salfred enum mlx4_resource type, int extra) 1188255932Salfred{ 1189255932Salfred u64 i; 1190255932Salfred int err; 1191255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1192255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1193255932Salfred struct res_common *r; 1194255932Salfred 1195255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1196255932Salfred for (i = base; i < base + count; ++i) { 1197255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], i); 1198255932Salfred if (!r) { 1199255932Salfred err = -ENOENT; 1200255932Salfred goto out; 1201255932Salfred } 1202255932Salfred if (r->owner != slave) { 1203255932Salfred err = -EPERM; 1204255932Salfred goto out; 1205255932Salfred } 1206255932Salfred err = remove_ok(r, type, extra); 1207255932Salfred if (err) 1208255932Salfred goto out; 1209255932Salfred } 1210255932Salfred 1211255932Salfred for (i = base; i < base + count; ++i) { 1212255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], i); 1213255932Salfred rb_erase(&r->node, &tracker->res_tree[type]); 1214255932Salfred list_del(&r->list); 1215255932Salfred kfree(r); 1216255932Salfred } 1217255932Salfred err = 0; 1218255932Salfred 1219255932Salfredout: 1220255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1221255932Salfred 1222255932Salfred return err; 1223255932Salfred} 1224255932Salfred 1225255932Salfredstatic int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn, 1226255932Salfred enum res_qp_states state, struct res_qp **qp, 1227255932Salfred int alloc) 1228255932Salfred{ 1229255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1230255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1231255932Salfred struct res_qp *r; 1232255932Salfred int err = 0; 1233255932Salfred 1234255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1235255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn); 1236255932Salfred if (!r) 1237255932Salfred err = -ENOENT; 1238255932Salfred else if (r->com.owner != slave) 1239255932Salfred err = -EPERM; 1240255932Salfred else { 1241255932Salfred switch (state) { 1242255932Salfred case RES_QP_BUSY: 1243255932Salfred mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n", 1244272027Shselasky __func__, (unsigned long long)r->com.res_id); 1245255932Salfred err = -EBUSY; 1246255932Salfred break; 1247255932Salfred 1248255932Salfred case RES_QP_RESERVED: 1249255932Salfred if (r->com.state == RES_QP_MAPPED && !alloc) 1250255932Salfred break; 1251255932Salfred 1252272027Shselasky mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", (unsigned long long)r->com.res_id); 1253255932Salfred err = -EINVAL; 1254255932Salfred break; 1255255932Salfred 1256255932Salfred case RES_QP_MAPPED: 1257255932Salfred if ((r->com.state == RES_QP_RESERVED && alloc) || 1258255932Salfred r->com.state == RES_QP_HW) 1259255932Salfred break; 1260255932Salfred else { 1261255932Salfred mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", 1262272027Shselasky (unsigned long long)r->com.res_id); 1263255932Salfred err = -EINVAL; 1264255932Salfred } 1265255932Salfred 1266255932Salfred break; 1267255932Salfred 1268255932Salfred case RES_QP_HW: 1269255932Salfred if (r->com.state != RES_QP_MAPPED) 1270255932Salfred err = -EINVAL; 1271255932Salfred break; 1272255932Salfred default: 1273255932Salfred err = -EINVAL; 1274255932Salfred } 1275255932Salfred 1276255932Salfred if (!err) { 1277255932Salfred r->com.from_state = r->com.state; 1278255932Salfred r->com.to_state = state; 1279255932Salfred r->com.state = RES_QP_BUSY; 1280255932Salfred if (qp) 1281255932Salfred *qp = r; 1282255932Salfred } 1283255932Salfred } 1284255932Salfred 1285255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1286255932Salfred 1287255932Salfred return err; 1288255932Salfred} 1289255932Salfred 1290255932Salfredstatic int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 1291255932Salfred enum res_mpt_states state, struct res_mpt **mpt) 1292255932Salfred{ 1293255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1294255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1295255932Salfred struct res_mpt *r; 1296255932Salfred int err = 0; 1297255932Salfred 1298255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1299255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index); 1300255932Salfred if (!r) 1301255932Salfred err = -ENOENT; 1302255932Salfred else if (r->com.owner != slave) 1303255932Salfred err = -EPERM; 1304255932Salfred else { 1305255932Salfred switch (state) { 1306255932Salfred case RES_MPT_BUSY: 1307255932Salfred err = -EINVAL; 1308255932Salfred break; 1309255932Salfred 1310255932Salfred case RES_MPT_RESERVED: 1311255932Salfred if (r->com.state != RES_MPT_MAPPED) 1312255932Salfred err = -EINVAL; 1313255932Salfred break; 1314255932Salfred 1315255932Salfred case RES_MPT_MAPPED: 1316255932Salfred if (r->com.state != RES_MPT_RESERVED && 1317255932Salfred r->com.state != RES_MPT_HW) 1318255932Salfred err = -EINVAL; 1319255932Salfred break; 1320255932Salfred 1321255932Salfred case RES_MPT_HW: 1322255932Salfred if (r->com.state != RES_MPT_MAPPED) 1323255932Salfred err = -EINVAL; 1324255932Salfred break; 1325255932Salfred default: 1326255932Salfred err = -EINVAL; 1327255932Salfred } 1328255932Salfred 1329255932Salfred if (!err) { 1330255932Salfred r->com.from_state = r->com.state; 1331255932Salfred r->com.to_state = state; 1332255932Salfred r->com.state = RES_MPT_BUSY; 1333255932Salfred if (mpt) 1334255932Salfred *mpt = r; 1335255932Salfred } 1336255932Salfred } 1337255932Salfred 1338255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1339255932Salfred 1340255932Salfred return err; 1341255932Salfred} 1342255932Salfred 1343255932Salfredstatic int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 1344255932Salfred enum res_eq_states state, struct res_eq **eq) 1345255932Salfred{ 1346255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1347255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1348255932Salfred struct res_eq *r; 1349255932Salfred int err = 0; 1350255932Salfred 1351255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1352255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index); 1353255932Salfred if (!r) 1354255932Salfred err = -ENOENT; 1355255932Salfred else if (r->com.owner != slave) 1356255932Salfred err = -EPERM; 1357255932Salfred else { 1358255932Salfred switch (state) { 1359255932Salfred case RES_EQ_BUSY: 1360255932Salfred err = -EINVAL; 1361255932Salfred break; 1362255932Salfred 1363255932Salfred case RES_EQ_RESERVED: 1364255932Salfred if (r->com.state != RES_EQ_HW) 1365255932Salfred err = -EINVAL; 1366255932Salfred break; 1367255932Salfred 1368255932Salfred case RES_EQ_HW: 1369255932Salfred if (r->com.state != RES_EQ_RESERVED) 1370255932Salfred err = -EINVAL; 1371255932Salfred break; 1372255932Salfred 1373255932Salfred default: 1374255932Salfred err = -EINVAL; 1375255932Salfred } 1376255932Salfred 1377255932Salfred if (!err) { 1378255932Salfred r->com.from_state = r->com.state; 1379255932Salfred r->com.to_state = state; 1380255932Salfred r->com.state = RES_EQ_BUSY; 1381255932Salfred if (eq) 1382255932Salfred *eq = r; 1383255932Salfred } 1384255932Salfred } 1385255932Salfred 1386255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1387255932Salfred 1388255932Salfred return err; 1389255932Salfred} 1390255932Salfred 1391255932Salfredstatic int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn, 1392255932Salfred enum res_cq_states state, struct res_cq **cq) 1393255932Salfred{ 1394255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1395255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1396255932Salfred struct res_cq *r; 1397255932Salfred int err; 1398255932Salfred 1399255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1400255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn); 1401255932Salfred if (!r) 1402255932Salfred err = -ENOENT; 1403255932Salfred else if (r->com.owner != slave) 1404255932Salfred err = -EPERM; 1405255932Salfred else { 1406255932Salfred switch (state) { 1407255932Salfred case RES_CQ_BUSY: 1408255932Salfred err = -EBUSY; 1409255932Salfred break; 1410255932Salfred 1411255932Salfred case RES_CQ_ALLOCATED: 1412255932Salfred if (r->com.state != RES_CQ_HW) 1413255932Salfred err = -EINVAL; 1414255932Salfred else if (atomic_read(&r->ref_count)) 1415255932Salfred err = -EBUSY; 1416255932Salfred else 1417255932Salfred err = 0; 1418255932Salfred break; 1419255932Salfred 1420255932Salfred case RES_CQ_HW: 1421255932Salfred if (r->com.state != RES_CQ_ALLOCATED) 1422255932Salfred err = -EINVAL; 1423255932Salfred else 1424255932Salfred err = 0; 1425255932Salfred break; 1426255932Salfred 1427255932Salfred default: 1428255932Salfred err = -EINVAL; 1429255932Salfred } 1430255932Salfred 1431255932Salfred if (!err) { 1432255932Salfred r->com.from_state = r->com.state; 1433255932Salfred r->com.to_state = state; 1434255932Salfred r->com.state = RES_CQ_BUSY; 1435255932Salfred if (cq) 1436255932Salfred *cq = r; 1437255932Salfred } 1438255932Salfred } 1439255932Salfred 1440255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1441255932Salfred 1442255932Salfred return err; 1443255932Salfred} 1444255932Salfred 1445255932Salfredstatic int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, 1446255932Salfred enum res_srq_states state, struct res_srq **srq) 1447255932Salfred{ 1448255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1449255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1450255932Salfred struct res_srq *r; 1451255932Salfred int err = 0; 1452255932Salfred 1453255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1454255932Salfred r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index); 1455255932Salfred if (!r) 1456255932Salfred err = -ENOENT; 1457255932Salfred else if (r->com.owner != slave) 1458255932Salfred err = -EPERM; 1459255932Salfred else { 1460255932Salfred switch (state) { 1461255932Salfred case RES_SRQ_BUSY: 1462255932Salfred err = -EINVAL; 1463255932Salfred break; 1464255932Salfred 1465255932Salfred case RES_SRQ_ALLOCATED: 1466255932Salfred if (r->com.state != RES_SRQ_HW) 1467255932Salfred err = -EINVAL; 1468255932Salfred else if (atomic_read(&r->ref_count)) 1469255932Salfred err = -EBUSY; 1470255932Salfred break; 1471255932Salfred 1472255932Salfred case RES_SRQ_HW: 1473255932Salfred if (r->com.state != RES_SRQ_ALLOCATED) 1474255932Salfred err = -EINVAL; 1475255932Salfred break; 1476255932Salfred 1477255932Salfred default: 1478255932Salfred err = -EINVAL; 1479255932Salfred } 1480255932Salfred 1481255932Salfred if (!err) { 1482255932Salfred r->com.from_state = r->com.state; 1483255932Salfred r->com.to_state = state; 1484255932Salfred r->com.state = RES_SRQ_BUSY; 1485255932Salfred if (srq) 1486255932Salfred *srq = r; 1487255932Salfred } 1488255932Salfred } 1489255932Salfred 1490255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1491255932Salfred 1492255932Salfred return err; 1493255932Salfred} 1494255932Salfred 1495255932Salfredstatic void res_abort_move(struct mlx4_dev *dev, int slave, 1496255932Salfred enum mlx4_resource type, int id) 1497255932Salfred{ 1498255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1499255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1500255932Salfred struct res_common *r; 1501255932Salfred 1502255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1503255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], id); 1504255932Salfred if (r && (r->owner == slave)) 1505255932Salfred r->state = r->from_state; 1506255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1507255932Salfred} 1508255932Salfred 1509255932Salfredstatic void res_end_move(struct mlx4_dev *dev, int slave, 1510255932Salfred enum mlx4_resource type, int id) 1511255932Salfred{ 1512255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1513255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1514255932Salfred struct res_common *r; 1515255932Salfred 1516255932Salfred spin_lock_irq(mlx4_tlock(dev)); 1517255932Salfred r = res_tracker_lookup(&tracker->res_tree[type], id); 1518255932Salfred if (r && (r->owner == slave)) 1519255932Salfred r->state = r->to_state; 1520255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 1521255932Salfred} 1522255932Salfred 1523255932Salfredstatic int valid_reserved(struct mlx4_dev *dev, int slave, int qpn) 1524255932Salfred{ 1525255932Salfred return mlx4_is_qp_reserved(dev, qpn) && 1526255932Salfred (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn)); 1527255932Salfred} 1528255932Salfred 1529255932Salfredstatic int fw_reserved(struct mlx4_dev *dev, int qpn) 1530255932Salfred{ 1531255932Salfred return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; 1532255932Salfred} 1533255932Salfred 1534255932Salfredstatic int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1535255932Salfred u64 in_param, u64 *out_param) 1536255932Salfred{ 1537255932Salfred int err; 1538255932Salfred int count; 1539255932Salfred int align; 1540255932Salfred int base; 1541255932Salfred int qpn; 1542272027Shselasky u8 flags; 1543255932Salfred 1544255932Salfred switch (op) { 1545255932Salfred case RES_OP_RESERVE: 1546255932Salfred count = get_param_l(&in_param) & 0xffffff; 1547272027Shselasky flags = get_param_l(&in_param) >> 24; 1548255932Salfred align = get_param_h(&in_param); 1549255932Salfred err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); 1550255932Salfred if (err) 1551255932Salfred return err; 1552255932Salfred 1553272027Shselasky err = __mlx4_qp_reserve_range(dev, count, align, &base, flags); 1554255932Salfred if (err) { 1555255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 1556255932Salfred return err; 1557255932Salfred } 1558255932Salfred 1559255932Salfred err = add_res_range(dev, slave, base, count, RES_QP, 0); 1560255932Salfred if (err) { 1561255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 1562255932Salfred __mlx4_qp_release_range(dev, base, count); 1563255932Salfred return err; 1564255932Salfred } 1565255932Salfred set_param_l(out_param, base); 1566255932Salfred break; 1567255932Salfred case RES_OP_MAP_ICM: 1568255932Salfred qpn = get_param_l(&in_param) & 0x7fffff; 1569255932Salfred if (valid_reserved(dev, slave, qpn)) { 1570255932Salfred err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); 1571255932Salfred if (err) 1572255932Salfred return err; 1573255932Salfred } 1574255932Salfred 1575255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, 1576255932Salfred NULL, 1); 1577255932Salfred if (err) 1578255932Salfred return err; 1579255932Salfred 1580255932Salfred if (!fw_reserved(dev, qpn)) { 1581255932Salfred err = __mlx4_qp_alloc_icm(dev, qpn); 1582255932Salfred if (err) { 1583255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 1584255932Salfred return err; 1585255932Salfred } 1586255932Salfred } 1587255932Salfred 1588255932Salfred res_end_move(dev, slave, RES_QP, qpn); 1589255932Salfred break; 1590255932Salfred 1591255932Salfred default: 1592255932Salfred err = -EINVAL; 1593255932Salfred break; 1594255932Salfred } 1595255932Salfred return err; 1596255932Salfred} 1597255932Salfred 1598255932Salfredstatic int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1599255932Salfred u64 in_param, u64 *out_param) 1600255932Salfred{ 1601255932Salfred int err = -EINVAL; 1602255932Salfred int base; 1603255932Salfred int order; 1604255932Salfred 1605255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1606255932Salfred return err; 1607255932Salfred 1608255932Salfred order = get_param_l(&in_param); 1609255932Salfred 1610255932Salfred err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); 1611255932Salfred if (err) 1612255932Salfred return err; 1613255932Salfred 1614255932Salfred base = __mlx4_alloc_mtt_range(dev, order); 1615255932Salfred if (base == -1) { 1616255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 1617255932Salfred return -ENOMEM; 1618255932Salfred } 1619255932Salfred 1620255932Salfred err = add_res_range(dev, slave, base, 1, RES_MTT, order); 1621255932Salfred if (err) { 1622255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 1623255932Salfred __mlx4_free_mtt_range(dev, base, order); 1624255932Salfred } else 1625255932Salfred set_param_l(out_param, base); 1626255932Salfred 1627255932Salfred return err; 1628255932Salfred} 1629255932Salfred 1630255932Salfredstatic int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1631255932Salfred u64 in_param, u64 *out_param) 1632255932Salfred{ 1633255932Salfred int err = -EINVAL; 1634255932Salfred int index; 1635255932Salfred int id; 1636255932Salfred struct res_mpt *mpt; 1637255932Salfred 1638255932Salfred switch (op) { 1639255932Salfred case RES_OP_RESERVE: 1640255932Salfred err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); 1641255932Salfred if (err) 1642255932Salfred break; 1643255932Salfred 1644272027Shselasky index = __mlx4_mpt_reserve(dev); 1645255932Salfred if (index == -1) { 1646255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 1647255932Salfred break; 1648255932Salfred } 1649255932Salfred id = index & mpt_mask(dev); 1650255932Salfred 1651255932Salfred err = add_res_range(dev, slave, id, 1, RES_MPT, index); 1652255932Salfred if (err) { 1653255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 1654272027Shselasky __mlx4_mpt_release(dev, index); 1655255932Salfred break; 1656255932Salfred } 1657255932Salfred set_param_l(out_param, index); 1658255932Salfred break; 1659255932Salfred case RES_OP_MAP_ICM: 1660255932Salfred index = get_param_l(&in_param); 1661255932Salfred id = index & mpt_mask(dev); 1662255932Salfred err = mr_res_start_move_to(dev, slave, id, 1663255932Salfred RES_MPT_MAPPED, &mpt); 1664255932Salfred if (err) 1665255932Salfred return err; 1666255932Salfred 1667272027Shselasky err = __mlx4_mpt_alloc_icm(dev, mpt->key); 1668255932Salfred if (err) { 1669255932Salfred res_abort_move(dev, slave, RES_MPT, id); 1670255932Salfred return err; 1671255932Salfred } 1672255932Salfred 1673255932Salfred res_end_move(dev, slave, RES_MPT, id); 1674255932Salfred break; 1675255932Salfred } 1676255932Salfred return err; 1677255932Salfred} 1678255932Salfred 1679255932Salfredstatic int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1680255932Salfred u64 in_param, u64 *out_param) 1681255932Salfred{ 1682255932Salfred int cqn; 1683255932Salfred int err; 1684255932Salfred 1685255932Salfred switch (op) { 1686255932Salfred case RES_OP_RESERVE_AND_MAP: 1687255932Salfred err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); 1688255932Salfred if (err) 1689255932Salfred break; 1690255932Salfred 1691255932Salfred err = __mlx4_cq_alloc_icm(dev, &cqn); 1692255932Salfred if (err) { 1693255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 1694255932Salfred break; 1695255932Salfred } 1696255932Salfred 1697255932Salfred err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); 1698255932Salfred if (err) { 1699255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 1700255932Salfred __mlx4_cq_free_icm(dev, cqn); 1701255932Salfred break; 1702255932Salfred } 1703255932Salfred 1704255932Salfred set_param_l(out_param, cqn); 1705255932Salfred break; 1706255932Salfred 1707255932Salfred default: 1708255932Salfred err = -EINVAL; 1709255932Salfred } 1710255932Salfred 1711255932Salfred return err; 1712255932Salfred} 1713255932Salfred 1714255932Salfredstatic int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1715255932Salfred u64 in_param, u64 *out_param) 1716255932Salfred{ 1717255932Salfred int srqn; 1718255932Salfred int err; 1719255932Salfred 1720255932Salfred switch (op) { 1721255932Salfred case RES_OP_RESERVE_AND_MAP: 1722255932Salfred err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); 1723255932Salfred if (err) 1724255932Salfred break; 1725255932Salfred 1726255932Salfred err = __mlx4_srq_alloc_icm(dev, &srqn); 1727255932Salfred if (err) { 1728255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 1729255932Salfred break; 1730255932Salfred } 1731255932Salfred 1732255932Salfred err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 1733255932Salfred if (err) { 1734255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 1735255932Salfred __mlx4_srq_free_icm(dev, srqn); 1736255932Salfred break; 1737255932Salfred } 1738255932Salfred 1739255932Salfred set_param_l(out_param, srqn); 1740255932Salfred break; 1741255932Salfred 1742255932Salfred default: 1743255932Salfred err = -EINVAL; 1744255932Salfred } 1745255932Salfred 1746255932Salfred return err; 1747255932Salfred} 1748255932Salfred 1749255932Salfredstatic int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, 1750255932Salfred u8 smac_index, u64 *mac) 1751255932Salfred{ 1752255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1753255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1754255932Salfred struct list_head *mac_list = 1755255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1756255932Salfred struct mac_res *res, *tmp; 1757255932Salfred 1758255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1759255932Salfred if (res->smac_index == smac_index && res->port == (u8) port) { 1760255932Salfred *mac = res->mac; 1761255932Salfred return 0; 1762255932Salfred } 1763255932Salfred } 1764255932Salfred return -ENOENT; 1765255932Salfred} 1766255932Salfred 1767255932Salfredstatic int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) 1768255932Salfred{ 1769255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1770255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1771255932Salfred struct list_head *mac_list = 1772255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1773255932Salfred struct mac_res *res, *tmp; 1774255932Salfred 1775255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1776255932Salfred if (res->mac == mac && res->port == (u8) port) { 1777255932Salfred /* mac found. update ref count */ 1778255932Salfred ++res->ref_count; 1779255932Salfred return 0; 1780255932Salfred } 1781255932Salfred } 1782255932Salfred 1783255932Salfred if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) 1784255932Salfred return -EINVAL; 1785255932Salfred res = kzalloc(sizeof *res, GFP_KERNEL); 1786255932Salfred if (!res) { 1787255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, port); 1788255932Salfred return -ENOMEM; 1789255932Salfred } 1790255932Salfred res->mac = mac; 1791255932Salfred res->port = (u8) port; 1792255932Salfred res->smac_index = smac_index; 1793255932Salfred res->ref_count = 1; 1794255932Salfred list_add_tail(&res->list, 1795255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]); 1796255932Salfred return 0; 1797255932Salfred} 1798255932Salfred 1799255932Salfred 1800255932Salfredstatic void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, 1801255932Salfred int port) 1802255932Salfred{ 1803255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1804255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1805255932Salfred struct list_head *mac_list = 1806255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1807255932Salfred struct mac_res *res, *tmp; 1808255932Salfred 1809255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1810255932Salfred if (res->mac == mac && res->port == (u8) port) { 1811255932Salfred if (!--res->ref_count) { 1812255932Salfred list_del(&res->list); 1813255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, port); 1814255932Salfred kfree(res); 1815255932Salfred } 1816255932Salfred break; 1817255932Salfred } 1818255932Salfred } 1819255932Salfred} 1820255932Salfred 1821255932Salfredstatic void rem_slave_macs(struct mlx4_dev *dev, int slave) 1822255932Salfred{ 1823255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1824255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1825255932Salfred struct list_head *mac_list = 1826255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1827255932Salfred struct mac_res *res, *tmp; 1828255932Salfred int i; 1829255932Salfred 1830255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1831255932Salfred list_del(&res->list); 1832255932Salfred /* dereference the mac the num times the slave referenced it */ 1833255932Salfred for (i = 0; i < res->ref_count; i++) 1834255932Salfred __mlx4_unregister_mac(dev, res->port, res->mac); 1835255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); 1836255932Salfred kfree(res); 1837255932Salfred } 1838255932Salfred} 1839255932Salfred 1840255932Salfredstatic int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1841255932Salfred u64 in_param, u64 *out_param, int in_port) 1842255932Salfred{ 1843255932Salfred int err = -EINVAL; 1844255932Salfred int port; 1845255932Salfred u64 mac; 1846272060Shselasky u8 smac_index = 0; 1847255932Salfred 1848255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1849255932Salfred return err; 1850255932Salfred 1851255932Salfred port = !in_port ? get_param_l(out_param) : in_port; 1852255932Salfred mac = in_param; 1853255932Salfred 1854255932Salfred err = __mlx4_register_mac(dev, port, mac); 1855255932Salfred if (err >= 0) { 1856255932Salfred smac_index = err; 1857255932Salfred set_param_l(out_param, err); 1858255932Salfred err = 0; 1859255932Salfred } 1860255932Salfred 1861255932Salfred if (!err) { 1862255932Salfred err = mac_add_to_slave(dev, slave, mac, port, smac_index); 1863255932Salfred if (err) 1864255932Salfred __mlx4_unregister_mac(dev, port, mac); 1865255932Salfred } 1866255932Salfred return err; 1867255932Salfred} 1868255932Salfred 1869255932Salfredstatic int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, 1870255932Salfred int port, int vlan_index) 1871255932Salfred{ 1872255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1873255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1874255932Salfred struct list_head *vlan_list = 1875255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1876255932Salfred struct vlan_res *res, *tmp; 1877255932Salfred 1878255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1879255932Salfred if (res->vlan == vlan && res->port == (u8) port) { 1880255932Salfred /* vlan found. update ref count */ 1881255932Salfred ++res->ref_count; 1882255932Salfred return 0; 1883255932Salfred } 1884255932Salfred } 1885255932Salfred 1886255932Salfred if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) 1887255932Salfred return -EINVAL; 1888255932Salfred res = kzalloc(sizeof(*res), GFP_KERNEL); 1889255932Salfred if (!res) { 1890255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1, port); 1891255932Salfred return -ENOMEM; 1892255932Salfred } 1893255932Salfred res->vlan = vlan; 1894255932Salfred res->port = (u8) port; 1895255932Salfred res->vlan_index = vlan_index; 1896255932Salfred res->ref_count = 1; 1897255932Salfred list_add_tail(&res->list, 1898255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]); 1899255932Salfred return 0; 1900255932Salfred} 1901255932Salfred 1902255932Salfred 1903255932Salfredstatic void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, 1904255932Salfred int port) 1905255932Salfred{ 1906255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1907255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1908255932Salfred struct list_head *vlan_list = 1909255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1910255932Salfred struct vlan_res *res, *tmp; 1911255932Salfred 1912255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1913255932Salfred if (res->vlan == vlan && res->port == (u8) port) { 1914255932Salfred if (!--res->ref_count) { 1915255932Salfred list_del(&res->list); 1916255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1917255932Salfred 1, port); 1918255932Salfred kfree(res); 1919255932Salfred } 1920255932Salfred break; 1921255932Salfred } 1922255932Salfred } 1923255932Salfred} 1924255932Salfred 1925255932Salfredstatic void rem_slave_vlans(struct mlx4_dev *dev, int slave) 1926255932Salfred{ 1927255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1928255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1929255932Salfred struct list_head *vlan_list = 1930255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1931255932Salfred struct vlan_res *res, *tmp; 1932255932Salfred int i; 1933255932Salfred 1934255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1935255932Salfred list_del(&res->list); 1936255932Salfred /* dereference the vlan the num times the slave referenced it */ 1937255932Salfred for (i = 0; i < res->ref_count; i++) 1938255932Salfred __mlx4_unregister_vlan(dev, res->port, res->vlan); 1939255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); 1940255932Salfred kfree(res); 1941255932Salfred } 1942255932Salfred} 1943255932Salfred 1944255932Salfredstatic int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1945272027Shselasky u64 in_param, u64 *out_param, int in_port) 1946255932Salfred{ 1947272027Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 1948272027Shselasky struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 1949255932Salfred int err = -EINVAL; 1950255932Salfred u16 vlan; 1951255932Salfred int vlan_index; 1952272027Shselasky int port; 1953255932Salfred 1954272027Shselasky port = !in_port ? get_param_l(out_param) : in_port; 1955272027Shselasky 1956255932Salfred if (!port) 1957255932Salfred return err; 1958255932Salfred 1959255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1960255932Salfred return err; 1961255932Salfred 1962272027Shselasky /* upstream kernels had NOP for reg/unreg vlan. Continue this. */ 1963272027Shselasky if (!in_port && port > 0 && port <= dev->caps.num_ports) { 1964272027Shselasky slave_state[slave].old_vlan_api = true; 1965272027Shselasky return 0; 1966272027Shselasky } 1967272027Shselasky 1968255932Salfred vlan = (u16) in_param; 1969255932Salfred 1970255932Salfred err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); 1971255932Salfred if (!err) { 1972255932Salfred set_param_l(out_param, (u32) vlan_index); 1973255932Salfred err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); 1974255932Salfred if (err) 1975255932Salfred __mlx4_unregister_vlan(dev, port, vlan); 1976255932Salfred } 1977255932Salfred return err; 1978255932Salfred} 1979255932Salfred 1980255932Salfredstatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1981272027Shselasky u64 in_param, u64 *out_param, int port) 1982255932Salfred{ 1983255932Salfred u32 index; 1984255932Salfred int err; 1985255932Salfred 1986255932Salfred if (op != RES_OP_RESERVE) 1987255932Salfred return -EINVAL; 1988255932Salfred 1989272027Shselasky err = __mlx4_counter_alloc(dev, slave, port, &index); 1990272027Shselasky if (!err) 1991255932Salfred set_param_l(out_param, index); 1992255932Salfred 1993255932Salfred return err; 1994255932Salfred} 1995255932Salfred 1996255932Salfredstatic int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1997255932Salfred u64 in_param, u64 *out_param) 1998255932Salfred{ 1999255932Salfred u32 xrcdn; 2000255932Salfred int err; 2001255932Salfred 2002255932Salfred if (op != RES_OP_RESERVE) 2003255932Salfred return -EINVAL; 2004255932Salfred 2005255932Salfred err = __mlx4_xrcd_alloc(dev, &xrcdn); 2006255932Salfred if (err) 2007255932Salfred return err; 2008255932Salfred 2009255932Salfred err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 2010255932Salfred if (err) 2011255932Salfred __mlx4_xrcd_free(dev, xrcdn); 2012255932Salfred else 2013255932Salfred set_param_l(out_param, xrcdn); 2014255932Salfred 2015255932Salfred return err; 2016255932Salfred} 2017255932Salfred 2018255932Salfredint mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, 2019255932Salfred struct mlx4_vhcr *vhcr, 2020255932Salfred struct mlx4_cmd_mailbox *inbox, 2021255932Salfred struct mlx4_cmd_mailbox *outbox, 2022255932Salfred struct mlx4_cmd_info *cmd) 2023255932Salfred{ 2024255932Salfred int err; 2025255932Salfred int alop = vhcr->op_modifier; 2026255932Salfred 2027255932Salfred switch (vhcr->in_modifier & 0xFF) { 2028255932Salfred case RES_QP: 2029255932Salfred err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, 2030255932Salfred vhcr->in_param, &vhcr->out_param); 2031255932Salfred break; 2032255932Salfred 2033255932Salfred case RES_MTT: 2034255932Salfred err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, 2035255932Salfred vhcr->in_param, &vhcr->out_param); 2036255932Salfred break; 2037255932Salfred 2038255932Salfred case RES_MPT: 2039255932Salfred err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, 2040255932Salfred vhcr->in_param, &vhcr->out_param); 2041255932Salfred break; 2042255932Salfred 2043255932Salfred case RES_CQ: 2044255932Salfred err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, 2045255932Salfred vhcr->in_param, &vhcr->out_param); 2046255932Salfred break; 2047255932Salfred 2048255932Salfred case RES_SRQ: 2049255932Salfred err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, 2050255932Salfred vhcr->in_param, &vhcr->out_param); 2051255932Salfred break; 2052255932Salfred 2053255932Salfred case RES_MAC: 2054255932Salfred err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, 2055255932Salfred vhcr->in_param, &vhcr->out_param, 2056255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2057255932Salfred break; 2058255932Salfred 2059255932Salfred case RES_VLAN: 2060255932Salfred err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, 2061255932Salfred vhcr->in_param, &vhcr->out_param, 2062255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2063255932Salfred break; 2064255932Salfred 2065255932Salfred case RES_COUNTER: 2066255932Salfred err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, 2067272027Shselasky vhcr->in_param, &vhcr->out_param, 2068272027Shselasky (vhcr->in_modifier >> 8) & 0xFF); 2069255932Salfred break; 2070255932Salfred 2071255932Salfred case RES_XRCD: 2072255932Salfred err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, 2073255932Salfred vhcr->in_param, &vhcr->out_param); 2074255932Salfred break; 2075255932Salfred 2076255932Salfred default: 2077255932Salfred err = -EINVAL; 2078255932Salfred break; 2079255932Salfred } 2080255932Salfred 2081255932Salfred return err; 2082255932Salfred} 2083255932Salfred 2084255932Salfredstatic int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2085255932Salfred u64 in_param) 2086255932Salfred{ 2087255932Salfred int err; 2088255932Salfred int count; 2089255932Salfred int base; 2090255932Salfred int qpn; 2091255932Salfred 2092255932Salfred switch (op) { 2093255932Salfred case RES_OP_RESERVE: 2094255932Salfred base = get_param_l(&in_param) & 0x7fffff; 2095255932Salfred count = get_param_h(&in_param); 2096255932Salfred err = rem_res_range(dev, slave, base, count, RES_QP, 0); 2097255932Salfred if (err) 2098255932Salfred break; 2099255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 2100255932Salfred __mlx4_qp_release_range(dev, base, count); 2101255932Salfred break; 2102255932Salfred case RES_OP_MAP_ICM: 2103255932Salfred qpn = get_param_l(&in_param) & 0x7fffff; 2104255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, 2105255932Salfred NULL, 0); 2106255932Salfred if (err) 2107255932Salfred return err; 2108255932Salfred 2109255932Salfred if (!fw_reserved(dev, qpn)) 2110255932Salfred __mlx4_qp_free_icm(dev, qpn); 2111255932Salfred 2112255932Salfred res_end_move(dev, slave, RES_QP, qpn); 2113255932Salfred 2114255932Salfred if (valid_reserved(dev, slave, qpn)) 2115255932Salfred err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); 2116255932Salfred break; 2117255932Salfred default: 2118255932Salfred err = -EINVAL; 2119255932Salfred break; 2120255932Salfred } 2121255932Salfred return err; 2122255932Salfred} 2123255932Salfred 2124255932Salfredstatic int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2125255932Salfred u64 in_param, u64 *out_param) 2126255932Salfred{ 2127255932Salfred int err = -EINVAL; 2128255932Salfred int base; 2129255932Salfred int order; 2130255932Salfred 2131255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 2132255932Salfred return err; 2133255932Salfred 2134255932Salfred base = get_param_l(&in_param); 2135255932Salfred order = get_param_h(&in_param); 2136255932Salfred err = rem_res_range(dev, slave, base, 1, RES_MTT, order); 2137255932Salfred if (!err) { 2138255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 2139255932Salfred __mlx4_free_mtt_range(dev, base, order); 2140255932Salfred } 2141255932Salfred return err; 2142255932Salfred} 2143255932Salfred 2144255932Salfredstatic int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2145255932Salfred u64 in_param) 2146255932Salfred{ 2147255932Salfred int err = -EINVAL; 2148255932Salfred int index; 2149255932Salfred int id; 2150255932Salfred struct res_mpt *mpt; 2151255932Salfred 2152255932Salfred switch (op) { 2153255932Salfred case RES_OP_RESERVE: 2154255932Salfred index = get_param_l(&in_param); 2155255932Salfred id = index & mpt_mask(dev); 2156255932Salfred err = get_res(dev, slave, id, RES_MPT, &mpt); 2157255932Salfred if (err) 2158255932Salfred break; 2159255932Salfred index = mpt->key; 2160255932Salfred put_res(dev, slave, id, RES_MPT); 2161255932Salfred 2162255932Salfred err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); 2163255932Salfred if (err) 2164255932Salfred break; 2165255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 2166272027Shselasky __mlx4_mpt_release(dev, index); 2167255932Salfred break; 2168255932Salfred case RES_OP_MAP_ICM: 2169255932Salfred index = get_param_l(&in_param); 2170255932Salfred id = index & mpt_mask(dev); 2171255932Salfred err = mr_res_start_move_to(dev, slave, id, 2172255932Salfred RES_MPT_RESERVED, &mpt); 2173255932Salfred if (err) 2174255932Salfred return err; 2175255932Salfred 2176272027Shselasky __mlx4_mpt_free_icm(dev, mpt->key); 2177255932Salfred res_end_move(dev, slave, RES_MPT, id); 2178255932Salfred return err; 2179255932Salfred break; 2180255932Salfred default: 2181255932Salfred err = -EINVAL; 2182255932Salfred break; 2183255932Salfred } 2184255932Salfred return err; 2185255932Salfred} 2186255932Salfred 2187255932Salfredstatic int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2188255932Salfred u64 in_param, u64 *out_param) 2189255932Salfred{ 2190255932Salfred int cqn; 2191255932Salfred int err; 2192255932Salfred 2193255932Salfred switch (op) { 2194255932Salfred case RES_OP_RESERVE_AND_MAP: 2195255932Salfred cqn = get_param_l(&in_param); 2196255932Salfred err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); 2197255932Salfred if (err) 2198255932Salfred break; 2199255932Salfred 2200255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 2201255932Salfred __mlx4_cq_free_icm(dev, cqn); 2202255932Salfred break; 2203255932Salfred 2204255932Salfred default: 2205255932Salfred err = -EINVAL; 2206255932Salfred break; 2207255932Salfred } 2208255932Salfred 2209255932Salfred return err; 2210255932Salfred} 2211255932Salfred 2212255932Salfredstatic int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2213255932Salfred u64 in_param, u64 *out_param) 2214255932Salfred{ 2215255932Salfred int srqn; 2216255932Salfred int err; 2217255932Salfred 2218255932Salfred switch (op) { 2219255932Salfred case RES_OP_RESERVE_AND_MAP: 2220255932Salfred srqn = get_param_l(&in_param); 2221255932Salfred err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 2222255932Salfred if (err) 2223255932Salfred break; 2224255932Salfred 2225255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 2226255932Salfred __mlx4_srq_free_icm(dev, srqn); 2227255932Salfred break; 2228255932Salfred 2229255932Salfred default: 2230255932Salfred err = -EINVAL; 2231255932Salfred break; 2232255932Salfred } 2233255932Salfred 2234255932Salfred return err; 2235255932Salfred} 2236255932Salfred 2237255932Salfredstatic int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2238255932Salfred u64 in_param, u64 *out_param, int in_port) 2239255932Salfred{ 2240255932Salfred int port; 2241255932Salfred int err = 0; 2242255932Salfred 2243255932Salfred switch (op) { 2244255932Salfred case RES_OP_RESERVE_AND_MAP: 2245255932Salfred port = !in_port ? get_param_l(out_param) : in_port; 2246255932Salfred mac_del_from_slave(dev, slave, in_param, port); 2247255932Salfred __mlx4_unregister_mac(dev, port, in_param); 2248255932Salfred break; 2249255932Salfred default: 2250255932Salfred err = -EINVAL; 2251255932Salfred break; 2252255932Salfred } 2253255932Salfred 2254255932Salfred return err; 2255255932Salfred 2256255932Salfred} 2257255932Salfred 2258255932Salfredstatic int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2259255932Salfred u64 in_param, u64 *out_param, int port) 2260255932Salfred{ 2261272027Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 2262272027Shselasky struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 2263255932Salfred int err = 0; 2264255932Salfred 2265255932Salfred switch (op) { 2266255932Salfred case RES_OP_RESERVE_AND_MAP: 2267272027Shselasky if (slave_state[slave].old_vlan_api == true) 2268272027Shselasky return 0; 2269255932Salfred if (!port) 2270255932Salfred return -EINVAL; 2271255932Salfred vlan_del_from_slave(dev, slave, in_param, port); 2272255932Salfred __mlx4_unregister_vlan(dev, port, in_param); 2273255932Salfred break; 2274255932Salfred default: 2275255932Salfred err = -EINVAL; 2276255932Salfred break; 2277255932Salfred } 2278255932Salfred 2279255932Salfred return err; 2280255932Salfred} 2281255932Salfred 2282255932Salfredstatic int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2283272027Shselasky u64 in_param, u64 *out_param, int port) 2284255932Salfred{ 2285255932Salfred int index; 2286255932Salfred 2287255932Salfred if (op != RES_OP_RESERVE) 2288255932Salfred return -EINVAL; 2289255932Salfred 2290255932Salfred index = get_param_l(&in_param); 2291255932Salfred 2292272027Shselasky __mlx4_counter_free(dev, slave, port, index); 2293255932Salfred 2294272027Shselasky return 0; 2295255932Salfred} 2296255932Salfred 2297255932Salfredstatic int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2298255932Salfred u64 in_param, u64 *out_param) 2299255932Salfred{ 2300255932Salfred int xrcdn; 2301255932Salfred int err; 2302255932Salfred 2303255932Salfred if (op != RES_OP_RESERVE) 2304255932Salfred return -EINVAL; 2305255932Salfred 2306255932Salfred xrcdn = get_param_l(&in_param); 2307255932Salfred err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 2308255932Salfred if (err) 2309255932Salfred return err; 2310255932Salfred 2311255932Salfred __mlx4_xrcd_free(dev, xrcdn); 2312255932Salfred 2313255932Salfred return err; 2314255932Salfred} 2315255932Salfred 2316255932Salfredint mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, 2317255932Salfred struct mlx4_vhcr *vhcr, 2318255932Salfred struct mlx4_cmd_mailbox *inbox, 2319255932Salfred struct mlx4_cmd_mailbox *outbox, 2320255932Salfred struct mlx4_cmd_info *cmd) 2321255932Salfred{ 2322255932Salfred int err = -EINVAL; 2323255932Salfred int alop = vhcr->op_modifier; 2324255932Salfred 2325255932Salfred switch (vhcr->in_modifier & 0xFF) { 2326255932Salfred case RES_QP: 2327255932Salfred err = qp_free_res(dev, slave, vhcr->op_modifier, alop, 2328255932Salfred vhcr->in_param); 2329255932Salfred break; 2330255932Salfred 2331255932Salfred case RES_MTT: 2332255932Salfred err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, 2333255932Salfred vhcr->in_param, &vhcr->out_param); 2334255932Salfred break; 2335255932Salfred 2336255932Salfred case RES_MPT: 2337255932Salfred err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, 2338255932Salfred vhcr->in_param); 2339255932Salfred break; 2340255932Salfred 2341255932Salfred case RES_CQ: 2342255932Salfred err = cq_free_res(dev, slave, vhcr->op_modifier, alop, 2343255932Salfred vhcr->in_param, &vhcr->out_param); 2344255932Salfred break; 2345255932Salfred 2346255932Salfred case RES_SRQ: 2347255932Salfred err = srq_free_res(dev, slave, vhcr->op_modifier, alop, 2348255932Salfred vhcr->in_param, &vhcr->out_param); 2349255932Salfred break; 2350255932Salfred 2351255932Salfred case RES_MAC: 2352255932Salfred err = mac_free_res(dev, slave, vhcr->op_modifier, alop, 2353255932Salfred vhcr->in_param, &vhcr->out_param, 2354255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2355255932Salfred break; 2356255932Salfred 2357255932Salfred case RES_VLAN: 2358255932Salfred err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, 2359255932Salfred vhcr->in_param, &vhcr->out_param, 2360255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2361255932Salfred break; 2362255932Salfred 2363255932Salfred case RES_COUNTER: 2364255932Salfred err = counter_free_res(dev, slave, vhcr->op_modifier, alop, 2365272027Shselasky vhcr->in_param, &vhcr->out_param, 2366272027Shselasky (vhcr->in_modifier >> 8) & 0xFF); 2367255932Salfred break; 2368255932Salfred 2369255932Salfred case RES_XRCD: 2370255932Salfred err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, 2371255932Salfred vhcr->in_param, &vhcr->out_param); 2372255932Salfred 2373255932Salfred default: 2374255932Salfred break; 2375255932Salfred } 2376255932Salfred return err; 2377255932Salfred} 2378255932Salfred 2379255932Salfred/* ugly but other choices are uglier */ 2380255932Salfredstatic int mr_phys_mpt(struct mlx4_mpt_entry *mpt) 2381255932Salfred{ 2382255932Salfred return (be32_to_cpu(mpt->flags) >> 9) & 1; 2383255932Salfred} 2384255932Salfred 2385255932Salfredstatic int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) 2386255932Salfred{ 2387255932Salfred return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; 2388255932Salfred} 2389255932Salfred 2390255932Salfredstatic int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) 2391255932Salfred{ 2392255932Salfred return be32_to_cpu(mpt->mtt_sz); 2393255932Salfred} 2394255932Salfred 2395272027Shselaskystatic u32 mr_get_pd(struct mlx4_mpt_entry *mpt) 2396272027Shselasky{ 2397272027Shselasky return be32_to_cpu(mpt->pd_flags) & 0x00ffffff; 2398272027Shselasky} 2399272027Shselasky 2400272027Shselaskystatic int mr_is_fmr(struct mlx4_mpt_entry *mpt) 2401272027Shselasky{ 2402272027Shselasky return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG; 2403272027Shselasky} 2404272027Shselasky 2405272027Shselaskystatic int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt) 2406272027Shselasky{ 2407272027Shselasky return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE; 2408272027Shselasky} 2409272027Shselasky 2410272027Shselaskystatic int mr_is_region(struct mlx4_mpt_entry *mpt) 2411272027Shselasky{ 2412272027Shselasky return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION; 2413272027Shselasky} 2414272027Shselasky 2415255932Salfredstatic int qp_get_mtt_addr(struct mlx4_qp_context *qpc) 2416255932Salfred{ 2417255932Salfred return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; 2418255932Salfred} 2419255932Salfred 2420255932Salfredstatic int srq_get_mtt_addr(struct mlx4_srq_context *srqc) 2421255932Salfred{ 2422255932Salfred return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; 2423255932Salfred} 2424255932Salfred 2425255932Salfredstatic int qp_get_mtt_size(struct mlx4_qp_context *qpc) 2426255932Salfred{ 2427255932Salfred int page_shift = (qpc->log_page_size & 0x3f) + 12; 2428255932Salfred int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; 2429255932Salfred int log_sq_sride = qpc->sq_size_stride & 7; 2430255932Salfred int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; 2431255932Salfred int log_rq_stride = qpc->rq_size_stride & 7; 2432255932Salfred int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; 2433255932Salfred int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; 2434272027Shselasky u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 2435272027Shselasky int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0; 2436255932Salfred int sq_size; 2437255932Salfred int rq_size; 2438255932Salfred int total_pages; 2439255932Salfred int total_mem; 2440255932Salfred int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; 2441255932Salfred 2442255932Salfred sq_size = 1 << (log_sq_size + log_sq_sride + 4); 2443255932Salfred rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); 2444255932Salfred total_mem = sq_size + rq_size; 2445255932Salfred total_pages = 2446255932Salfred roundup_pow_of_two((total_mem + (page_offset << 6)) >> 2447255932Salfred page_shift); 2448255932Salfred 2449255932Salfred return total_pages; 2450255932Salfred} 2451255932Salfred 2452255932Salfredstatic int check_mtt_range(struct mlx4_dev *dev, int slave, int start, 2453255932Salfred int size, struct res_mtt *mtt) 2454255932Salfred{ 2455255932Salfred int res_start = mtt->com.res_id; 2456255932Salfred int res_size = (1 << mtt->order); 2457255932Salfred 2458255932Salfred if (start < res_start || start + size > res_start + res_size) 2459255932Salfred return -EPERM; 2460255932Salfred return 0; 2461255932Salfred} 2462255932Salfred 2463255932Salfredint mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, 2464255932Salfred struct mlx4_vhcr *vhcr, 2465255932Salfred struct mlx4_cmd_mailbox *inbox, 2466255932Salfred struct mlx4_cmd_mailbox *outbox, 2467255932Salfred struct mlx4_cmd_info *cmd) 2468255932Salfred{ 2469255932Salfred int err; 2470255932Salfred int index = vhcr->in_modifier; 2471255932Salfred struct res_mtt *mtt; 2472255932Salfred struct res_mpt *mpt; 2473255932Salfred int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; 2474255932Salfred int phys; 2475255932Salfred int id; 2476272027Shselasky u32 pd; 2477272027Shselasky int pd_slave; 2478255932Salfred 2479255932Salfred id = index & mpt_mask(dev); 2480255932Salfred err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); 2481255932Salfred if (err) 2482255932Salfred return err; 2483255932Salfred 2484272027Shselasky /* Currently disable memory windows since this feature isn't tested yet 2485272027Shselasky * under virtualization. 2486272027Shselasky */ 2487272027Shselasky if (!mr_is_region(inbox->buf)) { 2488272027Shselasky err = -ENOSYS; 2489272027Shselasky goto ex_abort; 2490272027Shselasky } 2491272027Shselasky 2492272027Shselasky /* Make sure that the PD bits related to the slave id are zeros. */ 2493272027Shselasky pd = mr_get_pd(inbox->buf); 2494272027Shselasky pd_slave = (pd >> 17) & 0x7f; 2495272027Shselasky if (pd_slave != 0 && pd_slave != slave) { 2496272027Shselasky err = -EPERM; 2497272027Shselasky goto ex_abort; 2498272027Shselasky } 2499272027Shselasky 2500272027Shselasky if (mr_is_fmr(inbox->buf)) { 2501272027Shselasky /* FMR and Bind Enable are forbidden in slave devices. */ 2502272027Shselasky if (mr_is_bind_enabled(inbox->buf)) { 2503272027Shselasky err = -EPERM; 2504272027Shselasky goto ex_abort; 2505272027Shselasky } 2506272027Shselasky /* FMR and Memory Windows are also forbidden. */ 2507272027Shselasky if (!mr_is_region(inbox->buf)) { 2508272027Shselasky err = -EPERM; 2509272027Shselasky goto ex_abort; 2510272027Shselasky } 2511272027Shselasky } 2512272027Shselasky 2513255932Salfred phys = mr_phys_mpt(inbox->buf); 2514255932Salfred if (!phys) { 2515255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2516255932Salfred if (err) 2517255932Salfred goto ex_abort; 2518255932Salfred 2519255932Salfred err = check_mtt_range(dev, slave, mtt_base, 2520255932Salfred mr_get_mtt_size(inbox->buf), mtt); 2521255932Salfred if (err) 2522255932Salfred goto ex_put; 2523255932Salfred 2524255932Salfred mpt->mtt = mtt; 2525255932Salfred } 2526255932Salfred 2527255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2528255932Salfred if (err) 2529255932Salfred goto ex_put; 2530255932Salfred 2531255932Salfred if (!phys) { 2532255932Salfred atomic_inc(&mtt->ref_count); 2533255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2534255932Salfred } 2535255932Salfred 2536255932Salfred res_end_move(dev, slave, RES_MPT, id); 2537255932Salfred return 0; 2538255932Salfred 2539255932Salfredex_put: 2540255932Salfred if (!phys) 2541255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2542255932Salfredex_abort: 2543255932Salfred res_abort_move(dev, slave, RES_MPT, id); 2544255932Salfred 2545255932Salfred return err; 2546255932Salfred} 2547255932Salfred 2548255932Salfredint mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, 2549255932Salfred struct mlx4_vhcr *vhcr, 2550255932Salfred struct mlx4_cmd_mailbox *inbox, 2551255932Salfred struct mlx4_cmd_mailbox *outbox, 2552255932Salfred struct mlx4_cmd_info *cmd) 2553255932Salfred{ 2554255932Salfred int err; 2555255932Salfred int index = vhcr->in_modifier; 2556255932Salfred struct res_mpt *mpt; 2557255932Salfred int id; 2558255932Salfred 2559255932Salfred id = index & mpt_mask(dev); 2560255932Salfred err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); 2561255932Salfred if (err) 2562255932Salfred return err; 2563255932Salfred 2564255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2565255932Salfred if (err) 2566255932Salfred goto ex_abort; 2567255932Salfred 2568255932Salfred if (mpt->mtt) 2569255932Salfred atomic_dec(&mpt->mtt->ref_count); 2570255932Salfred 2571255932Salfred res_end_move(dev, slave, RES_MPT, id); 2572255932Salfred return 0; 2573255932Salfred 2574255932Salfredex_abort: 2575255932Salfred res_abort_move(dev, slave, RES_MPT, id); 2576255932Salfred 2577255932Salfred return err; 2578255932Salfred} 2579255932Salfred 2580255932Salfredint mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, 2581255932Salfred struct mlx4_vhcr *vhcr, 2582255932Salfred struct mlx4_cmd_mailbox *inbox, 2583255932Salfred struct mlx4_cmd_mailbox *outbox, 2584255932Salfred struct mlx4_cmd_info *cmd) 2585255932Salfred{ 2586255932Salfred int err; 2587255932Salfred int index = vhcr->in_modifier; 2588255932Salfred struct res_mpt *mpt; 2589255932Salfred int id; 2590255932Salfred 2591255932Salfred id = index & mpt_mask(dev); 2592255932Salfred err = get_res(dev, slave, id, RES_MPT, &mpt); 2593255932Salfred if (err) 2594255932Salfred return err; 2595255932Salfred 2596255932Salfred if (mpt->com.from_state != RES_MPT_HW) { 2597255932Salfred err = -EBUSY; 2598255932Salfred goto out; 2599255932Salfred } 2600255932Salfred 2601255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2602255932Salfred 2603255932Salfredout: 2604255932Salfred put_res(dev, slave, id, RES_MPT); 2605255932Salfred return err; 2606255932Salfred} 2607255932Salfred 2608255932Salfredstatic int qp_get_rcqn(struct mlx4_qp_context *qpc) 2609255932Salfred{ 2610255932Salfred return be32_to_cpu(qpc->cqn_recv) & 0xffffff; 2611255932Salfred} 2612255932Salfred 2613255932Salfredstatic int qp_get_scqn(struct mlx4_qp_context *qpc) 2614255932Salfred{ 2615255932Salfred return be32_to_cpu(qpc->cqn_send) & 0xffffff; 2616255932Salfred} 2617255932Salfred 2618255932Salfredstatic u32 qp_get_srqn(struct mlx4_qp_context *qpc) 2619255932Salfred{ 2620255932Salfred return be32_to_cpu(qpc->srqn) & 0x1ffffff; 2621255932Salfred} 2622255932Salfred 2623255932Salfredstatic void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, 2624255932Salfred struct mlx4_qp_context *context) 2625255932Salfred{ 2626255932Salfred u32 qpn = vhcr->in_modifier & 0xffffff; 2627255932Salfred u32 qkey = 0; 2628255932Salfred 2629255932Salfred if (mlx4_get_parav_qkey(dev, qpn, &qkey)) 2630255932Salfred return; 2631255932Salfred 2632255932Salfred /* adjust qkey in qp context */ 2633255932Salfred context->qkey = cpu_to_be32(qkey); 2634255932Salfred} 2635255932Salfred 2636255932Salfredint mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 2637255932Salfred struct mlx4_vhcr *vhcr, 2638255932Salfred struct mlx4_cmd_mailbox *inbox, 2639255932Salfred struct mlx4_cmd_mailbox *outbox, 2640255932Salfred struct mlx4_cmd_info *cmd) 2641255932Salfred{ 2642255932Salfred int err; 2643255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 2644255932Salfred struct res_mtt *mtt; 2645255932Salfred struct res_qp *qp; 2646255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 2647255932Salfred int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; 2648255932Salfred int mtt_size = qp_get_mtt_size(qpc); 2649255932Salfred struct res_cq *rcq; 2650255932Salfred struct res_cq *scq; 2651255932Salfred int rcqn = qp_get_rcqn(qpc); 2652255932Salfred int scqn = qp_get_scqn(qpc); 2653255932Salfred u32 srqn = qp_get_srqn(qpc) & 0xffffff; 2654255932Salfred int use_srq = (qp_get_srqn(qpc) >> 24) & 1; 2655255932Salfred struct res_srq *srq; 2656255932Salfred int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; 2657255932Salfred 2658255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); 2659255932Salfred if (err) 2660255932Salfred return err; 2661255932Salfred qp->local_qpn = local_qpn; 2662272027Shselasky qp->sched_queue = 0; 2663272027Shselasky qp->param3 = 0; 2664272027Shselasky qp->vlan_control = 0; 2665272027Shselasky qp->fvl_rx = 0; 2666272027Shselasky qp->pri_path_fl = 0; 2667272027Shselasky qp->vlan_index = 0; 2668272027Shselasky qp->feup = 0; 2669272027Shselasky qp->qpc_flags = be32_to_cpu(qpc->flags); 2670255932Salfred 2671255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2672255932Salfred if (err) 2673255932Salfred goto ex_abort; 2674255932Salfred 2675255932Salfred err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 2676255932Salfred if (err) 2677255932Salfred goto ex_put_mtt; 2678255932Salfred 2679255932Salfred err = get_res(dev, slave, rcqn, RES_CQ, &rcq); 2680255932Salfred if (err) 2681255932Salfred goto ex_put_mtt; 2682255932Salfred 2683255932Salfred if (scqn != rcqn) { 2684255932Salfred err = get_res(dev, slave, scqn, RES_CQ, &scq); 2685255932Salfred if (err) 2686255932Salfred goto ex_put_rcq; 2687255932Salfred } else 2688255932Salfred scq = rcq; 2689255932Salfred 2690255932Salfred if (use_srq) { 2691255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 2692255932Salfred if (err) 2693255932Salfred goto ex_put_scq; 2694255932Salfred } 2695255932Salfred 2696255932Salfred adjust_proxy_tun_qkey(dev, vhcr, qpc); 2697255932Salfred update_pkey_index(dev, slave, inbox); 2698255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2699255932Salfred if (err) 2700255932Salfred goto ex_put_srq; 2701255932Salfred atomic_inc(&mtt->ref_count); 2702255932Salfred qp->mtt = mtt; 2703255932Salfred atomic_inc(&rcq->ref_count); 2704255932Salfred qp->rcq = rcq; 2705255932Salfred atomic_inc(&scq->ref_count); 2706255932Salfred qp->scq = scq; 2707255932Salfred 2708255932Salfred if (scqn != rcqn) 2709255932Salfred put_res(dev, slave, scqn, RES_CQ); 2710255932Salfred 2711255932Salfred if (use_srq) { 2712255932Salfred atomic_inc(&srq->ref_count); 2713255932Salfred put_res(dev, slave, srqn, RES_SRQ); 2714255932Salfred qp->srq = srq; 2715255932Salfred } 2716255932Salfred put_res(dev, slave, rcqn, RES_CQ); 2717255932Salfred put_res(dev, slave, mtt_base, RES_MTT); 2718255932Salfred res_end_move(dev, slave, RES_QP, qpn); 2719255932Salfred 2720255932Salfred return 0; 2721255932Salfred 2722255932Salfredex_put_srq: 2723255932Salfred if (use_srq) 2724255932Salfred put_res(dev, slave, srqn, RES_SRQ); 2725255932Salfredex_put_scq: 2726255932Salfred if (scqn != rcqn) 2727255932Salfred put_res(dev, slave, scqn, RES_CQ); 2728255932Salfredex_put_rcq: 2729255932Salfred put_res(dev, slave, rcqn, RES_CQ); 2730255932Salfredex_put_mtt: 2731255932Salfred put_res(dev, slave, mtt_base, RES_MTT); 2732255932Salfredex_abort: 2733255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 2734255932Salfred 2735255932Salfred return err; 2736255932Salfred} 2737255932Salfred 2738255932Salfredstatic int eq_get_mtt_addr(struct mlx4_eq_context *eqc) 2739255932Salfred{ 2740255932Salfred return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; 2741255932Salfred} 2742255932Salfred 2743255932Salfredstatic int eq_get_mtt_size(struct mlx4_eq_context *eqc) 2744255932Salfred{ 2745255932Salfred int log_eq_size = eqc->log_eq_size & 0x1f; 2746255932Salfred int page_shift = (eqc->log_page_size & 0x3f) + 12; 2747255932Salfred 2748255932Salfred if (log_eq_size + 5 < page_shift) 2749255932Salfred return 1; 2750255932Salfred 2751255932Salfred return 1 << (log_eq_size + 5 - page_shift); 2752255932Salfred} 2753255932Salfred 2754255932Salfredstatic int cq_get_mtt_addr(struct mlx4_cq_context *cqc) 2755255932Salfred{ 2756255932Salfred return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; 2757255932Salfred} 2758255932Salfred 2759255932Salfredstatic int cq_get_mtt_size(struct mlx4_cq_context *cqc) 2760255932Salfred{ 2761255932Salfred int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; 2762255932Salfred int page_shift = (cqc->log_page_size & 0x3f) + 12; 2763255932Salfred 2764255932Salfred if (log_cq_size + 5 < page_shift) 2765255932Salfred return 1; 2766255932Salfred 2767255932Salfred return 1 << (log_cq_size + 5 - page_shift); 2768255932Salfred} 2769255932Salfred 2770255932Salfredint mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, 2771255932Salfred struct mlx4_vhcr *vhcr, 2772255932Salfred struct mlx4_cmd_mailbox *inbox, 2773255932Salfred struct mlx4_cmd_mailbox *outbox, 2774255932Salfred struct mlx4_cmd_info *cmd) 2775255932Salfred{ 2776255932Salfred int err; 2777255932Salfred int eqn = vhcr->in_modifier; 2778255932Salfred int res_id = (slave << 8) | eqn; 2779255932Salfred struct mlx4_eq_context *eqc = inbox->buf; 2780255932Salfred int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; 2781255932Salfred int mtt_size = eq_get_mtt_size(eqc); 2782255932Salfred struct res_eq *eq; 2783255932Salfred struct res_mtt *mtt; 2784255932Salfred 2785255932Salfred err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2786255932Salfred if (err) 2787255932Salfred return err; 2788255932Salfred err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); 2789255932Salfred if (err) 2790255932Salfred goto out_add; 2791255932Salfred 2792255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2793255932Salfred if (err) 2794255932Salfred goto out_move; 2795255932Salfred 2796255932Salfred err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 2797255932Salfred if (err) 2798255932Salfred goto out_put; 2799255932Salfred 2800255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2801255932Salfred if (err) 2802255932Salfred goto out_put; 2803255932Salfred 2804255932Salfred atomic_inc(&mtt->ref_count); 2805255932Salfred eq->mtt = mtt; 2806255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2807255932Salfred res_end_move(dev, slave, RES_EQ, res_id); 2808255932Salfred return 0; 2809255932Salfred 2810255932Salfredout_put: 2811255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2812255932Salfredout_move: 2813255932Salfred res_abort_move(dev, slave, RES_EQ, res_id); 2814255932Salfredout_add: 2815255932Salfred rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2816255932Salfred return err; 2817255932Salfred} 2818255932Salfred 2819255932Salfredstatic int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, 2820255932Salfred int len, struct res_mtt **res) 2821255932Salfred{ 2822255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2823255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 2824255932Salfred struct res_mtt *mtt; 2825255932Salfred int err = -EINVAL; 2826255932Salfred 2827255932Salfred spin_lock_irq(mlx4_tlock(dev)); 2828255932Salfred list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], 2829255932Salfred com.list) { 2830255932Salfred if (!check_mtt_range(dev, slave, start, len, mtt)) { 2831255932Salfred *res = mtt; 2832255932Salfred mtt->com.from_state = mtt->com.state; 2833255932Salfred mtt->com.state = RES_MTT_BUSY; 2834255932Salfred err = 0; 2835255932Salfred break; 2836255932Salfred } 2837255932Salfred } 2838255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 2839255932Salfred 2840255932Salfred return err; 2841255932Salfred} 2842255932Salfred 2843255932Salfredstatic int verify_qp_parameters(struct mlx4_dev *dev, 2844255932Salfred struct mlx4_cmd_mailbox *inbox, 2845255932Salfred enum qp_transition transition, u8 slave) 2846255932Salfred{ 2847255932Salfred u32 qp_type; 2848255932Salfred struct mlx4_qp_context *qp_ctx; 2849255932Salfred enum mlx4_qp_optpar optpar; 2850255932Salfred int port; 2851255932Salfred int num_gids; 2852255932Salfred 2853255932Salfred qp_ctx = inbox->buf + 8; 2854255932Salfred qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 2855255932Salfred optpar = be32_to_cpu(*(__be32 *) inbox->buf); 2856255932Salfred 2857255932Salfred switch (qp_type) { 2858255932Salfred case MLX4_QP_ST_RC: 2859255932Salfred case MLX4_QP_ST_UC: 2860255932Salfred switch (transition) { 2861255932Salfred case QP_TRANS_INIT2RTR: 2862255932Salfred case QP_TRANS_RTR2RTS: 2863255932Salfred case QP_TRANS_RTS2RTS: 2864255932Salfred case QP_TRANS_SQD2SQD: 2865255932Salfred case QP_TRANS_SQD2RTS: 2866255932Salfred if (slave != mlx4_master_func_num(dev)) 2867255932Salfred if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 2868255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 2869255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 2870255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 2871255932Salfred else 2872255932Salfred num_gids = 1; 2873255932Salfred if (qp_ctx->pri_path.mgid_index >= num_gids) 2874255932Salfred return -EINVAL; 2875255932Salfred } 2876255932Salfred if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 2877255932Salfred port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 2878255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 2879255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 2880255932Salfred else 2881255932Salfred num_gids = 1; 2882255932Salfred if (qp_ctx->alt_path.mgid_index >= num_gids) 2883255932Salfred return -EINVAL; 2884255932Salfred } 2885255932Salfred break; 2886255932Salfred default: 2887255932Salfred break; 2888255932Salfred } 2889255932Salfred 2890255932Salfred break; 2891255932Salfred default: 2892255932Salfred break; 2893255932Salfred } 2894255932Salfred 2895255932Salfred return 0; 2896255932Salfred} 2897255932Salfred 2898255932Salfredint mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, 2899255932Salfred struct mlx4_vhcr *vhcr, 2900255932Salfred struct mlx4_cmd_mailbox *inbox, 2901255932Salfred struct mlx4_cmd_mailbox *outbox, 2902255932Salfred struct mlx4_cmd_info *cmd) 2903255932Salfred{ 2904255932Salfred struct mlx4_mtt mtt; 2905255932Salfred __be64 *page_list = inbox->buf; 2906255932Salfred u64 *pg_list = (u64 *)page_list; 2907255932Salfred int i; 2908255932Salfred struct res_mtt *rmtt = NULL; 2909255932Salfred int start = be64_to_cpu(page_list[0]); 2910255932Salfred int npages = vhcr->in_modifier; 2911255932Salfred int err; 2912255932Salfred 2913255932Salfred err = get_containing_mtt(dev, slave, start, npages, &rmtt); 2914255932Salfred if (err) 2915255932Salfred return err; 2916255932Salfred 2917255932Salfred /* Call the SW implementation of write_mtt: 2918255932Salfred * - Prepare a dummy mtt struct 2919255932Salfred * - Translate inbox contents to simple addresses in host endianess */ 2920255932Salfred mtt.offset = 0; /* TBD this is broken but I don't handle it since 2921255932Salfred we don't really use it */ 2922255932Salfred mtt.order = 0; 2923255932Salfred mtt.page_shift = 0; 2924255932Salfred for (i = 0; i < npages; ++i) 2925255932Salfred pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); 2926255932Salfred 2927255932Salfred err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, 2928255932Salfred ((u64 *)page_list + 2)); 2929255932Salfred 2930255932Salfred if (rmtt) 2931255932Salfred put_res(dev, slave, rmtt->com.res_id, RES_MTT); 2932255932Salfred 2933255932Salfred return err; 2934255932Salfred} 2935255932Salfred 2936255932Salfredint mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, 2937255932Salfred struct mlx4_vhcr *vhcr, 2938255932Salfred struct mlx4_cmd_mailbox *inbox, 2939255932Salfred struct mlx4_cmd_mailbox *outbox, 2940255932Salfred struct mlx4_cmd_info *cmd) 2941255932Salfred{ 2942255932Salfred int eqn = vhcr->in_modifier; 2943255932Salfred int res_id = eqn | (slave << 8); 2944255932Salfred struct res_eq *eq; 2945255932Salfred int err; 2946255932Salfred 2947255932Salfred err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); 2948255932Salfred if (err) 2949255932Salfred return err; 2950255932Salfred 2951255932Salfred err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); 2952255932Salfred if (err) 2953255932Salfred goto ex_abort; 2954255932Salfred 2955255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2956255932Salfred if (err) 2957255932Salfred goto ex_put; 2958255932Salfred 2959255932Salfred atomic_dec(&eq->mtt->ref_count); 2960255932Salfred put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 2961255932Salfred res_end_move(dev, slave, RES_EQ, res_id); 2962255932Salfred rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2963255932Salfred 2964255932Salfred return 0; 2965255932Salfred 2966255932Salfredex_put: 2967255932Salfred put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 2968255932Salfredex_abort: 2969255932Salfred res_abort_move(dev, slave, RES_EQ, res_id); 2970255932Salfred 2971255932Salfred return err; 2972255932Salfred} 2973255932Salfred 2974255932Salfredint mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) 2975255932Salfred{ 2976255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2977255932Salfred struct mlx4_slave_event_eq_info *event_eq; 2978255932Salfred struct mlx4_cmd_mailbox *mailbox; 2979255932Salfred u32 in_modifier = 0; 2980255932Salfred int err; 2981255932Salfred int res_id; 2982255932Salfred struct res_eq *req; 2983255932Salfred 2984255932Salfred if (!priv->mfunc.master.slave_state) 2985255932Salfred return -EINVAL; 2986255932Salfred 2987272027Shselasky /* check for slave valid, slave not PF, and slave active */ 2988272027Shselasky if (slave < 0 || slave >= dev->num_slaves || 2989272027Shselasky slave == dev->caps.function || 2990272027Shselasky !priv->mfunc.master.slave_state[slave].active) 2991272027Shselasky return 0; 2992272027Shselasky 2993255932Salfred event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; 2994255932Salfred 2995255932Salfred /* Create the event only if the slave is registered */ 2996255932Salfred if (event_eq->eqn < 0) 2997255932Salfred return 0; 2998255932Salfred 2999255932Salfred mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); 3000255932Salfred res_id = (slave << 8) | event_eq->eqn; 3001255932Salfred err = get_res(dev, slave, res_id, RES_EQ, &req); 3002255932Salfred if (err) 3003255932Salfred goto unlock; 3004255932Salfred 3005255932Salfred if (req->com.from_state != RES_EQ_HW) { 3006255932Salfred err = -EINVAL; 3007255932Salfred goto put; 3008255932Salfred } 3009255932Salfred 3010255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 3011255932Salfred if (IS_ERR(mailbox)) { 3012255932Salfred err = PTR_ERR(mailbox); 3013255932Salfred goto put; 3014255932Salfred } 3015255932Salfred 3016255932Salfred if (eqe->type == MLX4_EVENT_TYPE_CMD) { 3017255932Salfred ++event_eq->token; 3018255932Salfred eqe->event.cmd.token = cpu_to_be16(event_eq->token); 3019255932Salfred } 3020255932Salfred 3021255932Salfred memcpy(mailbox->buf, (u8 *) eqe, 28); 3022255932Salfred 3023255932Salfred in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); 3024255932Salfred 3025255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, 3026255932Salfred MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, 3027255932Salfred MLX4_CMD_NATIVE); 3028255932Salfred 3029255932Salfred put_res(dev, slave, res_id, RES_EQ); 3030255932Salfred mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 3031255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 3032255932Salfred return err; 3033255932Salfred 3034255932Salfredput: 3035255932Salfred put_res(dev, slave, res_id, RES_EQ); 3036255932Salfred 3037255932Salfredunlock: 3038255932Salfred mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 3039255932Salfred return err; 3040255932Salfred} 3041255932Salfred 3042255932Salfredint mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, 3043255932Salfred struct mlx4_vhcr *vhcr, 3044255932Salfred struct mlx4_cmd_mailbox *inbox, 3045255932Salfred struct mlx4_cmd_mailbox *outbox, 3046255932Salfred struct mlx4_cmd_info *cmd) 3047255932Salfred{ 3048255932Salfred int eqn = vhcr->in_modifier; 3049255932Salfred int res_id = eqn | (slave << 8); 3050255932Salfred struct res_eq *eq; 3051255932Salfred int err; 3052255932Salfred 3053255932Salfred err = get_res(dev, slave, res_id, RES_EQ, &eq); 3054255932Salfred if (err) 3055255932Salfred return err; 3056255932Salfred 3057255932Salfred if (eq->com.from_state != RES_EQ_HW) { 3058255932Salfred err = -EINVAL; 3059255932Salfred goto ex_put; 3060255932Salfred } 3061255932Salfred 3062255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3063255932Salfred 3064255932Salfredex_put: 3065255932Salfred put_res(dev, slave, res_id, RES_EQ); 3066255932Salfred return err; 3067255932Salfred} 3068255932Salfred 3069255932Salfredint mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, 3070255932Salfred struct mlx4_vhcr *vhcr, 3071255932Salfred struct mlx4_cmd_mailbox *inbox, 3072255932Salfred struct mlx4_cmd_mailbox *outbox, 3073255932Salfred struct mlx4_cmd_info *cmd) 3074255932Salfred{ 3075255932Salfred int err; 3076255932Salfred int cqn = vhcr->in_modifier; 3077255932Salfred struct mlx4_cq_context *cqc = inbox->buf; 3078255932Salfred int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 3079255932Salfred struct res_cq *cq; 3080255932Salfred struct res_mtt *mtt; 3081255932Salfred 3082255932Salfred err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); 3083255932Salfred if (err) 3084255932Salfred return err; 3085255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3086255932Salfred if (err) 3087255932Salfred goto out_move; 3088255932Salfred err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 3089255932Salfred if (err) 3090255932Salfred goto out_put; 3091255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3092255932Salfred if (err) 3093255932Salfred goto out_put; 3094255932Salfred atomic_inc(&mtt->ref_count); 3095255932Salfred cq->mtt = mtt; 3096255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3097255932Salfred res_end_move(dev, slave, RES_CQ, cqn); 3098255932Salfred return 0; 3099255932Salfred 3100255932Salfredout_put: 3101255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3102255932Salfredout_move: 3103255932Salfred res_abort_move(dev, slave, RES_CQ, cqn); 3104255932Salfred return err; 3105255932Salfred} 3106255932Salfred 3107255932Salfredint mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, 3108255932Salfred struct mlx4_vhcr *vhcr, 3109255932Salfred struct mlx4_cmd_mailbox *inbox, 3110255932Salfred struct mlx4_cmd_mailbox *outbox, 3111255932Salfred struct mlx4_cmd_info *cmd) 3112255932Salfred{ 3113255932Salfred int err; 3114255932Salfred int cqn = vhcr->in_modifier; 3115255932Salfred struct res_cq *cq; 3116255932Salfred 3117255932Salfred err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); 3118255932Salfred if (err) 3119255932Salfred return err; 3120255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3121255932Salfred if (err) 3122255932Salfred goto out_move; 3123255932Salfred atomic_dec(&cq->mtt->ref_count); 3124255932Salfred res_end_move(dev, slave, RES_CQ, cqn); 3125255932Salfred return 0; 3126255932Salfred 3127255932Salfredout_move: 3128255932Salfred res_abort_move(dev, slave, RES_CQ, cqn); 3129255932Salfred return err; 3130255932Salfred} 3131255932Salfred 3132255932Salfredint mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, 3133255932Salfred struct mlx4_vhcr *vhcr, 3134255932Salfred struct mlx4_cmd_mailbox *inbox, 3135255932Salfred struct mlx4_cmd_mailbox *outbox, 3136255932Salfred struct mlx4_cmd_info *cmd) 3137255932Salfred{ 3138255932Salfred int cqn = vhcr->in_modifier; 3139255932Salfred struct res_cq *cq; 3140255932Salfred int err; 3141255932Salfred 3142255932Salfred err = get_res(dev, slave, cqn, RES_CQ, &cq); 3143255932Salfred if (err) 3144255932Salfred return err; 3145255932Salfred 3146255932Salfred if (cq->com.from_state != RES_CQ_HW) 3147255932Salfred goto ex_put; 3148255932Salfred 3149255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3150255932Salfredex_put: 3151255932Salfred put_res(dev, slave, cqn, RES_CQ); 3152255932Salfred 3153255932Salfred return err; 3154255932Salfred} 3155255932Salfred 3156255932Salfredstatic int handle_resize(struct mlx4_dev *dev, int slave, 3157255932Salfred struct mlx4_vhcr *vhcr, 3158255932Salfred struct mlx4_cmd_mailbox *inbox, 3159255932Salfred struct mlx4_cmd_mailbox *outbox, 3160255932Salfred struct mlx4_cmd_info *cmd, 3161255932Salfred struct res_cq *cq) 3162255932Salfred{ 3163255932Salfred int err; 3164255932Salfred struct res_mtt *orig_mtt; 3165255932Salfred struct res_mtt *mtt; 3166255932Salfred struct mlx4_cq_context *cqc = inbox->buf; 3167255932Salfred int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 3168255932Salfred 3169255932Salfred err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); 3170255932Salfred if (err) 3171255932Salfred return err; 3172255932Salfred 3173255932Salfred if (orig_mtt != cq->mtt) { 3174255932Salfred err = -EINVAL; 3175255932Salfred goto ex_put; 3176255932Salfred } 3177255932Salfred 3178255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3179255932Salfred if (err) 3180255932Salfred goto ex_put; 3181255932Salfred 3182255932Salfred err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 3183255932Salfred if (err) 3184255932Salfred goto ex_put1; 3185255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3186255932Salfred if (err) 3187255932Salfred goto ex_put1; 3188255932Salfred atomic_dec(&orig_mtt->ref_count); 3189255932Salfred put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 3190255932Salfred atomic_inc(&mtt->ref_count); 3191255932Salfred cq->mtt = mtt; 3192255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3193255932Salfred return 0; 3194255932Salfred 3195255932Salfredex_put1: 3196255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3197255932Salfredex_put: 3198255932Salfred put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 3199255932Salfred 3200255932Salfred return err; 3201255932Salfred 3202255932Salfred} 3203255932Salfred 3204255932Salfredint mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, 3205255932Salfred struct mlx4_vhcr *vhcr, 3206255932Salfred struct mlx4_cmd_mailbox *inbox, 3207255932Salfred struct mlx4_cmd_mailbox *outbox, 3208255932Salfred struct mlx4_cmd_info *cmd) 3209255932Salfred{ 3210255932Salfred int cqn = vhcr->in_modifier; 3211255932Salfred struct res_cq *cq; 3212255932Salfred int err; 3213255932Salfred 3214255932Salfred err = get_res(dev, slave, cqn, RES_CQ, &cq); 3215255932Salfred if (err) 3216255932Salfred return err; 3217255932Salfred 3218255932Salfred if (cq->com.from_state != RES_CQ_HW) 3219255932Salfred goto ex_put; 3220255932Salfred 3221255932Salfred if (vhcr->op_modifier == 0) { 3222255932Salfred err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); 3223255932Salfred goto ex_put; 3224255932Salfred } 3225255932Salfred 3226255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3227255932Salfredex_put: 3228255932Salfred put_res(dev, slave, cqn, RES_CQ); 3229255932Salfred 3230255932Salfred return err; 3231255932Salfred} 3232255932Salfred 3233255932Salfredstatic int srq_get_mtt_size(struct mlx4_srq_context *srqc) 3234255932Salfred{ 3235255932Salfred int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; 3236255932Salfred int log_rq_stride = srqc->logstride & 7; 3237255932Salfred int page_shift = (srqc->log_page_size & 0x3f) + 12; 3238255932Salfred 3239255932Salfred if (log_srq_size + log_rq_stride + 4 < page_shift) 3240255932Salfred return 1; 3241255932Salfred 3242255932Salfred return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); 3243255932Salfred} 3244255932Salfred 3245255932Salfredint mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3246255932Salfred struct mlx4_vhcr *vhcr, 3247255932Salfred struct mlx4_cmd_mailbox *inbox, 3248255932Salfred struct mlx4_cmd_mailbox *outbox, 3249255932Salfred struct mlx4_cmd_info *cmd) 3250255932Salfred{ 3251255932Salfred int err; 3252255932Salfred int srqn = vhcr->in_modifier; 3253255932Salfred struct res_mtt *mtt; 3254255932Salfred struct res_srq *srq; 3255255932Salfred struct mlx4_srq_context *srqc = inbox->buf; 3256255932Salfred int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; 3257255932Salfred 3258255932Salfred if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) 3259255932Salfred return -EINVAL; 3260255932Salfred 3261255932Salfred err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); 3262255932Salfred if (err) 3263255932Salfred return err; 3264255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3265255932Salfred if (err) 3266255932Salfred goto ex_abort; 3267255932Salfred err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), 3268255932Salfred mtt); 3269255932Salfred if (err) 3270255932Salfred goto ex_put_mtt; 3271255932Salfred 3272255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3273255932Salfred if (err) 3274255932Salfred goto ex_put_mtt; 3275255932Salfred 3276255932Salfred atomic_inc(&mtt->ref_count); 3277255932Salfred srq->mtt = mtt; 3278255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3279255932Salfred res_end_move(dev, slave, RES_SRQ, srqn); 3280255932Salfred return 0; 3281255932Salfred 3282255932Salfredex_put_mtt: 3283255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3284255932Salfredex_abort: 3285255932Salfred res_abort_move(dev, slave, RES_SRQ, srqn); 3286255932Salfred 3287255932Salfred return err; 3288255932Salfred} 3289255932Salfred 3290255932Salfredint mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3291255932Salfred struct mlx4_vhcr *vhcr, 3292255932Salfred struct mlx4_cmd_mailbox *inbox, 3293255932Salfred struct mlx4_cmd_mailbox *outbox, 3294255932Salfred struct mlx4_cmd_info *cmd) 3295255932Salfred{ 3296255932Salfred int err; 3297255932Salfred int srqn = vhcr->in_modifier; 3298255932Salfred struct res_srq *srq; 3299255932Salfred 3300255932Salfred err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); 3301255932Salfred if (err) 3302255932Salfred return err; 3303255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3304255932Salfred if (err) 3305255932Salfred goto ex_abort; 3306255932Salfred atomic_dec(&srq->mtt->ref_count); 3307255932Salfred if (srq->cq) 3308255932Salfred atomic_dec(&srq->cq->ref_count); 3309255932Salfred res_end_move(dev, slave, RES_SRQ, srqn); 3310255932Salfred 3311255932Salfred return 0; 3312255932Salfred 3313255932Salfredex_abort: 3314255932Salfred res_abort_move(dev, slave, RES_SRQ, srqn); 3315255932Salfred 3316255932Salfred return err; 3317255932Salfred} 3318255932Salfred 3319255932Salfredint mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3320255932Salfred struct mlx4_vhcr *vhcr, 3321255932Salfred struct mlx4_cmd_mailbox *inbox, 3322255932Salfred struct mlx4_cmd_mailbox *outbox, 3323255932Salfred struct mlx4_cmd_info *cmd) 3324255932Salfred{ 3325255932Salfred int err; 3326255932Salfred int srqn = vhcr->in_modifier; 3327255932Salfred struct res_srq *srq; 3328255932Salfred 3329255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 3330255932Salfred if (err) 3331255932Salfred return err; 3332255932Salfred if (srq->com.from_state != RES_SRQ_HW) { 3333255932Salfred err = -EBUSY; 3334255932Salfred goto out; 3335255932Salfred } 3336255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3337255932Salfredout: 3338255932Salfred put_res(dev, slave, srqn, RES_SRQ); 3339255932Salfred return err; 3340255932Salfred} 3341255932Salfred 3342255932Salfredint mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3343255932Salfred struct mlx4_vhcr *vhcr, 3344255932Salfred struct mlx4_cmd_mailbox *inbox, 3345255932Salfred struct mlx4_cmd_mailbox *outbox, 3346255932Salfred struct mlx4_cmd_info *cmd) 3347255932Salfred{ 3348255932Salfred int err; 3349255932Salfred int srqn = vhcr->in_modifier; 3350255932Salfred struct res_srq *srq; 3351255932Salfred 3352255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 3353255932Salfred if (err) 3354255932Salfred return err; 3355255932Salfred 3356255932Salfred if (srq->com.from_state != RES_SRQ_HW) { 3357255932Salfred err = -EBUSY; 3358255932Salfred goto out; 3359255932Salfred } 3360255932Salfred 3361255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3362255932Salfredout: 3363255932Salfred put_res(dev, slave, srqn, RES_SRQ); 3364255932Salfred return err; 3365255932Salfred} 3366255932Salfred 3367255932Salfredint mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, 3368255932Salfred struct mlx4_vhcr *vhcr, 3369255932Salfred struct mlx4_cmd_mailbox *inbox, 3370255932Salfred struct mlx4_cmd_mailbox *outbox, 3371255932Salfred struct mlx4_cmd_info *cmd) 3372255932Salfred{ 3373255932Salfred int err; 3374255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 3375255932Salfred struct res_qp *qp; 3376255932Salfred 3377255932Salfred err = get_res(dev, slave, qpn, RES_QP, &qp); 3378255932Salfred if (err) 3379255932Salfred return err; 3380255932Salfred if (qp->com.from_state != RES_QP_HW) { 3381255932Salfred err = -EBUSY; 3382255932Salfred goto out; 3383255932Salfred } 3384255932Salfred 3385255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3386255932Salfredout: 3387255932Salfred put_res(dev, slave, qpn, RES_QP); 3388255932Salfred return err; 3389255932Salfred} 3390255932Salfred 3391255932Salfredint mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 3392255932Salfred struct mlx4_vhcr *vhcr, 3393255932Salfred struct mlx4_cmd_mailbox *inbox, 3394255932Salfred struct mlx4_cmd_mailbox *outbox, 3395255932Salfred struct mlx4_cmd_info *cmd) 3396255932Salfred{ 3397255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3398255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3399255932Salfred update_pkey_index(dev, slave, inbox); 3400255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3401255932Salfred} 3402255932Salfred 3403255932Salfredstatic int roce_verify_mac(struct mlx4_dev *dev, int slave, 3404255932Salfred struct mlx4_qp_context *qpc, 3405255932Salfred struct mlx4_cmd_mailbox *inbox) 3406255932Salfred{ 3407255932Salfred u64 mac; 3408255932Salfred int port; 3409255932Salfred u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 3410255932Salfred u8 sched = *(u8 *)(inbox->buf + 64); 3411255932Salfred u8 smac_ix; 3412255932Salfred 3413255932Salfred port = (sched >> 6 & 1) + 1; 3414255932Salfred if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { 3415255932Salfred smac_ix = qpc->pri_path.grh_mylmc & 0x7f; 3416255932Salfred if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) 3417255932Salfred return -ENOENT; 3418255932Salfred } 3419255932Salfred return 0; 3420255932Salfred} 3421255932Salfred 3422255932Salfredint mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, 3423255932Salfred struct mlx4_vhcr *vhcr, 3424255932Salfred struct mlx4_cmd_mailbox *inbox, 3425255932Salfred struct mlx4_cmd_mailbox *outbox, 3426255932Salfred struct mlx4_cmd_info *cmd) 3427255932Salfred{ 3428255932Salfred int err; 3429255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 3430272027Shselasky int qpn = vhcr->in_modifier & 0x7fffff; 3431272027Shselasky struct res_qp *qp; 3432272027Shselasky u8 orig_sched_queue; 3433272027Shselasky __be32 orig_param3 = qpc->param3; 3434272027Shselasky u8 orig_vlan_control = qpc->pri_path.vlan_control; 3435272027Shselasky u8 orig_fvl_rx = qpc->pri_path.fvl_rx; 3436272027Shselasky u8 orig_pri_path_fl = qpc->pri_path.fl; 3437272027Shselasky u8 orig_vlan_index = qpc->pri_path.vlan_index; 3438272027Shselasky u8 orig_feup = qpc->pri_path.feup; 3439255932Salfred 3440255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); 3441255932Salfred if (err) 3442255932Salfred return err; 3443255932Salfred 3444255932Salfred if (roce_verify_mac(dev, slave, qpc, inbox)) 3445255932Salfred return -EINVAL; 3446255932Salfred 3447255932Salfred update_pkey_index(dev, slave, inbox); 3448255932Salfred update_gid(dev, inbox, (u8)slave); 3449255932Salfred adjust_proxy_tun_qkey(dev, vhcr, qpc); 3450272027Shselasky orig_sched_queue = qpc->pri_path.sched_queue; 3451272027Shselasky 3452272027Shselasky err = get_res(dev, slave, qpn, RES_QP, &qp); 3453255932Salfred if (err) 3454255932Salfred return err; 3455272027Shselasky if (qp->com.from_state != RES_QP_HW) { 3456272027Shselasky err = -EBUSY; 3457272027Shselasky goto out; 3458272027Shselasky } 3459255932Salfred 3460272027Shselasky /* do not modify vport QP params for RSS QPs */ 3461272027Shselasky if (!(qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET))) { 3462272027Shselasky err = update_vport_qp_param(dev, inbox, slave, qpn); 3463272027Shselasky if (err) 3464272027Shselasky goto out; 3465272027Shselasky } 3466272027Shselasky 3467272027Shselasky err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3468272027Shselaskyout: 3469272027Shselasky /* if no error, save sched queue value passed in by VF. This is 3470272027Shselasky * essentially the QOS value provided by the VF. This will be useful 3471272027Shselasky * if we allow dynamic changes from VST back to VGT 3472272027Shselasky */ 3473272027Shselasky if (!err) { 3474272027Shselasky qp->sched_queue = orig_sched_queue; 3475272027Shselasky qp->param3 = orig_param3; 3476272027Shselasky qp->vlan_control = orig_vlan_control; 3477272027Shselasky qp->fvl_rx = orig_fvl_rx; 3478272027Shselasky qp->pri_path_fl = orig_pri_path_fl; 3479272027Shselasky qp->vlan_index = orig_vlan_index; 3480272027Shselasky qp->feup = orig_feup; 3481272027Shselasky } 3482272027Shselasky put_res(dev, slave, qpn, RES_QP); 3483272027Shselasky return err; 3484255932Salfred} 3485255932Salfred 3486255932Salfredint mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3487255932Salfred struct mlx4_vhcr *vhcr, 3488255932Salfred struct mlx4_cmd_mailbox *inbox, 3489255932Salfred struct mlx4_cmd_mailbox *outbox, 3490255932Salfred struct mlx4_cmd_info *cmd) 3491255932Salfred{ 3492255932Salfred int err; 3493255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3494255932Salfred 3495255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave); 3496255932Salfred if (err) 3497255932Salfred return err; 3498255932Salfred 3499255932Salfred update_pkey_index(dev, slave, inbox); 3500255932Salfred update_gid(dev, inbox, (u8)slave); 3501255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3502255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3503255932Salfred} 3504255932Salfred 3505255932Salfredint mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3506255932Salfred struct mlx4_vhcr *vhcr, 3507255932Salfred struct mlx4_cmd_mailbox *inbox, 3508255932Salfred struct mlx4_cmd_mailbox *outbox, 3509255932Salfred struct mlx4_cmd_info *cmd) 3510255932Salfred{ 3511255932Salfred int err; 3512255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3513255932Salfred 3514255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave); 3515255932Salfred if (err) 3516255932Salfred return err; 3517255932Salfred 3518255932Salfred update_pkey_index(dev, slave, inbox); 3519255932Salfred update_gid(dev, inbox, (u8)slave); 3520255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3521255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3522255932Salfred} 3523255932Salfred 3524255932Salfred 3525255932Salfredint mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3526255932Salfred struct mlx4_vhcr *vhcr, 3527255932Salfred struct mlx4_cmd_mailbox *inbox, 3528255932Salfred struct mlx4_cmd_mailbox *outbox, 3529255932Salfred struct mlx4_cmd_info *cmd) 3530255932Salfred{ 3531255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3532255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3533255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3534255932Salfred} 3535255932Salfred 3536255932Salfredint mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, 3537255932Salfred struct mlx4_vhcr *vhcr, 3538255932Salfred struct mlx4_cmd_mailbox *inbox, 3539255932Salfred struct mlx4_cmd_mailbox *outbox, 3540255932Salfred struct mlx4_cmd_info *cmd) 3541255932Salfred{ 3542255932Salfred int err; 3543255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3544255932Salfred 3545255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave); 3546255932Salfred if (err) 3547255932Salfred return err; 3548255932Salfred 3549255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3550255932Salfred update_gid(dev, inbox, (u8)slave); 3551255932Salfred update_pkey_index(dev, slave, inbox); 3552255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3553255932Salfred} 3554255932Salfred 3555255932Salfredint mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3556255932Salfred struct mlx4_vhcr *vhcr, 3557255932Salfred struct mlx4_cmd_mailbox *inbox, 3558255932Salfred struct mlx4_cmd_mailbox *outbox, 3559255932Salfred struct mlx4_cmd_info *cmd) 3560255932Salfred{ 3561255932Salfred int err; 3562255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3563255932Salfred 3564255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave); 3565255932Salfred if (err) 3566255932Salfred return err; 3567255932Salfred 3568255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3569255932Salfred update_gid(dev, inbox, (u8)slave); 3570255932Salfred update_pkey_index(dev, slave, inbox); 3571255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3572255932Salfred} 3573255932Salfred 3574255932Salfredint mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, 3575255932Salfred struct mlx4_vhcr *vhcr, 3576255932Salfred struct mlx4_cmd_mailbox *inbox, 3577255932Salfred struct mlx4_cmd_mailbox *outbox, 3578255932Salfred struct mlx4_cmd_info *cmd) 3579255932Salfred{ 3580255932Salfred int err; 3581255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 3582255932Salfred struct res_qp *qp; 3583255932Salfred 3584255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); 3585255932Salfred if (err) 3586255932Salfred return err; 3587255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3588255932Salfred if (err) 3589255932Salfred goto ex_abort; 3590255932Salfred 3591255932Salfred atomic_dec(&qp->mtt->ref_count); 3592255932Salfred atomic_dec(&qp->rcq->ref_count); 3593255932Salfred atomic_dec(&qp->scq->ref_count); 3594255932Salfred if (qp->srq) 3595255932Salfred atomic_dec(&qp->srq->ref_count); 3596255932Salfred res_end_move(dev, slave, RES_QP, qpn); 3597255932Salfred return 0; 3598255932Salfred 3599255932Salfredex_abort: 3600255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 3601255932Salfred 3602255932Salfred return err; 3603255932Salfred} 3604255932Salfred 3605255932Salfredstatic struct res_gid *find_gid(struct mlx4_dev *dev, int slave, 3606255932Salfred struct res_qp *rqp, u8 *gid) 3607255932Salfred{ 3608255932Salfred struct res_gid *res; 3609255932Salfred 3610255932Salfred list_for_each_entry(res, &rqp->mcg_list, list) { 3611255932Salfred if (!memcmp(res->gid, gid, 16)) 3612255932Salfred return res; 3613255932Salfred } 3614255932Salfred return NULL; 3615255932Salfred} 3616255932Salfred 3617255932Salfredstatic int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 3618255932Salfred u8 *gid, enum mlx4_protocol prot, 3619272027Shselasky enum mlx4_steer_type steer, u64 reg_id) 3620255932Salfred{ 3621255932Salfred struct res_gid *res; 3622255932Salfred int err; 3623255932Salfred 3624255932Salfred res = kzalloc(sizeof *res, GFP_KERNEL); 3625255932Salfred if (!res) 3626255932Salfred return -ENOMEM; 3627255932Salfred 3628255932Salfred spin_lock_irq(&rqp->mcg_spl); 3629255932Salfred if (find_gid(dev, slave, rqp, gid)) { 3630255932Salfred kfree(res); 3631255932Salfred err = -EEXIST; 3632255932Salfred } else { 3633255932Salfred memcpy(res->gid, gid, 16); 3634255932Salfred res->prot = prot; 3635255932Salfred res->steer = steer; 3636272027Shselasky res->reg_id = reg_id; 3637255932Salfred list_add_tail(&res->list, &rqp->mcg_list); 3638255932Salfred err = 0; 3639255932Salfred } 3640255932Salfred spin_unlock_irq(&rqp->mcg_spl); 3641255932Salfred 3642255932Salfred return err; 3643255932Salfred} 3644255932Salfred 3645255932Salfredstatic int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 3646255932Salfred u8 *gid, enum mlx4_protocol prot, 3647272027Shselasky enum mlx4_steer_type steer, u64 *reg_id) 3648255932Salfred{ 3649255932Salfred struct res_gid *res; 3650255932Salfred int err; 3651255932Salfred 3652255932Salfred spin_lock_irq(&rqp->mcg_spl); 3653255932Salfred res = find_gid(dev, slave, rqp, gid); 3654255932Salfred if (!res || res->prot != prot || res->steer != steer) 3655255932Salfred err = -EINVAL; 3656255932Salfred else { 3657272027Shselasky *reg_id = res->reg_id; 3658255932Salfred list_del(&res->list); 3659255932Salfred kfree(res); 3660255932Salfred err = 0; 3661255932Salfred } 3662255932Salfred spin_unlock_irq(&rqp->mcg_spl); 3663255932Salfred 3664255932Salfred return err; 3665255932Salfred} 3666255932Salfred 3667272027Shselaskystatic int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 3668272027Shselasky int block_loopback, enum mlx4_protocol prot, 3669272027Shselasky enum mlx4_steer_type type, u64 *reg_id) 3670272027Shselasky{ 3671272027Shselasky switch (dev->caps.steering_mode) { 3672272027Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 3673272027Shselasky return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5], 3674272027Shselasky block_loopback, prot, 3675272027Shselasky reg_id); 3676272027Shselasky case MLX4_STEERING_MODE_B0: 3677272027Shselasky return mlx4_qp_attach_common(dev, qp, gid, 3678272027Shselasky block_loopback, prot, type); 3679272027Shselasky default: 3680272027Shselasky return -EINVAL; 3681272027Shselasky } 3682272027Shselasky} 3683272027Shselasky 3684272027Shselaskystatic int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 3685272027Shselasky enum mlx4_protocol prot, enum mlx4_steer_type type, 3686272027Shselasky u64 reg_id) 3687272027Shselasky{ 3688272027Shselasky switch (dev->caps.steering_mode) { 3689272027Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 3690272027Shselasky return mlx4_flow_detach(dev, reg_id); 3691272027Shselasky case MLX4_STEERING_MODE_B0: 3692272027Shselasky return mlx4_qp_detach_common(dev, qp, gid, prot, type); 3693272027Shselasky default: 3694272027Shselasky return -EINVAL; 3695272027Shselasky } 3696272027Shselasky} 3697272027Shselasky 3698255932Salfredint mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 3699255932Salfred struct mlx4_vhcr *vhcr, 3700255932Salfred struct mlx4_cmd_mailbox *inbox, 3701255932Salfred struct mlx4_cmd_mailbox *outbox, 3702255932Salfred struct mlx4_cmd_info *cmd) 3703255932Salfred{ 3704255932Salfred struct mlx4_qp qp; /* dummy for calling attach/detach */ 3705255932Salfred u8 *gid = inbox->buf; 3706255932Salfred enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; 3707255932Salfred int err; 3708255932Salfred int qpn; 3709255932Salfred struct res_qp *rqp; 3710272027Shselasky u64 reg_id = 0; 3711255932Salfred int attach = vhcr->op_modifier; 3712255932Salfred int block_loopback = vhcr->in_modifier >> 31; 3713255932Salfred u8 steer_type_mask = 2; 3714255932Salfred enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; 3715255932Salfred 3716255932Salfred qpn = vhcr->in_modifier & 0xffffff; 3717255932Salfred err = get_res(dev, slave, qpn, RES_QP, &rqp); 3718255932Salfred if (err) 3719255932Salfred return err; 3720255932Salfred 3721255932Salfred qp.qpn = qpn; 3722255932Salfred if (attach) { 3723272027Shselasky err = qp_attach(dev, &qp, gid, block_loopback, prot, 3724272027Shselasky type, ®_id); 3725272027Shselasky if (err) { 3726272027Shselasky pr_err("Fail to attach rule to qp 0x%x\n", qpn); 3727255932Salfred goto ex_put; 3728272027Shselasky } 3729272027Shselasky err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id); 3730255932Salfred if (err) 3731272027Shselasky goto ex_detach; 3732255932Salfred } else { 3733272027Shselasky err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id); 3734255932Salfred if (err) 3735255932Salfred goto ex_put; 3736272027Shselasky 3737272027Shselasky err = qp_detach(dev, &qp, gid, prot, type, reg_id); 3738272027Shselasky if (err) 3739272027Shselasky pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n", 3740272027Shselasky qpn, (unsigned long long)reg_id); 3741255932Salfred } 3742255932Salfred put_res(dev, slave, qpn, RES_QP); 3743272027Shselasky return err; 3744255932Salfred 3745272027Shselaskyex_detach: 3746272027Shselasky qp_detach(dev, &qp, gid, prot, type, reg_id); 3747255932Salfredex_put: 3748255932Salfred put_res(dev, slave, qpn, RES_QP); 3749255932Salfred return err; 3750255932Salfred} 3751255932Salfred 3752255932Salfred/* 3753255932Salfred * MAC validation for Flow Steering rules. 3754255932Salfred * VF can attach rules only with a mac address which is assigned to it. 3755255932Salfred */ 3756255932Salfredstatic int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, 3757255932Salfred struct list_head *rlist) 3758255932Salfred{ 3759255932Salfred struct mac_res *res, *tmp; 3760255932Salfred __be64 be_mac; 3761255932Salfred 3762255932Salfred /* make sure it isn't multicast or broadcast mac*/ 3763255932Salfred if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && 3764255932Salfred !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { 3765255932Salfred list_for_each_entry_safe(res, tmp, rlist, list) { 3766255932Salfred be_mac = cpu_to_be64(res->mac << 16); 3767255932Salfred if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN)) 3768255932Salfred return 0; 3769255932Salfred } 3770255932Salfred pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", 3771255932Salfred eth_header->eth.dst_mac, slave); 3772255932Salfred return -EINVAL; 3773255932Salfred } 3774255932Salfred return 0; 3775255932Salfred} 3776255932Salfred 3777255932Salfred/* 3778255932Salfred * In case of missing eth header, append eth header with a MAC address 3779255932Salfred * assigned to the VF. 3780255932Salfred */ 3781255932Salfredstatic int add_eth_header(struct mlx4_dev *dev, int slave, 3782255932Salfred struct mlx4_cmd_mailbox *inbox, 3783255932Salfred struct list_head *rlist, int header_id) 3784255932Salfred{ 3785255932Salfred struct mac_res *res, *tmp; 3786255932Salfred u8 port; 3787255932Salfred struct mlx4_net_trans_rule_hw_ctrl *ctrl; 3788255932Salfred struct mlx4_net_trans_rule_hw_eth *eth_header; 3789255932Salfred struct mlx4_net_trans_rule_hw_ipv4 *ip_header; 3790255932Salfred struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; 3791255932Salfred __be64 be_mac = 0; 3792255932Salfred __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); 3793255932Salfred 3794255932Salfred ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 3795255932Salfred port = ctrl->port; 3796255932Salfred eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); 3797255932Salfred 3798255932Salfred /* Clear a space in the inbox for eth header */ 3799255932Salfred switch (header_id) { 3800255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 3801255932Salfred ip_header = 3802255932Salfred (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); 3803255932Salfred memmove(ip_header, eth_header, 3804255932Salfred sizeof(*ip_header) + sizeof(*l4_header)); 3805255932Salfred break; 3806255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 3807255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 3808255932Salfred l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) 3809255932Salfred (eth_header + 1); 3810255932Salfred memmove(l4_header, eth_header, sizeof(*l4_header)); 3811255932Salfred break; 3812255932Salfred default: 3813255932Salfred return -EINVAL; 3814255932Salfred } 3815255932Salfred list_for_each_entry_safe(res, tmp, rlist, list) { 3816255932Salfred if (port == res->port) { 3817255932Salfred be_mac = cpu_to_be64(res->mac << 16); 3818255932Salfred break; 3819255932Salfred } 3820255932Salfred } 3821255932Salfred if (!be_mac) { 3822255932Salfred pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n", 3823255932Salfred port); 3824255932Salfred return -EINVAL; 3825255932Salfred } 3826255932Salfred 3827255932Salfred memset(eth_header, 0, sizeof(*eth_header)); 3828255932Salfred eth_header->size = sizeof(*eth_header) >> 2; 3829255932Salfred eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); 3830255932Salfred memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); 3831255932Salfred memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); 3832255932Salfred 3833255932Salfred return 0; 3834255932Salfred 3835255932Salfred} 3836255932Salfred 3837255932Salfredint mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 3838255932Salfred struct mlx4_vhcr *vhcr, 3839255932Salfred struct mlx4_cmd_mailbox *inbox, 3840255932Salfred struct mlx4_cmd_mailbox *outbox, 3841255932Salfred struct mlx4_cmd_info *cmd) 3842255932Salfred{ 3843255932Salfred 3844255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3845255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 3846255932Salfred struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; 3847255932Salfred int err; 3848272027Shselasky int qpn; 3849272027Shselasky struct res_qp *rqp; 3850255932Salfred struct mlx4_net_trans_rule_hw_ctrl *ctrl; 3851255932Salfred struct _rule_hw *rule_header; 3852255932Salfred int header_id; 3853255932Salfred 3854255932Salfred if (dev->caps.steering_mode != 3855255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 3856255932Salfred return -EOPNOTSUPP; 3857255932Salfred 3858255932Salfred ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 3859272027Shselasky qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; 3860272027Shselasky err = get_res(dev, slave, qpn, RES_QP, &rqp); 3861272027Shselasky if (err) { 3862272027Shselasky pr_err("Steering rule with qpn 0x%x rejected.\n", qpn); 3863272027Shselasky return err; 3864272027Shselasky } 3865255932Salfred rule_header = (struct _rule_hw *)(ctrl + 1); 3866255932Salfred header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); 3867255932Salfred 3868255932Salfred switch (header_id) { 3869255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 3870272027Shselasky if (validate_eth_header_mac(slave, rule_header, rlist)) { 3871272027Shselasky err = -EINVAL; 3872272027Shselasky goto err_put; 3873272027Shselasky } 3874255932Salfred break; 3875255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 3876255932Salfred break; 3877255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 3878255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 3879255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 3880255932Salfred pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n"); 3881272027Shselasky if (add_eth_header(dev, slave, inbox, rlist, header_id)) { 3882272027Shselasky err = -EINVAL; 3883272027Shselasky goto err_put; 3884272027Shselasky } 3885255932Salfred vhcr->in_modifier += 3886255932Salfred sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; 3887255932Salfred break; 3888255932Salfred default: 3889255932Salfred pr_err("Corrupted mailbox.\n"); 3890272027Shselasky err = -EINVAL; 3891272027Shselasky goto err_put; 3892255932Salfred } 3893255932Salfred 3894255932Salfred err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, 3895255932Salfred vhcr->in_modifier, 0, 3896255932Salfred MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 3897255932Salfred MLX4_CMD_NATIVE); 3898255932Salfred if (err) 3899272027Shselasky goto err_put; 3900255932Salfred 3901272027Shselasky err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); 3902255932Salfred if (err) { 3903255932Salfred mlx4_err(dev, "Fail to add flow steering resources.\n "); 3904255932Salfred /* detach rule*/ 3905255932Salfred mlx4_cmd(dev, vhcr->out_param, 0, 0, 3906272027Shselasky MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 3907255932Salfred MLX4_CMD_NATIVE); 3908272027Shselasky goto err_put; 3909255932Salfred } 3910272027Shselasky atomic_inc(&rqp->ref_count); 3911272027Shselaskyerr_put: 3912272027Shselasky put_res(dev, slave, qpn, RES_QP); 3913255932Salfred return err; 3914255932Salfred} 3915255932Salfred 3916255932Salfredint mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, 3917255932Salfred struct mlx4_vhcr *vhcr, 3918255932Salfred struct mlx4_cmd_mailbox *inbox, 3919255932Salfred struct mlx4_cmd_mailbox *outbox, 3920255932Salfred struct mlx4_cmd_info *cmd) 3921255932Salfred{ 3922255932Salfred int err; 3923272027Shselasky struct res_qp *rqp; 3924272027Shselasky struct res_fs_rule *rrule; 3925255932Salfred 3926255932Salfred if (dev->caps.steering_mode != 3927255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 3928255932Salfred return -EOPNOTSUPP; 3929255932Salfred 3930272027Shselasky err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); 3931272027Shselasky if (err) 3932255932Salfred return err; 3933272027Shselasky /* Release the rule form busy state before removal */ 3934272027Shselasky put_res(dev, slave, vhcr->in_param, RES_FS_RULE); 3935272027Shselasky err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); 3936272027Shselasky if (err) 3937272027Shselasky return err; 3938255932Salfred 3939255932Salfred err = mlx4_cmd(dev, vhcr->in_param, 0, 0, 3940255932Salfred MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 3941255932Salfred MLX4_CMD_NATIVE); 3942272027Shselasky if (!err) { 3943272027Shselasky err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 3944272027Shselasky 0); 3945272027Shselasky atomic_dec(&rqp->ref_count); 3946272027Shselasky 3947272027Shselasky if (err) { 3948272027Shselasky mlx4_err(dev, "Fail to remove flow steering resources.\n "); 3949272027Shselasky goto out; 3950272027Shselasky } 3951272027Shselasky } 3952272027Shselasky 3953272027Shselaskyout: 3954272027Shselasky put_res(dev, slave, rrule->qpn, RES_QP); 3955255932Salfred return err; 3956255932Salfred} 3957255932Salfred 3958255932Salfredenum { 3959255932Salfred BUSY_MAX_RETRIES = 10 3960255932Salfred}; 3961255932Salfred 3962255932Salfredint mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, 3963255932Salfred struct mlx4_vhcr *vhcr, 3964255932Salfred struct mlx4_cmd_mailbox *inbox, 3965255932Salfred struct mlx4_cmd_mailbox *outbox, 3966255932Salfred struct mlx4_cmd_info *cmd) 3967255932Salfred{ 3968255932Salfred int err; 3969255932Salfred 3970272027Shselasky err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3971255932Salfred 3972255932Salfred return err; 3973255932Salfred} 3974255932Salfred 3975255932Salfredstatic void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) 3976255932Salfred{ 3977255932Salfred struct res_gid *rgid; 3978255932Salfred struct res_gid *tmp; 3979255932Salfred struct mlx4_qp qp; /* dummy for calling attach/detach */ 3980255932Salfred 3981255932Salfred list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { 3982272027Shselasky switch (dev->caps.steering_mode) { 3983272027Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 3984272027Shselasky mlx4_flow_detach(dev, rgid->reg_id); 3985272027Shselasky break; 3986272027Shselasky case MLX4_STEERING_MODE_B0: 3987272027Shselasky qp.qpn = rqp->local_qpn; 3988272027Shselasky (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, 3989272027Shselasky rgid->prot, rgid->steer); 3990272027Shselasky break; 3991272027Shselasky } 3992255932Salfred list_del(&rgid->list); 3993255932Salfred kfree(rgid); 3994255932Salfred } 3995255932Salfred} 3996255932Salfred 3997255932Salfredstatic int _move_all_busy(struct mlx4_dev *dev, int slave, 3998255932Salfred enum mlx4_resource type, int print) 3999255932Salfred{ 4000255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4001255932Salfred struct mlx4_resource_tracker *tracker = 4002255932Salfred &priv->mfunc.master.res_tracker; 4003255932Salfred struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; 4004255932Salfred struct res_common *r; 4005255932Salfred struct res_common *tmp; 4006255932Salfred int busy; 4007255932Salfred 4008255932Salfred busy = 0; 4009255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4010255932Salfred list_for_each_entry_safe(r, tmp, rlist, list) { 4011255932Salfred if (r->owner == slave) { 4012255932Salfred if (!r->removing) { 4013255932Salfred if (r->state == RES_ANY_BUSY) { 4014255932Salfred if (print) 4015255932Salfred mlx4_dbg(dev, 4016255932Salfred "%s id 0x%llx is busy\n", 4017255932Salfred ResourceType(type), 4018272027Shselasky (unsigned long long)r->res_id); 4019255932Salfred ++busy; 4020255932Salfred } else { 4021255932Salfred r->from_state = r->state; 4022255932Salfred r->state = RES_ANY_BUSY; 4023255932Salfred r->removing = 1; 4024255932Salfred } 4025255932Salfred } 4026255932Salfred } 4027255932Salfred } 4028255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4029255932Salfred 4030255932Salfred return busy; 4031255932Salfred} 4032255932Salfred 4033255932Salfredstatic int move_all_busy(struct mlx4_dev *dev, int slave, 4034255932Salfred enum mlx4_resource type) 4035255932Salfred{ 4036255932Salfred unsigned long begin; 4037255932Salfred int busy; 4038255932Salfred 4039255932Salfred begin = jiffies; 4040255932Salfred do { 4041255932Salfred busy = _move_all_busy(dev, slave, type, 0); 4042255932Salfred if (time_after(jiffies, begin + 5 * HZ)) 4043255932Salfred break; 4044255932Salfred if (busy) 4045255932Salfred cond_resched(); 4046255932Salfred } while (busy); 4047255932Salfred 4048255932Salfred if (busy) 4049255932Salfred busy = _move_all_busy(dev, slave, type, 1); 4050255932Salfred 4051255932Salfred return busy; 4052255932Salfred} 4053255932Salfredstatic void rem_slave_qps(struct mlx4_dev *dev, int slave) 4054255932Salfred{ 4055255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4056255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4057255932Salfred struct list_head *qp_list = 4058255932Salfred &tracker->slave_list[slave].res_list[RES_QP]; 4059255932Salfred struct res_qp *qp; 4060255932Salfred struct res_qp *tmp; 4061255932Salfred int state; 4062255932Salfred u64 in_param; 4063255932Salfred int qpn; 4064255932Salfred int err; 4065255932Salfred 4066255932Salfred err = move_all_busy(dev, slave, RES_QP); 4067255932Salfred if (err) 4068255932Salfred mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy" 4069255932Salfred "for slave %d\n", slave); 4070255932Salfred 4071255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4072255932Salfred list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 4073255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4074255932Salfred if (qp->com.owner == slave) { 4075255932Salfred qpn = qp->com.res_id; 4076255932Salfred detach_qp(dev, slave, qp); 4077255932Salfred state = qp->com.from_state; 4078255932Salfred while (state != 0) { 4079255932Salfred switch (state) { 4080255932Salfred case RES_QP_RESERVED: 4081255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4082255932Salfred rb_erase(&qp->com.node, 4083255932Salfred &tracker->res_tree[RES_QP]); 4084255932Salfred list_del(&qp->com.list); 4085255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4086272027Shselasky if (!valid_reserved(dev, slave, qpn)) { 4087272027Shselasky __mlx4_qp_release_range(dev, qpn, 1); 4088272027Shselasky mlx4_release_resource(dev, slave, 4089272027Shselasky RES_QP, 1, 0); 4090272027Shselasky } 4091255932Salfred kfree(qp); 4092255932Salfred state = 0; 4093255932Salfred break; 4094255932Salfred case RES_QP_MAPPED: 4095255932Salfred if (!valid_reserved(dev, slave, qpn)) 4096255932Salfred __mlx4_qp_free_icm(dev, qpn); 4097255932Salfred state = RES_QP_RESERVED; 4098255932Salfred break; 4099255932Salfred case RES_QP_HW: 4100255932Salfred in_param = slave; 4101255932Salfred err = mlx4_cmd(dev, in_param, 4102255932Salfred qp->local_qpn, 2, 4103255932Salfred MLX4_CMD_2RST_QP, 4104255932Salfred MLX4_CMD_TIME_CLASS_A, 4105255932Salfred MLX4_CMD_NATIVE); 4106255932Salfred if (err) 4107255932Salfred mlx4_dbg(dev, "rem_slave_qps: failed" 4108255932Salfred " to move slave %d qpn %d to" 4109255932Salfred " reset\n", slave, 4110255932Salfred qp->local_qpn); 4111255932Salfred atomic_dec(&qp->rcq->ref_count); 4112255932Salfred atomic_dec(&qp->scq->ref_count); 4113255932Salfred atomic_dec(&qp->mtt->ref_count); 4114255932Salfred if (qp->srq) 4115255932Salfred atomic_dec(&qp->srq->ref_count); 4116255932Salfred state = RES_QP_MAPPED; 4117255932Salfred break; 4118255932Salfred default: 4119255932Salfred state = 0; 4120255932Salfred } 4121255932Salfred } 4122255932Salfred } 4123255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4124255932Salfred } 4125255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4126255932Salfred} 4127255932Salfred 4128255932Salfredstatic void rem_slave_srqs(struct mlx4_dev *dev, int slave) 4129255932Salfred{ 4130255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4131255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4132255932Salfred struct list_head *srq_list = 4133255932Salfred &tracker->slave_list[slave].res_list[RES_SRQ]; 4134255932Salfred struct res_srq *srq; 4135255932Salfred struct res_srq *tmp; 4136255932Salfred int state; 4137255932Salfred u64 in_param; 4138255932Salfred LIST_HEAD(tlist); 4139255932Salfred int srqn; 4140255932Salfred int err; 4141255932Salfred 4142255932Salfred err = move_all_busy(dev, slave, RES_SRQ); 4143255932Salfred if (err) 4144255932Salfred mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs to " 4145255932Salfred "busy for slave %d\n", slave); 4146255932Salfred 4147255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4148255932Salfred list_for_each_entry_safe(srq, tmp, srq_list, com.list) { 4149255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4150255932Salfred if (srq->com.owner == slave) { 4151255932Salfred srqn = srq->com.res_id; 4152255932Salfred state = srq->com.from_state; 4153255932Salfred while (state != 0) { 4154255932Salfred switch (state) { 4155255932Salfred case RES_SRQ_ALLOCATED: 4156255932Salfred __mlx4_srq_free_icm(dev, srqn); 4157255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4158255932Salfred rb_erase(&srq->com.node, 4159255932Salfred &tracker->res_tree[RES_SRQ]); 4160255932Salfred list_del(&srq->com.list); 4161255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4162272027Shselasky mlx4_release_resource(dev, slave, 4163272027Shselasky RES_SRQ, 1, 0); 4164255932Salfred kfree(srq); 4165255932Salfred state = 0; 4166255932Salfred break; 4167255932Salfred 4168255932Salfred case RES_SRQ_HW: 4169255932Salfred in_param = slave; 4170255932Salfred err = mlx4_cmd(dev, in_param, srqn, 1, 4171255932Salfred MLX4_CMD_HW2SW_SRQ, 4172255932Salfred MLX4_CMD_TIME_CLASS_A, 4173255932Salfred MLX4_CMD_NATIVE); 4174255932Salfred if (err) 4175255932Salfred mlx4_dbg(dev, "rem_slave_srqs: failed" 4176255932Salfred " to move slave %d srq %d to" 4177255932Salfred " SW ownership\n", 4178255932Salfred slave, srqn); 4179255932Salfred 4180255932Salfred atomic_dec(&srq->mtt->ref_count); 4181255932Salfred if (srq->cq) 4182255932Salfred atomic_dec(&srq->cq->ref_count); 4183255932Salfred state = RES_SRQ_ALLOCATED; 4184255932Salfred break; 4185255932Salfred 4186255932Salfred default: 4187255932Salfred state = 0; 4188255932Salfred } 4189255932Salfred } 4190255932Salfred } 4191255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4192255932Salfred } 4193255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4194255932Salfred} 4195255932Salfred 4196255932Salfredstatic void rem_slave_cqs(struct mlx4_dev *dev, int slave) 4197255932Salfred{ 4198255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4199255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4200255932Salfred struct list_head *cq_list = 4201255932Salfred &tracker->slave_list[slave].res_list[RES_CQ]; 4202255932Salfred struct res_cq *cq; 4203255932Salfred struct res_cq *tmp; 4204255932Salfred int state; 4205255932Salfred u64 in_param; 4206255932Salfred LIST_HEAD(tlist); 4207255932Salfred int cqn; 4208255932Salfred int err; 4209255932Salfred 4210255932Salfred err = move_all_busy(dev, slave, RES_CQ); 4211255932Salfred if (err) 4212255932Salfred mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs to " 4213255932Salfred "busy for slave %d\n", slave); 4214255932Salfred 4215255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4216255932Salfred list_for_each_entry_safe(cq, tmp, cq_list, com.list) { 4217255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4218255932Salfred if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { 4219255932Salfred cqn = cq->com.res_id; 4220255932Salfred state = cq->com.from_state; 4221255932Salfred while (state != 0) { 4222255932Salfred switch (state) { 4223255932Salfred case RES_CQ_ALLOCATED: 4224255932Salfred __mlx4_cq_free_icm(dev, cqn); 4225255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4226255932Salfred rb_erase(&cq->com.node, 4227255932Salfred &tracker->res_tree[RES_CQ]); 4228255932Salfred list_del(&cq->com.list); 4229255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4230272027Shselasky mlx4_release_resource(dev, slave, 4231272027Shselasky RES_CQ, 1, 0); 4232255932Salfred kfree(cq); 4233255932Salfred state = 0; 4234255932Salfred break; 4235255932Salfred 4236255932Salfred case RES_CQ_HW: 4237255932Salfred in_param = slave; 4238255932Salfred err = mlx4_cmd(dev, in_param, cqn, 1, 4239255932Salfred MLX4_CMD_HW2SW_CQ, 4240255932Salfred MLX4_CMD_TIME_CLASS_A, 4241255932Salfred MLX4_CMD_NATIVE); 4242255932Salfred if (err) 4243255932Salfred mlx4_dbg(dev, "rem_slave_cqs: failed" 4244255932Salfred " to move slave %d cq %d to" 4245255932Salfred " SW ownership\n", 4246255932Salfred slave, cqn); 4247255932Salfred atomic_dec(&cq->mtt->ref_count); 4248255932Salfred state = RES_CQ_ALLOCATED; 4249255932Salfred break; 4250255932Salfred 4251255932Salfred default: 4252255932Salfred state = 0; 4253255932Salfred } 4254255932Salfred } 4255255932Salfred } 4256255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4257255932Salfred } 4258255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4259255932Salfred} 4260255932Salfred 4261255932Salfredstatic void rem_slave_mrs(struct mlx4_dev *dev, int slave) 4262255932Salfred{ 4263255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4264255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4265255932Salfred struct list_head *mpt_list = 4266255932Salfred &tracker->slave_list[slave].res_list[RES_MPT]; 4267255932Salfred struct res_mpt *mpt; 4268255932Salfred struct res_mpt *tmp; 4269255932Salfred int state; 4270255932Salfred u64 in_param; 4271255932Salfred LIST_HEAD(tlist); 4272255932Salfred int mptn; 4273255932Salfred int err; 4274255932Salfred 4275255932Salfred err = move_all_busy(dev, slave, RES_MPT); 4276255932Salfred if (err) 4277255932Salfred mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts to " 4278255932Salfred "busy for slave %d\n", slave); 4279255932Salfred 4280255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4281255932Salfred list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { 4282255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4283255932Salfred if (mpt->com.owner == slave) { 4284255932Salfred mptn = mpt->com.res_id; 4285255932Salfred state = mpt->com.from_state; 4286255932Salfred while (state != 0) { 4287255932Salfred switch (state) { 4288255932Salfred case RES_MPT_RESERVED: 4289272027Shselasky __mlx4_mpt_release(dev, mpt->key); 4290255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4291255932Salfred rb_erase(&mpt->com.node, 4292255932Salfred &tracker->res_tree[RES_MPT]); 4293255932Salfred list_del(&mpt->com.list); 4294255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4295272027Shselasky mlx4_release_resource(dev, slave, 4296272027Shselasky RES_MPT, 1, 0); 4297255932Salfred kfree(mpt); 4298255932Salfred state = 0; 4299255932Salfred break; 4300255932Salfred 4301255932Salfred case RES_MPT_MAPPED: 4302272027Shselasky __mlx4_mpt_free_icm(dev, mpt->key); 4303255932Salfred state = RES_MPT_RESERVED; 4304255932Salfred break; 4305255932Salfred 4306255932Salfred case RES_MPT_HW: 4307255932Salfred in_param = slave; 4308255932Salfred err = mlx4_cmd(dev, in_param, mptn, 0, 4309255932Salfred MLX4_CMD_HW2SW_MPT, 4310255932Salfred MLX4_CMD_TIME_CLASS_A, 4311255932Salfred MLX4_CMD_NATIVE); 4312255932Salfred if (err) 4313255932Salfred mlx4_dbg(dev, "rem_slave_mrs: failed" 4314255932Salfred " to move slave %d mpt %d to" 4315255932Salfred " SW ownership\n", 4316255932Salfred slave, mptn); 4317255932Salfred if (mpt->mtt) 4318255932Salfred atomic_dec(&mpt->mtt->ref_count); 4319255932Salfred state = RES_MPT_MAPPED; 4320255932Salfred break; 4321255932Salfred default: 4322255932Salfred state = 0; 4323255932Salfred } 4324255932Salfred } 4325255932Salfred } 4326255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4327255932Salfred } 4328255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4329255932Salfred} 4330255932Salfred 4331255932Salfredstatic void rem_slave_mtts(struct mlx4_dev *dev, int slave) 4332255932Salfred{ 4333255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4334255932Salfred struct mlx4_resource_tracker *tracker = 4335255932Salfred &priv->mfunc.master.res_tracker; 4336255932Salfred struct list_head *mtt_list = 4337255932Salfred &tracker->slave_list[slave].res_list[RES_MTT]; 4338255932Salfred struct res_mtt *mtt; 4339255932Salfred struct res_mtt *tmp; 4340255932Salfred int state; 4341255932Salfred LIST_HEAD(tlist); 4342255932Salfred int base; 4343255932Salfred int err; 4344255932Salfred 4345255932Salfred err = move_all_busy(dev, slave, RES_MTT); 4346255932Salfred if (err) 4347255932Salfred mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts to " 4348255932Salfred "busy for slave %d\n", slave); 4349255932Salfred 4350255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4351255932Salfred list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { 4352255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4353255932Salfred if (mtt->com.owner == slave) { 4354255932Salfred base = mtt->com.res_id; 4355255932Salfred state = mtt->com.from_state; 4356255932Salfred while (state != 0) { 4357255932Salfred switch (state) { 4358255932Salfred case RES_MTT_ALLOCATED: 4359255932Salfred __mlx4_free_mtt_range(dev, base, 4360255932Salfred mtt->order); 4361255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4362255932Salfred rb_erase(&mtt->com.node, 4363255932Salfred &tracker->res_tree[RES_MTT]); 4364255932Salfred list_del(&mtt->com.list); 4365255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4366272027Shselasky mlx4_release_resource(dev, slave, RES_MTT, 4367272027Shselasky 1 << mtt->order, 0); 4368255932Salfred kfree(mtt); 4369255932Salfred state = 0; 4370255932Salfred break; 4371255932Salfred 4372255932Salfred default: 4373255932Salfred state = 0; 4374255932Salfred } 4375255932Salfred } 4376255932Salfred } 4377255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4378255932Salfred } 4379255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4380255932Salfred} 4381255932Salfred 4382255932Salfredstatic void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) 4383255932Salfred{ 4384255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4385255932Salfred struct mlx4_resource_tracker *tracker = 4386255932Salfred &priv->mfunc.master.res_tracker; 4387255932Salfred struct list_head *fs_rule_list = 4388255932Salfred &tracker->slave_list[slave].res_list[RES_FS_RULE]; 4389255932Salfred struct res_fs_rule *fs_rule; 4390255932Salfred struct res_fs_rule *tmp; 4391255932Salfred int state; 4392255932Salfred u64 base; 4393255932Salfred int err; 4394255932Salfred 4395255932Salfred err = move_all_busy(dev, slave, RES_FS_RULE); 4396255932Salfred if (err) 4397255932Salfred mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", 4398255932Salfred slave); 4399255932Salfred 4400255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4401255932Salfred list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { 4402255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4403255932Salfred if (fs_rule->com.owner == slave) { 4404255932Salfred base = fs_rule->com.res_id; 4405255932Salfred state = fs_rule->com.from_state; 4406255932Salfred while (state != 0) { 4407255932Salfred switch (state) { 4408255932Salfred case RES_FS_RULE_ALLOCATED: 4409255932Salfred /* detach rule */ 4410255932Salfred err = mlx4_cmd(dev, base, 0, 0, 4411255932Salfred MLX4_QP_FLOW_STEERING_DETACH, 4412255932Salfred MLX4_CMD_TIME_CLASS_A, 4413255932Salfred MLX4_CMD_NATIVE); 4414255932Salfred 4415255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4416255932Salfred rb_erase(&fs_rule->com.node, 4417255932Salfred &tracker->res_tree[RES_FS_RULE]); 4418255932Salfred list_del(&fs_rule->com.list); 4419255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4420255932Salfred kfree(fs_rule); 4421255932Salfred state = 0; 4422255932Salfred break; 4423255932Salfred 4424255932Salfred default: 4425255932Salfred state = 0; 4426255932Salfred } 4427255932Salfred } 4428255932Salfred } 4429255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4430255932Salfred } 4431255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4432255932Salfred} 4433255932Salfred 4434255932Salfredstatic void rem_slave_eqs(struct mlx4_dev *dev, int slave) 4435255932Salfred{ 4436255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4437255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4438255932Salfred struct list_head *eq_list = 4439255932Salfred &tracker->slave_list[slave].res_list[RES_EQ]; 4440255932Salfred struct res_eq *eq; 4441255932Salfred struct res_eq *tmp; 4442255932Salfred int err; 4443255932Salfred int state; 4444255932Salfred LIST_HEAD(tlist); 4445255932Salfred int eqn; 4446255932Salfred struct mlx4_cmd_mailbox *mailbox; 4447255932Salfred 4448255932Salfred err = move_all_busy(dev, slave, RES_EQ); 4449255932Salfred if (err) 4450255932Salfred mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs to " 4451255932Salfred "busy for slave %d\n", slave); 4452255932Salfred 4453255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4454255932Salfred list_for_each_entry_safe(eq, tmp, eq_list, com.list) { 4455255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4456255932Salfred if (eq->com.owner == slave) { 4457255932Salfred eqn = eq->com.res_id; 4458255932Salfred state = eq->com.from_state; 4459255932Salfred while (state != 0) { 4460255932Salfred switch (state) { 4461255932Salfred case RES_EQ_RESERVED: 4462255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4463255932Salfred rb_erase(&eq->com.node, 4464255932Salfred &tracker->res_tree[RES_EQ]); 4465255932Salfred list_del(&eq->com.list); 4466255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4467255932Salfred kfree(eq); 4468255932Salfred state = 0; 4469255932Salfred break; 4470255932Salfred 4471255932Salfred case RES_EQ_HW: 4472255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 4473255932Salfred if (IS_ERR(mailbox)) { 4474255932Salfred cond_resched(); 4475255932Salfred continue; 4476255932Salfred } 4477255932Salfred err = mlx4_cmd_box(dev, slave, 0, 4478255932Salfred eqn & 0xff, 0, 4479255932Salfred MLX4_CMD_HW2SW_EQ, 4480255932Salfred MLX4_CMD_TIME_CLASS_A, 4481255932Salfred MLX4_CMD_NATIVE); 4482255932Salfred if (err) 4483255932Salfred mlx4_dbg(dev, "rem_slave_eqs: failed" 4484255932Salfred " to move slave %d eqs %d to" 4485255932Salfred " SW ownership\n", slave, eqn); 4486255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 4487255932Salfred atomic_dec(&eq->mtt->ref_count); 4488255932Salfred state = RES_EQ_RESERVED; 4489255932Salfred break; 4490255932Salfred 4491255932Salfred default: 4492255932Salfred state = 0; 4493255932Salfred } 4494255932Salfred } 4495255932Salfred } 4496255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4497255932Salfred } 4498255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4499255932Salfred} 4500255932Salfred 4501255932Salfredstatic void rem_slave_counters(struct mlx4_dev *dev, int slave) 4502255932Salfred{ 4503272027Shselasky __mlx4_slave_counters_free(dev, slave); 4504255932Salfred} 4505255932Salfred 4506255932Salfredstatic void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) 4507255932Salfred{ 4508255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4509255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4510255932Salfred struct list_head *xrcdn_list = 4511255932Salfred &tracker->slave_list[slave].res_list[RES_XRCD]; 4512255932Salfred struct res_xrcdn *xrcd; 4513255932Salfred struct res_xrcdn *tmp; 4514255932Salfred int err; 4515255932Salfred int xrcdn; 4516255932Salfred 4517255932Salfred err = move_all_busy(dev, slave, RES_XRCD); 4518255932Salfred if (err) 4519255932Salfred mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns to " 4520255932Salfred "busy for slave %d\n", slave); 4521255932Salfred 4522255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4523255932Salfred list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { 4524255932Salfred if (xrcd->com.owner == slave) { 4525255932Salfred xrcdn = xrcd->com.res_id; 4526255932Salfred rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); 4527255932Salfred list_del(&xrcd->com.list); 4528255932Salfred kfree(xrcd); 4529255932Salfred __mlx4_xrcd_free(dev, xrcdn); 4530255932Salfred } 4531255932Salfred } 4532255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4533255932Salfred} 4534255932Salfred 4535255932Salfredvoid mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) 4536255932Salfred{ 4537255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4538255932Salfred 4539255932Salfred mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 4540255932Salfred rem_slave_macs(dev, slave); 4541255932Salfred rem_slave_vlans(dev, slave); 4542272027Shselasky rem_slave_fs_rule(dev, slave); 4543255932Salfred rem_slave_qps(dev, slave); 4544255932Salfred rem_slave_srqs(dev, slave); 4545255932Salfred rem_slave_cqs(dev, slave); 4546255932Salfred rem_slave_mrs(dev, slave); 4547255932Salfred rem_slave_eqs(dev, slave); 4548255932Salfred rem_slave_mtts(dev, slave); 4549255932Salfred rem_slave_counters(dev, slave); 4550255932Salfred rem_slave_xrcdns(dev, slave); 4551255932Salfred mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 4552255932Salfred} 4553272027Shselasky 4554272027Shselaskyvoid mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) 4555272027Shselasky{ 4556272027Shselasky struct mlx4_vf_immed_vlan_work *work = 4557272027Shselasky container_of(_work, struct mlx4_vf_immed_vlan_work, work); 4558272027Shselasky struct mlx4_cmd_mailbox *mailbox; 4559272027Shselasky struct mlx4_update_qp_context *upd_context; 4560272027Shselasky struct mlx4_dev *dev = &work->priv->dev; 4561272027Shselasky struct mlx4_resource_tracker *tracker = 4562272027Shselasky &work->priv->mfunc.master.res_tracker; 4563272027Shselasky struct list_head *qp_list = 4564272027Shselasky &tracker->slave_list[work->slave].res_list[RES_QP]; 4565272027Shselasky struct res_qp *qp; 4566272027Shselasky struct res_qp *tmp; 4567272027Shselasky u64 qp_path_mask_vlan_ctrl = 4568272027Shselasky ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | 4569272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | 4570272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | 4571272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | 4572272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | 4573272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED)); 4574272027Shselasky 4575272027Shselasky u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | 4576272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) | 4577272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_CV) | 4578272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) | 4579272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) | 4580272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) | 4581272027Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); 4582272027Shselasky 4583272027Shselasky int err; 4584272027Shselasky int port, errors = 0; 4585272027Shselasky u8 vlan_control; 4586272027Shselasky 4587272027Shselasky if (mlx4_is_slave(dev)) { 4588272027Shselasky mlx4_warn(dev, "Trying to update-qp in slave %d\n", 4589272027Shselasky work->slave); 4590272027Shselasky goto out; 4591272027Shselasky } 4592272027Shselasky 4593272027Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 4594272027Shselasky if (IS_ERR(mailbox)) 4595272027Shselasky goto out; 4596272027Shselasky 4597272027Shselasky if (!work->vlan_id) 4598272027Shselasky vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 4599272027Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 4600272027Shselasky else 4601272027Shselasky vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 4602272027Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 4603272027Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 4604272027Shselasky 4605272027Shselasky upd_context = mailbox->buf; 4606272027Shselasky upd_context->qp_mask = cpu_to_be64(MLX4_UPD_QP_MASK_VSD); 4607272027Shselasky 4608272027Shselasky spin_lock_irq(mlx4_tlock(dev)); 4609272027Shselasky list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 4610272027Shselasky spin_unlock_irq(mlx4_tlock(dev)); 4611272027Shselasky if (qp->com.owner == work->slave) { 4612272027Shselasky if (qp->com.from_state != RES_QP_HW || 4613272027Shselasky !qp->sched_queue || /* no INIT2RTR trans yet */ 4614272027Shselasky mlx4_is_qp_reserved(dev, qp->local_qpn) || 4615272027Shselasky qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { 4616272027Shselasky spin_lock_irq(mlx4_tlock(dev)); 4617272027Shselasky continue; 4618272027Shselasky } 4619272027Shselasky port = (qp->sched_queue >> 6 & 1) + 1; 4620272027Shselasky if (port != work->port) { 4621272027Shselasky spin_lock_irq(mlx4_tlock(dev)); 4622272027Shselasky continue; 4623272027Shselasky } 4624272027Shselasky if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff)) 4625272027Shselasky upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask); 4626272027Shselasky else 4627272027Shselasky upd_context->primary_addr_path_mask = 4628272027Shselasky cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl); 4629272027Shselasky if (work->vlan_id == MLX4_VGT) { 4630272027Shselasky upd_context->qp_context.param3 = qp->param3; 4631272027Shselasky upd_context->qp_context.pri_path.vlan_control = qp->vlan_control; 4632272027Shselasky upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx; 4633272027Shselasky upd_context->qp_context.pri_path.vlan_index = qp->vlan_index; 4634272027Shselasky upd_context->qp_context.pri_path.fl = qp->pri_path_fl; 4635272027Shselasky upd_context->qp_context.pri_path.feup = qp->feup; 4636272027Shselasky upd_context->qp_context.pri_path.sched_queue = 4637272027Shselasky qp->sched_queue; 4638272027Shselasky } else { 4639272027Shselasky upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN); 4640272027Shselasky upd_context->qp_context.pri_path.vlan_control = vlan_control; 4641272027Shselasky upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; 4642272027Shselasky upd_context->qp_context.pri_path.fvl_rx = 4643272027Shselasky qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN; 4644272027Shselasky upd_context->qp_context.pri_path.fl = 4645272027Shselasky qp->pri_path_fl | MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; 4646272027Shselasky upd_context->qp_context.pri_path.feup = 4647272027Shselasky qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 4648272027Shselasky upd_context->qp_context.pri_path.sched_queue = 4649272027Shselasky qp->sched_queue & 0xC7; 4650272027Shselasky upd_context->qp_context.pri_path.sched_queue |= 4651272027Shselasky ((work->qos & 0x7) << 3); 4652272027Shselasky } 4653272027Shselasky 4654272027Shselasky err = mlx4_cmd(dev, mailbox->dma, 4655272027Shselasky qp->local_qpn & 0xffffff, 4656272027Shselasky 0, MLX4_CMD_UPDATE_QP, 4657272027Shselasky MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 4658272027Shselasky if (err) { 4659272027Shselasky mlx4_info(dev, "UPDATE_QP failed for slave %d, " 4660272027Shselasky "port %d, qpn %d (%d)\n", 4661272027Shselasky work->slave, port, qp->local_qpn, 4662272027Shselasky err); 4663272027Shselasky errors++; 4664272027Shselasky } 4665272027Shselasky } 4666272027Shselasky spin_lock_irq(mlx4_tlock(dev)); 4667272027Shselasky } 4668272027Shselasky spin_unlock_irq(mlx4_tlock(dev)); 4669272027Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 4670272027Shselasky 4671272027Shselasky if (errors) 4672272027Shselasky mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", 4673272027Shselasky errors, work->slave, work->port); 4674272027Shselasky 4675272027Shselasky /* unregister previous vlan_id if needed and we had no errors 4676272027Shselasky * while updating the QPs 4677272027Shselasky */ 4678272027Shselasky if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && 4679272027Shselasky NO_INDX != work->orig_vlan_ix) 4680272027Shselasky __mlx4_unregister_vlan(&work->priv->dev, work->port, 4681272027Shselasky work->orig_vlan_id); 4682272027Shselaskyout: 4683272027Shselasky kfree(work); 4684272027Shselasky return; 4685272027Shselasky} 4686272027Shselasky 4687