1255932Salfred/* 2255932Salfred * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3272407Shselasky * 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> 45272407Shselasky#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; 88272407Shselasky 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; 113272407Shselasky atomic_t ref_count; 114272407Shselasky u32 qpc_flags; 115272407Shselasky /* saved qp params before VST enforcement in order to restore on VGT */ 116272407Shselasky u8 sched_queue; 117272407Shselasky __be32 param3; 118272407Shselasky u8 vlan_control; 119272407Shselasky u8 fvl_rx; 120272407Shselasky u8 pri_path_fl; 121272407Shselasky u8 vlan_index; 122272407Shselasky 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; 221272407Shselasky 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 637272407Shselaskystatic int check_counter_index_validity(struct mlx4_dev *dev, int slave, int port, int idx) 638272407Shselasky{ 639272407Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 640272407Shselasky struct counter_index *counter, *tmp_counter; 641272407Shselasky 642272407Shselasky if (slave == 0) { 643272407Shselasky list_for_each_entry_safe(counter, tmp_counter, 644272407Shselasky &priv->counters_table.global_port_list[port - 1], 645272407Shselasky list) { 646272407Shselasky if (counter->index == idx) 647272407Shselasky return 0; 648272407Shselasky } 649272407Shselasky return -EINVAL; 650272407Shselasky } else { 651272407Shselasky list_for_each_entry_safe(counter, tmp_counter, 652272407Shselasky &priv->counters_table.vf_list[slave - 1][port - 1], 653272407Shselasky list) { 654272407Shselasky if (counter->index == idx) 655272407Shselasky return 0; 656272407Shselasky } 657272407Shselasky return -EINVAL; 658272407Shselasky } 659272407Shselasky} 660272407Shselasky 661255932Salfredstatic int update_vport_qp_param(struct mlx4_dev *dev, 662255932Salfred struct mlx4_cmd_mailbox *inbox, 663272407Shselasky 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]; 674272407Shselasky qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 675255932Salfred 676272407Shselasky if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && 677272407Shselasky qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX) { 678272407Shselasky if (check_counter_index_validity(dev, slave, port, 679272407Shselasky qpc->pri_path.counter_index)) 680255932Salfred return -EINVAL; 681272407Shselasky } 682255932Salfred 683272407Shselasky mlx4_dbg(dev, "%s: QP counter_index %d for slave %d port %d\n", 684272407Shselasky __func__, qpc->pri_path.counter_index, slave, port); 685272407Shselasky 686272407Shselasky if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) && 687272407Shselasky dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && 688272407Shselasky !mlx4_is_qp_reserved(dev, qpn) && 689272407Shselasky qp_type == MLX4_QP_ST_MLX && 690272407Shselasky qpc->pri_path.counter_index != 0xFF) { 691272407Shselasky /* disable multicast loopback to qp with same counter */ 692272407Shselasky qpc->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB; 693272407Shselasky qpc->pri_path.vlan_control |= 694272407Shselasky MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; 695272407Shselasky } 696272407Shselasky 697272407Shselasky if (MLX4_VGT != vp_oper->state.default_vlan) { 698272407Shselasky /* the reserved QPs (special, proxy, tunnel) 699272407Shselasky * do not operate over vlans 700272407Shselasky */ 701272407Shselasky if (mlx4_is_qp_reserved(dev, qpn)) 702272407Shselasky return 0; 703272407Shselasky 704272407Shselasky /* force strip vlan by clear vsd */ 705272407Shselasky qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); 706272407Shselasky /* preserve IF_COUNTER flag */ 707272407Shselasky qpc->pri_path.vlan_control &= 708272407Shselasky MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; 709272407Shselasky if (MLX4_QP_ST_RC != qp_type) { 710272407Shselasky if (0 != vp_oper->state.default_vlan) { 711272407Shselasky qpc->pri_path.vlan_control |= 712272407Shselasky MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 713272407Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 714272407Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 715272407Shselasky } else { /* priority tagged */ 716272407Shselasky qpc->pri_path.vlan_control |= 717272407Shselasky MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 718272407Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 719272407Shselasky } 720272407Shselasky } 721272407Shselasky qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN; 722255932Salfred qpc->pri_path.vlan_index = vp_oper->vlan_idx; 723272407Shselasky qpc->pri_path.fl |= MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; 724272407Shselasky 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) { 729272407Shselasky 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 740272407Shselaskystatic 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) { 759272407Shselasky 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); 832272407Shselasky 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 940272407Shselaskystatic 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; 950272407Shselasky 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: 988272407Shselasky 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: 1042272407Shselasky for (--i; i >= 0; --i) { 1043255932Salfred rb_erase(&res_arr[i]->node, root); 1044272407Shselasky list_del_init(&res_arr[i]->list); 1045272407Shselasky } 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{ 1059272407Shselasky if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || 1060272407Shselasky !list_empty(&res->mcg_list)) { 1061272407Shselasky pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", 1062272407Shselasky res->com.state, atomic_read(&res->ref_count)); 1063255932Salfred return -EBUSY; 1064272407Shselasky } else if (res->com.state != RES_QP_RESERVED) { 1065255932Salfred return -EPERM; 1066272407Shselasky } 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", 1244272407Shselasky __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 1252272407Shselasky 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", 1262272407Shselasky (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; 1542272407Shselasky u8 flags; 1543255932Salfred 1544255932Salfred switch (op) { 1545255932Salfred case RES_OP_RESERVE: 1546255932Salfred count = get_param_l(&in_param) & 0xffffff; 1547318533Shselasky /* Turn off all unsupported QP allocation flags that the 1548318533Shselasky * slave tries to set. 1549318533Shselasky */ 1550318533Shselasky flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask; 1551255932Salfred align = get_param_h(&in_param); 1552255932Salfred err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); 1553255932Salfred if (err) 1554255932Salfred return err; 1555255932Salfred 1556272407Shselasky err = __mlx4_qp_reserve_range(dev, count, align, &base, flags); 1557255932Salfred if (err) { 1558255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 1559255932Salfred return err; 1560255932Salfred } 1561255932Salfred 1562255932Salfred err = add_res_range(dev, slave, base, count, RES_QP, 0); 1563255932Salfred if (err) { 1564255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 1565255932Salfred __mlx4_qp_release_range(dev, base, count); 1566255932Salfred return err; 1567255932Salfred } 1568255932Salfred set_param_l(out_param, base); 1569255932Salfred break; 1570255932Salfred case RES_OP_MAP_ICM: 1571255932Salfred qpn = get_param_l(&in_param) & 0x7fffff; 1572255932Salfred if (valid_reserved(dev, slave, qpn)) { 1573255932Salfred err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); 1574255932Salfred if (err) 1575255932Salfred return err; 1576255932Salfred } 1577255932Salfred 1578255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, 1579255932Salfred NULL, 1); 1580255932Salfred if (err) 1581255932Salfred return err; 1582255932Salfred 1583255932Salfred if (!fw_reserved(dev, qpn)) { 1584255932Salfred err = __mlx4_qp_alloc_icm(dev, qpn); 1585255932Salfred if (err) { 1586255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 1587255932Salfred return err; 1588255932Salfred } 1589255932Salfred } 1590255932Salfred 1591255932Salfred res_end_move(dev, slave, RES_QP, qpn); 1592255932Salfred break; 1593255932Salfred 1594255932Salfred default: 1595255932Salfred err = -EINVAL; 1596255932Salfred break; 1597255932Salfred } 1598255932Salfred return err; 1599255932Salfred} 1600255932Salfred 1601255932Salfredstatic int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1602255932Salfred u64 in_param, u64 *out_param) 1603255932Salfred{ 1604255932Salfred int err = -EINVAL; 1605255932Salfred int base; 1606255932Salfred int order; 1607255932Salfred 1608255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1609255932Salfred return err; 1610255932Salfred 1611255932Salfred order = get_param_l(&in_param); 1612255932Salfred 1613255932Salfred err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); 1614255932Salfred if (err) 1615255932Salfred return err; 1616255932Salfred 1617255932Salfred base = __mlx4_alloc_mtt_range(dev, order); 1618255932Salfred if (base == -1) { 1619255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 1620255932Salfred return -ENOMEM; 1621255932Salfred } 1622255932Salfred 1623255932Salfred err = add_res_range(dev, slave, base, 1, RES_MTT, order); 1624255932Salfred if (err) { 1625255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 1626255932Salfred __mlx4_free_mtt_range(dev, base, order); 1627255932Salfred } else 1628255932Salfred set_param_l(out_param, base); 1629255932Salfred 1630255932Salfred return err; 1631255932Salfred} 1632255932Salfred 1633255932Salfredstatic int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1634255932Salfred u64 in_param, u64 *out_param) 1635255932Salfred{ 1636255932Salfred int err = -EINVAL; 1637255932Salfred int index; 1638255932Salfred int id; 1639255932Salfred struct res_mpt *mpt; 1640255932Salfred 1641255932Salfred switch (op) { 1642255932Salfred case RES_OP_RESERVE: 1643255932Salfred err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); 1644255932Salfred if (err) 1645255932Salfred break; 1646255932Salfred 1647272407Shselasky index = __mlx4_mpt_reserve(dev); 1648255932Salfred if (index == -1) { 1649255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 1650255932Salfred break; 1651255932Salfred } 1652255932Salfred id = index & mpt_mask(dev); 1653255932Salfred 1654255932Salfred err = add_res_range(dev, slave, id, 1, RES_MPT, index); 1655255932Salfred if (err) { 1656255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 1657272407Shselasky __mlx4_mpt_release(dev, index); 1658255932Salfred break; 1659255932Salfred } 1660255932Salfred set_param_l(out_param, index); 1661255932Salfred break; 1662255932Salfred case RES_OP_MAP_ICM: 1663255932Salfred index = get_param_l(&in_param); 1664255932Salfred id = index & mpt_mask(dev); 1665255932Salfred err = mr_res_start_move_to(dev, slave, id, 1666255932Salfred RES_MPT_MAPPED, &mpt); 1667255932Salfred if (err) 1668255932Salfred return err; 1669255932Salfred 1670272407Shselasky err = __mlx4_mpt_alloc_icm(dev, mpt->key); 1671255932Salfred if (err) { 1672255932Salfred res_abort_move(dev, slave, RES_MPT, id); 1673255932Salfred return err; 1674255932Salfred } 1675255932Salfred 1676255932Salfred res_end_move(dev, slave, RES_MPT, id); 1677255932Salfred break; 1678255932Salfred } 1679255932Salfred return err; 1680255932Salfred} 1681255932Salfred 1682255932Salfredstatic int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1683255932Salfred u64 in_param, u64 *out_param) 1684255932Salfred{ 1685255932Salfred int cqn; 1686255932Salfred int err; 1687255932Salfred 1688255932Salfred switch (op) { 1689255932Salfred case RES_OP_RESERVE_AND_MAP: 1690255932Salfred err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); 1691255932Salfred if (err) 1692255932Salfred break; 1693255932Salfred 1694255932Salfred err = __mlx4_cq_alloc_icm(dev, &cqn); 1695255932Salfred if (err) { 1696255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 1697255932Salfred break; 1698255932Salfred } 1699255932Salfred 1700255932Salfred err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); 1701255932Salfred if (err) { 1702255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 1703255932Salfred __mlx4_cq_free_icm(dev, cqn); 1704255932Salfred break; 1705255932Salfred } 1706255932Salfred 1707255932Salfred set_param_l(out_param, cqn); 1708255932Salfred break; 1709255932Salfred 1710255932Salfred default: 1711255932Salfred err = -EINVAL; 1712255932Salfred } 1713255932Salfred 1714255932Salfred return err; 1715255932Salfred} 1716255932Salfred 1717255932Salfredstatic int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1718255932Salfred u64 in_param, u64 *out_param) 1719255932Salfred{ 1720255932Salfred int srqn; 1721255932Salfred int err; 1722255932Salfred 1723255932Salfred switch (op) { 1724255932Salfred case RES_OP_RESERVE_AND_MAP: 1725255932Salfred err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); 1726255932Salfred if (err) 1727255932Salfred break; 1728255932Salfred 1729255932Salfred err = __mlx4_srq_alloc_icm(dev, &srqn); 1730255932Salfred if (err) { 1731255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 1732255932Salfred break; 1733255932Salfred } 1734255932Salfred 1735255932Salfred err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 1736255932Salfred if (err) { 1737255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 1738255932Salfred __mlx4_srq_free_icm(dev, srqn); 1739255932Salfred break; 1740255932Salfred } 1741255932Salfred 1742255932Salfred set_param_l(out_param, srqn); 1743255932Salfred break; 1744255932Salfred 1745255932Salfred default: 1746255932Salfred err = -EINVAL; 1747255932Salfred } 1748255932Salfred 1749255932Salfred return err; 1750255932Salfred} 1751255932Salfred 1752255932Salfredstatic int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, 1753255932Salfred u8 smac_index, u64 *mac) 1754255932Salfred{ 1755255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1756255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1757255932Salfred struct list_head *mac_list = 1758255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1759255932Salfred struct mac_res *res, *tmp; 1760255932Salfred 1761255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1762255932Salfred if (res->smac_index == smac_index && res->port == (u8) port) { 1763255932Salfred *mac = res->mac; 1764255932Salfred return 0; 1765255932Salfred } 1766255932Salfred } 1767255932Salfred return -ENOENT; 1768255932Salfred} 1769255932Salfred 1770255932Salfredstatic int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) 1771255932Salfred{ 1772255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1773255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1774255932Salfred struct list_head *mac_list = 1775255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1776255932Salfred struct mac_res *res, *tmp; 1777255932Salfred 1778255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1779255932Salfred if (res->mac == mac && res->port == (u8) port) { 1780255932Salfred /* mac found. update ref count */ 1781255932Salfred ++res->ref_count; 1782255932Salfred return 0; 1783255932Salfred } 1784255932Salfred } 1785255932Salfred 1786255932Salfred if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) 1787255932Salfred return -EINVAL; 1788255932Salfred res = kzalloc(sizeof *res, GFP_KERNEL); 1789255932Salfred if (!res) { 1790255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, port); 1791255932Salfred return -ENOMEM; 1792255932Salfred } 1793255932Salfred res->mac = mac; 1794255932Salfred res->port = (u8) port; 1795255932Salfred res->smac_index = smac_index; 1796255932Salfred res->ref_count = 1; 1797255932Salfred list_add_tail(&res->list, 1798255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]); 1799255932Salfred return 0; 1800255932Salfred} 1801255932Salfred 1802255932Salfred 1803255932Salfredstatic void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, 1804255932Salfred int port) 1805255932Salfred{ 1806255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1807255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1808255932Salfred struct list_head *mac_list = 1809255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1810255932Salfred struct mac_res *res, *tmp; 1811255932Salfred 1812255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1813255932Salfred if (res->mac == mac && res->port == (u8) port) { 1814255932Salfred if (!--res->ref_count) { 1815255932Salfred list_del(&res->list); 1816255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, port); 1817255932Salfred kfree(res); 1818255932Salfred } 1819255932Salfred break; 1820255932Salfred } 1821255932Salfred } 1822255932Salfred} 1823255932Salfred 1824255932Salfredstatic void rem_slave_macs(struct mlx4_dev *dev, int slave) 1825255932Salfred{ 1826255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1827255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1828255932Salfred struct list_head *mac_list = 1829255932Salfred &tracker->slave_list[slave].res_list[RES_MAC]; 1830255932Salfred struct mac_res *res, *tmp; 1831255932Salfred int i; 1832255932Salfred 1833255932Salfred list_for_each_entry_safe(res, tmp, mac_list, list) { 1834255932Salfred list_del(&res->list); 1835255932Salfred /* dereference the mac the num times the slave referenced it */ 1836255932Salfred for (i = 0; i < res->ref_count; i++) 1837255932Salfred __mlx4_unregister_mac(dev, res->port, res->mac); 1838255932Salfred mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); 1839255932Salfred kfree(res); 1840255932Salfred } 1841255932Salfred} 1842255932Salfred 1843255932Salfredstatic int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1844255932Salfred u64 in_param, u64 *out_param, int in_port) 1845255932Salfred{ 1846255932Salfred int err = -EINVAL; 1847255932Salfred int port; 1848255932Salfred u64 mac; 1849255932Salfred u8 smac_index = 0; 1850255932Salfred 1851255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1852255932Salfred return err; 1853255932Salfred 1854255932Salfred port = !in_port ? get_param_l(out_param) : in_port; 1855255932Salfred mac = in_param; 1856255932Salfred 1857255932Salfred err = __mlx4_register_mac(dev, port, mac); 1858255932Salfred if (err >= 0) { 1859255932Salfred smac_index = err; 1860255932Salfred set_param_l(out_param, err); 1861255932Salfred err = 0; 1862255932Salfred } 1863255932Salfred 1864255932Salfred if (!err) { 1865255932Salfred err = mac_add_to_slave(dev, slave, mac, port, smac_index); 1866255932Salfred if (err) 1867255932Salfred __mlx4_unregister_mac(dev, port, mac); 1868255932Salfred } 1869255932Salfred return err; 1870255932Salfred} 1871255932Salfred 1872255932Salfredstatic int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, 1873255932Salfred int port, int vlan_index) 1874255932Salfred{ 1875255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1876255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1877255932Salfred struct list_head *vlan_list = 1878255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1879255932Salfred struct vlan_res *res, *tmp; 1880255932Salfred 1881255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1882255932Salfred if (res->vlan == vlan && res->port == (u8) port) { 1883255932Salfred /* vlan found. update ref count */ 1884255932Salfred ++res->ref_count; 1885255932Salfred return 0; 1886255932Salfred } 1887255932Salfred } 1888255932Salfred 1889255932Salfred if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) 1890255932Salfred return -EINVAL; 1891255932Salfred res = kzalloc(sizeof(*res), GFP_KERNEL); 1892255932Salfred if (!res) { 1893255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1, port); 1894255932Salfred return -ENOMEM; 1895255932Salfred } 1896255932Salfred res->vlan = vlan; 1897255932Salfred res->port = (u8) port; 1898255932Salfred res->vlan_index = vlan_index; 1899255932Salfred res->ref_count = 1; 1900255932Salfred list_add_tail(&res->list, 1901255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]); 1902255932Salfred return 0; 1903255932Salfred} 1904255932Salfred 1905255932Salfred 1906255932Salfredstatic void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, 1907255932Salfred int port) 1908255932Salfred{ 1909255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1910255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1911255932Salfred struct list_head *vlan_list = 1912255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1913255932Salfred struct vlan_res *res, *tmp; 1914255932Salfred 1915255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1916255932Salfred if (res->vlan == vlan && res->port == (u8) port) { 1917255932Salfred if (!--res->ref_count) { 1918255932Salfred list_del(&res->list); 1919255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1920255932Salfred 1, port); 1921255932Salfred kfree(res); 1922255932Salfred } 1923255932Salfred break; 1924255932Salfred } 1925255932Salfred } 1926255932Salfred} 1927255932Salfred 1928255932Salfredstatic void rem_slave_vlans(struct mlx4_dev *dev, int slave) 1929255932Salfred{ 1930255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1931255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 1932255932Salfred struct list_head *vlan_list = 1933255932Salfred &tracker->slave_list[slave].res_list[RES_VLAN]; 1934255932Salfred struct vlan_res *res, *tmp; 1935255932Salfred int i; 1936255932Salfred 1937255932Salfred list_for_each_entry_safe(res, tmp, vlan_list, list) { 1938255932Salfred list_del(&res->list); 1939255932Salfred /* dereference the vlan the num times the slave referenced it */ 1940255932Salfred for (i = 0; i < res->ref_count; i++) 1941255932Salfred __mlx4_unregister_vlan(dev, res->port, res->vlan); 1942255932Salfred mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); 1943255932Salfred kfree(res); 1944255932Salfred } 1945255932Salfred} 1946255932Salfred 1947255932Salfredstatic int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1948272407Shselasky u64 in_param, u64 *out_param, int in_port) 1949255932Salfred{ 1950272407Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 1951272407Shselasky struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 1952255932Salfred int err = -EINVAL; 1953255932Salfred u16 vlan; 1954255932Salfred int vlan_index; 1955272407Shselasky int port; 1956255932Salfred 1957272407Shselasky port = !in_port ? get_param_l(out_param) : in_port; 1958272407Shselasky 1959255932Salfred if (!port) 1960255932Salfred return err; 1961255932Salfred 1962255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 1963255932Salfred return err; 1964255932Salfred 1965272407Shselasky /* upstream kernels had NOP for reg/unreg vlan. Continue this. */ 1966272407Shselasky if (!in_port && port > 0 && port <= dev->caps.num_ports) { 1967272407Shselasky slave_state[slave].old_vlan_api = true; 1968272407Shselasky return 0; 1969272407Shselasky } 1970272407Shselasky 1971255932Salfred vlan = (u16) in_param; 1972255932Salfred 1973255932Salfred err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); 1974255932Salfred if (!err) { 1975255932Salfred set_param_l(out_param, (u32) vlan_index); 1976255932Salfred err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); 1977255932Salfred if (err) 1978255932Salfred __mlx4_unregister_vlan(dev, port, vlan); 1979255932Salfred } 1980255932Salfred return err; 1981255932Salfred} 1982255932Salfred 1983255932Salfredstatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1984272407Shselasky u64 in_param, u64 *out_param, int port) 1985255932Salfred{ 1986255932Salfred u32 index; 1987255932Salfred int err; 1988255932Salfred 1989255932Salfred if (op != RES_OP_RESERVE) 1990255932Salfred return -EINVAL; 1991255932Salfred 1992272407Shselasky err = __mlx4_counter_alloc(dev, slave, port, &index); 1993272407Shselasky if (!err) 1994255932Salfred set_param_l(out_param, index); 1995255932Salfred 1996255932Salfred return err; 1997255932Salfred} 1998255932Salfred 1999255932Salfredstatic int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2000255932Salfred u64 in_param, u64 *out_param) 2001255932Salfred{ 2002255932Salfred u32 xrcdn; 2003255932Salfred int err; 2004255932Salfred 2005255932Salfred if (op != RES_OP_RESERVE) 2006255932Salfred return -EINVAL; 2007255932Salfred 2008255932Salfred err = __mlx4_xrcd_alloc(dev, &xrcdn); 2009255932Salfred if (err) 2010255932Salfred return err; 2011255932Salfred 2012255932Salfred err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 2013255932Salfred if (err) 2014255932Salfred __mlx4_xrcd_free(dev, xrcdn); 2015255932Salfred else 2016255932Salfred set_param_l(out_param, xrcdn); 2017255932Salfred 2018255932Salfred return err; 2019255932Salfred} 2020255932Salfred 2021255932Salfredint mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, 2022255932Salfred struct mlx4_vhcr *vhcr, 2023255932Salfred struct mlx4_cmd_mailbox *inbox, 2024255932Salfred struct mlx4_cmd_mailbox *outbox, 2025255932Salfred struct mlx4_cmd_info *cmd) 2026255932Salfred{ 2027255932Salfred int err; 2028255932Salfred int alop = vhcr->op_modifier; 2029255932Salfred 2030255932Salfred switch (vhcr->in_modifier & 0xFF) { 2031255932Salfred case RES_QP: 2032255932Salfred err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, 2033255932Salfred vhcr->in_param, &vhcr->out_param); 2034255932Salfred break; 2035255932Salfred 2036255932Salfred case RES_MTT: 2037255932Salfred err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, 2038255932Salfred vhcr->in_param, &vhcr->out_param); 2039255932Salfred break; 2040255932Salfred 2041255932Salfred case RES_MPT: 2042255932Salfred err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, 2043255932Salfred vhcr->in_param, &vhcr->out_param); 2044255932Salfred break; 2045255932Salfred 2046255932Salfred case RES_CQ: 2047255932Salfred err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, 2048255932Salfred vhcr->in_param, &vhcr->out_param); 2049255932Salfred break; 2050255932Salfred 2051255932Salfred case RES_SRQ: 2052255932Salfred err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, 2053255932Salfred vhcr->in_param, &vhcr->out_param); 2054255932Salfred break; 2055255932Salfred 2056255932Salfred case RES_MAC: 2057255932Salfred err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, 2058255932Salfred vhcr->in_param, &vhcr->out_param, 2059255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2060255932Salfred break; 2061255932Salfred 2062255932Salfred case RES_VLAN: 2063255932Salfred err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, 2064255932Salfred vhcr->in_param, &vhcr->out_param, 2065255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2066255932Salfred break; 2067255932Salfred 2068255932Salfred case RES_COUNTER: 2069255932Salfred err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, 2070272407Shselasky vhcr->in_param, &vhcr->out_param, 2071272407Shselasky (vhcr->in_modifier >> 8) & 0xFF); 2072255932Salfred break; 2073255932Salfred 2074255932Salfred case RES_XRCD: 2075255932Salfred err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, 2076255932Salfred vhcr->in_param, &vhcr->out_param); 2077255932Salfred break; 2078255932Salfred 2079255932Salfred default: 2080255932Salfred err = -EINVAL; 2081255932Salfred break; 2082255932Salfred } 2083255932Salfred 2084255932Salfred return err; 2085255932Salfred} 2086255932Salfred 2087255932Salfredstatic int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2088255932Salfred u64 in_param) 2089255932Salfred{ 2090255932Salfred int err; 2091255932Salfred int count; 2092255932Salfred int base; 2093255932Salfred int qpn; 2094255932Salfred 2095255932Salfred switch (op) { 2096255932Salfred case RES_OP_RESERVE: 2097255932Salfred base = get_param_l(&in_param) & 0x7fffff; 2098255932Salfred count = get_param_h(&in_param); 2099255932Salfred err = rem_res_range(dev, slave, base, count, RES_QP, 0); 2100255932Salfred if (err) 2101255932Salfred break; 2102255932Salfred mlx4_release_resource(dev, slave, RES_QP, count, 0); 2103255932Salfred __mlx4_qp_release_range(dev, base, count); 2104255932Salfred break; 2105255932Salfred case RES_OP_MAP_ICM: 2106255932Salfred qpn = get_param_l(&in_param) & 0x7fffff; 2107255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, 2108255932Salfred NULL, 0); 2109255932Salfred if (err) 2110255932Salfred return err; 2111255932Salfred 2112255932Salfred if (!fw_reserved(dev, qpn)) 2113255932Salfred __mlx4_qp_free_icm(dev, qpn); 2114255932Salfred 2115255932Salfred res_end_move(dev, slave, RES_QP, qpn); 2116255932Salfred 2117255932Salfred if (valid_reserved(dev, slave, qpn)) 2118255932Salfred err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); 2119255932Salfred break; 2120255932Salfred default: 2121255932Salfred err = -EINVAL; 2122255932Salfred break; 2123255932Salfred } 2124255932Salfred return err; 2125255932Salfred} 2126255932Salfred 2127255932Salfredstatic int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2128255932Salfred u64 in_param, u64 *out_param) 2129255932Salfred{ 2130255932Salfred int err = -EINVAL; 2131255932Salfred int base; 2132255932Salfred int order; 2133255932Salfred 2134255932Salfred if (op != RES_OP_RESERVE_AND_MAP) 2135255932Salfred return err; 2136255932Salfred 2137255932Salfred base = get_param_l(&in_param); 2138255932Salfred order = get_param_h(&in_param); 2139255932Salfred err = rem_res_range(dev, slave, base, 1, RES_MTT, order); 2140255932Salfred if (!err) { 2141255932Salfred mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); 2142255932Salfred __mlx4_free_mtt_range(dev, base, order); 2143255932Salfred } 2144255932Salfred return err; 2145255932Salfred} 2146255932Salfred 2147255932Salfredstatic int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2148255932Salfred u64 in_param) 2149255932Salfred{ 2150255932Salfred int err = -EINVAL; 2151255932Salfred int index; 2152255932Salfred int id; 2153255932Salfred struct res_mpt *mpt; 2154255932Salfred 2155255932Salfred switch (op) { 2156255932Salfred case RES_OP_RESERVE: 2157255932Salfred index = get_param_l(&in_param); 2158255932Salfred id = index & mpt_mask(dev); 2159255932Salfred err = get_res(dev, slave, id, RES_MPT, &mpt); 2160255932Salfred if (err) 2161255932Salfred break; 2162255932Salfred index = mpt->key; 2163255932Salfred put_res(dev, slave, id, RES_MPT); 2164255932Salfred 2165255932Salfred err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); 2166255932Salfred if (err) 2167255932Salfred break; 2168255932Salfred mlx4_release_resource(dev, slave, RES_MPT, 1, 0); 2169272407Shselasky __mlx4_mpt_release(dev, index); 2170255932Salfred break; 2171255932Salfred case RES_OP_MAP_ICM: 2172255932Salfred index = get_param_l(&in_param); 2173255932Salfred id = index & mpt_mask(dev); 2174255932Salfred err = mr_res_start_move_to(dev, slave, id, 2175255932Salfred RES_MPT_RESERVED, &mpt); 2176255932Salfred if (err) 2177255932Salfred return err; 2178255932Salfred 2179272407Shselasky __mlx4_mpt_free_icm(dev, mpt->key); 2180255932Salfred res_end_move(dev, slave, RES_MPT, id); 2181255932Salfred return err; 2182255932Salfred break; 2183255932Salfred default: 2184255932Salfred err = -EINVAL; 2185255932Salfred break; 2186255932Salfred } 2187255932Salfred return err; 2188255932Salfred} 2189255932Salfred 2190255932Salfredstatic int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2191255932Salfred u64 in_param, u64 *out_param) 2192255932Salfred{ 2193255932Salfred int cqn; 2194255932Salfred int err; 2195255932Salfred 2196255932Salfred switch (op) { 2197255932Salfred case RES_OP_RESERVE_AND_MAP: 2198255932Salfred cqn = get_param_l(&in_param); 2199255932Salfred err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); 2200255932Salfred if (err) 2201255932Salfred break; 2202255932Salfred 2203255932Salfred mlx4_release_resource(dev, slave, RES_CQ, 1, 0); 2204255932Salfred __mlx4_cq_free_icm(dev, cqn); 2205255932Salfred break; 2206255932Salfred 2207255932Salfred default: 2208255932Salfred err = -EINVAL; 2209255932Salfred break; 2210255932Salfred } 2211255932Salfred 2212255932Salfred return err; 2213255932Salfred} 2214255932Salfred 2215255932Salfredstatic int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2216255932Salfred u64 in_param, u64 *out_param) 2217255932Salfred{ 2218255932Salfred int srqn; 2219255932Salfred int err; 2220255932Salfred 2221255932Salfred switch (op) { 2222255932Salfred case RES_OP_RESERVE_AND_MAP: 2223255932Salfred srqn = get_param_l(&in_param); 2224255932Salfred err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); 2225255932Salfred if (err) 2226255932Salfred break; 2227255932Salfred 2228255932Salfred mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); 2229255932Salfred __mlx4_srq_free_icm(dev, srqn); 2230255932Salfred break; 2231255932Salfred 2232255932Salfred default: 2233255932Salfred err = -EINVAL; 2234255932Salfred break; 2235255932Salfred } 2236255932Salfred 2237255932Salfred return err; 2238255932Salfred} 2239255932Salfred 2240255932Salfredstatic int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2241255932Salfred u64 in_param, u64 *out_param, int in_port) 2242255932Salfred{ 2243255932Salfred int port; 2244255932Salfred int err = 0; 2245255932Salfred 2246255932Salfred switch (op) { 2247255932Salfred case RES_OP_RESERVE_AND_MAP: 2248255932Salfred port = !in_port ? get_param_l(out_param) : in_port; 2249255932Salfred mac_del_from_slave(dev, slave, in_param, port); 2250255932Salfred __mlx4_unregister_mac(dev, port, in_param); 2251255932Salfred break; 2252255932Salfred default: 2253255932Salfred err = -EINVAL; 2254255932Salfred break; 2255255932Salfred } 2256255932Salfred 2257255932Salfred return err; 2258255932Salfred 2259255932Salfred} 2260255932Salfred 2261255932Salfredstatic int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2262255932Salfred u64 in_param, u64 *out_param, int port) 2263255932Salfred{ 2264272407Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 2265272407Shselasky struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 2266255932Salfred int err = 0; 2267255932Salfred 2268255932Salfred switch (op) { 2269255932Salfred case RES_OP_RESERVE_AND_MAP: 2270272407Shselasky if (slave_state[slave].old_vlan_api == true) 2271272407Shselasky return 0; 2272255932Salfred if (!port) 2273255932Salfred return -EINVAL; 2274255932Salfred vlan_del_from_slave(dev, slave, in_param, port); 2275255932Salfred __mlx4_unregister_vlan(dev, port, in_param); 2276255932Salfred break; 2277255932Salfred default: 2278255932Salfred err = -EINVAL; 2279255932Salfred break; 2280255932Salfred } 2281255932Salfred 2282255932Salfred return err; 2283255932Salfred} 2284255932Salfred 2285255932Salfredstatic int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2286272407Shselasky u64 in_param, u64 *out_param, int port) 2287255932Salfred{ 2288255932Salfred int index; 2289255932Salfred 2290255932Salfred if (op != RES_OP_RESERVE) 2291255932Salfred return -EINVAL; 2292255932Salfred 2293255932Salfred index = get_param_l(&in_param); 2294255932Salfred 2295272407Shselasky __mlx4_counter_free(dev, slave, port, index); 2296255932Salfred 2297272407Shselasky return 0; 2298255932Salfred} 2299255932Salfred 2300255932Salfredstatic int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 2301255932Salfred u64 in_param, u64 *out_param) 2302255932Salfred{ 2303255932Salfred int xrcdn; 2304255932Salfred int err; 2305255932Salfred 2306255932Salfred if (op != RES_OP_RESERVE) 2307255932Salfred return -EINVAL; 2308255932Salfred 2309255932Salfred xrcdn = get_param_l(&in_param); 2310255932Salfred err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); 2311255932Salfred if (err) 2312255932Salfred return err; 2313255932Salfred 2314255932Salfred __mlx4_xrcd_free(dev, xrcdn); 2315255932Salfred 2316255932Salfred return err; 2317255932Salfred} 2318255932Salfred 2319255932Salfredint mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, 2320255932Salfred struct mlx4_vhcr *vhcr, 2321255932Salfred struct mlx4_cmd_mailbox *inbox, 2322255932Salfred struct mlx4_cmd_mailbox *outbox, 2323255932Salfred struct mlx4_cmd_info *cmd) 2324255932Salfred{ 2325255932Salfred int err = -EINVAL; 2326255932Salfred int alop = vhcr->op_modifier; 2327255932Salfred 2328255932Salfred switch (vhcr->in_modifier & 0xFF) { 2329255932Salfred case RES_QP: 2330255932Salfred err = qp_free_res(dev, slave, vhcr->op_modifier, alop, 2331255932Salfred vhcr->in_param); 2332255932Salfred break; 2333255932Salfred 2334255932Salfred case RES_MTT: 2335255932Salfred err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, 2336255932Salfred vhcr->in_param, &vhcr->out_param); 2337255932Salfred break; 2338255932Salfred 2339255932Salfred case RES_MPT: 2340255932Salfred err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, 2341255932Salfred vhcr->in_param); 2342255932Salfred break; 2343255932Salfred 2344255932Salfred case RES_CQ: 2345255932Salfred err = cq_free_res(dev, slave, vhcr->op_modifier, alop, 2346255932Salfred vhcr->in_param, &vhcr->out_param); 2347255932Salfred break; 2348255932Salfred 2349255932Salfred case RES_SRQ: 2350255932Salfred err = srq_free_res(dev, slave, vhcr->op_modifier, alop, 2351255932Salfred vhcr->in_param, &vhcr->out_param); 2352255932Salfred break; 2353255932Salfred 2354255932Salfred case RES_MAC: 2355255932Salfred err = mac_free_res(dev, slave, vhcr->op_modifier, alop, 2356255932Salfred vhcr->in_param, &vhcr->out_param, 2357255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2358255932Salfred break; 2359255932Salfred 2360255932Salfred case RES_VLAN: 2361255932Salfred err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, 2362255932Salfred vhcr->in_param, &vhcr->out_param, 2363255932Salfred (vhcr->in_modifier >> 8) & 0xFF); 2364255932Salfred break; 2365255932Salfred 2366255932Salfred case RES_COUNTER: 2367255932Salfred err = counter_free_res(dev, slave, vhcr->op_modifier, alop, 2368272407Shselasky vhcr->in_param, &vhcr->out_param, 2369272407Shselasky (vhcr->in_modifier >> 8) & 0xFF); 2370255932Salfred break; 2371255932Salfred 2372255932Salfred case RES_XRCD: 2373255932Salfred err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, 2374255932Salfred vhcr->in_param, &vhcr->out_param); 2375255932Salfred 2376255932Salfred default: 2377255932Salfred break; 2378255932Salfred } 2379255932Salfred return err; 2380255932Salfred} 2381255932Salfred 2382255932Salfred/* ugly but other choices are uglier */ 2383255932Salfredstatic int mr_phys_mpt(struct mlx4_mpt_entry *mpt) 2384255932Salfred{ 2385255932Salfred return (be32_to_cpu(mpt->flags) >> 9) & 1; 2386255932Salfred} 2387255932Salfred 2388255932Salfredstatic int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) 2389255932Salfred{ 2390255932Salfred return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; 2391255932Salfred} 2392255932Salfred 2393255932Salfredstatic int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) 2394255932Salfred{ 2395255932Salfred return be32_to_cpu(mpt->mtt_sz); 2396255932Salfred} 2397255932Salfred 2398272407Shselaskystatic u32 mr_get_pd(struct mlx4_mpt_entry *mpt) 2399272407Shselasky{ 2400272407Shselasky return be32_to_cpu(mpt->pd_flags) & 0x00ffffff; 2401272407Shselasky} 2402272407Shselasky 2403272407Shselaskystatic int mr_is_fmr(struct mlx4_mpt_entry *mpt) 2404272407Shselasky{ 2405272407Shselasky return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG; 2406272407Shselasky} 2407272407Shselasky 2408272407Shselaskystatic int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt) 2409272407Shselasky{ 2410272407Shselasky return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE; 2411272407Shselasky} 2412272407Shselasky 2413272407Shselaskystatic int mr_is_region(struct mlx4_mpt_entry *mpt) 2414272407Shselasky{ 2415272407Shselasky return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION; 2416272407Shselasky} 2417272407Shselasky 2418255932Salfredstatic int qp_get_mtt_addr(struct mlx4_qp_context *qpc) 2419255932Salfred{ 2420255932Salfred return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; 2421255932Salfred} 2422255932Salfred 2423255932Salfredstatic int srq_get_mtt_addr(struct mlx4_srq_context *srqc) 2424255932Salfred{ 2425255932Salfred return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; 2426255932Salfred} 2427255932Salfred 2428255932Salfredstatic int qp_get_mtt_size(struct mlx4_qp_context *qpc) 2429255932Salfred{ 2430255932Salfred int page_shift = (qpc->log_page_size & 0x3f) + 12; 2431255932Salfred int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; 2432255932Salfred int log_sq_sride = qpc->sq_size_stride & 7; 2433255932Salfred int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; 2434255932Salfred int log_rq_stride = qpc->rq_size_stride & 7; 2435255932Salfred int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; 2436255932Salfred int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; 2437272407Shselasky u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 2438272407Shselasky int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0; 2439255932Salfred int sq_size; 2440255932Salfred int rq_size; 2441255932Salfred int total_pages; 2442255932Salfred int total_mem; 2443255932Salfred int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; 2444255932Salfred 2445255932Salfred sq_size = 1 << (log_sq_size + log_sq_sride + 4); 2446255932Salfred rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); 2447255932Salfred total_mem = sq_size + rq_size; 2448255932Salfred total_pages = 2449255932Salfred roundup_pow_of_two((total_mem + (page_offset << 6)) >> 2450255932Salfred page_shift); 2451255932Salfred 2452255932Salfred return total_pages; 2453255932Salfred} 2454255932Salfred 2455255932Salfredstatic int check_mtt_range(struct mlx4_dev *dev, int slave, int start, 2456255932Salfred int size, struct res_mtt *mtt) 2457255932Salfred{ 2458255932Salfred int res_start = mtt->com.res_id; 2459255932Salfred int res_size = (1 << mtt->order); 2460255932Salfred 2461255932Salfred if (start < res_start || start + size > res_start + res_size) 2462255932Salfred return -EPERM; 2463255932Salfred return 0; 2464255932Salfred} 2465255932Salfred 2466255932Salfredint mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, 2467255932Salfred struct mlx4_vhcr *vhcr, 2468255932Salfred struct mlx4_cmd_mailbox *inbox, 2469255932Salfred struct mlx4_cmd_mailbox *outbox, 2470255932Salfred struct mlx4_cmd_info *cmd) 2471255932Salfred{ 2472255932Salfred int err; 2473255932Salfred int index = vhcr->in_modifier; 2474255932Salfred struct res_mtt *mtt; 2475255932Salfred struct res_mpt *mpt; 2476255932Salfred int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; 2477255932Salfred int phys; 2478255932Salfred int id; 2479272407Shselasky u32 pd; 2480272407Shselasky int pd_slave; 2481255932Salfred 2482255932Salfred id = index & mpt_mask(dev); 2483255932Salfred err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); 2484255932Salfred if (err) 2485255932Salfred return err; 2486255932Salfred 2487272407Shselasky /* Currently disable memory windows since this feature isn't tested yet 2488272407Shselasky * under virtualization. 2489272407Shselasky */ 2490272407Shselasky if (!mr_is_region(inbox->buf)) { 2491272407Shselasky err = -ENOSYS; 2492272407Shselasky goto ex_abort; 2493272407Shselasky } 2494272407Shselasky 2495272407Shselasky /* Make sure that the PD bits related to the slave id are zeros. */ 2496272407Shselasky pd = mr_get_pd(inbox->buf); 2497272407Shselasky pd_slave = (pd >> 17) & 0x7f; 2498272407Shselasky if (pd_slave != 0 && pd_slave != slave) { 2499272407Shselasky err = -EPERM; 2500272407Shselasky goto ex_abort; 2501272407Shselasky } 2502272407Shselasky 2503272407Shselasky if (mr_is_fmr(inbox->buf)) { 2504272407Shselasky /* FMR and Bind Enable are forbidden in slave devices. */ 2505272407Shselasky if (mr_is_bind_enabled(inbox->buf)) { 2506272407Shselasky err = -EPERM; 2507272407Shselasky goto ex_abort; 2508272407Shselasky } 2509272407Shselasky /* FMR and Memory Windows are also forbidden. */ 2510272407Shselasky if (!mr_is_region(inbox->buf)) { 2511272407Shselasky err = -EPERM; 2512272407Shselasky goto ex_abort; 2513272407Shselasky } 2514272407Shselasky } 2515272407Shselasky 2516255932Salfred phys = mr_phys_mpt(inbox->buf); 2517255932Salfred if (!phys) { 2518255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2519255932Salfred if (err) 2520255932Salfred goto ex_abort; 2521255932Salfred 2522255932Salfred err = check_mtt_range(dev, slave, mtt_base, 2523255932Salfred mr_get_mtt_size(inbox->buf), mtt); 2524255932Salfred if (err) 2525255932Salfred goto ex_put; 2526255932Salfred 2527255932Salfred mpt->mtt = mtt; 2528255932Salfred } 2529255932Salfred 2530255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2531255932Salfred if (err) 2532255932Salfred goto ex_put; 2533255932Salfred 2534255932Salfred if (!phys) { 2535255932Salfred atomic_inc(&mtt->ref_count); 2536255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2537255932Salfred } 2538255932Salfred 2539255932Salfred res_end_move(dev, slave, RES_MPT, id); 2540255932Salfred return 0; 2541255932Salfred 2542255932Salfredex_put: 2543255932Salfred if (!phys) 2544255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2545255932Salfredex_abort: 2546255932Salfred res_abort_move(dev, slave, RES_MPT, id); 2547255932Salfred 2548255932Salfred return err; 2549255932Salfred} 2550255932Salfred 2551255932Salfredint mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, 2552255932Salfred struct mlx4_vhcr *vhcr, 2553255932Salfred struct mlx4_cmd_mailbox *inbox, 2554255932Salfred struct mlx4_cmd_mailbox *outbox, 2555255932Salfred struct mlx4_cmd_info *cmd) 2556255932Salfred{ 2557255932Salfred int err; 2558255932Salfred int index = vhcr->in_modifier; 2559255932Salfred struct res_mpt *mpt; 2560255932Salfred int id; 2561255932Salfred 2562255932Salfred id = index & mpt_mask(dev); 2563255932Salfred err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); 2564255932Salfred if (err) 2565255932Salfred return err; 2566255932Salfred 2567255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2568255932Salfred if (err) 2569255932Salfred goto ex_abort; 2570255932Salfred 2571255932Salfred if (mpt->mtt) 2572255932Salfred atomic_dec(&mpt->mtt->ref_count); 2573255932Salfred 2574255932Salfred res_end_move(dev, slave, RES_MPT, id); 2575255932Salfred return 0; 2576255932Salfred 2577255932Salfredex_abort: 2578255932Salfred res_abort_move(dev, slave, RES_MPT, id); 2579255932Salfred 2580255932Salfred return err; 2581255932Salfred} 2582255932Salfred 2583255932Salfredint mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, 2584255932Salfred struct mlx4_vhcr *vhcr, 2585255932Salfred struct mlx4_cmd_mailbox *inbox, 2586255932Salfred struct mlx4_cmd_mailbox *outbox, 2587255932Salfred struct mlx4_cmd_info *cmd) 2588255932Salfred{ 2589255932Salfred int err; 2590255932Salfred int index = vhcr->in_modifier; 2591255932Salfred struct res_mpt *mpt; 2592255932Salfred int id; 2593255932Salfred 2594255932Salfred id = index & mpt_mask(dev); 2595255932Salfred err = get_res(dev, slave, id, RES_MPT, &mpt); 2596255932Salfred if (err) 2597255932Salfred return err; 2598255932Salfred 2599255932Salfred if (mpt->com.from_state != RES_MPT_HW) { 2600255932Salfred err = -EBUSY; 2601255932Salfred goto out; 2602255932Salfred } 2603255932Salfred 2604255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2605255932Salfred 2606255932Salfredout: 2607255932Salfred put_res(dev, slave, id, RES_MPT); 2608255932Salfred return err; 2609255932Salfred} 2610255932Salfred 2611255932Salfredstatic int qp_get_rcqn(struct mlx4_qp_context *qpc) 2612255932Salfred{ 2613255932Salfred return be32_to_cpu(qpc->cqn_recv) & 0xffffff; 2614255932Salfred} 2615255932Salfred 2616255932Salfredstatic int qp_get_scqn(struct mlx4_qp_context *qpc) 2617255932Salfred{ 2618255932Salfred return be32_to_cpu(qpc->cqn_send) & 0xffffff; 2619255932Salfred} 2620255932Salfred 2621255932Salfredstatic u32 qp_get_srqn(struct mlx4_qp_context *qpc) 2622255932Salfred{ 2623255932Salfred return be32_to_cpu(qpc->srqn) & 0x1ffffff; 2624255932Salfred} 2625255932Salfred 2626255932Salfredstatic void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, 2627255932Salfred struct mlx4_qp_context *context) 2628255932Salfred{ 2629255932Salfred u32 qpn = vhcr->in_modifier & 0xffffff; 2630255932Salfred u32 qkey = 0; 2631255932Salfred 2632255932Salfred if (mlx4_get_parav_qkey(dev, qpn, &qkey)) 2633255932Salfred return; 2634255932Salfred 2635255932Salfred /* adjust qkey in qp context */ 2636255932Salfred context->qkey = cpu_to_be32(qkey); 2637255932Salfred} 2638255932Salfred 2639255932Salfredint mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 2640255932Salfred struct mlx4_vhcr *vhcr, 2641255932Salfred struct mlx4_cmd_mailbox *inbox, 2642255932Salfred struct mlx4_cmd_mailbox *outbox, 2643255932Salfred struct mlx4_cmd_info *cmd) 2644255932Salfred{ 2645255932Salfred int err; 2646255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 2647255932Salfred struct res_mtt *mtt; 2648255932Salfred struct res_qp *qp; 2649255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 2650255932Salfred int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; 2651255932Salfred int mtt_size = qp_get_mtt_size(qpc); 2652255932Salfred struct res_cq *rcq; 2653255932Salfred struct res_cq *scq; 2654255932Salfred int rcqn = qp_get_rcqn(qpc); 2655255932Salfred int scqn = qp_get_scqn(qpc); 2656255932Salfred u32 srqn = qp_get_srqn(qpc) & 0xffffff; 2657255932Salfred int use_srq = (qp_get_srqn(qpc) >> 24) & 1; 2658255932Salfred struct res_srq *srq; 2659255932Salfred int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; 2660255932Salfred 2661255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); 2662255932Salfred if (err) 2663255932Salfred return err; 2664255932Salfred qp->local_qpn = local_qpn; 2665272407Shselasky qp->sched_queue = 0; 2666272407Shselasky qp->param3 = 0; 2667272407Shselasky qp->vlan_control = 0; 2668272407Shselasky qp->fvl_rx = 0; 2669272407Shselasky qp->pri_path_fl = 0; 2670272407Shselasky qp->vlan_index = 0; 2671272407Shselasky qp->feup = 0; 2672272407Shselasky qp->qpc_flags = be32_to_cpu(qpc->flags); 2673255932Salfred 2674255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2675255932Salfred if (err) 2676255932Salfred goto ex_abort; 2677255932Salfred 2678255932Salfred err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 2679255932Salfred if (err) 2680255932Salfred goto ex_put_mtt; 2681255932Salfred 2682255932Salfred err = get_res(dev, slave, rcqn, RES_CQ, &rcq); 2683255932Salfred if (err) 2684255932Salfred goto ex_put_mtt; 2685255932Salfred 2686255932Salfred if (scqn != rcqn) { 2687255932Salfred err = get_res(dev, slave, scqn, RES_CQ, &scq); 2688255932Salfred if (err) 2689255932Salfred goto ex_put_rcq; 2690255932Salfred } else 2691255932Salfred scq = rcq; 2692255932Salfred 2693255932Salfred if (use_srq) { 2694255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 2695255932Salfred if (err) 2696255932Salfred goto ex_put_scq; 2697255932Salfred } 2698255932Salfred 2699255932Salfred adjust_proxy_tun_qkey(dev, vhcr, qpc); 2700255932Salfred update_pkey_index(dev, slave, inbox); 2701255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2702255932Salfred if (err) 2703255932Salfred goto ex_put_srq; 2704255932Salfred atomic_inc(&mtt->ref_count); 2705255932Salfred qp->mtt = mtt; 2706255932Salfred atomic_inc(&rcq->ref_count); 2707255932Salfred qp->rcq = rcq; 2708255932Salfred atomic_inc(&scq->ref_count); 2709255932Salfred qp->scq = scq; 2710255932Salfred 2711255932Salfred if (scqn != rcqn) 2712255932Salfred put_res(dev, slave, scqn, RES_CQ); 2713255932Salfred 2714255932Salfred if (use_srq) { 2715255932Salfred atomic_inc(&srq->ref_count); 2716255932Salfred put_res(dev, slave, srqn, RES_SRQ); 2717255932Salfred qp->srq = srq; 2718255932Salfred } 2719255932Salfred put_res(dev, slave, rcqn, RES_CQ); 2720255932Salfred put_res(dev, slave, mtt_base, RES_MTT); 2721255932Salfred res_end_move(dev, slave, RES_QP, qpn); 2722255932Salfred 2723255932Salfred return 0; 2724255932Salfred 2725255932Salfredex_put_srq: 2726255932Salfred if (use_srq) 2727255932Salfred put_res(dev, slave, srqn, RES_SRQ); 2728255932Salfredex_put_scq: 2729255932Salfred if (scqn != rcqn) 2730255932Salfred put_res(dev, slave, scqn, RES_CQ); 2731255932Salfredex_put_rcq: 2732255932Salfred put_res(dev, slave, rcqn, RES_CQ); 2733255932Salfredex_put_mtt: 2734255932Salfred put_res(dev, slave, mtt_base, RES_MTT); 2735255932Salfredex_abort: 2736255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 2737255932Salfred 2738255932Salfred return err; 2739255932Salfred} 2740255932Salfred 2741255932Salfredstatic int eq_get_mtt_addr(struct mlx4_eq_context *eqc) 2742255932Salfred{ 2743255932Salfred return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; 2744255932Salfred} 2745255932Salfred 2746255932Salfredstatic int eq_get_mtt_size(struct mlx4_eq_context *eqc) 2747255932Salfred{ 2748255932Salfred int log_eq_size = eqc->log_eq_size & 0x1f; 2749255932Salfred int page_shift = (eqc->log_page_size & 0x3f) + 12; 2750255932Salfred 2751255932Salfred if (log_eq_size + 5 < page_shift) 2752255932Salfred return 1; 2753255932Salfred 2754255932Salfred return 1 << (log_eq_size + 5 - page_shift); 2755255932Salfred} 2756255932Salfred 2757255932Salfredstatic int cq_get_mtt_addr(struct mlx4_cq_context *cqc) 2758255932Salfred{ 2759255932Salfred return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; 2760255932Salfred} 2761255932Salfred 2762255932Salfredstatic int cq_get_mtt_size(struct mlx4_cq_context *cqc) 2763255932Salfred{ 2764255932Salfred int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; 2765255932Salfred int page_shift = (cqc->log_page_size & 0x3f) + 12; 2766255932Salfred 2767255932Salfred if (log_cq_size + 5 < page_shift) 2768255932Salfred return 1; 2769255932Salfred 2770255932Salfred return 1 << (log_cq_size + 5 - page_shift); 2771255932Salfred} 2772255932Salfred 2773255932Salfredint mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, 2774255932Salfred struct mlx4_vhcr *vhcr, 2775255932Salfred struct mlx4_cmd_mailbox *inbox, 2776255932Salfred struct mlx4_cmd_mailbox *outbox, 2777255932Salfred struct mlx4_cmd_info *cmd) 2778255932Salfred{ 2779255932Salfred int err; 2780255932Salfred int eqn = vhcr->in_modifier; 2781255932Salfred int res_id = (slave << 8) | eqn; 2782255932Salfred struct mlx4_eq_context *eqc = inbox->buf; 2783255932Salfred int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; 2784255932Salfred int mtt_size = eq_get_mtt_size(eqc); 2785255932Salfred struct res_eq *eq; 2786255932Salfred struct res_mtt *mtt; 2787255932Salfred 2788255932Salfred err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2789255932Salfred if (err) 2790255932Salfred return err; 2791255932Salfred err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); 2792255932Salfred if (err) 2793255932Salfred goto out_add; 2794255932Salfred 2795255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 2796255932Salfred if (err) 2797255932Salfred goto out_move; 2798255932Salfred 2799255932Salfred err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); 2800255932Salfred if (err) 2801255932Salfred goto out_put; 2802255932Salfred 2803255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2804255932Salfred if (err) 2805255932Salfred goto out_put; 2806255932Salfred 2807255932Salfred atomic_inc(&mtt->ref_count); 2808255932Salfred eq->mtt = mtt; 2809255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2810255932Salfred res_end_move(dev, slave, RES_EQ, res_id); 2811255932Salfred return 0; 2812255932Salfred 2813255932Salfredout_put: 2814255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 2815255932Salfredout_move: 2816255932Salfred res_abort_move(dev, slave, RES_EQ, res_id); 2817255932Salfredout_add: 2818255932Salfred rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2819255932Salfred return err; 2820255932Salfred} 2821255932Salfred 2822255932Salfredstatic int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, 2823255932Salfred int len, struct res_mtt **res) 2824255932Salfred{ 2825255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2826255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 2827255932Salfred struct res_mtt *mtt; 2828255932Salfred int err = -EINVAL; 2829255932Salfred 2830255932Salfred spin_lock_irq(mlx4_tlock(dev)); 2831255932Salfred list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], 2832255932Salfred com.list) { 2833255932Salfred if (!check_mtt_range(dev, slave, start, len, mtt)) { 2834255932Salfred *res = mtt; 2835255932Salfred mtt->com.from_state = mtt->com.state; 2836255932Salfred mtt->com.state = RES_MTT_BUSY; 2837255932Salfred err = 0; 2838255932Salfred break; 2839255932Salfred } 2840255932Salfred } 2841255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 2842255932Salfred 2843255932Salfred return err; 2844255932Salfred} 2845255932Salfred 2846255932Salfredstatic int verify_qp_parameters(struct mlx4_dev *dev, 2847255932Salfred struct mlx4_cmd_mailbox *inbox, 2848255932Salfred enum qp_transition transition, u8 slave) 2849255932Salfred{ 2850255932Salfred u32 qp_type; 2851255932Salfred struct mlx4_qp_context *qp_ctx; 2852255932Salfred enum mlx4_qp_optpar optpar; 2853255932Salfred int port; 2854255932Salfred int num_gids; 2855255932Salfred 2856255932Salfred qp_ctx = inbox->buf + 8; 2857255932Salfred qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; 2858255932Salfred optpar = be32_to_cpu(*(__be32 *) inbox->buf); 2859255932Salfred 2860255932Salfred switch (qp_type) { 2861255932Salfred case MLX4_QP_ST_RC: 2862255932Salfred case MLX4_QP_ST_UC: 2863255932Salfred switch (transition) { 2864255932Salfred case QP_TRANS_INIT2RTR: 2865255932Salfred case QP_TRANS_RTR2RTS: 2866255932Salfred case QP_TRANS_RTS2RTS: 2867255932Salfred case QP_TRANS_SQD2SQD: 2868255932Salfred case QP_TRANS_SQD2RTS: 2869255932Salfred if (slave != mlx4_master_func_num(dev)) 2870255932Salfred if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { 2871255932Salfred port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; 2872255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 2873255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 2874255932Salfred else 2875255932Salfred num_gids = 1; 2876255932Salfred if (qp_ctx->pri_path.mgid_index >= num_gids) 2877255932Salfred return -EINVAL; 2878255932Salfred } 2879255932Salfred if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { 2880255932Salfred port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; 2881255932Salfred if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) 2882255932Salfred num_gids = mlx4_get_slave_num_gids(dev, slave); 2883255932Salfred else 2884255932Salfred num_gids = 1; 2885255932Salfred if (qp_ctx->alt_path.mgid_index >= num_gids) 2886255932Salfred return -EINVAL; 2887255932Salfred } 2888255932Salfred break; 2889255932Salfred default: 2890255932Salfred break; 2891255932Salfred } 2892255932Salfred 2893255932Salfred break; 2894255932Salfred default: 2895255932Salfred break; 2896255932Salfred } 2897255932Salfred 2898255932Salfred return 0; 2899255932Salfred} 2900255932Salfred 2901255932Salfredint mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, 2902255932Salfred struct mlx4_vhcr *vhcr, 2903255932Salfred struct mlx4_cmd_mailbox *inbox, 2904255932Salfred struct mlx4_cmd_mailbox *outbox, 2905255932Salfred struct mlx4_cmd_info *cmd) 2906255932Salfred{ 2907255932Salfred struct mlx4_mtt mtt; 2908255932Salfred __be64 *page_list = inbox->buf; 2909255932Salfred u64 *pg_list = (u64 *)page_list; 2910255932Salfred int i; 2911255932Salfred struct res_mtt *rmtt = NULL; 2912255932Salfred int start = be64_to_cpu(page_list[0]); 2913255932Salfred int npages = vhcr->in_modifier; 2914255932Salfred int err; 2915255932Salfred 2916255932Salfred err = get_containing_mtt(dev, slave, start, npages, &rmtt); 2917255932Salfred if (err) 2918255932Salfred return err; 2919255932Salfred 2920255932Salfred /* Call the SW implementation of write_mtt: 2921255932Salfred * - Prepare a dummy mtt struct 2922255932Salfred * - Translate inbox contents to simple addresses in host endianess */ 2923255932Salfred mtt.offset = 0; /* TBD this is broken but I don't handle it since 2924255932Salfred we don't really use it */ 2925255932Salfred mtt.order = 0; 2926255932Salfred mtt.page_shift = 0; 2927255932Salfred for (i = 0; i < npages; ++i) 2928255932Salfred pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); 2929255932Salfred 2930255932Salfred err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, 2931255932Salfred ((u64 *)page_list + 2)); 2932255932Salfred 2933255932Salfred if (rmtt) 2934255932Salfred put_res(dev, slave, rmtt->com.res_id, RES_MTT); 2935255932Salfred 2936255932Salfred return err; 2937255932Salfred} 2938255932Salfred 2939255932Salfredint mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, 2940255932Salfred struct mlx4_vhcr *vhcr, 2941255932Salfred struct mlx4_cmd_mailbox *inbox, 2942255932Salfred struct mlx4_cmd_mailbox *outbox, 2943255932Salfred struct mlx4_cmd_info *cmd) 2944255932Salfred{ 2945255932Salfred int eqn = vhcr->in_modifier; 2946255932Salfred int res_id = eqn | (slave << 8); 2947255932Salfred struct res_eq *eq; 2948255932Salfred int err; 2949255932Salfred 2950255932Salfred err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); 2951255932Salfred if (err) 2952255932Salfred return err; 2953255932Salfred 2954255932Salfred err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); 2955255932Salfred if (err) 2956255932Salfred goto ex_abort; 2957255932Salfred 2958255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 2959255932Salfred if (err) 2960255932Salfred goto ex_put; 2961255932Salfred 2962255932Salfred atomic_dec(&eq->mtt->ref_count); 2963255932Salfred put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 2964255932Salfred res_end_move(dev, slave, RES_EQ, res_id); 2965255932Salfred rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); 2966255932Salfred 2967255932Salfred return 0; 2968255932Salfred 2969255932Salfredex_put: 2970255932Salfred put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); 2971255932Salfredex_abort: 2972255932Salfred res_abort_move(dev, slave, RES_EQ, res_id); 2973255932Salfred 2974255932Salfred return err; 2975255932Salfred} 2976255932Salfred 2977255932Salfredint mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) 2978255932Salfred{ 2979255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2980255932Salfred struct mlx4_slave_event_eq_info *event_eq; 2981255932Salfred struct mlx4_cmd_mailbox *mailbox; 2982255932Salfred u32 in_modifier = 0; 2983255932Salfred int err; 2984255932Salfred int res_id; 2985255932Salfred struct res_eq *req; 2986255932Salfred 2987255932Salfred if (!priv->mfunc.master.slave_state) 2988255932Salfred return -EINVAL; 2989255932Salfred 2990272407Shselasky /* check for slave valid, slave not PF, and slave active */ 2991272407Shselasky if (slave < 0 || slave >= dev->num_slaves || 2992272407Shselasky slave == dev->caps.function || 2993272407Shselasky !priv->mfunc.master.slave_state[slave].active) 2994272407Shselasky return 0; 2995272407Shselasky 2996255932Salfred event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; 2997255932Salfred 2998255932Salfred /* Create the event only if the slave is registered */ 2999255932Salfred if (event_eq->eqn < 0) 3000255932Salfred return 0; 3001255932Salfred 3002255932Salfred mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); 3003255932Salfred res_id = (slave << 8) | event_eq->eqn; 3004255932Salfred err = get_res(dev, slave, res_id, RES_EQ, &req); 3005255932Salfred if (err) 3006255932Salfred goto unlock; 3007255932Salfred 3008255932Salfred if (req->com.from_state != RES_EQ_HW) { 3009255932Salfred err = -EINVAL; 3010255932Salfred goto put; 3011255932Salfred } 3012255932Salfred 3013255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 3014255932Salfred if (IS_ERR(mailbox)) { 3015255932Salfred err = PTR_ERR(mailbox); 3016255932Salfred goto put; 3017255932Salfred } 3018255932Salfred 3019255932Salfred if (eqe->type == MLX4_EVENT_TYPE_CMD) { 3020255932Salfred ++event_eq->token; 3021255932Salfred eqe->event.cmd.token = cpu_to_be16(event_eq->token); 3022255932Salfred } 3023255932Salfred 3024255932Salfred memcpy(mailbox->buf, (u8 *) eqe, 28); 3025255932Salfred 3026255932Salfred in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); 3027255932Salfred 3028255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, 3029255932Salfred MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, 3030255932Salfred MLX4_CMD_NATIVE); 3031255932Salfred 3032255932Salfred put_res(dev, slave, res_id, RES_EQ); 3033255932Salfred mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 3034255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 3035255932Salfred return err; 3036255932Salfred 3037255932Salfredput: 3038255932Salfred put_res(dev, slave, res_id, RES_EQ); 3039255932Salfred 3040255932Salfredunlock: 3041255932Salfred mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); 3042255932Salfred return err; 3043255932Salfred} 3044255932Salfred 3045255932Salfredint mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, 3046255932Salfred struct mlx4_vhcr *vhcr, 3047255932Salfred struct mlx4_cmd_mailbox *inbox, 3048255932Salfred struct mlx4_cmd_mailbox *outbox, 3049255932Salfred struct mlx4_cmd_info *cmd) 3050255932Salfred{ 3051255932Salfred int eqn = vhcr->in_modifier; 3052255932Salfred int res_id = eqn | (slave << 8); 3053255932Salfred struct res_eq *eq; 3054255932Salfred int err; 3055255932Salfred 3056255932Salfred err = get_res(dev, slave, res_id, RES_EQ, &eq); 3057255932Salfred if (err) 3058255932Salfred return err; 3059255932Salfred 3060255932Salfred if (eq->com.from_state != RES_EQ_HW) { 3061255932Salfred err = -EINVAL; 3062255932Salfred goto ex_put; 3063255932Salfred } 3064255932Salfred 3065255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3066255932Salfred 3067255932Salfredex_put: 3068255932Salfred put_res(dev, slave, res_id, RES_EQ); 3069255932Salfred return err; 3070255932Salfred} 3071255932Salfred 3072255932Salfredint mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, 3073255932Salfred struct mlx4_vhcr *vhcr, 3074255932Salfred struct mlx4_cmd_mailbox *inbox, 3075255932Salfred struct mlx4_cmd_mailbox *outbox, 3076255932Salfred struct mlx4_cmd_info *cmd) 3077255932Salfred{ 3078255932Salfred int err; 3079255932Salfred int cqn = vhcr->in_modifier; 3080255932Salfred struct mlx4_cq_context *cqc = inbox->buf; 3081255932Salfred int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 3082255932Salfred struct res_cq *cq; 3083255932Salfred struct res_mtt *mtt; 3084255932Salfred 3085255932Salfred err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); 3086255932Salfred if (err) 3087255932Salfred return err; 3088255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3089255932Salfred if (err) 3090255932Salfred goto out_move; 3091255932Salfred err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 3092255932Salfred if (err) 3093255932Salfred goto out_put; 3094255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3095255932Salfred if (err) 3096255932Salfred goto out_put; 3097255932Salfred atomic_inc(&mtt->ref_count); 3098255932Salfred cq->mtt = mtt; 3099255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3100255932Salfred res_end_move(dev, slave, RES_CQ, cqn); 3101255932Salfred return 0; 3102255932Salfred 3103255932Salfredout_put: 3104255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3105255932Salfredout_move: 3106255932Salfred res_abort_move(dev, slave, RES_CQ, cqn); 3107255932Salfred return err; 3108255932Salfred} 3109255932Salfred 3110255932Salfredint mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, 3111255932Salfred struct mlx4_vhcr *vhcr, 3112255932Salfred struct mlx4_cmd_mailbox *inbox, 3113255932Salfred struct mlx4_cmd_mailbox *outbox, 3114255932Salfred struct mlx4_cmd_info *cmd) 3115255932Salfred{ 3116255932Salfred int err; 3117255932Salfred int cqn = vhcr->in_modifier; 3118255932Salfred struct res_cq *cq; 3119255932Salfred 3120255932Salfred err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); 3121255932Salfred if (err) 3122255932Salfred return err; 3123255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3124255932Salfred if (err) 3125255932Salfred goto out_move; 3126255932Salfred atomic_dec(&cq->mtt->ref_count); 3127255932Salfred res_end_move(dev, slave, RES_CQ, cqn); 3128255932Salfred return 0; 3129255932Salfred 3130255932Salfredout_move: 3131255932Salfred res_abort_move(dev, slave, RES_CQ, cqn); 3132255932Salfred return err; 3133255932Salfred} 3134255932Salfred 3135255932Salfredint mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, 3136255932Salfred struct mlx4_vhcr *vhcr, 3137255932Salfred struct mlx4_cmd_mailbox *inbox, 3138255932Salfred struct mlx4_cmd_mailbox *outbox, 3139255932Salfred struct mlx4_cmd_info *cmd) 3140255932Salfred{ 3141255932Salfred int cqn = vhcr->in_modifier; 3142255932Salfred struct res_cq *cq; 3143255932Salfred int err; 3144255932Salfred 3145255932Salfred err = get_res(dev, slave, cqn, RES_CQ, &cq); 3146255932Salfred if (err) 3147255932Salfred return err; 3148255932Salfred 3149255932Salfred if (cq->com.from_state != RES_CQ_HW) 3150255932Salfred goto ex_put; 3151255932Salfred 3152255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3153255932Salfredex_put: 3154255932Salfred put_res(dev, slave, cqn, RES_CQ); 3155255932Salfred 3156255932Salfred return err; 3157255932Salfred} 3158255932Salfred 3159255932Salfredstatic int handle_resize(struct mlx4_dev *dev, int slave, 3160255932Salfred struct mlx4_vhcr *vhcr, 3161255932Salfred struct mlx4_cmd_mailbox *inbox, 3162255932Salfred struct mlx4_cmd_mailbox *outbox, 3163255932Salfred struct mlx4_cmd_info *cmd, 3164255932Salfred struct res_cq *cq) 3165255932Salfred{ 3166255932Salfred int err; 3167255932Salfred struct res_mtt *orig_mtt; 3168255932Salfred struct res_mtt *mtt; 3169255932Salfred struct mlx4_cq_context *cqc = inbox->buf; 3170255932Salfred int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; 3171255932Salfred 3172255932Salfred err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); 3173255932Salfred if (err) 3174255932Salfred return err; 3175255932Salfred 3176255932Salfred if (orig_mtt != cq->mtt) { 3177255932Salfred err = -EINVAL; 3178255932Salfred goto ex_put; 3179255932Salfred } 3180255932Salfred 3181255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3182255932Salfred if (err) 3183255932Salfred goto ex_put; 3184255932Salfred 3185255932Salfred err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); 3186255932Salfred if (err) 3187255932Salfred goto ex_put1; 3188255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3189255932Salfred if (err) 3190255932Salfred goto ex_put1; 3191255932Salfred atomic_dec(&orig_mtt->ref_count); 3192255932Salfred put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 3193255932Salfred atomic_inc(&mtt->ref_count); 3194255932Salfred cq->mtt = mtt; 3195255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3196255932Salfred return 0; 3197255932Salfred 3198255932Salfredex_put1: 3199255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3200255932Salfredex_put: 3201255932Salfred put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); 3202255932Salfred 3203255932Salfred return err; 3204255932Salfred 3205255932Salfred} 3206255932Salfred 3207255932Salfredint mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, 3208255932Salfred struct mlx4_vhcr *vhcr, 3209255932Salfred struct mlx4_cmd_mailbox *inbox, 3210255932Salfred struct mlx4_cmd_mailbox *outbox, 3211255932Salfred struct mlx4_cmd_info *cmd) 3212255932Salfred{ 3213255932Salfred int cqn = vhcr->in_modifier; 3214255932Salfred struct res_cq *cq; 3215255932Salfred int err; 3216255932Salfred 3217255932Salfred err = get_res(dev, slave, cqn, RES_CQ, &cq); 3218255932Salfred if (err) 3219255932Salfred return err; 3220255932Salfred 3221255932Salfred if (cq->com.from_state != RES_CQ_HW) 3222255932Salfred goto ex_put; 3223255932Salfred 3224255932Salfred if (vhcr->op_modifier == 0) { 3225255932Salfred err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); 3226255932Salfred goto ex_put; 3227255932Salfred } 3228255932Salfred 3229255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3230255932Salfredex_put: 3231255932Salfred put_res(dev, slave, cqn, RES_CQ); 3232255932Salfred 3233255932Salfred return err; 3234255932Salfred} 3235255932Salfred 3236255932Salfredstatic int srq_get_mtt_size(struct mlx4_srq_context *srqc) 3237255932Salfred{ 3238255932Salfred int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; 3239255932Salfred int log_rq_stride = srqc->logstride & 7; 3240255932Salfred int page_shift = (srqc->log_page_size & 0x3f) + 12; 3241255932Salfred 3242255932Salfred if (log_srq_size + log_rq_stride + 4 < page_shift) 3243255932Salfred return 1; 3244255932Salfred 3245255932Salfred return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); 3246255932Salfred} 3247255932Salfred 3248255932Salfredint mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3249255932Salfred struct mlx4_vhcr *vhcr, 3250255932Salfred struct mlx4_cmd_mailbox *inbox, 3251255932Salfred struct mlx4_cmd_mailbox *outbox, 3252255932Salfred struct mlx4_cmd_info *cmd) 3253255932Salfred{ 3254255932Salfred int err; 3255255932Salfred int srqn = vhcr->in_modifier; 3256255932Salfred struct res_mtt *mtt; 3257255932Salfred struct res_srq *srq; 3258255932Salfred struct mlx4_srq_context *srqc = inbox->buf; 3259255932Salfred int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; 3260255932Salfred 3261255932Salfred if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) 3262255932Salfred return -EINVAL; 3263255932Salfred 3264255932Salfred err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); 3265255932Salfred if (err) 3266255932Salfred return err; 3267255932Salfred err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); 3268255932Salfred if (err) 3269255932Salfred goto ex_abort; 3270255932Salfred err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), 3271255932Salfred mtt); 3272255932Salfred if (err) 3273255932Salfred goto ex_put_mtt; 3274255932Salfred 3275255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3276255932Salfred if (err) 3277255932Salfred goto ex_put_mtt; 3278255932Salfred 3279255932Salfred atomic_inc(&mtt->ref_count); 3280255932Salfred srq->mtt = mtt; 3281255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3282255932Salfred res_end_move(dev, slave, RES_SRQ, srqn); 3283255932Salfred return 0; 3284255932Salfred 3285255932Salfredex_put_mtt: 3286255932Salfred put_res(dev, slave, mtt->com.res_id, RES_MTT); 3287255932Salfredex_abort: 3288255932Salfred res_abort_move(dev, slave, RES_SRQ, srqn); 3289255932Salfred 3290255932Salfred return err; 3291255932Salfred} 3292255932Salfred 3293255932Salfredint mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3294255932Salfred struct mlx4_vhcr *vhcr, 3295255932Salfred struct mlx4_cmd_mailbox *inbox, 3296255932Salfred struct mlx4_cmd_mailbox *outbox, 3297255932Salfred struct mlx4_cmd_info *cmd) 3298255932Salfred{ 3299255932Salfred int err; 3300255932Salfred int srqn = vhcr->in_modifier; 3301255932Salfred struct res_srq *srq; 3302255932Salfred 3303255932Salfred err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); 3304255932Salfred if (err) 3305255932Salfred return err; 3306255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3307255932Salfred if (err) 3308255932Salfred goto ex_abort; 3309255932Salfred atomic_dec(&srq->mtt->ref_count); 3310255932Salfred if (srq->cq) 3311255932Salfred atomic_dec(&srq->cq->ref_count); 3312255932Salfred res_end_move(dev, slave, RES_SRQ, srqn); 3313255932Salfred 3314255932Salfred return 0; 3315255932Salfred 3316255932Salfredex_abort: 3317255932Salfred res_abort_move(dev, slave, RES_SRQ, srqn); 3318255932Salfred 3319255932Salfred return err; 3320255932Salfred} 3321255932Salfred 3322255932Salfredint mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3323255932Salfred struct mlx4_vhcr *vhcr, 3324255932Salfred struct mlx4_cmd_mailbox *inbox, 3325255932Salfred struct mlx4_cmd_mailbox *outbox, 3326255932Salfred struct mlx4_cmd_info *cmd) 3327255932Salfred{ 3328255932Salfred int err; 3329255932Salfred int srqn = vhcr->in_modifier; 3330255932Salfred struct res_srq *srq; 3331255932Salfred 3332255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 3333255932Salfred if (err) 3334255932Salfred return err; 3335255932Salfred if (srq->com.from_state != RES_SRQ_HW) { 3336255932Salfred err = -EBUSY; 3337255932Salfred goto out; 3338255932Salfred } 3339255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3340255932Salfredout: 3341255932Salfred put_res(dev, slave, srqn, RES_SRQ); 3342255932Salfred return err; 3343255932Salfred} 3344255932Salfred 3345255932Salfredint mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, 3346255932Salfred struct mlx4_vhcr *vhcr, 3347255932Salfred struct mlx4_cmd_mailbox *inbox, 3348255932Salfred struct mlx4_cmd_mailbox *outbox, 3349255932Salfred struct mlx4_cmd_info *cmd) 3350255932Salfred{ 3351255932Salfred int err; 3352255932Salfred int srqn = vhcr->in_modifier; 3353255932Salfred struct res_srq *srq; 3354255932Salfred 3355255932Salfred err = get_res(dev, slave, srqn, RES_SRQ, &srq); 3356255932Salfred if (err) 3357255932Salfred return err; 3358255932Salfred 3359255932Salfred if (srq->com.from_state != RES_SRQ_HW) { 3360255932Salfred err = -EBUSY; 3361255932Salfred goto out; 3362255932Salfred } 3363255932Salfred 3364255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3365255932Salfredout: 3366255932Salfred put_res(dev, slave, srqn, RES_SRQ); 3367255932Salfred return err; 3368255932Salfred} 3369255932Salfred 3370255932Salfredint mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, 3371255932Salfred struct mlx4_vhcr *vhcr, 3372255932Salfred struct mlx4_cmd_mailbox *inbox, 3373255932Salfred struct mlx4_cmd_mailbox *outbox, 3374255932Salfred struct mlx4_cmd_info *cmd) 3375255932Salfred{ 3376255932Salfred int err; 3377255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 3378255932Salfred struct res_qp *qp; 3379255932Salfred 3380255932Salfred err = get_res(dev, slave, qpn, RES_QP, &qp); 3381255932Salfred if (err) 3382255932Salfred return err; 3383255932Salfred if (qp->com.from_state != RES_QP_HW) { 3384255932Salfred err = -EBUSY; 3385255932Salfred goto out; 3386255932Salfred } 3387255932Salfred 3388255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3389255932Salfredout: 3390255932Salfred put_res(dev, slave, qpn, RES_QP); 3391255932Salfred return err; 3392255932Salfred} 3393255932Salfred 3394255932Salfredint mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, 3395255932Salfred struct mlx4_vhcr *vhcr, 3396255932Salfred struct mlx4_cmd_mailbox *inbox, 3397255932Salfred struct mlx4_cmd_mailbox *outbox, 3398255932Salfred struct mlx4_cmd_info *cmd) 3399255932Salfred{ 3400255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3401255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3402255932Salfred update_pkey_index(dev, slave, inbox); 3403255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3404255932Salfred} 3405255932Salfred 3406255932Salfredstatic int roce_verify_mac(struct mlx4_dev *dev, int slave, 3407255932Salfred struct mlx4_qp_context *qpc, 3408255932Salfred struct mlx4_cmd_mailbox *inbox) 3409255932Salfred{ 3410255932Salfred u64 mac; 3411255932Salfred int port; 3412255932Salfred u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; 3413255932Salfred u8 sched = *(u8 *)(inbox->buf + 64); 3414255932Salfred u8 smac_ix; 3415255932Salfred 3416255932Salfred port = (sched >> 6 & 1) + 1; 3417255932Salfred if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { 3418255932Salfred smac_ix = qpc->pri_path.grh_mylmc & 0x7f; 3419255932Salfred if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) 3420255932Salfred return -ENOENT; 3421255932Salfred } 3422255932Salfred return 0; 3423255932Salfred} 3424255932Salfred 3425255932Salfredint mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, 3426255932Salfred struct mlx4_vhcr *vhcr, 3427255932Salfred struct mlx4_cmd_mailbox *inbox, 3428255932Salfred struct mlx4_cmd_mailbox *outbox, 3429255932Salfred struct mlx4_cmd_info *cmd) 3430255932Salfred{ 3431255932Salfred int err; 3432255932Salfred struct mlx4_qp_context *qpc = inbox->buf + 8; 3433272407Shselasky int qpn = vhcr->in_modifier & 0x7fffff; 3434272407Shselasky struct res_qp *qp; 3435272407Shselasky u8 orig_sched_queue; 3436272407Shselasky __be32 orig_param3 = qpc->param3; 3437272407Shselasky u8 orig_vlan_control = qpc->pri_path.vlan_control; 3438272407Shselasky u8 orig_fvl_rx = qpc->pri_path.fvl_rx; 3439272407Shselasky u8 orig_pri_path_fl = qpc->pri_path.fl; 3440272407Shselasky u8 orig_vlan_index = qpc->pri_path.vlan_index; 3441272407Shselasky u8 orig_feup = qpc->pri_path.feup; 3442255932Salfred 3443255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); 3444255932Salfred if (err) 3445255932Salfred return err; 3446255932Salfred 3447255932Salfred if (roce_verify_mac(dev, slave, qpc, inbox)) 3448255932Salfred return -EINVAL; 3449255932Salfred 3450255932Salfred update_pkey_index(dev, slave, inbox); 3451255932Salfred update_gid(dev, inbox, (u8)slave); 3452255932Salfred adjust_proxy_tun_qkey(dev, vhcr, qpc); 3453272407Shselasky orig_sched_queue = qpc->pri_path.sched_queue; 3454272407Shselasky 3455272407Shselasky err = get_res(dev, slave, qpn, RES_QP, &qp); 3456255932Salfred if (err) 3457255932Salfred return err; 3458272407Shselasky if (qp->com.from_state != RES_QP_HW) { 3459272407Shselasky err = -EBUSY; 3460272407Shselasky goto out; 3461272407Shselasky } 3462255932Salfred 3463272407Shselasky /* do not modify vport QP params for RSS QPs */ 3464272407Shselasky if (!(qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET))) { 3465272407Shselasky err = update_vport_qp_param(dev, inbox, slave, qpn); 3466272407Shselasky if (err) 3467272407Shselasky goto out; 3468272407Shselasky } 3469272407Shselasky 3470272407Shselasky err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3471272407Shselaskyout: 3472272407Shselasky /* if no error, save sched queue value passed in by VF. This is 3473272407Shselasky * essentially the QOS value provided by the VF. This will be useful 3474272407Shselasky * if we allow dynamic changes from VST back to VGT 3475272407Shselasky */ 3476272407Shselasky if (!err) { 3477272407Shselasky qp->sched_queue = orig_sched_queue; 3478272407Shselasky qp->param3 = orig_param3; 3479272407Shselasky qp->vlan_control = orig_vlan_control; 3480272407Shselasky qp->fvl_rx = orig_fvl_rx; 3481272407Shselasky qp->pri_path_fl = orig_pri_path_fl; 3482272407Shselasky qp->vlan_index = orig_vlan_index; 3483272407Shselasky qp->feup = orig_feup; 3484272407Shselasky } 3485272407Shselasky put_res(dev, slave, qpn, RES_QP); 3486272407Shselasky return err; 3487255932Salfred} 3488255932Salfred 3489255932Salfredint mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3490255932Salfred struct mlx4_vhcr *vhcr, 3491255932Salfred struct mlx4_cmd_mailbox *inbox, 3492255932Salfred struct mlx4_cmd_mailbox *outbox, 3493255932Salfred struct mlx4_cmd_info *cmd) 3494255932Salfred{ 3495255932Salfred int err; 3496255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3497255932Salfred 3498255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave); 3499255932Salfred if (err) 3500255932Salfred return err; 3501255932Salfred 3502255932Salfred update_pkey_index(dev, slave, inbox); 3503255932Salfred update_gid(dev, inbox, (u8)slave); 3504255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3505255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3506255932Salfred} 3507255932Salfred 3508255932Salfredint mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3509255932Salfred struct mlx4_vhcr *vhcr, 3510255932Salfred struct mlx4_cmd_mailbox *inbox, 3511255932Salfred struct mlx4_cmd_mailbox *outbox, 3512255932Salfred struct mlx4_cmd_info *cmd) 3513255932Salfred{ 3514255932Salfred int err; 3515255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3516255932Salfred 3517255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave); 3518255932Salfred if (err) 3519255932Salfred return err; 3520255932Salfred 3521255932Salfred update_pkey_index(dev, slave, inbox); 3522255932Salfred update_gid(dev, inbox, (u8)slave); 3523255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3524255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3525255932Salfred} 3526255932Salfred 3527255932Salfred 3528255932Salfredint mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3529255932Salfred struct mlx4_vhcr *vhcr, 3530255932Salfred struct mlx4_cmd_mailbox *inbox, 3531255932Salfred struct mlx4_cmd_mailbox *outbox, 3532255932Salfred struct mlx4_cmd_info *cmd) 3533255932Salfred{ 3534255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3535255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3536255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3537255932Salfred} 3538255932Salfred 3539255932Salfredint mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, 3540255932Salfred struct mlx4_vhcr *vhcr, 3541255932Salfred struct mlx4_cmd_mailbox *inbox, 3542255932Salfred struct mlx4_cmd_mailbox *outbox, 3543255932Salfred struct mlx4_cmd_info *cmd) 3544255932Salfred{ 3545255932Salfred int err; 3546255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3547255932Salfred 3548255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave); 3549255932Salfred if (err) 3550255932Salfred return err; 3551255932Salfred 3552255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3553255932Salfred update_gid(dev, inbox, (u8)slave); 3554255932Salfred update_pkey_index(dev, slave, inbox); 3555255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3556255932Salfred} 3557255932Salfred 3558255932Salfredint mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, 3559255932Salfred struct mlx4_vhcr *vhcr, 3560255932Salfred struct mlx4_cmd_mailbox *inbox, 3561255932Salfred struct mlx4_cmd_mailbox *outbox, 3562255932Salfred struct mlx4_cmd_info *cmd) 3563255932Salfred{ 3564255932Salfred int err; 3565255932Salfred struct mlx4_qp_context *context = inbox->buf + 8; 3566255932Salfred 3567255932Salfred err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave); 3568255932Salfred if (err) 3569255932Salfred return err; 3570255932Salfred 3571255932Salfred adjust_proxy_tun_qkey(dev, vhcr, context); 3572255932Salfred update_gid(dev, inbox, (u8)slave); 3573255932Salfred update_pkey_index(dev, slave, inbox); 3574255932Salfred return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3575255932Salfred} 3576255932Salfred 3577255932Salfredint mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, 3578255932Salfred struct mlx4_vhcr *vhcr, 3579255932Salfred struct mlx4_cmd_mailbox *inbox, 3580255932Salfred struct mlx4_cmd_mailbox *outbox, 3581255932Salfred struct mlx4_cmd_info *cmd) 3582255932Salfred{ 3583255932Salfred int err; 3584255932Salfred int qpn = vhcr->in_modifier & 0x7fffff; 3585255932Salfred struct res_qp *qp; 3586255932Salfred 3587255932Salfred err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); 3588255932Salfred if (err) 3589255932Salfred return err; 3590255932Salfred err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3591255932Salfred if (err) 3592255932Salfred goto ex_abort; 3593255932Salfred 3594255932Salfred atomic_dec(&qp->mtt->ref_count); 3595255932Salfred atomic_dec(&qp->rcq->ref_count); 3596255932Salfred atomic_dec(&qp->scq->ref_count); 3597255932Salfred if (qp->srq) 3598255932Salfred atomic_dec(&qp->srq->ref_count); 3599255932Salfred res_end_move(dev, slave, RES_QP, qpn); 3600255932Salfred return 0; 3601255932Salfred 3602255932Salfredex_abort: 3603255932Salfred res_abort_move(dev, slave, RES_QP, qpn); 3604255932Salfred 3605255932Salfred return err; 3606255932Salfred} 3607255932Salfred 3608255932Salfredstatic struct res_gid *find_gid(struct mlx4_dev *dev, int slave, 3609255932Salfred struct res_qp *rqp, u8 *gid) 3610255932Salfred{ 3611255932Salfred struct res_gid *res; 3612255932Salfred 3613255932Salfred list_for_each_entry(res, &rqp->mcg_list, list) { 3614255932Salfred if (!memcmp(res->gid, gid, 16)) 3615255932Salfred return res; 3616255932Salfred } 3617255932Salfred return NULL; 3618255932Salfred} 3619255932Salfred 3620255932Salfredstatic int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 3621255932Salfred u8 *gid, enum mlx4_protocol prot, 3622272407Shselasky enum mlx4_steer_type steer, u64 reg_id) 3623255932Salfred{ 3624255932Salfred struct res_gid *res; 3625255932Salfred int err; 3626255932Salfred 3627255932Salfred res = kzalloc(sizeof *res, GFP_KERNEL); 3628255932Salfred if (!res) 3629255932Salfred return -ENOMEM; 3630255932Salfred 3631255932Salfred spin_lock_irq(&rqp->mcg_spl); 3632255932Salfred if (find_gid(dev, slave, rqp, gid)) { 3633255932Salfred kfree(res); 3634255932Salfred err = -EEXIST; 3635255932Salfred } else { 3636255932Salfred memcpy(res->gid, gid, 16); 3637255932Salfred res->prot = prot; 3638255932Salfred res->steer = steer; 3639272407Shselasky res->reg_id = reg_id; 3640255932Salfred list_add_tail(&res->list, &rqp->mcg_list); 3641255932Salfred err = 0; 3642255932Salfred } 3643255932Salfred spin_unlock_irq(&rqp->mcg_spl); 3644255932Salfred 3645255932Salfred return err; 3646255932Salfred} 3647255932Salfred 3648255932Salfredstatic int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, 3649255932Salfred u8 *gid, enum mlx4_protocol prot, 3650272407Shselasky enum mlx4_steer_type steer, u64 *reg_id) 3651255932Salfred{ 3652255932Salfred struct res_gid *res; 3653255932Salfred int err; 3654255932Salfred 3655255932Salfred spin_lock_irq(&rqp->mcg_spl); 3656255932Salfred res = find_gid(dev, slave, rqp, gid); 3657255932Salfred if (!res || res->prot != prot || res->steer != steer) 3658255932Salfred err = -EINVAL; 3659255932Salfred else { 3660272407Shselasky *reg_id = res->reg_id; 3661255932Salfred list_del(&res->list); 3662255932Salfred kfree(res); 3663255932Salfred err = 0; 3664255932Salfred } 3665255932Salfred spin_unlock_irq(&rqp->mcg_spl); 3666255932Salfred 3667255932Salfred return err; 3668255932Salfred} 3669255932Salfred 3670272407Shselaskystatic int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 3671272407Shselasky int block_loopback, enum mlx4_protocol prot, 3672272407Shselasky enum mlx4_steer_type type, u64 *reg_id) 3673272407Shselasky{ 3674272407Shselasky switch (dev->caps.steering_mode) { 3675272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 3676272407Shselasky return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5], 3677272407Shselasky block_loopback, prot, 3678272407Shselasky reg_id); 3679272407Shselasky case MLX4_STEERING_MODE_B0: 3680272407Shselasky return mlx4_qp_attach_common(dev, qp, gid, 3681272407Shselasky block_loopback, prot, type); 3682272407Shselasky default: 3683272407Shselasky return -EINVAL; 3684272407Shselasky } 3685272407Shselasky} 3686272407Shselasky 3687272407Shselaskystatic int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 3688272407Shselasky enum mlx4_protocol prot, enum mlx4_steer_type type, 3689272407Shselasky u64 reg_id) 3690272407Shselasky{ 3691272407Shselasky switch (dev->caps.steering_mode) { 3692272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 3693272407Shselasky return mlx4_flow_detach(dev, reg_id); 3694272407Shselasky case MLX4_STEERING_MODE_B0: 3695272407Shselasky return mlx4_qp_detach_common(dev, qp, gid, prot, type); 3696272407Shselasky default: 3697272407Shselasky return -EINVAL; 3698272407Shselasky } 3699272407Shselasky} 3700272407Shselasky 3701255932Salfredint mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 3702255932Salfred struct mlx4_vhcr *vhcr, 3703255932Salfred struct mlx4_cmd_mailbox *inbox, 3704255932Salfred struct mlx4_cmd_mailbox *outbox, 3705255932Salfred struct mlx4_cmd_info *cmd) 3706255932Salfred{ 3707255932Salfred struct mlx4_qp qp; /* dummy for calling attach/detach */ 3708255932Salfred u8 *gid = inbox->buf; 3709255932Salfred enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; 3710255932Salfred int err; 3711255932Salfred int qpn; 3712255932Salfred struct res_qp *rqp; 3713272407Shselasky u64 reg_id = 0; 3714255932Salfred int attach = vhcr->op_modifier; 3715255932Salfred int block_loopback = vhcr->in_modifier >> 31; 3716255932Salfred u8 steer_type_mask = 2; 3717255932Salfred enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; 3718255932Salfred 3719255932Salfred qpn = vhcr->in_modifier & 0xffffff; 3720255932Salfred err = get_res(dev, slave, qpn, RES_QP, &rqp); 3721255932Salfred if (err) 3722255932Salfred return err; 3723255932Salfred 3724255932Salfred qp.qpn = qpn; 3725255932Salfred if (attach) { 3726272407Shselasky err = qp_attach(dev, &qp, gid, block_loopback, prot, 3727272407Shselasky type, ®_id); 3728272407Shselasky if (err) { 3729272407Shselasky pr_err("Fail to attach rule to qp 0x%x\n", qpn); 3730255932Salfred goto ex_put; 3731272407Shselasky } 3732272407Shselasky err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id); 3733255932Salfred if (err) 3734272407Shselasky goto ex_detach; 3735255932Salfred } else { 3736272407Shselasky err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id); 3737255932Salfred if (err) 3738255932Salfred goto ex_put; 3739272407Shselasky 3740272407Shselasky err = qp_detach(dev, &qp, gid, prot, type, reg_id); 3741272407Shselasky if (err) 3742272407Shselasky pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n", 3743272407Shselasky qpn, (unsigned long long)reg_id); 3744255932Salfred } 3745255932Salfred put_res(dev, slave, qpn, RES_QP); 3746272407Shselasky return err; 3747255932Salfred 3748272407Shselaskyex_detach: 3749272407Shselasky qp_detach(dev, &qp, gid, prot, type, reg_id); 3750255932Salfredex_put: 3751255932Salfred put_res(dev, slave, qpn, RES_QP); 3752255932Salfred return err; 3753255932Salfred} 3754255932Salfred 3755255932Salfred/* 3756255932Salfred * MAC validation for Flow Steering rules. 3757255932Salfred * VF can attach rules only with a mac address which is assigned to it. 3758255932Salfred */ 3759255932Salfredstatic int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, 3760255932Salfred struct list_head *rlist) 3761255932Salfred{ 3762255932Salfred struct mac_res *res, *tmp; 3763255932Salfred __be64 be_mac; 3764255932Salfred 3765255932Salfred /* make sure it isn't multicast or broadcast mac*/ 3766255932Salfred if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && 3767255932Salfred !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { 3768255932Salfred list_for_each_entry_safe(res, tmp, rlist, list) { 3769255932Salfred be_mac = cpu_to_be64(res->mac << 16); 3770255932Salfred if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN)) 3771255932Salfred return 0; 3772255932Salfred } 3773255932Salfred pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", 3774255932Salfred eth_header->eth.dst_mac, slave); 3775255932Salfred return -EINVAL; 3776255932Salfred } 3777255932Salfred return 0; 3778255932Salfred} 3779255932Salfred 3780255932Salfred/* 3781255932Salfred * In case of missing eth header, append eth header with a MAC address 3782255932Salfred * assigned to the VF. 3783255932Salfred */ 3784255932Salfredstatic int add_eth_header(struct mlx4_dev *dev, int slave, 3785255932Salfred struct mlx4_cmd_mailbox *inbox, 3786255932Salfred struct list_head *rlist, int header_id) 3787255932Salfred{ 3788255932Salfred struct mac_res *res, *tmp; 3789255932Salfred u8 port; 3790255932Salfred struct mlx4_net_trans_rule_hw_ctrl *ctrl; 3791255932Salfred struct mlx4_net_trans_rule_hw_eth *eth_header; 3792255932Salfred struct mlx4_net_trans_rule_hw_ipv4 *ip_header; 3793255932Salfred struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; 3794255932Salfred __be64 be_mac = 0; 3795255932Salfred __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); 3796255932Salfred 3797255932Salfred ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 3798255932Salfred port = ctrl->port; 3799255932Salfred eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); 3800255932Salfred 3801255932Salfred /* Clear a space in the inbox for eth header */ 3802255932Salfred switch (header_id) { 3803255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 3804255932Salfred ip_header = 3805255932Salfred (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); 3806255932Salfred memmove(ip_header, eth_header, 3807255932Salfred sizeof(*ip_header) + sizeof(*l4_header)); 3808255932Salfred break; 3809255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 3810255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 3811255932Salfred l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) 3812255932Salfred (eth_header + 1); 3813255932Salfred memmove(l4_header, eth_header, sizeof(*l4_header)); 3814255932Salfred break; 3815255932Salfred default: 3816255932Salfred return -EINVAL; 3817255932Salfred } 3818255932Salfred list_for_each_entry_safe(res, tmp, rlist, list) { 3819255932Salfred if (port == res->port) { 3820255932Salfred be_mac = cpu_to_be64(res->mac << 16); 3821255932Salfred break; 3822255932Salfred } 3823255932Salfred } 3824255932Salfred if (!be_mac) { 3825255932Salfred pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n", 3826255932Salfred port); 3827255932Salfred return -EINVAL; 3828255932Salfred } 3829255932Salfred 3830255932Salfred memset(eth_header, 0, sizeof(*eth_header)); 3831255932Salfred eth_header->size = sizeof(*eth_header) >> 2; 3832255932Salfred eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); 3833255932Salfred memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); 3834255932Salfred memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); 3835255932Salfred 3836255932Salfred return 0; 3837255932Salfred 3838255932Salfred} 3839255932Salfred 3840255932Salfredint mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, 3841255932Salfred struct mlx4_vhcr *vhcr, 3842255932Salfred struct mlx4_cmd_mailbox *inbox, 3843255932Salfred struct mlx4_cmd_mailbox *outbox, 3844255932Salfred struct mlx4_cmd_info *cmd) 3845255932Salfred{ 3846255932Salfred 3847255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 3848255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 3849255932Salfred struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; 3850255932Salfred int err; 3851272407Shselasky int qpn; 3852272407Shselasky struct res_qp *rqp; 3853255932Salfred struct mlx4_net_trans_rule_hw_ctrl *ctrl; 3854255932Salfred struct _rule_hw *rule_header; 3855255932Salfred int header_id; 3856255932Salfred 3857255932Salfred if (dev->caps.steering_mode != 3858255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 3859255932Salfred return -EOPNOTSUPP; 3860255932Salfred 3861255932Salfred ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; 3862272407Shselasky qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; 3863272407Shselasky err = get_res(dev, slave, qpn, RES_QP, &rqp); 3864272407Shselasky if (err) { 3865272407Shselasky pr_err("Steering rule with qpn 0x%x rejected.\n", qpn); 3866272407Shselasky return err; 3867272407Shselasky } 3868255932Salfred rule_header = (struct _rule_hw *)(ctrl + 1); 3869255932Salfred header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); 3870255932Salfred 3871255932Salfred switch (header_id) { 3872255932Salfred case MLX4_NET_TRANS_RULE_ID_ETH: 3873272407Shselasky if (validate_eth_header_mac(slave, rule_header, rlist)) { 3874272407Shselasky err = -EINVAL; 3875272407Shselasky goto err_put; 3876272407Shselasky } 3877255932Salfred break; 3878255932Salfred case MLX4_NET_TRANS_RULE_ID_IB: 3879255932Salfred break; 3880255932Salfred case MLX4_NET_TRANS_RULE_ID_IPV4: 3881255932Salfred case MLX4_NET_TRANS_RULE_ID_TCP: 3882255932Salfred case MLX4_NET_TRANS_RULE_ID_UDP: 3883255932Salfred pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n"); 3884272407Shselasky if (add_eth_header(dev, slave, inbox, rlist, header_id)) { 3885272407Shselasky err = -EINVAL; 3886272407Shselasky goto err_put; 3887272407Shselasky } 3888255932Salfred vhcr->in_modifier += 3889255932Salfred sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; 3890255932Salfred break; 3891255932Salfred default: 3892255932Salfred pr_err("Corrupted mailbox.\n"); 3893272407Shselasky err = -EINVAL; 3894272407Shselasky goto err_put; 3895255932Salfred } 3896255932Salfred 3897255932Salfred err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, 3898255932Salfred vhcr->in_modifier, 0, 3899255932Salfred MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, 3900255932Salfred MLX4_CMD_NATIVE); 3901255932Salfred if (err) 3902272407Shselasky goto err_put; 3903255932Salfred 3904272407Shselasky err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); 3905255932Salfred if (err) { 3906255932Salfred mlx4_err(dev, "Fail to add flow steering resources.\n "); 3907255932Salfred /* detach rule*/ 3908255932Salfred mlx4_cmd(dev, vhcr->out_param, 0, 0, 3909272407Shselasky MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 3910255932Salfred MLX4_CMD_NATIVE); 3911272407Shselasky goto err_put; 3912255932Salfred } 3913272407Shselasky atomic_inc(&rqp->ref_count); 3914272407Shselaskyerr_put: 3915272407Shselasky put_res(dev, slave, qpn, RES_QP); 3916255932Salfred return err; 3917255932Salfred} 3918255932Salfred 3919255932Salfredint mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, 3920255932Salfred struct mlx4_vhcr *vhcr, 3921255932Salfred struct mlx4_cmd_mailbox *inbox, 3922255932Salfred struct mlx4_cmd_mailbox *outbox, 3923255932Salfred struct mlx4_cmd_info *cmd) 3924255932Salfred{ 3925255932Salfred int err; 3926272407Shselasky struct res_qp *rqp; 3927272407Shselasky struct res_fs_rule *rrule; 3928255932Salfred 3929255932Salfred if (dev->caps.steering_mode != 3930255932Salfred MLX4_STEERING_MODE_DEVICE_MANAGED) 3931255932Salfred return -EOPNOTSUPP; 3932255932Salfred 3933272407Shselasky err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); 3934272407Shselasky if (err) 3935255932Salfred return err; 3936272407Shselasky /* Release the rule form busy state before removal */ 3937272407Shselasky put_res(dev, slave, vhcr->in_param, RES_FS_RULE); 3938272407Shselasky err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); 3939272407Shselasky if (err) 3940272407Shselasky return err; 3941255932Salfred 3942255932Salfred err = mlx4_cmd(dev, vhcr->in_param, 0, 0, 3943255932Salfred MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, 3944255932Salfred MLX4_CMD_NATIVE); 3945272407Shselasky if (!err) { 3946272407Shselasky err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 3947272407Shselasky 0); 3948272407Shselasky atomic_dec(&rqp->ref_count); 3949272407Shselasky 3950272407Shselasky if (err) { 3951272407Shselasky mlx4_err(dev, "Fail to remove flow steering resources.\n "); 3952272407Shselasky goto out; 3953272407Shselasky } 3954272407Shselasky } 3955272407Shselasky 3956272407Shselaskyout: 3957272407Shselasky put_res(dev, slave, rrule->qpn, RES_QP); 3958255932Salfred return err; 3959255932Salfred} 3960255932Salfred 3961255932Salfredenum { 3962255932Salfred BUSY_MAX_RETRIES = 10 3963255932Salfred}; 3964255932Salfred 3965255932Salfredint mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, 3966255932Salfred struct mlx4_vhcr *vhcr, 3967255932Salfred struct mlx4_cmd_mailbox *inbox, 3968255932Salfred struct mlx4_cmd_mailbox *outbox, 3969255932Salfred struct mlx4_cmd_info *cmd) 3970255932Salfred{ 3971255932Salfred int err; 3972255932Salfred 3973272407Shselasky err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); 3974255932Salfred 3975255932Salfred return err; 3976255932Salfred} 3977255932Salfred 3978255932Salfredstatic void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) 3979255932Salfred{ 3980255932Salfred struct res_gid *rgid; 3981255932Salfred struct res_gid *tmp; 3982255932Salfred struct mlx4_qp qp; /* dummy for calling attach/detach */ 3983255932Salfred 3984255932Salfred list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { 3985272407Shselasky switch (dev->caps.steering_mode) { 3986272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 3987272407Shselasky mlx4_flow_detach(dev, rgid->reg_id); 3988272407Shselasky break; 3989272407Shselasky case MLX4_STEERING_MODE_B0: 3990272407Shselasky qp.qpn = rqp->local_qpn; 3991272407Shselasky (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, 3992272407Shselasky rgid->prot, rgid->steer); 3993272407Shselasky break; 3994272407Shselasky } 3995255932Salfred list_del(&rgid->list); 3996255932Salfred kfree(rgid); 3997255932Salfred } 3998255932Salfred} 3999255932Salfred 4000255932Salfredstatic int _move_all_busy(struct mlx4_dev *dev, int slave, 4001255932Salfred enum mlx4_resource type, int print) 4002255932Salfred{ 4003255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4004255932Salfred struct mlx4_resource_tracker *tracker = 4005255932Salfred &priv->mfunc.master.res_tracker; 4006255932Salfred struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; 4007255932Salfred struct res_common *r; 4008255932Salfred struct res_common *tmp; 4009255932Salfred int busy; 4010255932Salfred 4011255932Salfred busy = 0; 4012255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4013255932Salfred list_for_each_entry_safe(r, tmp, rlist, list) { 4014255932Salfred if (r->owner == slave) { 4015255932Salfred if (!r->removing) { 4016255932Salfred if (r->state == RES_ANY_BUSY) { 4017255932Salfred if (print) 4018255932Salfred mlx4_dbg(dev, 4019255932Salfred "%s id 0x%llx is busy\n", 4020255932Salfred ResourceType(type), 4021272407Shselasky (unsigned long long)r->res_id); 4022255932Salfred ++busy; 4023255932Salfred } else { 4024255932Salfred r->from_state = r->state; 4025255932Salfred r->state = RES_ANY_BUSY; 4026255932Salfred r->removing = 1; 4027255932Salfred } 4028255932Salfred } 4029255932Salfred } 4030255932Salfred } 4031255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4032255932Salfred 4033255932Salfred return busy; 4034255932Salfred} 4035255932Salfred 4036255932Salfredstatic int move_all_busy(struct mlx4_dev *dev, int slave, 4037255932Salfred enum mlx4_resource type) 4038255932Salfred{ 4039255932Salfred unsigned long begin; 4040255932Salfred int busy; 4041255932Salfred 4042255932Salfred begin = jiffies; 4043255932Salfred do { 4044255932Salfred busy = _move_all_busy(dev, slave, type, 0); 4045255932Salfred if (time_after(jiffies, begin + 5 * HZ)) 4046255932Salfred break; 4047255932Salfred if (busy) 4048255932Salfred cond_resched(); 4049255932Salfred } while (busy); 4050255932Salfred 4051255932Salfred if (busy) 4052255932Salfred busy = _move_all_busy(dev, slave, type, 1); 4053255932Salfred 4054255932Salfred return busy; 4055255932Salfred} 4056255932Salfredstatic void rem_slave_qps(struct mlx4_dev *dev, int slave) 4057255932Salfred{ 4058255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4059255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4060255932Salfred struct list_head *qp_list = 4061255932Salfred &tracker->slave_list[slave].res_list[RES_QP]; 4062255932Salfred struct res_qp *qp; 4063255932Salfred struct res_qp *tmp; 4064255932Salfred int state; 4065255932Salfred u64 in_param; 4066255932Salfred int qpn; 4067255932Salfred int err; 4068255932Salfred 4069255932Salfred err = move_all_busy(dev, slave, RES_QP); 4070255932Salfred if (err) 4071255932Salfred mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy" 4072255932Salfred "for slave %d\n", slave); 4073255932Salfred 4074255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4075255932Salfred list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 4076255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4077255932Salfred if (qp->com.owner == slave) { 4078255932Salfred qpn = qp->com.res_id; 4079255932Salfred detach_qp(dev, slave, qp); 4080255932Salfred state = qp->com.from_state; 4081255932Salfred while (state != 0) { 4082255932Salfred switch (state) { 4083255932Salfred case RES_QP_RESERVED: 4084255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4085255932Salfred rb_erase(&qp->com.node, 4086255932Salfred &tracker->res_tree[RES_QP]); 4087255932Salfred list_del(&qp->com.list); 4088255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4089272407Shselasky if (!valid_reserved(dev, slave, qpn)) { 4090272407Shselasky __mlx4_qp_release_range(dev, qpn, 1); 4091272407Shselasky mlx4_release_resource(dev, slave, 4092272407Shselasky RES_QP, 1, 0); 4093272407Shselasky } 4094255932Salfred kfree(qp); 4095255932Salfred state = 0; 4096255932Salfred break; 4097255932Salfred case RES_QP_MAPPED: 4098255932Salfred if (!valid_reserved(dev, slave, qpn)) 4099255932Salfred __mlx4_qp_free_icm(dev, qpn); 4100255932Salfred state = RES_QP_RESERVED; 4101255932Salfred break; 4102255932Salfred case RES_QP_HW: 4103255932Salfred in_param = slave; 4104255932Salfred err = mlx4_cmd(dev, in_param, 4105255932Salfred qp->local_qpn, 2, 4106255932Salfred MLX4_CMD_2RST_QP, 4107255932Salfred MLX4_CMD_TIME_CLASS_A, 4108255932Salfred MLX4_CMD_NATIVE); 4109255932Salfred if (err) 4110255932Salfred mlx4_dbg(dev, "rem_slave_qps: failed" 4111255932Salfred " to move slave %d qpn %d to" 4112255932Salfred " reset\n", slave, 4113255932Salfred qp->local_qpn); 4114255932Salfred atomic_dec(&qp->rcq->ref_count); 4115255932Salfred atomic_dec(&qp->scq->ref_count); 4116255932Salfred atomic_dec(&qp->mtt->ref_count); 4117255932Salfred if (qp->srq) 4118255932Salfred atomic_dec(&qp->srq->ref_count); 4119255932Salfred state = RES_QP_MAPPED; 4120255932Salfred break; 4121255932Salfred default: 4122255932Salfred state = 0; 4123255932Salfred } 4124255932Salfred } 4125255932Salfred } 4126255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4127255932Salfred } 4128255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4129255932Salfred} 4130255932Salfred 4131255932Salfredstatic void rem_slave_srqs(struct mlx4_dev *dev, int slave) 4132255932Salfred{ 4133255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4134255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4135255932Salfred struct list_head *srq_list = 4136255932Salfred &tracker->slave_list[slave].res_list[RES_SRQ]; 4137255932Salfred struct res_srq *srq; 4138255932Salfred struct res_srq *tmp; 4139255932Salfred int state; 4140255932Salfred u64 in_param; 4141255932Salfred LIST_HEAD(tlist); 4142255932Salfred int srqn; 4143255932Salfred int err; 4144255932Salfred 4145255932Salfred err = move_all_busy(dev, slave, RES_SRQ); 4146255932Salfred if (err) 4147255932Salfred mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs to " 4148255932Salfred "busy for slave %d\n", slave); 4149255932Salfred 4150255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4151255932Salfred list_for_each_entry_safe(srq, tmp, srq_list, com.list) { 4152255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4153255932Salfred if (srq->com.owner == slave) { 4154255932Salfred srqn = srq->com.res_id; 4155255932Salfred state = srq->com.from_state; 4156255932Salfred while (state != 0) { 4157255932Salfred switch (state) { 4158255932Salfred case RES_SRQ_ALLOCATED: 4159255932Salfred __mlx4_srq_free_icm(dev, srqn); 4160255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4161255932Salfred rb_erase(&srq->com.node, 4162255932Salfred &tracker->res_tree[RES_SRQ]); 4163255932Salfred list_del(&srq->com.list); 4164255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4165272407Shselasky mlx4_release_resource(dev, slave, 4166272407Shselasky RES_SRQ, 1, 0); 4167255932Salfred kfree(srq); 4168255932Salfred state = 0; 4169255932Salfred break; 4170255932Salfred 4171255932Salfred case RES_SRQ_HW: 4172255932Salfred in_param = slave; 4173255932Salfred err = mlx4_cmd(dev, in_param, srqn, 1, 4174255932Salfred MLX4_CMD_HW2SW_SRQ, 4175255932Salfred MLX4_CMD_TIME_CLASS_A, 4176255932Salfred MLX4_CMD_NATIVE); 4177255932Salfred if (err) 4178255932Salfred mlx4_dbg(dev, "rem_slave_srqs: failed" 4179255932Salfred " to move slave %d srq %d to" 4180255932Salfred " SW ownership\n", 4181255932Salfred slave, srqn); 4182255932Salfred 4183255932Salfred atomic_dec(&srq->mtt->ref_count); 4184255932Salfred if (srq->cq) 4185255932Salfred atomic_dec(&srq->cq->ref_count); 4186255932Salfred state = RES_SRQ_ALLOCATED; 4187255932Salfred break; 4188255932Salfred 4189255932Salfred default: 4190255932Salfred state = 0; 4191255932Salfred } 4192255932Salfred } 4193255932Salfred } 4194255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4195255932Salfred } 4196255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4197255932Salfred} 4198255932Salfred 4199255932Salfredstatic void rem_slave_cqs(struct mlx4_dev *dev, int slave) 4200255932Salfred{ 4201255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4202255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4203255932Salfred struct list_head *cq_list = 4204255932Salfred &tracker->slave_list[slave].res_list[RES_CQ]; 4205255932Salfred struct res_cq *cq; 4206255932Salfred struct res_cq *tmp; 4207255932Salfred int state; 4208255932Salfred u64 in_param; 4209255932Salfred LIST_HEAD(tlist); 4210255932Salfred int cqn; 4211255932Salfred int err; 4212255932Salfred 4213255932Salfred err = move_all_busy(dev, slave, RES_CQ); 4214255932Salfred if (err) 4215255932Salfred mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs to " 4216255932Salfred "busy for slave %d\n", slave); 4217255932Salfred 4218255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4219255932Salfred list_for_each_entry_safe(cq, tmp, cq_list, com.list) { 4220255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4221255932Salfred if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { 4222255932Salfred cqn = cq->com.res_id; 4223255932Salfred state = cq->com.from_state; 4224255932Salfred while (state != 0) { 4225255932Salfred switch (state) { 4226255932Salfred case RES_CQ_ALLOCATED: 4227255932Salfred __mlx4_cq_free_icm(dev, cqn); 4228255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4229255932Salfred rb_erase(&cq->com.node, 4230255932Salfred &tracker->res_tree[RES_CQ]); 4231255932Salfred list_del(&cq->com.list); 4232255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4233272407Shselasky mlx4_release_resource(dev, slave, 4234272407Shselasky RES_CQ, 1, 0); 4235255932Salfred kfree(cq); 4236255932Salfred state = 0; 4237255932Salfred break; 4238255932Salfred 4239255932Salfred case RES_CQ_HW: 4240255932Salfred in_param = slave; 4241255932Salfred err = mlx4_cmd(dev, in_param, cqn, 1, 4242255932Salfred MLX4_CMD_HW2SW_CQ, 4243255932Salfred MLX4_CMD_TIME_CLASS_A, 4244255932Salfred MLX4_CMD_NATIVE); 4245255932Salfred if (err) 4246255932Salfred mlx4_dbg(dev, "rem_slave_cqs: failed" 4247255932Salfred " to move slave %d cq %d to" 4248255932Salfred " SW ownership\n", 4249255932Salfred slave, cqn); 4250255932Salfred atomic_dec(&cq->mtt->ref_count); 4251255932Salfred state = RES_CQ_ALLOCATED; 4252255932Salfred break; 4253255932Salfred 4254255932Salfred default: 4255255932Salfred state = 0; 4256255932Salfred } 4257255932Salfred } 4258255932Salfred } 4259255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4260255932Salfred } 4261255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4262255932Salfred} 4263255932Salfred 4264255932Salfredstatic void rem_slave_mrs(struct mlx4_dev *dev, int slave) 4265255932Salfred{ 4266255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4267255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4268255932Salfred struct list_head *mpt_list = 4269255932Salfred &tracker->slave_list[slave].res_list[RES_MPT]; 4270255932Salfred struct res_mpt *mpt; 4271255932Salfred struct res_mpt *tmp; 4272255932Salfred int state; 4273255932Salfred u64 in_param; 4274255932Salfred LIST_HEAD(tlist); 4275255932Salfred int mptn; 4276255932Salfred int err; 4277255932Salfred 4278255932Salfred err = move_all_busy(dev, slave, RES_MPT); 4279255932Salfred if (err) 4280255932Salfred mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts to " 4281255932Salfred "busy for slave %d\n", slave); 4282255932Salfred 4283255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4284255932Salfred list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { 4285255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4286255932Salfred if (mpt->com.owner == slave) { 4287255932Salfred mptn = mpt->com.res_id; 4288255932Salfred state = mpt->com.from_state; 4289255932Salfred while (state != 0) { 4290255932Salfred switch (state) { 4291255932Salfred case RES_MPT_RESERVED: 4292272407Shselasky __mlx4_mpt_release(dev, mpt->key); 4293255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4294255932Salfred rb_erase(&mpt->com.node, 4295255932Salfred &tracker->res_tree[RES_MPT]); 4296255932Salfred list_del(&mpt->com.list); 4297255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4298272407Shselasky mlx4_release_resource(dev, slave, 4299272407Shselasky RES_MPT, 1, 0); 4300255932Salfred kfree(mpt); 4301255932Salfred state = 0; 4302255932Salfred break; 4303255932Salfred 4304255932Salfred case RES_MPT_MAPPED: 4305272407Shselasky __mlx4_mpt_free_icm(dev, mpt->key); 4306255932Salfred state = RES_MPT_RESERVED; 4307255932Salfred break; 4308255932Salfred 4309255932Salfred case RES_MPT_HW: 4310255932Salfred in_param = slave; 4311255932Salfred err = mlx4_cmd(dev, in_param, mptn, 0, 4312255932Salfred MLX4_CMD_HW2SW_MPT, 4313255932Salfred MLX4_CMD_TIME_CLASS_A, 4314255932Salfred MLX4_CMD_NATIVE); 4315255932Salfred if (err) 4316255932Salfred mlx4_dbg(dev, "rem_slave_mrs: failed" 4317255932Salfred " to move slave %d mpt %d to" 4318255932Salfred " SW ownership\n", 4319255932Salfred slave, mptn); 4320255932Salfred if (mpt->mtt) 4321255932Salfred atomic_dec(&mpt->mtt->ref_count); 4322255932Salfred state = RES_MPT_MAPPED; 4323255932Salfred break; 4324255932Salfred default: 4325255932Salfred state = 0; 4326255932Salfred } 4327255932Salfred } 4328255932Salfred } 4329255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4330255932Salfred } 4331255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4332255932Salfred} 4333255932Salfred 4334255932Salfredstatic void rem_slave_mtts(struct mlx4_dev *dev, int slave) 4335255932Salfred{ 4336255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4337255932Salfred struct mlx4_resource_tracker *tracker = 4338255932Salfred &priv->mfunc.master.res_tracker; 4339255932Salfred struct list_head *mtt_list = 4340255932Salfred &tracker->slave_list[slave].res_list[RES_MTT]; 4341255932Salfred struct res_mtt *mtt; 4342255932Salfred struct res_mtt *tmp; 4343255932Salfred int state; 4344255932Salfred LIST_HEAD(tlist); 4345255932Salfred int base; 4346255932Salfred int err; 4347255932Salfred 4348255932Salfred err = move_all_busy(dev, slave, RES_MTT); 4349255932Salfred if (err) 4350255932Salfred mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts to " 4351255932Salfred "busy for slave %d\n", slave); 4352255932Salfred 4353255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4354255932Salfred list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { 4355255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4356255932Salfred if (mtt->com.owner == slave) { 4357255932Salfred base = mtt->com.res_id; 4358255932Salfred state = mtt->com.from_state; 4359255932Salfred while (state != 0) { 4360255932Salfred switch (state) { 4361255932Salfred case RES_MTT_ALLOCATED: 4362255932Salfred __mlx4_free_mtt_range(dev, base, 4363255932Salfred mtt->order); 4364255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4365255932Salfred rb_erase(&mtt->com.node, 4366255932Salfred &tracker->res_tree[RES_MTT]); 4367255932Salfred list_del(&mtt->com.list); 4368255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4369272407Shselasky mlx4_release_resource(dev, slave, RES_MTT, 4370272407Shselasky 1 << mtt->order, 0); 4371255932Salfred kfree(mtt); 4372255932Salfred state = 0; 4373255932Salfred break; 4374255932Salfred 4375255932Salfred default: 4376255932Salfred state = 0; 4377255932Salfred } 4378255932Salfred } 4379255932Salfred } 4380255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4381255932Salfred } 4382255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4383255932Salfred} 4384255932Salfred 4385255932Salfredstatic void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) 4386255932Salfred{ 4387255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4388255932Salfred struct mlx4_resource_tracker *tracker = 4389255932Salfred &priv->mfunc.master.res_tracker; 4390255932Salfred struct list_head *fs_rule_list = 4391255932Salfred &tracker->slave_list[slave].res_list[RES_FS_RULE]; 4392255932Salfred struct res_fs_rule *fs_rule; 4393255932Salfred struct res_fs_rule *tmp; 4394255932Salfred int state; 4395255932Salfred u64 base; 4396255932Salfred int err; 4397255932Salfred 4398255932Salfred err = move_all_busy(dev, slave, RES_FS_RULE); 4399255932Salfred if (err) 4400255932Salfred mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", 4401255932Salfred slave); 4402255932Salfred 4403255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4404255932Salfred list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { 4405255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4406255932Salfred if (fs_rule->com.owner == slave) { 4407255932Salfred base = fs_rule->com.res_id; 4408255932Salfred state = fs_rule->com.from_state; 4409255932Salfred while (state != 0) { 4410255932Salfred switch (state) { 4411255932Salfred case RES_FS_RULE_ALLOCATED: 4412255932Salfred /* detach rule */ 4413255932Salfred err = mlx4_cmd(dev, base, 0, 0, 4414255932Salfred MLX4_QP_FLOW_STEERING_DETACH, 4415255932Salfred MLX4_CMD_TIME_CLASS_A, 4416255932Salfred MLX4_CMD_NATIVE); 4417255932Salfred 4418255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4419255932Salfred rb_erase(&fs_rule->com.node, 4420255932Salfred &tracker->res_tree[RES_FS_RULE]); 4421255932Salfred list_del(&fs_rule->com.list); 4422255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4423255932Salfred kfree(fs_rule); 4424255932Salfred state = 0; 4425255932Salfred break; 4426255932Salfred 4427255932Salfred default: 4428255932Salfred state = 0; 4429255932Salfred } 4430255932Salfred } 4431255932Salfred } 4432255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4433255932Salfred } 4434255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4435255932Salfred} 4436255932Salfred 4437255932Salfredstatic void rem_slave_eqs(struct mlx4_dev *dev, int slave) 4438255932Salfred{ 4439255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4440255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4441255932Salfred struct list_head *eq_list = 4442255932Salfred &tracker->slave_list[slave].res_list[RES_EQ]; 4443255932Salfred struct res_eq *eq; 4444255932Salfred struct res_eq *tmp; 4445255932Salfred int err; 4446255932Salfred int state; 4447255932Salfred LIST_HEAD(tlist); 4448255932Salfred int eqn; 4449255932Salfred struct mlx4_cmd_mailbox *mailbox; 4450255932Salfred 4451255932Salfred err = move_all_busy(dev, slave, RES_EQ); 4452255932Salfred if (err) 4453255932Salfred mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs to " 4454255932Salfred "busy for slave %d\n", slave); 4455255932Salfred 4456255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4457255932Salfred list_for_each_entry_safe(eq, tmp, eq_list, com.list) { 4458255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4459255932Salfred if (eq->com.owner == slave) { 4460255932Salfred eqn = eq->com.res_id; 4461255932Salfred state = eq->com.from_state; 4462255932Salfred while (state != 0) { 4463255932Salfred switch (state) { 4464255932Salfred case RES_EQ_RESERVED: 4465255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4466255932Salfred rb_erase(&eq->com.node, 4467255932Salfred &tracker->res_tree[RES_EQ]); 4468255932Salfred list_del(&eq->com.list); 4469255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4470255932Salfred kfree(eq); 4471255932Salfred state = 0; 4472255932Salfred break; 4473255932Salfred 4474255932Salfred case RES_EQ_HW: 4475255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 4476255932Salfred if (IS_ERR(mailbox)) { 4477255932Salfred cond_resched(); 4478255932Salfred continue; 4479255932Salfred } 4480255932Salfred err = mlx4_cmd_box(dev, slave, 0, 4481255932Salfred eqn & 0xff, 0, 4482255932Salfred MLX4_CMD_HW2SW_EQ, 4483255932Salfred MLX4_CMD_TIME_CLASS_A, 4484255932Salfred MLX4_CMD_NATIVE); 4485255932Salfred if (err) 4486255932Salfred mlx4_dbg(dev, "rem_slave_eqs: failed" 4487255932Salfred " to move slave %d eqs %d to" 4488255932Salfred " SW ownership\n", slave, eqn); 4489255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 4490255932Salfred atomic_dec(&eq->mtt->ref_count); 4491255932Salfred state = RES_EQ_RESERVED; 4492255932Salfred break; 4493255932Salfred 4494255932Salfred default: 4495255932Salfred state = 0; 4496255932Salfred } 4497255932Salfred } 4498255932Salfred } 4499255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4500255932Salfred } 4501255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4502255932Salfred} 4503255932Salfred 4504255932Salfredstatic void rem_slave_counters(struct mlx4_dev *dev, int slave) 4505255932Salfred{ 4506272407Shselasky __mlx4_slave_counters_free(dev, slave); 4507255932Salfred} 4508255932Salfred 4509255932Salfredstatic void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) 4510255932Salfred{ 4511255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4512255932Salfred struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; 4513255932Salfred struct list_head *xrcdn_list = 4514255932Salfred &tracker->slave_list[slave].res_list[RES_XRCD]; 4515255932Salfred struct res_xrcdn *xrcd; 4516255932Salfred struct res_xrcdn *tmp; 4517255932Salfred int err; 4518255932Salfred int xrcdn; 4519255932Salfred 4520255932Salfred err = move_all_busy(dev, slave, RES_XRCD); 4521255932Salfred if (err) 4522255932Salfred mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns to " 4523255932Salfred "busy for slave %d\n", slave); 4524255932Salfred 4525255932Salfred spin_lock_irq(mlx4_tlock(dev)); 4526255932Salfred list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { 4527255932Salfred if (xrcd->com.owner == slave) { 4528255932Salfred xrcdn = xrcd->com.res_id; 4529255932Salfred rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); 4530255932Salfred list_del(&xrcd->com.list); 4531255932Salfred kfree(xrcd); 4532255932Salfred __mlx4_xrcd_free(dev, xrcdn); 4533255932Salfred } 4534255932Salfred } 4535255932Salfred spin_unlock_irq(mlx4_tlock(dev)); 4536255932Salfred} 4537255932Salfred 4538255932Salfredvoid mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) 4539255932Salfred{ 4540255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 4541255932Salfred 4542255932Salfred mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 4543255932Salfred rem_slave_macs(dev, slave); 4544255932Salfred rem_slave_vlans(dev, slave); 4545272407Shselasky rem_slave_fs_rule(dev, slave); 4546255932Salfred rem_slave_qps(dev, slave); 4547255932Salfred rem_slave_srqs(dev, slave); 4548255932Salfred rem_slave_cqs(dev, slave); 4549255932Salfred rem_slave_mrs(dev, slave); 4550255932Salfred rem_slave_eqs(dev, slave); 4551255932Salfred rem_slave_mtts(dev, slave); 4552255932Salfred rem_slave_counters(dev, slave); 4553255932Salfred rem_slave_xrcdns(dev, slave); 4554255932Salfred mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); 4555255932Salfred} 4556272407Shselasky 4557272407Shselaskyvoid mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) 4558272407Shselasky{ 4559272407Shselasky struct mlx4_vf_immed_vlan_work *work = 4560272407Shselasky container_of(_work, struct mlx4_vf_immed_vlan_work, work); 4561272407Shselasky struct mlx4_cmd_mailbox *mailbox; 4562272407Shselasky struct mlx4_update_qp_context *upd_context; 4563272407Shselasky struct mlx4_dev *dev = &work->priv->dev; 4564272407Shselasky struct mlx4_resource_tracker *tracker = 4565272407Shselasky &work->priv->mfunc.master.res_tracker; 4566272407Shselasky struct list_head *qp_list = 4567272407Shselasky &tracker->slave_list[work->slave].res_list[RES_QP]; 4568272407Shselasky struct res_qp *qp; 4569272407Shselasky struct res_qp *tmp; 4570272407Shselasky u64 qp_path_mask_vlan_ctrl = 4571272407Shselasky ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | 4572272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | 4573272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | 4574272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | 4575272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | 4576272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED)); 4577272407Shselasky 4578272407Shselasky u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | 4579272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) | 4580272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_CV) | 4581272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) | 4582272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) | 4583272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) | 4584272407Shselasky (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); 4585272407Shselasky 4586272407Shselasky int err; 4587272407Shselasky int port, errors = 0; 4588272407Shselasky u8 vlan_control; 4589272407Shselasky 4590272407Shselasky if (mlx4_is_slave(dev)) { 4591272407Shselasky mlx4_warn(dev, "Trying to update-qp in slave %d\n", 4592272407Shselasky work->slave); 4593272407Shselasky goto out; 4594272407Shselasky } 4595272407Shselasky 4596272407Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 4597272407Shselasky if (IS_ERR(mailbox)) 4598272407Shselasky goto out; 4599272407Shselasky 4600272407Shselasky if (!work->vlan_id) 4601272407Shselasky vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 4602272407Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; 4603272407Shselasky else 4604272407Shselasky vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | 4605272407Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | 4606272407Shselasky MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; 4607272407Shselasky 4608272407Shselasky upd_context = mailbox->buf; 4609272407Shselasky upd_context->qp_mask = cpu_to_be64(MLX4_UPD_QP_MASK_VSD); 4610272407Shselasky 4611272407Shselasky spin_lock_irq(mlx4_tlock(dev)); 4612272407Shselasky list_for_each_entry_safe(qp, tmp, qp_list, com.list) { 4613272407Shselasky spin_unlock_irq(mlx4_tlock(dev)); 4614272407Shselasky if (qp->com.owner == work->slave) { 4615272407Shselasky if (qp->com.from_state != RES_QP_HW || 4616272407Shselasky !qp->sched_queue || /* no INIT2RTR trans yet */ 4617272407Shselasky mlx4_is_qp_reserved(dev, qp->local_qpn) || 4618272407Shselasky qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { 4619272407Shselasky spin_lock_irq(mlx4_tlock(dev)); 4620272407Shselasky continue; 4621272407Shselasky } 4622272407Shselasky port = (qp->sched_queue >> 6 & 1) + 1; 4623272407Shselasky if (port != work->port) { 4624272407Shselasky spin_lock_irq(mlx4_tlock(dev)); 4625272407Shselasky continue; 4626272407Shselasky } 4627272407Shselasky if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff)) 4628272407Shselasky upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask); 4629272407Shselasky else 4630272407Shselasky upd_context->primary_addr_path_mask = 4631272407Shselasky cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl); 4632272407Shselasky if (work->vlan_id == MLX4_VGT) { 4633272407Shselasky upd_context->qp_context.param3 = qp->param3; 4634272407Shselasky upd_context->qp_context.pri_path.vlan_control = qp->vlan_control; 4635272407Shselasky upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx; 4636272407Shselasky upd_context->qp_context.pri_path.vlan_index = qp->vlan_index; 4637272407Shselasky upd_context->qp_context.pri_path.fl = qp->pri_path_fl; 4638272407Shselasky upd_context->qp_context.pri_path.feup = qp->feup; 4639272407Shselasky upd_context->qp_context.pri_path.sched_queue = 4640272407Shselasky qp->sched_queue; 4641272407Shselasky } else { 4642272407Shselasky upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN); 4643272407Shselasky upd_context->qp_context.pri_path.vlan_control = vlan_control; 4644272407Shselasky upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; 4645272407Shselasky upd_context->qp_context.pri_path.fvl_rx = 4646272407Shselasky qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN; 4647272407Shselasky upd_context->qp_context.pri_path.fl = 4648272407Shselasky qp->pri_path_fl | MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; 4649272407Shselasky upd_context->qp_context.pri_path.feup = 4650272407Shselasky qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; 4651272407Shselasky upd_context->qp_context.pri_path.sched_queue = 4652272407Shselasky qp->sched_queue & 0xC7; 4653272407Shselasky upd_context->qp_context.pri_path.sched_queue |= 4654272407Shselasky ((work->qos & 0x7) << 3); 4655272407Shselasky } 4656272407Shselasky 4657272407Shselasky err = mlx4_cmd(dev, mailbox->dma, 4658272407Shselasky qp->local_qpn & 0xffffff, 4659272407Shselasky 0, MLX4_CMD_UPDATE_QP, 4660272407Shselasky MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 4661272407Shselasky if (err) { 4662272407Shselasky mlx4_info(dev, "UPDATE_QP failed for slave %d, " 4663272407Shselasky "port %d, qpn %d (%d)\n", 4664272407Shselasky work->slave, port, qp->local_qpn, 4665272407Shselasky err); 4666272407Shselasky errors++; 4667272407Shselasky } 4668272407Shselasky } 4669272407Shselasky spin_lock_irq(mlx4_tlock(dev)); 4670272407Shselasky } 4671272407Shselasky spin_unlock_irq(mlx4_tlock(dev)); 4672272407Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 4673272407Shselasky 4674272407Shselasky if (errors) 4675272407Shselasky mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", 4676272407Shselasky errors, work->slave, work->port); 4677272407Shselasky 4678272407Shselasky /* unregister previous vlan_id if needed and we had no errors 4679272407Shselasky * while updating the QPs 4680272407Shselasky */ 4681272407Shselasky if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && 4682272407Shselasky NO_INDX != work->orig_vlan_ix) 4683272407Shselasky __mlx4_unregister_vlan(&work->priv->dev, work->port, 4684272407Shselasky work->orig_vlan_id); 4685272407Shselaskyout: 4686272407Shselasky kfree(work); 4687272407Shselasky return; 4688272407Shselasky} 4689272407Shselasky 4690