5424 lines · c
1/*2 * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.3 * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies.4 * All rights reserved.5 * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved.6 *7 * This software is available to you under a choice of one of two8 * licenses. You may choose to be licensed under the terms of the GNU9 * General Public License (GPL) Version 2, available from the file10 * COPYING in the main directory of this source tree, or the11 * OpenIB.org BSD license below:12 *13 * Redistribution and use in source and binary forms, with or14 * without modification, are permitted provided that the following15 * conditions are met:16 *17 * - Redistributions of source code must retain the above18 * copyright notice, this list of conditions and the following19 * disclaimer.20 *21 * - Redistributions in binary form must reproduce the above22 * copyright notice, this list of conditions and the following23 * disclaimer in the documentation and/or other materials24 * provided with the distribution.25 *26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE33 * SOFTWARE.34 */35 36#include <linux/sched.h>37#include <linux/pci.h>38#include <linux/errno.h>39#include <linux/kernel.h>40#include <linux/io.h>41#include <linux/slab.h>42#include <linux/mlx4/cmd.h>43#include <linux/mlx4/qp.h>44#include <linux/if_ether.h>45#include <linux/etherdevice.h>46 47#include "mlx4.h"48#include "fw.h"49#include "mlx4_stats.h"50 51#define MLX4_MAC_VALID (1ull << 63)52#define MLX4_PF_COUNTERS_PER_PORT 253#define MLX4_VF_COUNTERS_PER_PORT 154 55struct mac_res {56 struct list_head list;57 u64 mac;58 int ref_count;59 u8 smac_index;60 u8 port;61};62 63struct vlan_res {64 struct list_head list;65 u16 vlan;66 int ref_count;67 int vlan_index;68 u8 port;69};70 71struct res_common {72 struct list_head list;73 struct rb_node node;74 u64 res_id;75 int owner;76 int state;77 int from_state;78 int to_state;79 int removing;80 const char *func_name;81};82 83enum {84 RES_ANY_BUSY = 185};86 87struct res_gid {88 struct list_head list;89 u8 gid[16];90 enum mlx4_protocol prot;91 enum mlx4_steer_type steer;92 u64 reg_id;93};94 95enum res_qp_states {96 RES_QP_BUSY = RES_ANY_BUSY,97 98 /* QP number was allocated */99 RES_QP_RESERVED,100 101 /* ICM memory for QP context was mapped */102 RES_QP_MAPPED,103 104 /* QP is in hw ownership */105 RES_QP_HW106};107 108struct res_qp {109 struct res_common com;110 struct res_mtt *mtt;111 struct res_cq *rcq;112 struct res_cq *scq;113 struct res_srq *srq;114 struct list_head mcg_list;115 spinlock_t mcg_spl;116 int local_qpn;117 atomic_t ref_count;118 u32 qpc_flags;119 /* saved qp params before VST enforcement in order to restore on VGT */120 u8 sched_queue;121 __be32 param3;122 u8 vlan_control;123 u8 fvl_rx;124 u8 pri_path_fl;125 u8 vlan_index;126 u8 feup;127};128 129enum res_mtt_states {130 RES_MTT_BUSY = RES_ANY_BUSY,131 RES_MTT_ALLOCATED,132};133 134static inline const char *mtt_states_str(enum res_mtt_states state)135{136 switch (state) {137 case RES_MTT_BUSY: return "RES_MTT_BUSY";138 case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED";139 default: return "Unknown";140 }141}142 143struct res_mtt {144 struct res_common com;145 int order;146 atomic_t ref_count;147};148 149enum res_mpt_states {150 RES_MPT_BUSY = RES_ANY_BUSY,151 RES_MPT_RESERVED,152 RES_MPT_MAPPED,153 RES_MPT_HW,154};155 156struct res_mpt {157 struct res_common com;158 struct res_mtt *mtt;159 int key;160};161 162enum res_eq_states {163 RES_EQ_BUSY = RES_ANY_BUSY,164 RES_EQ_RESERVED,165 RES_EQ_HW,166};167 168struct res_eq {169 struct res_common com;170 struct res_mtt *mtt;171};172 173enum res_cq_states {174 RES_CQ_BUSY = RES_ANY_BUSY,175 RES_CQ_ALLOCATED,176 RES_CQ_HW,177};178 179struct res_cq {180 struct res_common com;181 struct res_mtt *mtt;182 atomic_t ref_count;183};184 185enum res_srq_states {186 RES_SRQ_BUSY = RES_ANY_BUSY,187 RES_SRQ_ALLOCATED,188 RES_SRQ_HW,189};190 191struct res_srq {192 struct res_common com;193 struct res_mtt *mtt;194 struct res_cq *cq;195 atomic_t ref_count;196};197 198enum res_counter_states {199 RES_COUNTER_BUSY = RES_ANY_BUSY,200 RES_COUNTER_ALLOCATED,201};202 203struct res_counter {204 struct res_common com;205 int port;206};207 208enum res_xrcdn_states {209 RES_XRCD_BUSY = RES_ANY_BUSY,210 RES_XRCD_ALLOCATED,211};212 213struct res_xrcdn {214 struct res_common com;215 int port;216};217 218enum res_fs_rule_states {219 RES_FS_RULE_BUSY = RES_ANY_BUSY,220 RES_FS_RULE_ALLOCATED,221};222 223struct res_fs_rule {224 struct res_common com;225 int qpn;226 /* VF DMFS mbox with port flipped */227 void *mirr_mbox;228 /* > 0 --> apply mirror when getting into HA mode */229 /* = 0 --> un-apply mirror when getting out of HA mode */230 u32 mirr_mbox_size;231 struct list_head mirr_list;232 u64 mirr_rule_id;233};234 235static void *res_tracker_lookup(struct rb_root *root, u64 res_id)236{237 struct rb_node *node = root->rb_node;238 239 while (node) {240 struct res_common *res = rb_entry(node, struct res_common,241 node);242 243 if (res_id < res->res_id)244 node = node->rb_left;245 else if (res_id > res->res_id)246 node = node->rb_right;247 else248 return res;249 }250 return NULL;251}252 253static int res_tracker_insert(struct rb_root *root, struct res_common *res)254{255 struct rb_node **new = &(root->rb_node), *parent = NULL;256 257 /* Figure out where to put new node */258 while (*new) {259 struct res_common *this = rb_entry(*new, struct res_common,260 node);261 262 parent = *new;263 if (res->res_id < this->res_id)264 new = &((*new)->rb_left);265 else if (res->res_id > this->res_id)266 new = &((*new)->rb_right);267 else268 return -EEXIST;269 }270 271 /* Add new node and rebalance tree. */272 rb_link_node(&res->node, parent, new);273 rb_insert_color(&res->node, root);274 275 return 0;276}277 278enum qp_transition {279 QP_TRANS_INIT2RTR,280 QP_TRANS_RTR2RTS,281 QP_TRANS_RTS2RTS,282 QP_TRANS_SQERR2RTS,283 QP_TRANS_SQD2SQD,284 QP_TRANS_SQD2RTS285};286 287/* For Debug uses */288static const char *resource_str(enum mlx4_resource rt)289{290 switch (rt) {291 case RES_QP: return "RES_QP";292 case RES_CQ: return "RES_CQ";293 case RES_SRQ: return "RES_SRQ";294 case RES_MPT: return "RES_MPT";295 case RES_MTT: return "RES_MTT";296 case RES_MAC: return "RES_MAC";297 case RES_VLAN: return "RES_VLAN";298 case RES_EQ: return "RES_EQ";299 case RES_COUNTER: return "RES_COUNTER";300 case RES_FS_RULE: return "RES_FS_RULE";301 case RES_XRCD: return "RES_XRCD";302 default: return "Unknown resource type !!!";303 }304}305 306static void rem_slave_vlans(struct mlx4_dev *dev, int slave);307static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,308 enum mlx4_resource res_type, int count,309 int port)310{311 struct mlx4_priv *priv = mlx4_priv(dev);312 struct resource_allocator *res_alloc =313 &priv->mfunc.master.res_tracker.res_alloc[res_type];314 int err = -EDQUOT;315 int allocated, free, reserved, guaranteed, from_free;316 int from_rsvd;317 318 if (slave > dev->persist->num_vfs)319 return -EINVAL;320 321 spin_lock(&res_alloc->alloc_lock);322 allocated = (port > 0) ?323 res_alloc->allocated[(port - 1) *324 (dev->persist->num_vfs + 1) + slave] :325 res_alloc->allocated[slave];326 free = (port > 0) ? res_alloc->res_port_free[port - 1] :327 res_alloc->res_free;328 reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] :329 res_alloc->res_reserved;330 guaranteed = res_alloc->guaranteed[slave];331 332 if (allocated + count > res_alloc->quota[slave]) {333 mlx4_warn(dev, "VF %d port %d res %s: quota exceeded, count %d alloc %d quota %d\n",334 slave, port, resource_str(res_type), count,335 allocated, res_alloc->quota[slave]);336 goto out;337 }338 339 if (allocated + count <= guaranteed) {340 err = 0;341 from_rsvd = count;342 } else {343 /* portion may need to be obtained from free area */344 if (guaranteed - allocated > 0)345 from_free = count - (guaranteed - allocated);346 else347 from_free = count;348 349 from_rsvd = count - from_free;350 351 if (free - from_free >= reserved)352 err = 0;353 else354 mlx4_warn(dev, "VF %d port %d res %s: free pool empty, free %d from_free %d rsvd %d\n",355 slave, port, resource_str(res_type), free,356 from_free, reserved);357 }358 359 if (!err) {360 /* grant the request */361 if (port > 0) {362 res_alloc->allocated[(port - 1) *363 (dev->persist->num_vfs + 1) + slave] += count;364 res_alloc->res_port_free[port - 1] -= count;365 res_alloc->res_port_rsvd[port - 1] -= from_rsvd;366 } else {367 res_alloc->allocated[slave] += count;368 res_alloc->res_free -= count;369 res_alloc->res_reserved -= from_rsvd;370 }371 }372 373out:374 spin_unlock(&res_alloc->alloc_lock);375 return err;376}377 378static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,379 enum mlx4_resource res_type, int count,380 int port)381{382 struct mlx4_priv *priv = mlx4_priv(dev);383 struct resource_allocator *res_alloc =384 &priv->mfunc.master.res_tracker.res_alloc[res_type];385 int allocated, guaranteed, from_rsvd;386 387 if (slave > dev->persist->num_vfs)388 return;389 390 spin_lock(&res_alloc->alloc_lock);391 392 allocated = (port > 0) ?393 res_alloc->allocated[(port - 1) *394 (dev->persist->num_vfs + 1) + slave] :395 res_alloc->allocated[slave];396 guaranteed = res_alloc->guaranteed[slave];397 398 if (allocated - count >= guaranteed) {399 from_rsvd = 0;400 } else {401 /* portion may need to be returned to reserved area */402 if (allocated - guaranteed > 0)403 from_rsvd = count - (allocated - guaranteed);404 else405 from_rsvd = count;406 }407 408 if (port > 0) {409 res_alloc->allocated[(port - 1) *410 (dev->persist->num_vfs + 1) + slave] -= count;411 res_alloc->res_port_free[port - 1] += count;412 res_alloc->res_port_rsvd[port - 1] += from_rsvd;413 } else {414 res_alloc->allocated[slave] -= count;415 res_alloc->res_free += count;416 res_alloc->res_reserved += from_rsvd;417 }418 419 spin_unlock(&res_alloc->alloc_lock);420 return;421}422 423static inline void initialize_res_quotas(struct mlx4_dev *dev,424 struct resource_allocator *res_alloc,425 enum mlx4_resource res_type,426 int vf, int num_instances)427{428 res_alloc->guaranteed[vf] = num_instances /429 (2 * (dev->persist->num_vfs + 1));430 res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf];431 if (vf == mlx4_master_func_num(dev)) {432 res_alloc->res_free = num_instances;433 if (res_type == RES_MTT) {434 /* reserved mtts will be taken out of the PF allocation */435 res_alloc->res_free += dev->caps.reserved_mtts;436 res_alloc->guaranteed[vf] += dev->caps.reserved_mtts;437 res_alloc->quota[vf] += dev->caps.reserved_mtts;438 }439 }440}441 442void mlx4_init_quotas(struct mlx4_dev *dev)443{444 struct mlx4_priv *priv = mlx4_priv(dev);445 int pf;446 447 /* quotas for VFs are initialized in mlx4_slave_cap */448 if (mlx4_is_slave(dev))449 return;450 451 if (!mlx4_is_mfunc(dev)) {452 dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps -453 mlx4_num_reserved_sqps(dev);454 dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs;455 dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs;456 dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts;457 dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws;458 return;459 }460 461 pf = mlx4_master_func_num(dev);462 dev->quotas.qp =463 priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf];464 dev->quotas.cq =465 priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf];466 dev->quotas.srq =467 priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf];468 dev->quotas.mtt =469 priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf];470 dev->quotas.mpt =471 priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];472}473 474static int475mlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev,476 struct resource_allocator *res_alloc,477 int vf)478{479 struct mlx4_active_ports actv_ports;480 int ports, counters_guaranteed;481 482 /* For master, only allocate according to the number of phys ports */483 if (vf == mlx4_master_func_num(dev))484 return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports;485 486 /* calculate real number of ports for the VF */487 actv_ports = mlx4_get_active_ports(dev, vf);488 ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);489 counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT;490 491 /* If we do not have enough counters for this VF, do not492 * allocate any for it. '-1' to reduce the sink counter.493 */494 if ((res_alloc->res_reserved + counters_guaranteed) >495 (dev->caps.max_counters - 1))496 return 0;497 498 return counters_guaranteed;499}500 501int mlx4_init_resource_tracker(struct mlx4_dev *dev)502{503 struct mlx4_priv *priv = mlx4_priv(dev);504 int i, j;505 int t;506 507 priv->mfunc.master.res_tracker.slave_list =508 kcalloc(dev->num_slaves, sizeof(struct slave_list),509 GFP_KERNEL);510 if (!priv->mfunc.master.res_tracker.slave_list)511 return -ENOMEM;512 513 for (i = 0 ; i < dev->num_slaves; i++) {514 for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t)515 INIT_LIST_HEAD(&priv->mfunc.master.res_tracker.516 slave_list[i].res_list[t]);517 mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex);518 }519 520 mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n",521 dev->num_slaves);522 for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++)523 priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT;524 525 for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {526 struct resource_allocator *res_alloc =527 &priv->mfunc.master.res_tracker.res_alloc[i];528 res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1,529 sizeof(int),530 GFP_KERNEL);531 res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1,532 sizeof(int),533 GFP_KERNEL);534 if (i == RES_MAC || i == RES_VLAN)535 res_alloc->allocated =536 kcalloc(MLX4_MAX_PORTS *537 (dev->persist->num_vfs + 1),538 sizeof(int), GFP_KERNEL);539 else540 res_alloc->allocated =541 kcalloc(dev->persist->num_vfs + 1,542 sizeof(int), GFP_KERNEL);543 /* Reduce the sink counter */544 if (i == RES_COUNTER)545 res_alloc->res_free = dev->caps.max_counters - 1;546 547 if (!res_alloc->quota || !res_alloc->guaranteed ||548 !res_alloc->allocated)549 goto no_mem_err;550 551 spin_lock_init(&res_alloc->alloc_lock);552 for (t = 0; t < dev->persist->num_vfs + 1; t++) {553 struct mlx4_active_ports actv_ports =554 mlx4_get_active_ports(dev, t);555 switch (i) {556 case RES_QP:557 initialize_res_quotas(dev, res_alloc, RES_QP,558 t, dev->caps.num_qps -559 dev->caps.reserved_qps -560 mlx4_num_reserved_sqps(dev));561 break;562 case RES_CQ:563 initialize_res_quotas(dev, res_alloc, RES_CQ,564 t, dev->caps.num_cqs -565 dev->caps.reserved_cqs);566 break;567 case RES_SRQ:568 initialize_res_quotas(dev, res_alloc, RES_SRQ,569 t, dev->caps.num_srqs -570 dev->caps.reserved_srqs);571 break;572 case RES_MPT:573 initialize_res_quotas(dev, res_alloc, RES_MPT,574 t, dev->caps.num_mpts -575 dev->caps.reserved_mrws);576 break;577 case RES_MTT:578 initialize_res_quotas(dev, res_alloc, RES_MTT,579 t, dev->caps.num_mtts -580 dev->caps.reserved_mtts);581 break;582 case RES_MAC:583 if (t == mlx4_master_func_num(dev)) {584 int max_vfs_pport = 0;585 /* Calculate the max vfs per port for */586 /* both ports. */587 for (j = 0; j < dev->caps.num_ports;588 j++) {589 struct mlx4_slaves_pport slaves_pport =590 mlx4_phys_to_slaves_pport(dev, j + 1);591 unsigned current_slaves =592 bitmap_weight(slaves_pport.slaves,593 dev->caps.num_ports) - 1;594 if (max_vfs_pport < current_slaves)595 max_vfs_pport =596 current_slaves;597 }598 res_alloc->quota[t] =599 MLX4_MAX_MAC_NUM -600 2 * max_vfs_pport;601 res_alloc->guaranteed[t] = 2;602 for (j = 0; j < MLX4_MAX_PORTS; j++)603 res_alloc->res_port_free[j] =604 MLX4_MAX_MAC_NUM;605 } else {606 res_alloc->quota[t] = MLX4_MAX_MAC_NUM;607 res_alloc->guaranteed[t] = 2;608 }609 break;610 case RES_VLAN:611 if (t == mlx4_master_func_num(dev)) {612 res_alloc->quota[t] = MLX4_MAX_VLAN_NUM;613 res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2;614 for (j = 0; j < MLX4_MAX_PORTS; j++)615 res_alloc->res_port_free[j] =616 res_alloc->quota[t];617 } else {618 res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2;619 res_alloc->guaranteed[t] = 0;620 }621 break;622 case RES_COUNTER:623 res_alloc->quota[t] = dev->caps.max_counters;624 res_alloc->guaranteed[t] =625 mlx4_calc_res_counter_guaranteed(dev, res_alloc, t);626 break;627 default:628 break;629 }630 if (i == RES_MAC || i == RES_VLAN) {631 for (j = 0; j < dev->caps.num_ports; j++)632 if (test_bit(j, actv_ports.ports))633 res_alloc->res_port_rsvd[j] +=634 res_alloc->guaranteed[t];635 } else {636 res_alloc->res_reserved += res_alloc->guaranteed[t];637 }638 }639 }640 spin_lock_init(&priv->mfunc.master.res_tracker.lock);641 return 0;642 643no_mem_err:644 for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {645 kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);646 priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;647 kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);648 priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;649 kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);650 priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;651 }652 return -ENOMEM;653}654 655void mlx4_free_resource_tracker(struct mlx4_dev *dev,656 enum mlx4_res_tracker_free_type type)657{658 struct mlx4_priv *priv = mlx4_priv(dev);659 int i;660 661 if (priv->mfunc.master.res_tracker.slave_list) {662 if (type != RES_TR_FREE_STRUCTS_ONLY) {663 for (i = 0; i < dev->num_slaves; i++) {664 if (type == RES_TR_FREE_ALL ||665 dev->caps.function != i)666 mlx4_delete_all_resources_for_slave(dev, i);667 }668 /* free master's vlans */669 i = dev->caps.function;670 mlx4_reset_roce_gids(dev, i);671 mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);672 rem_slave_vlans(dev, i);673 mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);674 }675 676 if (type != RES_TR_FREE_SLAVES_ONLY) {677 for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {678 kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);679 priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;680 kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);681 priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;682 kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);683 priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;684 }685 kfree(priv->mfunc.master.res_tracker.slave_list);686 priv->mfunc.master.res_tracker.slave_list = NULL;687 }688 }689}690 691static void update_pkey_index(struct mlx4_dev *dev, int slave,692 struct mlx4_cmd_mailbox *inbox)693{694 u8 sched = *(u8 *)(inbox->buf + 64);695 u8 orig_index = *(u8 *)(inbox->buf + 35);696 u8 new_index;697 struct mlx4_priv *priv = mlx4_priv(dev);698 int port;699 700 port = (sched >> 6 & 1) + 1;701 702 new_index = priv->virt2phys_pkey[slave][port - 1][orig_index];703 *(u8 *)(inbox->buf + 35) = new_index;704}705 706static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,707 u8 slave)708{709 struct mlx4_qp_context *qp_ctx = inbox->buf + 8;710 enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf);711 u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;712 int port;713 714 if (MLX4_QP_ST_UD == ts) {715 port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;716 if (mlx4_is_eth(dev, port))717 qp_ctx->pri_path.mgid_index =718 mlx4_get_base_gid_ix(dev, slave, port) | 0x80;719 else720 qp_ctx->pri_path.mgid_index = slave | 0x80;721 722 } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {723 if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {724 port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;725 if (mlx4_is_eth(dev, port)) {726 qp_ctx->pri_path.mgid_index +=727 mlx4_get_base_gid_ix(dev, slave, port);728 qp_ctx->pri_path.mgid_index &= 0x7f;729 } else {730 qp_ctx->pri_path.mgid_index = slave & 0x7F;731 }732 }733 if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {734 port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;735 if (mlx4_is_eth(dev, port)) {736 qp_ctx->alt_path.mgid_index +=737 mlx4_get_base_gid_ix(dev, slave, port);738 qp_ctx->alt_path.mgid_index &= 0x7f;739 } else {740 qp_ctx->alt_path.mgid_index = slave & 0x7F;741 }742 }743 }744}745 746static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,747 u8 slave, int port);748 749static int update_vport_qp_param(struct mlx4_dev *dev,750 struct mlx4_cmd_mailbox *inbox,751 u8 slave, u32 qpn)752{753 struct mlx4_qp_context *qpc = inbox->buf + 8;754 struct mlx4_vport_oper_state *vp_oper;755 struct mlx4_priv *priv;756 u32 qp_type;757 int port, err = 0;758 759 port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;760 priv = mlx4_priv(dev);761 vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];762 qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;763 764 err = handle_counter(dev, qpc, slave, port);765 if (err)766 goto out;767 768 if (MLX4_VGT != vp_oper->state.default_vlan) {769 /* the reserved QPs (special, proxy, tunnel)770 * do not operate over vlans771 */772 if (mlx4_is_qp_reserved(dev, qpn))773 return 0;774 775 /* force strip vlan by clear vsd, MLX QP refers to Raw Ethernet */776 if (qp_type == MLX4_QP_ST_UD ||777 (qp_type == MLX4_QP_ST_MLX && mlx4_is_eth(dev, port))) {778 if (dev->caps.bmme_flags & MLX4_BMME_FLAG_VSD_INIT2RTR) {779 *(__be32 *)inbox->buf =780 cpu_to_be32(be32_to_cpu(*(__be32 *)inbox->buf) |781 MLX4_QP_OPTPAR_VLAN_STRIPPING);782 qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN);783 } else {784 struct mlx4_update_qp_params params = {.flags = 0};785 786 err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, ¶ms);787 if (err)788 goto out;789 }790 }791 792 /* preserve IF_COUNTER flag */793 qpc->pri_path.vlan_control &=794 MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;795 if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&796 dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {797 qpc->pri_path.vlan_control |=798 MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |799 MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |800 MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |801 MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |802 MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |803 MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;804 } else if (0 != vp_oper->state.default_vlan) {805 if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) {806 /* vst QinQ should block untagged on TX,807 * but cvlan is in payload and phv is set so808 * hw see it as untagged. Block tagged instead.809 */810 qpc->pri_path.vlan_control |=811 MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |812 MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |813 MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |814 MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;815 } else { /* vst 802.1Q */816 qpc->pri_path.vlan_control |=817 MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |818 MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |819 MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;820 }821 } else { /* priority tagged */822 qpc->pri_path.vlan_control |=823 MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |824 MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;825 }826 827 qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN;828 qpc->pri_path.vlan_index = vp_oper->vlan_idx;829 qpc->pri_path.fl |= MLX4_FL_ETH_HIDE_CQE_VLAN;830 if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD))831 qpc->pri_path.fl |= MLX4_FL_SV;832 else833 qpc->pri_path.fl |= MLX4_FL_CV;834 qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;835 qpc->pri_path.sched_queue &= 0xC7;836 qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;837 qpc->qos_vport = vp_oper->state.qos_vport;838 }839 if (vp_oper->state.spoofchk) {840 qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;841 qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;842 }843out:844 return err;845}846 847static int mpt_mask(struct mlx4_dev *dev)848{849 return dev->caps.num_mpts - 1;850}851 852static const char *mlx4_resource_type_to_str(enum mlx4_resource t)853{854 switch (t) {855 case RES_QP:856 return "QP";857 case RES_CQ:858 return "CQ";859 case RES_SRQ:860 return "SRQ";861 case RES_XRCD:862 return "XRCD";863 case RES_MPT:864 return "MPT";865 case RES_MTT:866 return "MTT";867 case RES_MAC:868 return "MAC";869 case RES_VLAN:870 return "VLAN";871 case RES_COUNTER:872 return "COUNTER";873 case RES_FS_RULE:874 return "FS_RULE";875 case RES_EQ:876 return "EQ";877 default:878 return "INVALID RESOURCE";879 }880}881 882static void *find_res(struct mlx4_dev *dev, u64 res_id,883 enum mlx4_resource type)884{885 struct mlx4_priv *priv = mlx4_priv(dev);886 887 return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type],888 res_id);889}890 891static int _get_res(struct mlx4_dev *dev, int slave, u64 res_id,892 enum mlx4_resource type,893 void *res, const char *func_name)894{895 struct res_common *r;896 int err = 0;897 898 spin_lock_irq(mlx4_tlock(dev));899 r = find_res(dev, res_id, type);900 if (!r) {901 err = -ENONET;902 goto exit;903 }904 905 if (r->state == RES_ANY_BUSY) {906 mlx4_warn(dev,907 "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n",908 func_name, slave, res_id, mlx4_resource_type_to_str(type),909 r->func_name);910 err = -EBUSY;911 goto exit;912 }913 914 if (r->owner != slave) {915 err = -EPERM;916 goto exit;917 }918 919 r->from_state = r->state;920 r->state = RES_ANY_BUSY;921 r->func_name = func_name;922 923 if (res)924 *((struct res_common **)res) = r;925 926exit:927 spin_unlock_irq(mlx4_tlock(dev));928 return err;929}930 931#define get_res(dev, slave, res_id, type, res) \932 _get_res((dev), (slave), (res_id), (type), (res), __func__)933 934int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev,935 enum mlx4_resource type,936 u64 res_id, int *slave)937{938 939 struct res_common *r;940 int err = -ENOENT;941 int id = res_id;942 943 if (type == RES_QP)944 id &= 0x7fffff;945 spin_lock(mlx4_tlock(dev));946 947 r = find_res(dev, id, type);948 if (r) {949 *slave = r->owner;950 err = 0;951 }952 spin_unlock(mlx4_tlock(dev));953 954 return err;955}956 957static void put_res(struct mlx4_dev *dev, int slave, u64 res_id,958 enum mlx4_resource type)959{960 struct res_common *r;961 962 spin_lock_irq(mlx4_tlock(dev));963 r = find_res(dev, res_id, type);964 if (r) {965 r->state = r->from_state;966 r->func_name = "";967 }968 spin_unlock_irq(mlx4_tlock(dev));969}970 971static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,972 u64 in_param, u64 *out_param, int port);973 974static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,975 int counter_index)976{977 struct res_common *r;978 struct res_counter *counter;979 int ret = 0;980 981 if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))982 return ret;983 984 spin_lock_irq(mlx4_tlock(dev));985 r = find_res(dev, counter_index, RES_COUNTER);986 if (!r || r->owner != slave) {987 ret = -EINVAL;988 } else {989 counter = container_of(r, struct res_counter, com);990 if (!counter->port)991 counter->port = port;992 }993 994 spin_unlock_irq(mlx4_tlock(dev));995 return ret;996}997 998static int handle_unexisting_counter(struct mlx4_dev *dev,999 struct mlx4_qp_context *qpc, u8 slave,1000 int port)1001{1002 struct mlx4_priv *priv = mlx4_priv(dev);1003 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1004 struct res_common *tmp;1005 struct res_counter *counter;1006 u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev);1007 int err = 0;1008 1009 spin_lock_irq(mlx4_tlock(dev));1010 list_for_each_entry(tmp,1011 &tracker->slave_list[slave].res_list[RES_COUNTER],1012 list) {1013 counter = container_of(tmp, struct res_counter, com);1014 if (port == counter->port) {1015 qpc->pri_path.counter_index = counter->com.res_id;1016 spin_unlock_irq(mlx4_tlock(dev));1017 return 0;1018 }1019 }1020 spin_unlock_irq(mlx4_tlock(dev));1021 1022 /* No existing counter, need to allocate a new counter */1023 err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx,1024 port);1025 if (err == -ENOENT) {1026 err = 0;1027 } else if (err && err != -ENOSPC) {1028 mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n",1029 __func__, slave, err);1030 } else {1031 qpc->pri_path.counter_index = counter_idx;1032 mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n",1033 __func__, slave, qpc->pri_path.counter_index);1034 err = 0;1035 }1036 1037 return err;1038}1039 1040static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,1041 u8 slave, int port)1042{1043 if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev))1044 return handle_existing_counter(dev, slave, port,1045 qpc->pri_path.counter_index);1046 1047 return handle_unexisting_counter(dev, qpc, slave, port);1048}1049 1050static struct res_common *alloc_qp_tr(int id)1051{1052 struct res_qp *ret;1053 1054 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1055 if (!ret)1056 return NULL;1057 1058 ret->com.res_id = id;1059 ret->com.state = RES_QP_RESERVED;1060 ret->local_qpn = id;1061 INIT_LIST_HEAD(&ret->mcg_list);1062 spin_lock_init(&ret->mcg_spl);1063 atomic_set(&ret->ref_count, 0);1064 1065 return &ret->com;1066}1067 1068static struct res_common *alloc_mtt_tr(int id, int order)1069{1070 struct res_mtt *ret;1071 1072 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1073 if (!ret)1074 return NULL;1075 1076 ret->com.res_id = id;1077 ret->order = order;1078 ret->com.state = RES_MTT_ALLOCATED;1079 atomic_set(&ret->ref_count, 0);1080 1081 return &ret->com;1082}1083 1084static struct res_common *alloc_mpt_tr(int id, int key)1085{1086 struct res_mpt *ret;1087 1088 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1089 if (!ret)1090 return NULL;1091 1092 ret->com.res_id = id;1093 ret->com.state = RES_MPT_RESERVED;1094 ret->key = key;1095 1096 return &ret->com;1097}1098 1099static struct res_common *alloc_eq_tr(int id)1100{1101 struct res_eq *ret;1102 1103 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1104 if (!ret)1105 return NULL;1106 1107 ret->com.res_id = id;1108 ret->com.state = RES_EQ_RESERVED;1109 1110 return &ret->com;1111}1112 1113static struct res_common *alloc_cq_tr(int id)1114{1115 struct res_cq *ret;1116 1117 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1118 if (!ret)1119 return NULL;1120 1121 ret->com.res_id = id;1122 ret->com.state = RES_CQ_ALLOCATED;1123 atomic_set(&ret->ref_count, 0);1124 1125 return &ret->com;1126}1127 1128static struct res_common *alloc_srq_tr(int id)1129{1130 struct res_srq *ret;1131 1132 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1133 if (!ret)1134 return NULL;1135 1136 ret->com.res_id = id;1137 ret->com.state = RES_SRQ_ALLOCATED;1138 atomic_set(&ret->ref_count, 0);1139 1140 return &ret->com;1141}1142 1143static struct res_common *alloc_counter_tr(int id, int port)1144{1145 struct res_counter *ret;1146 1147 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1148 if (!ret)1149 return NULL;1150 1151 ret->com.res_id = id;1152 ret->com.state = RES_COUNTER_ALLOCATED;1153 ret->port = port;1154 1155 return &ret->com;1156}1157 1158static struct res_common *alloc_xrcdn_tr(int id)1159{1160 struct res_xrcdn *ret;1161 1162 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1163 if (!ret)1164 return NULL;1165 1166 ret->com.res_id = id;1167 ret->com.state = RES_XRCD_ALLOCATED;1168 1169 return &ret->com;1170}1171 1172static struct res_common *alloc_fs_rule_tr(u64 id, int qpn)1173{1174 struct res_fs_rule *ret;1175 1176 ret = kzalloc(sizeof(*ret), GFP_KERNEL);1177 if (!ret)1178 return NULL;1179 1180 ret->com.res_id = id;1181 ret->com.state = RES_FS_RULE_ALLOCATED;1182 ret->qpn = qpn;1183 return &ret->com;1184}1185 1186static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,1187 int extra)1188{1189 struct res_common *ret;1190 1191 switch (type) {1192 case RES_QP:1193 ret = alloc_qp_tr(id);1194 break;1195 case RES_MPT:1196 ret = alloc_mpt_tr(id, extra);1197 break;1198 case RES_MTT:1199 ret = alloc_mtt_tr(id, extra);1200 break;1201 case RES_EQ:1202 ret = alloc_eq_tr(id);1203 break;1204 case RES_CQ:1205 ret = alloc_cq_tr(id);1206 break;1207 case RES_SRQ:1208 ret = alloc_srq_tr(id);1209 break;1210 case RES_MAC:1211 pr_err("implementation missing\n");1212 return NULL;1213 case RES_COUNTER:1214 ret = alloc_counter_tr(id, extra);1215 break;1216 case RES_XRCD:1217 ret = alloc_xrcdn_tr(id);1218 break;1219 case RES_FS_RULE:1220 ret = alloc_fs_rule_tr(id, extra);1221 break;1222 default:1223 return NULL;1224 }1225 if (ret)1226 ret->owner = slave;1227 1228 return ret;1229}1230 1231int mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,1232 struct mlx4_counter *data)1233{1234 struct mlx4_priv *priv = mlx4_priv(dev);1235 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1236 struct res_common *tmp;1237 struct res_counter *counter;1238 int *counters_arr;1239 int i = 0, err = 0;1240 1241 memset(data, 0, sizeof(*data));1242 1243 counters_arr = kmalloc_array(dev->caps.max_counters,1244 sizeof(*counters_arr), GFP_KERNEL);1245 if (!counters_arr)1246 return -ENOMEM;1247 1248 spin_lock_irq(mlx4_tlock(dev));1249 list_for_each_entry(tmp,1250 &tracker->slave_list[slave].res_list[RES_COUNTER],1251 list) {1252 counter = container_of(tmp, struct res_counter, com);1253 if (counter->port == port) {1254 counters_arr[i] = (int)tmp->res_id;1255 i++;1256 }1257 }1258 spin_unlock_irq(mlx4_tlock(dev));1259 counters_arr[i] = -1;1260 1261 i = 0;1262 1263 while (counters_arr[i] != -1) {1264 err = mlx4_get_counter_stats(dev, counters_arr[i], data,1265 0);1266 if (err) {1267 memset(data, 0, sizeof(*data));1268 goto table_changed;1269 }1270 i++;1271 }1272 1273table_changed:1274 kfree(counters_arr);1275 return 0;1276}1277 1278static int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,1279 enum mlx4_resource type, int extra)1280{1281 int i;1282 int err;1283 struct mlx4_priv *priv = mlx4_priv(dev);1284 struct res_common **res_arr;1285 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1286 struct rb_root *root = &tracker->res_tree[type];1287 1288 res_arr = kcalloc(count, sizeof(*res_arr), GFP_KERNEL);1289 if (!res_arr)1290 return -ENOMEM;1291 1292 for (i = 0; i < count; ++i) {1293 res_arr[i] = alloc_tr(base + i, type, slave, extra);1294 if (!res_arr[i]) {1295 for (--i; i >= 0; --i)1296 kfree(res_arr[i]);1297 1298 kfree(res_arr);1299 return -ENOMEM;1300 }1301 }1302 1303 spin_lock_irq(mlx4_tlock(dev));1304 for (i = 0; i < count; ++i) {1305 if (find_res(dev, base + i, type)) {1306 err = -EEXIST;1307 goto undo;1308 }1309 err = res_tracker_insert(root, res_arr[i]);1310 if (err)1311 goto undo;1312 list_add_tail(&res_arr[i]->list,1313 &tracker->slave_list[slave].res_list[type]);1314 }1315 spin_unlock_irq(mlx4_tlock(dev));1316 kfree(res_arr);1317 1318 return 0;1319 1320undo:1321 for (--i; i >= 0; --i) {1322 rb_erase(&res_arr[i]->node, root);1323 list_del_init(&res_arr[i]->list);1324 }1325 1326 spin_unlock_irq(mlx4_tlock(dev));1327 1328 for (i = 0; i < count; ++i)1329 kfree(res_arr[i]);1330 1331 kfree(res_arr);1332 1333 return err;1334}1335 1336static int remove_qp_ok(struct res_qp *res)1337{1338 if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) ||1339 !list_empty(&res->mcg_list)) {1340 pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n",1341 res->com.state, atomic_read(&res->ref_count));1342 return -EBUSY;1343 } else if (res->com.state != RES_QP_RESERVED) {1344 return -EPERM;1345 }1346 1347 return 0;1348}1349 1350static int remove_mtt_ok(struct res_mtt *res, int order)1351{1352 if (res->com.state == RES_MTT_BUSY ||1353 atomic_read(&res->ref_count)) {1354 pr_devel("%s-%d: state %s, ref_count %d\n",1355 __func__, __LINE__,1356 mtt_states_str(res->com.state),1357 atomic_read(&res->ref_count));1358 return -EBUSY;1359 } else if (res->com.state != RES_MTT_ALLOCATED)1360 return -EPERM;1361 else if (res->order != order)1362 return -EINVAL;1363 1364 return 0;1365}1366 1367static int remove_mpt_ok(struct res_mpt *res)1368{1369 if (res->com.state == RES_MPT_BUSY)1370 return -EBUSY;1371 else if (res->com.state != RES_MPT_RESERVED)1372 return -EPERM;1373 1374 return 0;1375}1376 1377static int remove_eq_ok(struct res_eq *res)1378{1379 if (res->com.state == RES_MPT_BUSY)1380 return -EBUSY;1381 else if (res->com.state != RES_MPT_RESERVED)1382 return -EPERM;1383 1384 return 0;1385}1386 1387static int remove_counter_ok(struct res_counter *res)1388{1389 if (res->com.state == RES_COUNTER_BUSY)1390 return -EBUSY;1391 else if (res->com.state != RES_COUNTER_ALLOCATED)1392 return -EPERM;1393 1394 return 0;1395}1396 1397static int remove_xrcdn_ok(struct res_xrcdn *res)1398{1399 if (res->com.state == RES_XRCD_BUSY)1400 return -EBUSY;1401 else if (res->com.state != RES_XRCD_ALLOCATED)1402 return -EPERM;1403 1404 return 0;1405}1406 1407static int remove_fs_rule_ok(struct res_fs_rule *res)1408{1409 if (res->com.state == RES_FS_RULE_BUSY)1410 return -EBUSY;1411 else if (res->com.state != RES_FS_RULE_ALLOCATED)1412 return -EPERM;1413 1414 return 0;1415}1416 1417static int remove_cq_ok(struct res_cq *res)1418{1419 if (res->com.state == RES_CQ_BUSY)1420 return -EBUSY;1421 else if (res->com.state != RES_CQ_ALLOCATED)1422 return -EPERM;1423 1424 return 0;1425}1426 1427static int remove_srq_ok(struct res_srq *res)1428{1429 if (res->com.state == RES_SRQ_BUSY)1430 return -EBUSY;1431 else if (res->com.state != RES_SRQ_ALLOCATED)1432 return -EPERM;1433 1434 return 0;1435}1436 1437static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra)1438{1439 switch (type) {1440 case RES_QP:1441 return remove_qp_ok((struct res_qp *)res);1442 case RES_CQ:1443 return remove_cq_ok((struct res_cq *)res);1444 case RES_SRQ:1445 return remove_srq_ok((struct res_srq *)res);1446 case RES_MPT:1447 return remove_mpt_ok((struct res_mpt *)res);1448 case RES_MTT:1449 return remove_mtt_ok((struct res_mtt *)res, extra);1450 case RES_MAC:1451 return -EOPNOTSUPP;1452 case RES_EQ:1453 return remove_eq_ok((struct res_eq *)res);1454 case RES_COUNTER:1455 return remove_counter_ok((struct res_counter *)res);1456 case RES_XRCD:1457 return remove_xrcdn_ok((struct res_xrcdn *)res);1458 case RES_FS_RULE:1459 return remove_fs_rule_ok((struct res_fs_rule *)res);1460 default:1461 return -EINVAL;1462 }1463}1464 1465static int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,1466 enum mlx4_resource type, int extra)1467{1468 u64 i;1469 int err;1470 struct mlx4_priv *priv = mlx4_priv(dev);1471 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1472 struct res_common *r;1473 1474 spin_lock_irq(mlx4_tlock(dev));1475 for (i = base; i < base + count; ++i) {1476 r = res_tracker_lookup(&tracker->res_tree[type], i);1477 if (!r) {1478 err = -ENOENT;1479 goto out;1480 }1481 if (r->owner != slave) {1482 err = -EPERM;1483 goto out;1484 }1485 err = remove_ok(r, type, extra);1486 if (err)1487 goto out;1488 }1489 1490 for (i = base; i < base + count; ++i) {1491 r = res_tracker_lookup(&tracker->res_tree[type], i);1492 rb_erase(&r->node, &tracker->res_tree[type]);1493 list_del(&r->list);1494 kfree(r);1495 }1496 err = 0;1497 1498out:1499 spin_unlock_irq(mlx4_tlock(dev));1500 1501 return err;1502}1503 1504static int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn,1505 enum res_qp_states state, struct res_qp **qp,1506 int alloc)1507{1508 struct mlx4_priv *priv = mlx4_priv(dev);1509 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1510 struct res_qp *r;1511 int err = 0;1512 1513 spin_lock_irq(mlx4_tlock(dev));1514 r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn);1515 if (!r)1516 err = -ENOENT;1517 else if (r->com.owner != slave)1518 err = -EPERM;1519 else {1520 switch (state) {1521 case RES_QP_BUSY:1522 mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n",1523 __func__, r->com.res_id);1524 err = -EBUSY;1525 break;1526 1527 case RES_QP_RESERVED:1528 if (r->com.state == RES_QP_MAPPED && !alloc)1529 break;1530 1531 mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id);1532 err = -EINVAL;1533 break;1534 1535 case RES_QP_MAPPED:1536 if ((r->com.state == RES_QP_RESERVED && alloc) ||1537 r->com.state == RES_QP_HW)1538 break;1539 else {1540 mlx4_dbg(dev, "failed RES_QP, 0x%llx\n",1541 r->com.res_id);1542 err = -EINVAL;1543 }1544 1545 break;1546 1547 case RES_QP_HW:1548 if (r->com.state != RES_QP_MAPPED)1549 err = -EINVAL;1550 break;1551 default:1552 err = -EINVAL;1553 }1554 1555 if (!err) {1556 r->com.from_state = r->com.state;1557 r->com.to_state = state;1558 r->com.state = RES_QP_BUSY;1559 if (qp)1560 *qp = r;1561 }1562 }1563 1564 spin_unlock_irq(mlx4_tlock(dev));1565 1566 return err;1567}1568 1569static int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index,1570 enum res_mpt_states state, struct res_mpt **mpt)1571{1572 struct mlx4_priv *priv = mlx4_priv(dev);1573 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1574 struct res_mpt *r;1575 int err = 0;1576 1577 spin_lock_irq(mlx4_tlock(dev));1578 r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index);1579 if (!r)1580 err = -ENOENT;1581 else if (r->com.owner != slave)1582 err = -EPERM;1583 else {1584 switch (state) {1585 case RES_MPT_BUSY:1586 err = -EINVAL;1587 break;1588 1589 case RES_MPT_RESERVED:1590 if (r->com.state != RES_MPT_MAPPED)1591 err = -EINVAL;1592 break;1593 1594 case RES_MPT_MAPPED:1595 if (r->com.state != RES_MPT_RESERVED &&1596 r->com.state != RES_MPT_HW)1597 err = -EINVAL;1598 break;1599 1600 case RES_MPT_HW:1601 if (r->com.state != RES_MPT_MAPPED)1602 err = -EINVAL;1603 break;1604 default:1605 err = -EINVAL;1606 }1607 1608 if (!err) {1609 r->com.from_state = r->com.state;1610 r->com.to_state = state;1611 r->com.state = RES_MPT_BUSY;1612 if (mpt)1613 *mpt = r;1614 }1615 }1616 1617 spin_unlock_irq(mlx4_tlock(dev));1618 1619 return err;1620}1621 1622static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,1623 enum res_eq_states state, struct res_eq **eq)1624{1625 struct mlx4_priv *priv = mlx4_priv(dev);1626 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1627 struct res_eq *r;1628 int err = 0;1629 1630 spin_lock_irq(mlx4_tlock(dev));1631 r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index);1632 if (!r)1633 err = -ENOENT;1634 else if (r->com.owner != slave)1635 err = -EPERM;1636 else {1637 switch (state) {1638 case RES_EQ_BUSY:1639 err = -EINVAL;1640 break;1641 1642 case RES_EQ_RESERVED:1643 if (r->com.state != RES_EQ_HW)1644 err = -EINVAL;1645 break;1646 1647 case RES_EQ_HW:1648 if (r->com.state != RES_EQ_RESERVED)1649 err = -EINVAL;1650 break;1651 1652 default:1653 err = -EINVAL;1654 }1655 1656 if (!err) {1657 r->com.from_state = r->com.state;1658 r->com.to_state = state;1659 r->com.state = RES_EQ_BUSY;1660 }1661 }1662 1663 spin_unlock_irq(mlx4_tlock(dev));1664 1665 if (!err && eq)1666 *eq = r;1667 1668 return err;1669}1670 1671static int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn,1672 enum res_cq_states state, struct res_cq **cq)1673{1674 struct mlx4_priv *priv = mlx4_priv(dev);1675 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1676 struct res_cq *r;1677 int err;1678 1679 spin_lock_irq(mlx4_tlock(dev));1680 r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn);1681 if (!r) {1682 err = -ENOENT;1683 } else if (r->com.owner != slave) {1684 err = -EPERM;1685 } else if (state == RES_CQ_ALLOCATED) {1686 if (r->com.state != RES_CQ_HW)1687 err = -EINVAL;1688 else if (atomic_read(&r->ref_count))1689 err = -EBUSY;1690 else1691 err = 0;1692 } else if (state != RES_CQ_HW || r->com.state != RES_CQ_ALLOCATED) {1693 err = -EINVAL;1694 } else {1695 err = 0;1696 }1697 1698 if (!err) {1699 r->com.from_state = r->com.state;1700 r->com.to_state = state;1701 r->com.state = RES_CQ_BUSY;1702 if (cq)1703 *cq = r;1704 }1705 1706 spin_unlock_irq(mlx4_tlock(dev));1707 1708 return err;1709}1710 1711static int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,1712 enum res_srq_states state, struct res_srq **srq)1713{1714 struct mlx4_priv *priv = mlx4_priv(dev);1715 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1716 struct res_srq *r;1717 int err = 0;1718 1719 spin_lock_irq(mlx4_tlock(dev));1720 r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index);1721 if (!r) {1722 err = -ENOENT;1723 } else if (r->com.owner != slave) {1724 err = -EPERM;1725 } else if (state == RES_SRQ_ALLOCATED) {1726 if (r->com.state != RES_SRQ_HW)1727 err = -EINVAL;1728 else if (atomic_read(&r->ref_count))1729 err = -EBUSY;1730 } else if (state != RES_SRQ_HW || r->com.state != RES_SRQ_ALLOCATED) {1731 err = -EINVAL;1732 }1733 1734 if (!err) {1735 r->com.from_state = r->com.state;1736 r->com.to_state = state;1737 r->com.state = RES_SRQ_BUSY;1738 if (srq)1739 *srq = r;1740 }1741 1742 spin_unlock_irq(mlx4_tlock(dev));1743 1744 return err;1745}1746 1747static void res_abort_move(struct mlx4_dev *dev, int slave,1748 enum mlx4_resource type, int id)1749{1750 struct mlx4_priv *priv = mlx4_priv(dev);1751 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1752 struct res_common *r;1753 1754 spin_lock_irq(mlx4_tlock(dev));1755 r = res_tracker_lookup(&tracker->res_tree[type], id);1756 if (r && (r->owner == slave))1757 r->state = r->from_state;1758 spin_unlock_irq(mlx4_tlock(dev));1759}1760 1761static void res_end_move(struct mlx4_dev *dev, int slave,1762 enum mlx4_resource type, int id)1763{1764 struct mlx4_priv *priv = mlx4_priv(dev);1765 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;1766 struct res_common *r;1767 1768 spin_lock_irq(mlx4_tlock(dev));1769 r = res_tracker_lookup(&tracker->res_tree[type], id);1770 if (r && (r->owner == slave))1771 r->state = r->to_state;1772 spin_unlock_irq(mlx4_tlock(dev));1773}1774 1775static int valid_reserved(struct mlx4_dev *dev, int slave, int qpn)1776{1777 return mlx4_is_qp_reserved(dev, qpn) &&1778 (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn));1779}1780 1781static int fw_reserved(struct mlx4_dev *dev, int qpn)1782{1783 return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];1784}1785 1786static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,1787 u64 in_param, u64 *out_param)1788{1789 int err;1790 int count;1791 int align;1792 int base;1793 int qpn;1794 u8 flags;1795 1796 switch (op) {1797 case RES_OP_RESERVE:1798 count = get_param_l(&in_param) & 0xffffff;1799 /* Turn off all unsupported QP allocation flags that the1800 * slave tries to set.1801 */1802 flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask;1803 align = get_param_h(&in_param);1804 err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);1805 if (err)1806 return err;1807 1808 err = __mlx4_qp_reserve_range(dev, count, align, &base, flags);1809 if (err) {1810 mlx4_release_resource(dev, slave, RES_QP, count, 0);1811 return err;1812 }1813 1814 err = add_res_range(dev, slave, base, count, RES_QP, 0);1815 if (err) {1816 mlx4_release_resource(dev, slave, RES_QP, count, 0);1817 __mlx4_qp_release_range(dev, base, count);1818 return err;1819 }1820 set_param_l(out_param, base);1821 break;1822 case RES_OP_MAP_ICM:1823 qpn = get_param_l(&in_param) & 0x7fffff;1824 if (valid_reserved(dev, slave, qpn)) {1825 err = add_res_range(dev, slave, qpn, 1, RES_QP, 0);1826 if (err)1827 return err;1828 }1829 1830 err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED,1831 NULL, 1);1832 if (err)1833 return err;1834 1835 if (!fw_reserved(dev, qpn)) {1836 err = __mlx4_qp_alloc_icm(dev, qpn);1837 if (err) {1838 res_abort_move(dev, slave, RES_QP, qpn);1839 return err;1840 }1841 }1842 1843 res_end_move(dev, slave, RES_QP, qpn);1844 break;1845 1846 default:1847 err = -EINVAL;1848 break;1849 }1850 return err;1851}1852 1853static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,1854 u64 in_param, u64 *out_param)1855{1856 int err = -EINVAL;1857 int base;1858 int order;1859 1860 if (op != RES_OP_RESERVE_AND_MAP)1861 return err;1862 1863 order = get_param_l(&in_param);1864 1865 err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0);1866 if (err)1867 return err;1868 1869 base = __mlx4_alloc_mtt_range(dev, order);1870 if (base == -1) {1871 mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);1872 return -ENOMEM;1873 }1874 1875 err = add_res_range(dev, slave, base, 1, RES_MTT, order);1876 if (err) {1877 mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);1878 __mlx4_free_mtt_range(dev, base, order);1879 } else {1880 set_param_l(out_param, base);1881 }1882 1883 return err;1884}1885 1886static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,1887 u64 in_param, u64 *out_param)1888{1889 int err = -EINVAL;1890 int index;1891 int id;1892 struct res_mpt *mpt;1893 1894 switch (op) {1895 case RES_OP_RESERVE:1896 err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0);1897 if (err)1898 break;1899 1900 index = __mlx4_mpt_reserve(dev);1901 if (index == -1) {1902 mlx4_release_resource(dev, slave, RES_MPT, 1, 0);1903 break;1904 }1905 id = index & mpt_mask(dev);1906 1907 err = add_res_range(dev, slave, id, 1, RES_MPT, index);1908 if (err) {1909 mlx4_release_resource(dev, slave, RES_MPT, 1, 0);1910 __mlx4_mpt_release(dev, index);1911 break;1912 }1913 set_param_l(out_param, index);1914 break;1915 case RES_OP_MAP_ICM:1916 index = get_param_l(&in_param);1917 id = index & mpt_mask(dev);1918 err = mr_res_start_move_to(dev, slave, id,1919 RES_MPT_MAPPED, &mpt);1920 if (err)1921 return err;1922 1923 err = __mlx4_mpt_alloc_icm(dev, mpt->key);1924 if (err) {1925 res_abort_move(dev, slave, RES_MPT, id);1926 return err;1927 }1928 1929 res_end_move(dev, slave, RES_MPT, id);1930 break;1931 }1932 return err;1933}1934 1935static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,1936 u64 in_param, u64 *out_param)1937{1938 int cqn;1939 int err;1940 1941 switch (op) {1942 case RES_OP_RESERVE_AND_MAP:1943 err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0);1944 if (err)1945 break;1946 1947 err = __mlx4_cq_alloc_icm(dev, &cqn);1948 if (err) {1949 mlx4_release_resource(dev, slave, RES_CQ, 1, 0);1950 break;1951 }1952 1953 err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0);1954 if (err) {1955 mlx4_release_resource(dev, slave, RES_CQ, 1, 0);1956 __mlx4_cq_free_icm(dev, cqn);1957 break;1958 }1959 1960 set_param_l(out_param, cqn);1961 break;1962 1963 default:1964 err = -EINVAL;1965 }1966 1967 return err;1968}1969 1970static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,1971 u64 in_param, u64 *out_param)1972{1973 int srqn;1974 int err;1975 1976 switch (op) {1977 case RES_OP_RESERVE_AND_MAP:1978 err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0);1979 if (err)1980 break;1981 1982 err = __mlx4_srq_alloc_icm(dev, &srqn);1983 if (err) {1984 mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);1985 break;1986 }1987 1988 err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0);1989 if (err) {1990 mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);1991 __mlx4_srq_free_icm(dev, srqn);1992 break;1993 }1994 1995 set_param_l(out_param, srqn);1996 break;1997 1998 default:1999 err = -EINVAL;2000 }2001 2002 return err;2003}2004 2005static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,2006 u8 smac_index, u64 *mac)2007{2008 struct mlx4_priv *priv = mlx4_priv(dev);2009 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2010 struct list_head *mac_list =2011 &tracker->slave_list[slave].res_list[RES_MAC];2012 struct mac_res *res, *tmp;2013 2014 list_for_each_entry_safe(res, tmp, mac_list, list) {2015 if (res->smac_index == smac_index && res->port == (u8) port) {2016 *mac = res->mac;2017 return 0;2018 }2019 }2020 return -ENOENT;2021}2022 2023static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)2024{2025 struct mlx4_priv *priv = mlx4_priv(dev);2026 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2027 struct list_head *mac_list =2028 &tracker->slave_list[slave].res_list[RES_MAC];2029 struct mac_res *res, *tmp;2030 2031 list_for_each_entry_safe(res, tmp, mac_list, list) {2032 if (res->mac == mac && res->port == (u8) port) {2033 /* mac found. update ref count */2034 ++res->ref_count;2035 return 0;2036 }2037 }2038 2039 if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))2040 return -EINVAL;2041 res = kzalloc(sizeof(*res), GFP_KERNEL);2042 if (!res) {2043 mlx4_release_resource(dev, slave, RES_MAC, 1, port);2044 return -ENOMEM;2045 }2046 res->mac = mac;2047 res->port = (u8) port;2048 res->smac_index = smac_index;2049 res->ref_count = 1;2050 list_add_tail(&res->list,2051 &tracker->slave_list[slave].res_list[RES_MAC]);2052 return 0;2053}2054 2055static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,2056 int port)2057{2058 struct mlx4_priv *priv = mlx4_priv(dev);2059 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2060 struct list_head *mac_list =2061 &tracker->slave_list[slave].res_list[RES_MAC];2062 struct mac_res *res, *tmp;2063 2064 list_for_each_entry_safe(res, tmp, mac_list, list) {2065 if (res->mac == mac && res->port == (u8) port) {2066 if (!--res->ref_count) {2067 list_del(&res->list);2068 mlx4_release_resource(dev, slave, RES_MAC, 1, port);2069 kfree(res);2070 }2071 break;2072 }2073 }2074}2075 2076static void rem_slave_macs(struct mlx4_dev *dev, int slave)2077{2078 struct mlx4_priv *priv = mlx4_priv(dev);2079 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2080 struct list_head *mac_list =2081 &tracker->slave_list[slave].res_list[RES_MAC];2082 struct mac_res *res, *tmp;2083 int i;2084 2085 list_for_each_entry_safe(res, tmp, mac_list, list) {2086 list_del(&res->list);2087 /* dereference the mac the num times the slave referenced it */2088 for (i = 0; i < res->ref_count; i++)2089 __mlx4_unregister_mac(dev, res->port, res->mac);2090 mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);2091 kfree(res);2092 }2093}2094 2095static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,2096 u64 in_param, u64 *out_param, int in_port)2097{2098 int err = -EINVAL;2099 int port;2100 u64 mac;2101 u8 smac_index;2102 2103 if (op != RES_OP_RESERVE_AND_MAP)2104 return err;2105 2106 port = !in_port ? get_param_l(out_param) : in_port;2107 port = mlx4_slave_convert_port(2108 dev, slave, port);2109 2110 if (port < 0)2111 return -EINVAL;2112 mac = in_param;2113 2114 err = __mlx4_register_mac(dev, port, mac);2115 if (err >= 0) {2116 smac_index = err;2117 set_param_l(out_param, err);2118 err = 0;2119 }2120 2121 if (!err) {2122 err = mac_add_to_slave(dev, slave, mac, port, smac_index);2123 if (err)2124 __mlx4_unregister_mac(dev, port, mac);2125 }2126 return err;2127}2128 2129static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan,2130 int port, int vlan_index)2131{2132 struct mlx4_priv *priv = mlx4_priv(dev);2133 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2134 struct list_head *vlan_list =2135 &tracker->slave_list[slave].res_list[RES_VLAN];2136 struct vlan_res *res, *tmp;2137 2138 list_for_each_entry_safe(res, tmp, vlan_list, list) {2139 if (res->vlan == vlan && res->port == (u8) port) {2140 /* vlan found. update ref count */2141 ++res->ref_count;2142 return 0;2143 }2144 }2145 2146 if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port))2147 return -EINVAL;2148 res = kzalloc(sizeof(*res), GFP_KERNEL);2149 if (!res) {2150 mlx4_release_resource(dev, slave, RES_VLAN, 1, port);2151 return -ENOMEM;2152 }2153 res->vlan = vlan;2154 res->port = (u8) port;2155 res->vlan_index = vlan_index;2156 res->ref_count = 1;2157 list_add_tail(&res->list,2158 &tracker->slave_list[slave].res_list[RES_VLAN]);2159 return 0;2160}2161 2162 2163static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan,2164 int port)2165{2166 struct mlx4_priv *priv = mlx4_priv(dev);2167 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2168 struct list_head *vlan_list =2169 &tracker->slave_list[slave].res_list[RES_VLAN];2170 struct vlan_res *res, *tmp;2171 2172 list_for_each_entry_safe(res, tmp, vlan_list, list) {2173 if (res->vlan == vlan && res->port == (u8) port) {2174 if (!--res->ref_count) {2175 list_del(&res->list);2176 mlx4_release_resource(dev, slave, RES_VLAN,2177 1, port);2178 kfree(res);2179 }2180 break;2181 }2182 }2183}2184 2185static void rem_slave_vlans(struct mlx4_dev *dev, int slave)2186{2187 struct mlx4_priv *priv = mlx4_priv(dev);2188 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;2189 struct list_head *vlan_list =2190 &tracker->slave_list[slave].res_list[RES_VLAN];2191 struct vlan_res *res, *tmp;2192 int i;2193 2194 list_for_each_entry_safe(res, tmp, vlan_list, list) {2195 list_del(&res->list);2196 /* dereference the vlan the num times the slave referenced it */2197 for (i = 0; i < res->ref_count; i++)2198 __mlx4_unregister_vlan(dev, res->port, res->vlan);2199 mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port);2200 kfree(res);2201 }2202}2203 2204static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,2205 u64 in_param, u64 *out_param, int in_port)2206{2207 struct mlx4_priv *priv = mlx4_priv(dev);2208 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;2209 int err;2210 u16 vlan;2211 int vlan_index;2212 int port;2213 2214 port = !in_port ? get_param_l(out_param) : in_port;2215 2216 if (!port || op != RES_OP_RESERVE_AND_MAP)2217 return -EINVAL;2218 2219 port = mlx4_slave_convert_port(2220 dev, slave, port);2221 2222 if (port < 0)2223 return -EINVAL;2224 /* upstream kernels had NOP for reg/unreg vlan. Continue this. */2225 if (!in_port && port > 0 && port <= dev->caps.num_ports) {2226 slave_state[slave].old_vlan_api = true;2227 return 0;2228 }2229 2230 vlan = (u16) in_param;2231 2232 err = __mlx4_register_vlan(dev, port, vlan, &vlan_index);2233 if (!err) {2234 set_param_l(out_param, (u32) vlan_index);2235 err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index);2236 if (err)2237 __mlx4_unregister_vlan(dev, port, vlan);2238 }2239 return err;2240}2241 2242static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,2243 u64 in_param, u64 *out_param, int port)2244{2245 u32 index;2246 int err;2247 2248 if (op != RES_OP_RESERVE)2249 return -EINVAL;2250 2251 err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0);2252 if (err)2253 return err;2254 2255 err = __mlx4_counter_alloc(dev, &index);2256 if (err) {2257 mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);2258 return err;2259 }2260 2261 err = add_res_range(dev, slave, index, 1, RES_COUNTER, port);2262 if (err) {2263 __mlx4_counter_free(dev, index);2264 mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);2265 } else {2266 set_param_l(out_param, index);2267 }2268 2269 return err;2270}2271 2272static int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,2273 u64 in_param, u64 *out_param)2274{2275 u32 xrcdn;2276 int err;2277 2278 if (op != RES_OP_RESERVE)2279 return -EINVAL;2280 2281 err = __mlx4_xrcd_alloc(dev, &xrcdn);2282 if (err)2283 return err;2284 2285 err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);2286 if (err)2287 __mlx4_xrcd_free(dev, xrcdn);2288 else2289 set_param_l(out_param, xrcdn);2290 2291 return err;2292}2293 2294int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,2295 struct mlx4_vhcr *vhcr,2296 struct mlx4_cmd_mailbox *inbox,2297 struct mlx4_cmd_mailbox *outbox,2298 struct mlx4_cmd_info *cmd)2299{2300 int err;2301 int alop = vhcr->op_modifier;2302 2303 switch (vhcr->in_modifier & 0xFF) {2304 case RES_QP:2305 err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop,2306 vhcr->in_param, &vhcr->out_param);2307 break;2308 2309 case RES_MTT:2310 err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop,2311 vhcr->in_param, &vhcr->out_param);2312 break;2313 2314 case RES_MPT:2315 err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop,2316 vhcr->in_param, &vhcr->out_param);2317 break;2318 2319 case RES_CQ:2320 err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop,2321 vhcr->in_param, &vhcr->out_param);2322 break;2323 2324 case RES_SRQ:2325 err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop,2326 vhcr->in_param, &vhcr->out_param);2327 break;2328 2329 case RES_MAC:2330 err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop,2331 vhcr->in_param, &vhcr->out_param,2332 (vhcr->in_modifier >> 8) & 0xFF);2333 break;2334 2335 case RES_VLAN:2336 err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop,2337 vhcr->in_param, &vhcr->out_param,2338 (vhcr->in_modifier >> 8) & 0xFF);2339 break;2340 2341 case RES_COUNTER:2342 err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop,2343 vhcr->in_param, &vhcr->out_param, 0);2344 break;2345 2346 case RES_XRCD:2347 err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop,2348 vhcr->in_param, &vhcr->out_param);2349 break;2350 2351 default:2352 err = -EINVAL;2353 break;2354 }2355 2356 return err;2357}2358 2359static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2360 u64 in_param)2361{2362 int err;2363 int count;2364 int base;2365 int qpn;2366 2367 switch (op) {2368 case RES_OP_RESERVE:2369 base = get_param_l(&in_param) & 0x7fffff;2370 count = get_param_h(&in_param);2371 err = rem_res_range(dev, slave, base, count, RES_QP, 0);2372 if (err)2373 break;2374 mlx4_release_resource(dev, slave, RES_QP, count, 0);2375 __mlx4_qp_release_range(dev, base, count);2376 break;2377 case RES_OP_MAP_ICM:2378 qpn = get_param_l(&in_param) & 0x7fffff;2379 err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED,2380 NULL, 0);2381 if (err)2382 return err;2383 2384 if (!fw_reserved(dev, qpn))2385 __mlx4_qp_free_icm(dev, qpn);2386 2387 res_end_move(dev, slave, RES_QP, qpn);2388 2389 if (valid_reserved(dev, slave, qpn))2390 err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0);2391 break;2392 default:2393 err = -EINVAL;2394 break;2395 }2396 return err;2397}2398 2399static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2400 u64 in_param, u64 *out_param)2401{2402 int err = -EINVAL;2403 int base;2404 int order;2405 2406 if (op != RES_OP_RESERVE_AND_MAP)2407 return err;2408 2409 base = get_param_l(&in_param);2410 order = get_param_h(&in_param);2411 err = rem_res_range(dev, slave, base, 1, RES_MTT, order);2412 if (!err) {2413 mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);2414 __mlx4_free_mtt_range(dev, base, order);2415 }2416 return err;2417}2418 2419static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2420 u64 in_param)2421{2422 int err = -EINVAL;2423 int index;2424 int id;2425 struct res_mpt *mpt;2426 2427 switch (op) {2428 case RES_OP_RESERVE:2429 index = get_param_l(&in_param);2430 id = index & mpt_mask(dev);2431 err = get_res(dev, slave, id, RES_MPT, &mpt);2432 if (err)2433 break;2434 index = mpt->key;2435 put_res(dev, slave, id, RES_MPT);2436 2437 err = rem_res_range(dev, slave, id, 1, RES_MPT, 0);2438 if (err)2439 break;2440 mlx4_release_resource(dev, slave, RES_MPT, 1, 0);2441 __mlx4_mpt_release(dev, index);2442 break;2443 case RES_OP_MAP_ICM:2444 index = get_param_l(&in_param);2445 id = index & mpt_mask(dev);2446 err = mr_res_start_move_to(dev, slave, id,2447 RES_MPT_RESERVED, &mpt);2448 if (err)2449 return err;2450 2451 __mlx4_mpt_free_icm(dev, mpt->key);2452 res_end_move(dev, slave, RES_MPT, id);2453 break;2454 default:2455 err = -EINVAL;2456 break;2457 }2458 return err;2459}2460 2461static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2462 u64 in_param, u64 *out_param)2463{2464 int cqn;2465 int err;2466 2467 switch (op) {2468 case RES_OP_RESERVE_AND_MAP:2469 cqn = get_param_l(&in_param);2470 err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0);2471 if (err)2472 break;2473 2474 mlx4_release_resource(dev, slave, RES_CQ, 1, 0);2475 __mlx4_cq_free_icm(dev, cqn);2476 break;2477 2478 default:2479 err = -EINVAL;2480 break;2481 }2482 2483 return err;2484}2485 2486static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2487 u64 in_param, u64 *out_param)2488{2489 int srqn;2490 int err;2491 2492 switch (op) {2493 case RES_OP_RESERVE_AND_MAP:2494 srqn = get_param_l(&in_param);2495 err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0);2496 if (err)2497 break;2498 2499 mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);2500 __mlx4_srq_free_icm(dev, srqn);2501 break;2502 2503 default:2504 err = -EINVAL;2505 break;2506 }2507 2508 return err;2509}2510 2511static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2512 u64 in_param, u64 *out_param, int in_port)2513{2514 int port;2515 int err = 0;2516 2517 switch (op) {2518 case RES_OP_RESERVE_AND_MAP:2519 port = !in_port ? get_param_l(out_param) : in_port;2520 port = mlx4_slave_convert_port(2521 dev, slave, port);2522 2523 if (port < 0)2524 return -EINVAL;2525 mac_del_from_slave(dev, slave, in_param, port);2526 __mlx4_unregister_mac(dev, port, in_param);2527 break;2528 default:2529 err = -EINVAL;2530 break;2531 }2532 2533 return err;2534 2535}2536 2537static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2538 u64 in_param, u64 *out_param, int port)2539{2540 struct mlx4_priv *priv = mlx4_priv(dev);2541 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;2542 int err = 0;2543 2544 port = mlx4_slave_convert_port(2545 dev, slave, port);2546 2547 if (port < 0)2548 return -EINVAL;2549 switch (op) {2550 case RES_OP_RESERVE_AND_MAP:2551 if (slave_state[slave].old_vlan_api)2552 return 0;2553 if (!port)2554 return -EINVAL;2555 vlan_del_from_slave(dev, slave, in_param, port);2556 __mlx4_unregister_vlan(dev, port, in_param);2557 break;2558 default:2559 err = -EINVAL;2560 break;2561 }2562 2563 return err;2564}2565 2566static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2567 u64 in_param, u64 *out_param)2568{2569 int index;2570 int err;2571 2572 if (op != RES_OP_RESERVE)2573 return -EINVAL;2574 2575 index = get_param_l(&in_param);2576 if (index == MLX4_SINK_COUNTER_INDEX(dev))2577 return 0;2578 2579 err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0);2580 if (err)2581 return err;2582 2583 __mlx4_counter_free(dev, index);2584 mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);2585 2586 return err;2587}2588 2589static int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,2590 u64 in_param, u64 *out_param)2591{2592 int xrcdn;2593 int err;2594 2595 if (op != RES_OP_RESERVE)2596 return -EINVAL;2597 2598 xrcdn = get_param_l(&in_param);2599 err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);2600 if (err)2601 return err;2602 2603 __mlx4_xrcd_free(dev, xrcdn);2604 2605 return err;2606}2607 2608int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,2609 struct mlx4_vhcr *vhcr,2610 struct mlx4_cmd_mailbox *inbox,2611 struct mlx4_cmd_mailbox *outbox,2612 struct mlx4_cmd_info *cmd)2613{2614 int err = -EINVAL;2615 int alop = vhcr->op_modifier;2616 2617 switch (vhcr->in_modifier & 0xFF) {2618 case RES_QP:2619 err = qp_free_res(dev, slave, vhcr->op_modifier, alop,2620 vhcr->in_param);2621 break;2622 2623 case RES_MTT:2624 err = mtt_free_res(dev, slave, vhcr->op_modifier, alop,2625 vhcr->in_param, &vhcr->out_param);2626 break;2627 2628 case RES_MPT:2629 err = mpt_free_res(dev, slave, vhcr->op_modifier, alop,2630 vhcr->in_param);2631 break;2632 2633 case RES_CQ:2634 err = cq_free_res(dev, slave, vhcr->op_modifier, alop,2635 vhcr->in_param, &vhcr->out_param);2636 break;2637 2638 case RES_SRQ:2639 err = srq_free_res(dev, slave, vhcr->op_modifier, alop,2640 vhcr->in_param, &vhcr->out_param);2641 break;2642 2643 case RES_MAC:2644 err = mac_free_res(dev, slave, vhcr->op_modifier, alop,2645 vhcr->in_param, &vhcr->out_param,2646 (vhcr->in_modifier >> 8) & 0xFF);2647 break;2648 2649 case RES_VLAN:2650 err = vlan_free_res(dev, slave, vhcr->op_modifier, alop,2651 vhcr->in_param, &vhcr->out_param,2652 (vhcr->in_modifier >> 8) & 0xFF);2653 break;2654 2655 case RES_COUNTER:2656 err = counter_free_res(dev, slave, vhcr->op_modifier, alop,2657 vhcr->in_param, &vhcr->out_param);2658 break;2659 2660 case RES_XRCD:2661 err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop,2662 vhcr->in_param, &vhcr->out_param);2663 break;2664 2665 default:2666 break;2667 }2668 return err;2669}2670 2671/* ugly but other choices are uglier */2672static int mr_phys_mpt(struct mlx4_mpt_entry *mpt)2673{2674 return (be32_to_cpu(mpt->flags) >> 9) & 1;2675}2676 2677static int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt)2678{2679 return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8;2680}2681 2682static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt)2683{2684 return be32_to_cpu(mpt->mtt_sz);2685}2686 2687static u32 mr_get_pd(struct mlx4_mpt_entry *mpt)2688{2689 return be32_to_cpu(mpt->pd_flags) & 0x00ffffff;2690}2691 2692static int mr_is_fmr(struct mlx4_mpt_entry *mpt)2693{2694 return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG;2695}2696 2697static int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt)2698{2699 return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE;2700}2701 2702static int mr_is_region(struct mlx4_mpt_entry *mpt)2703{2704 return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION;2705}2706 2707static int qp_get_mtt_addr(struct mlx4_qp_context *qpc)2708{2709 return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8;2710}2711 2712static int srq_get_mtt_addr(struct mlx4_srq_context *srqc)2713{2714 return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8;2715}2716 2717static int qp_get_mtt_size(struct mlx4_qp_context *qpc)2718{2719 int page_shift = (qpc->log_page_size & 0x3f) + 12;2720 int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf;2721 int log_sq_sride = qpc->sq_size_stride & 7;2722 int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf;2723 int log_rq_stride = qpc->rq_size_stride & 7;2724 int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1;2725 int rss = (be32_to_cpu(qpc->flags) >> 13) & 1;2726 u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;2727 int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0;2728 int sq_size;2729 int rq_size;2730 int total_pages;2731 int total_mem;2732 int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f;2733 int tot;2734 2735 sq_size = 1 << (log_sq_size + log_sq_sride + 4);2736 rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4));2737 total_mem = sq_size + rq_size;2738 tot = (total_mem + (page_offset << 6)) >> page_shift;2739 total_pages = !tot ? 1 : roundup_pow_of_two(tot);2740 2741 return total_pages;2742}2743 2744static int check_mtt_range(struct mlx4_dev *dev, int slave, int start,2745 int size, struct res_mtt *mtt)2746{2747 int res_start = mtt->com.res_id;2748 int res_size = (1 << mtt->order);2749 2750 if (start < res_start || start + size > res_start + res_size)2751 return -EPERM;2752 return 0;2753}2754 2755int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave,2756 struct mlx4_vhcr *vhcr,2757 struct mlx4_cmd_mailbox *inbox,2758 struct mlx4_cmd_mailbox *outbox,2759 struct mlx4_cmd_info *cmd)2760{2761 int err;2762 int index = vhcr->in_modifier;2763 struct res_mtt *mtt;2764 struct res_mpt *mpt = NULL;2765 int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz;2766 int phys;2767 int id;2768 u32 pd;2769 int pd_slave;2770 2771 id = index & mpt_mask(dev);2772 err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt);2773 if (err)2774 return err;2775 2776 /* Disable memory windows for VFs. */2777 if (!mr_is_region(inbox->buf)) {2778 err = -EPERM;2779 goto ex_abort;2780 }2781 2782 /* Make sure that the PD bits related to the slave id are zeros. */2783 pd = mr_get_pd(inbox->buf);2784 pd_slave = (pd >> 17) & 0x7f;2785 if (pd_slave != 0 && --pd_slave != slave) {2786 err = -EPERM;2787 goto ex_abort;2788 }2789 2790 if (mr_is_fmr(inbox->buf)) {2791 /* FMR and Bind Enable are forbidden in slave devices. */2792 if (mr_is_bind_enabled(inbox->buf)) {2793 err = -EPERM;2794 goto ex_abort;2795 }2796 /* FMR and Memory Windows are also forbidden. */2797 if (!mr_is_region(inbox->buf)) {2798 err = -EPERM;2799 goto ex_abort;2800 }2801 }2802 2803 phys = mr_phys_mpt(inbox->buf);2804 if (!phys) {2805 err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);2806 if (err)2807 goto ex_abort;2808 2809 err = check_mtt_range(dev, slave, mtt_base,2810 mr_get_mtt_size(inbox->buf), mtt);2811 if (err)2812 goto ex_put;2813 2814 mpt->mtt = mtt;2815 }2816 2817 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);2818 if (err)2819 goto ex_put;2820 2821 if (!phys) {2822 atomic_inc(&mtt->ref_count);2823 put_res(dev, slave, mtt->com.res_id, RES_MTT);2824 }2825 2826 res_end_move(dev, slave, RES_MPT, id);2827 return 0;2828 2829ex_put:2830 if (!phys)2831 put_res(dev, slave, mtt->com.res_id, RES_MTT);2832ex_abort:2833 res_abort_move(dev, slave, RES_MPT, id);2834 2835 return err;2836}2837 2838int mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave,2839 struct mlx4_vhcr *vhcr,2840 struct mlx4_cmd_mailbox *inbox,2841 struct mlx4_cmd_mailbox *outbox,2842 struct mlx4_cmd_info *cmd)2843{2844 int err;2845 int index = vhcr->in_modifier;2846 struct res_mpt *mpt;2847 int id;2848 2849 id = index & mpt_mask(dev);2850 err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt);2851 if (err)2852 return err;2853 2854 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);2855 if (err)2856 goto ex_abort;2857 2858 if (mpt->mtt)2859 atomic_dec(&mpt->mtt->ref_count);2860 2861 res_end_move(dev, slave, RES_MPT, id);2862 return 0;2863 2864ex_abort:2865 res_abort_move(dev, slave, RES_MPT, id);2866 2867 return err;2868}2869 2870int mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave,2871 struct mlx4_vhcr *vhcr,2872 struct mlx4_cmd_mailbox *inbox,2873 struct mlx4_cmd_mailbox *outbox,2874 struct mlx4_cmd_info *cmd)2875{2876 int err;2877 int index = vhcr->in_modifier;2878 struct res_mpt *mpt;2879 int id;2880 2881 id = index & mpt_mask(dev);2882 err = get_res(dev, slave, id, RES_MPT, &mpt);2883 if (err)2884 return err;2885 2886 if (mpt->com.from_state == RES_MPT_MAPPED) {2887 /* In order to allow rereg in SRIOV, we need to alter the MPT entry. To do2888 * that, the VF must read the MPT. But since the MPT entry memory is not2889 * in the VF's virtual memory space, it must use QUERY_MPT to obtain the2890 * entry contents. To guarantee that the MPT cannot be changed, the driver2891 * must perform HW2SW_MPT before this query and return the MPT entry to HW2892 * ownership fofollowing the change. The change here allows the VF to2893 * perform QUERY_MPT also when the entry is in SW ownership.2894 */2895 struct mlx4_mpt_entry *mpt_entry = mlx4_table_find(2896 &mlx4_priv(dev)->mr_table.dmpt_table,2897 mpt->key, NULL);2898 2899 if (NULL == mpt_entry || NULL == outbox->buf) {2900 err = -EINVAL;2901 goto out;2902 }2903 2904 memcpy(outbox->buf, mpt_entry, sizeof(*mpt_entry));2905 2906 err = 0;2907 } else if (mpt->com.from_state == RES_MPT_HW) {2908 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);2909 } else {2910 err = -EBUSY;2911 goto out;2912 }2913 2914 2915out:2916 put_res(dev, slave, id, RES_MPT);2917 return err;2918}2919 2920static int qp_get_rcqn(struct mlx4_qp_context *qpc)2921{2922 return be32_to_cpu(qpc->cqn_recv) & 0xffffff;2923}2924 2925static int qp_get_scqn(struct mlx4_qp_context *qpc)2926{2927 return be32_to_cpu(qpc->cqn_send) & 0xffffff;2928}2929 2930static u32 qp_get_srqn(struct mlx4_qp_context *qpc)2931{2932 return be32_to_cpu(qpc->srqn) & 0x1ffffff;2933}2934 2935static void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr,2936 struct mlx4_qp_context *context)2937{2938 u32 qpn = vhcr->in_modifier & 0xffffff;2939 u32 qkey = 0;2940 2941 if (mlx4_get_parav_qkey(dev, qpn, &qkey))2942 return;2943 2944 /* adjust qkey in qp context */2945 context->qkey = cpu_to_be32(qkey);2946}2947 2948static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,2949 struct mlx4_qp_context *qpc,2950 struct mlx4_cmd_mailbox *inbox);2951 2952int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,2953 struct mlx4_vhcr *vhcr,2954 struct mlx4_cmd_mailbox *inbox,2955 struct mlx4_cmd_mailbox *outbox,2956 struct mlx4_cmd_info *cmd)2957{2958 int err;2959 int qpn = vhcr->in_modifier & 0x7fffff;2960 struct res_mtt *mtt;2961 struct res_qp *qp;2962 struct mlx4_qp_context *qpc = inbox->buf + 8;2963 int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz;2964 int mtt_size = qp_get_mtt_size(qpc);2965 struct res_cq *rcq;2966 struct res_cq *scq;2967 int rcqn = qp_get_rcqn(qpc);2968 int scqn = qp_get_scqn(qpc);2969 u32 srqn = qp_get_srqn(qpc) & 0xffffff;2970 int use_srq = (qp_get_srqn(qpc) >> 24) & 1;2971 struct res_srq *srq;2972 int local_qpn = vhcr->in_modifier & 0xffffff;2973 2974 err = adjust_qp_sched_queue(dev, slave, qpc, inbox);2975 if (err)2976 return err;2977 2978 err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0);2979 if (err)2980 return err;2981 qp->local_qpn = local_qpn;2982 qp->sched_queue = 0;2983 qp->param3 = 0;2984 qp->vlan_control = 0;2985 qp->fvl_rx = 0;2986 qp->pri_path_fl = 0;2987 qp->vlan_index = 0;2988 qp->feup = 0;2989 qp->qpc_flags = be32_to_cpu(qpc->flags);2990 2991 err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);2992 if (err)2993 goto ex_abort;2994 2995 err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt);2996 if (err)2997 goto ex_put_mtt;2998 2999 err = get_res(dev, slave, rcqn, RES_CQ, &rcq);3000 if (err)3001 goto ex_put_mtt;3002 3003 if (scqn != rcqn) {3004 err = get_res(dev, slave, scqn, RES_CQ, &scq);3005 if (err)3006 goto ex_put_rcq;3007 } else3008 scq = rcq;3009 3010 if (use_srq) {3011 err = get_res(dev, slave, srqn, RES_SRQ, &srq);3012 if (err)3013 goto ex_put_scq;3014 }3015 3016 adjust_proxy_tun_qkey(dev, vhcr, qpc);3017 update_pkey_index(dev, slave, inbox);3018 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3019 if (err)3020 goto ex_put_srq;3021 atomic_inc(&mtt->ref_count);3022 qp->mtt = mtt;3023 atomic_inc(&rcq->ref_count);3024 qp->rcq = rcq;3025 atomic_inc(&scq->ref_count);3026 qp->scq = scq;3027 3028 if (scqn != rcqn)3029 put_res(dev, slave, scqn, RES_CQ);3030 3031 if (use_srq) {3032 atomic_inc(&srq->ref_count);3033 put_res(dev, slave, srqn, RES_SRQ);3034 qp->srq = srq;3035 }3036 3037 /* Save param3 for dynamic changes from VST back to VGT */3038 qp->param3 = qpc->param3;3039 put_res(dev, slave, rcqn, RES_CQ);3040 put_res(dev, slave, mtt_base, RES_MTT);3041 res_end_move(dev, slave, RES_QP, qpn);3042 3043 return 0;3044 3045ex_put_srq:3046 if (use_srq)3047 put_res(dev, slave, srqn, RES_SRQ);3048ex_put_scq:3049 if (scqn != rcqn)3050 put_res(dev, slave, scqn, RES_CQ);3051ex_put_rcq:3052 put_res(dev, slave, rcqn, RES_CQ);3053ex_put_mtt:3054 put_res(dev, slave, mtt_base, RES_MTT);3055ex_abort:3056 res_abort_move(dev, slave, RES_QP, qpn);3057 3058 return err;3059}3060 3061static int eq_get_mtt_addr(struct mlx4_eq_context *eqc)3062{3063 return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8;3064}3065 3066static int eq_get_mtt_size(struct mlx4_eq_context *eqc)3067{3068 int log_eq_size = eqc->log_eq_size & 0x1f;3069 int page_shift = (eqc->log_page_size & 0x3f) + 12;3070 3071 if (log_eq_size + 5 < page_shift)3072 return 1;3073 3074 return 1 << (log_eq_size + 5 - page_shift);3075}3076 3077static int cq_get_mtt_addr(struct mlx4_cq_context *cqc)3078{3079 return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8;3080}3081 3082static int cq_get_mtt_size(struct mlx4_cq_context *cqc)3083{3084 int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f;3085 int page_shift = (cqc->log_page_size & 0x3f) + 12;3086 3087 if (log_cq_size + 5 < page_shift)3088 return 1;3089 3090 return 1 << (log_cq_size + 5 - page_shift);3091}3092 3093int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave,3094 struct mlx4_vhcr *vhcr,3095 struct mlx4_cmd_mailbox *inbox,3096 struct mlx4_cmd_mailbox *outbox,3097 struct mlx4_cmd_info *cmd)3098{3099 int err;3100 int eqn = vhcr->in_modifier;3101 int res_id = (slave << 10) | eqn;3102 struct mlx4_eq_context *eqc = inbox->buf;3103 int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz;3104 int mtt_size = eq_get_mtt_size(eqc);3105 struct res_eq *eq;3106 struct res_mtt *mtt;3107 3108 err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0);3109 if (err)3110 return err;3111 err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq);3112 if (err)3113 goto out_add;3114 3115 err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);3116 if (err)3117 goto out_move;3118 3119 err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt);3120 if (err)3121 goto out_put;3122 3123 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3124 if (err)3125 goto out_put;3126 3127 atomic_inc(&mtt->ref_count);3128 eq->mtt = mtt;3129 put_res(dev, slave, mtt->com.res_id, RES_MTT);3130 res_end_move(dev, slave, RES_EQ, res_id);3131 return 0;3132 3133out_put:3134 put_res(dev, slave, mtt->com.res_id, RES_MTT);3135out_move:3136 res_abort_move(dev, slave, RES_EQ, res_id);3137out_add:3138 rem_res_range(dev, slave, res_id, 1, RES_EQ, 0);3139 return err;3140}3141 3142int mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave,3143 struct mlx4_vhcr *vhcr,3144 struct mlx4_cmd_mailbox *inbox,3145 struct mlx4_cmd_mailbox *outbox,3146 struct mlx4_cmd_info *cmd)3147{3148 int err;3149 u8 get = vhcr->op_modifier;3150 3151 if (get != 1)3152 return -EPERM;3153 3154 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3155 3156 return err;3157}3158 3159static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start,3160 int len, struct res_mtt **res)3161{3162 struct mlx4_priv *priv = mlx4_priv(dev);3163 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;3164 struct res_mtt *mtt;3165 int err = -EINVAL;3166 3167 spin_lock_irq(mlx4_tlock(dev));3168 list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT],3169 com.list) {3170 if (!check_mtt_range(dev, slave, start, len, mtt)) {3171 *res = mtt;3172 mtt->com.from_state = mtt->com.state;3173 mtt->com.state = RES_MTT_BUSY;3174 err = 0;3175 break;3176 }3177 }3178 spin_unlock_irq(mlx4_tlock(dev));3179 3180 return err;3181}3182 3183static int verify_qp_parameters(struct mlx4_dev *dev,3184 struct mlx4_vhcr *vhcr,3185 struct mlx4_cmd_mailbox *inbox,3186 enum qp_transition transition, u8 slave)3187{3188 u32 qp_type;3189 u32 qpn;3190 struct mlx4_qp_context *qp_ctx;3191 enum mlx4_qp_optpar optpar;3192 int port;3193 int num_gids;3194 3195 qp_ctx = inbox->buf + 8;3196 qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;3197 optpar = be32_to_cpu(*(__be32 *) inbox->buf);3198 3199 if (slave != mlx4_master_func_num(dev)) {3200 qp_ctx->params2 &= ~cpu_to_be32(MLX4_QP_BIT_FPP);3201 /* setting QP rate-limit is disallowed for VFs */3202 if (qp_ctx->rate_limit_params)3203 return -EPERM;3204 }3205 3206 switch (qp_type) {3207 case MLX4_QP_ST_RC:3208 case MLX4_QP_ST_XRC:3209 case MLX4_QP_ST_UC:3210 switch (transition) {3211 case QP_TRANS_INIT2RTR:3212 case QP_TRANS_RTR2RTS:3213 case QP_TRANS_RTS2RTS:3214 case QP_TRANS_SQD2SQD:3215 case QP_TRANS_SQD2RTS:3216 if (slave != mlx4_master_func_num(dev)) {3217 if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {3218 port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;3219 if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)3220 num_gids = mlx4_get_slave_num_gids(dev, slave, port);3221 else3222 num_gids = 1;3223 if (qp_ctx->pri_path.mgid_index >= num_gids)3224 return -EINVAL;3225 }3226 if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {3227 port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;3228 if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)3229 num_gids = mlx4_get_slave_num_gids(dev, slave, port);3230 else3231 num_gids = 1;3232 if (qp_ctx->alt_path.mgid_index >= num_gids)3233 return -EINVAL;3234 }3235 }3236 break;3237 default:3238 break;3239 }3240 break;3241 3242 case MLX4_QP_ST_MLX:3243 qpn = vhcr->in_modifier & 0x7fffff;3244 port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;3245 if (transition == QP_TRANS_INIT2RTR &&3246 slave != mlx4_master_func_num(dev) &&3247 mlx4_is_qp_reserved(dev, qpn) &&3248 !mlx4_vf_smi_enabled(dev, slave, port)) {3249 /* only enabled VFs may create MLX proxy QPs */3250 mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n",3251 __func__, slave, port);3252 return -EPERM;3253 }3254 break;3255 3256 default:3257 break;3258 }3259 3260 return 0;3261}3262 3263int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave,3264 struct mlx4_vhcr *vhcr,3265 struct mlx4_cmd_mailbox *inbox,3266 struct mlx4_cmd_mailbox *outbox,3267 struct mlx4_cmd_info *cmd)3268{3269 struct mlx4_mtt mtt;3270 __be64 *page_list = inbox->buf;3271 u64 *pg_list = (u64 *)page_list;3272 int i;3273 struct res_mtt *rmtt = NULL;3274 int start = be64_to_cpu(page_list[0]);3275 int npages = vhcr->in_modifier;3276 int err;3277 3278 err = get_containing_mtt(dev, slave, start, npages, &rmtt);3279 if (err)3280 return err;3281 3282 /* Call the SW implementation of write_mtt:3283 * - Prepare a dummy mtt struct3284 * - Translate inbox contents to simple addresses in host endianness */3285 mtt.offset = 0; /* TBD this is broken but I don't handle it since3286 we don't really use it */3287 mtt.order = 0;3288 mtt.page_shift = 0;3289 for (i = 0; i < npages; ++i)3290 pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL);3291 3292 err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages,3293 ((u64 *)page_list + 2));3294 3295 if (rmtt)3296 put_res(dev, slave, rmtt->com.res_id, RES_MTT);3297 3298 return err;3299}3300 3301int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave,3302 struct mlx4_vhcr *vhcr,3303 struct mlx4_cmd_mailbox *inbox,3304 struct mlx4_cmd_mailbox *outbox,3305 struct mlx4_cmd_info *cmd)3306{3307 int eqn = vhcr->in_modifier;3308 int res_id = eqn | (slave << 10);3309 struct res_eq *eq;3310 int err;3311 3312 err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq);3313 if (err)3314 return err;3315 3316 err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL);3317 if (err)3318 goto ex_abort;3319 3320 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3321 if (err)3322 goto ex_put;3323 3324 atomic_dec(&eq->mtt->ref_count);3325 put_res(dev, slave, eq->mtt->com.res_id, RES_MTT);3326 res_end_move(dev, slave, RES_EQ, res_id);3327 rem_res_range(dev, slave, res_id, 1, RES_EQ, 0);3328 3329 return 0;3330 3331ex_put:3332 put_res(dev, slave, eq->mtt->com.res_id, RES_MTT);3333ex_abort:3334 res_abort_move(dev, slave, RES_EQ, res_id);3335 3336 return err;3337}3338 3339int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)3340{3341 struct mlx4_priv *priv = mlx4_priv(dev);3342 struct mlx4_slave_event_eq_info *event_eq;3343 struct mlx4_cmd_mailbox *mailbox;3344 u32 in_modifier = 0;3345 int err;3346 int res_id;3347 struct res_eq *req;3348 3349 if (!priv->mfunc.master.slave_state)3350 return -EINVAL;3351 3352 /* check for slave valid, slave not PF, and slave active */3353 if (slave < 0 || slave > dev->persist->num_vfs ||3354 slave == dev->caps.function ||3355 !priv->mfunc.master.slave_state[slave].active)3356 return 0;3357 3358 event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type];3359 3360 /* Create the event only if the slave is registered */3361 if (event_eq->eqn < 0)3362 return 0;3363 3364 mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]);3365 res_id = (slave << 10) | event_eq->eqn;3366 err = get_res(dev, slave, res_id, RES_EQ, &req);3367 if (err)3368 goto unlock;3369 3370 if (req->com.from_state != RES_EQ_HW) {3371 err = -EINVAL;3372 goto put;3373 }3374 3375 mailbox = mlx4_alloc_cmd_mailbox(dev);3376 if (IS_ERR(mailbox)) {3377 err = PTR_ERR(mailbox);3378 goto put;3379 }3380 3381 if (eqe->type == MLX4_EVENT_TYPE_CMD) {3382 ++event_eq->token;3383 eqe->event.cmd.token = cpu_to_be16(event_eq->token);3384 }3385 3386 memcpy(mailbox->buf, (u8 *) eqe, 28);3387 3388 in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16);3389 3390 err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0,3391 MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B,3392 MLX4_CMD_NATIVE);3393 3394 put_res(dev, slave, res_id, RES_EQ);3395 mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]);3396 mlx4_free_cmd_mailbox(dev, mailbox);3397 return err;3398 3399put:3400 put_res(dev, slave, res_id, RES_EQ);3401 3402unlock:3403 mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]);3404 return err;3405}3406 3407int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave,3408 struct mlx4_vhcr *vhcr,3409 struct mlx4_cmd_mailbox *inbox,3410 struct mlx4_cmd_mailbox *outbox,3411 struct mlx4_cmd_info *cmd)3412{3413 int eqn = vhcr->in_modifier;3414 int res_id = eqn | (slave << 10);3415 struct res_eq *eq;3416 int err;3417 3418 err = get_res(dev, slave, res_id, RES_EQ, &eq);3419 if (err)3420 return err;3421 3422 if (eq->com.from_state != RES_EQ_HW) {3423 err = -EINVAL;3424 goto ex_put;3425 }3426 3427 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3428 3429ex_put:3430 put_res(dev, slave, res_id, RES_EQ);3431 return err;3432}3433 3434int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave,3435 struct mlx4_vhcr *vhcr,3436 struct mlx4_cmd_mailbox *inbox,3437 struct mlx4_cmd_mailbox *outbox,3438 struct mlx4_cmd_info *cmd)3439{3440 int err;3441 int cqn = vhcr->in_modifier;3442 struct mlx4_cq_context *cqc = inbox->buf;3443 int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;3444 struct res_cq *cq = NULL;3445 struct res_mtt *mtt;3446 3447 err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq);3448 if (err)3449 return err;3450 err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);3451 if (err)3452 goto out_move;3453 err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt);3454 if (err)3455 goto out_put;3456 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3457 if (err)3458 goto out_put;3459 atomic_inc(&mtt->ref_count);3460 cq->mtt = mtt;3461 put_res(dev, slave, mtt->com.res_id, RES_MTT);3462 res_end_move(dev, slave, RES_CQ, cqn);3463 return 0;3464 3465out_put:3466 put_res(dev, slave, mtt->com.res_id, RES_MTT);3467out_move:3468 res_abort_move(dev, slave, RES_CQ, cqn);3469 return err;3470}3471 3472int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave,3473 struct mlx4_vhcr *vhcr,3474 struct mlx4_cmd_mailbox *inbox,3475 struct mlx4_cmd_mailbox *outbox,3476 struct mlx4_cmd_info *cmd)3477{3478 int err;3479 int cqn = vhcr->in_modifier;3480 struct res_cq *cq = NULL;3481 3482 err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq);3483 if (err)3484 return err;3485 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3486 if (err)3487 goto out_move;3488 atomic_dec(&cq->mtt->ref_count);3489 res_end_move(dev, slave, RES_CQ, cqn);3490 return 0;3491 3492out_move:3493 res_abort_move(dev, slave, RES_CQ, cqn);3494 return err;3495}3496 3497int mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave,3498 struct mlx4_vhcr *vhcr,3499 struct mlx4_cmd_mailbox *inbox,3500 struct mlx4_cmd_mailbox *outbox,3501 struct mlx4_cmd_info *cmd)3502{3503 int cqn = vhcr->in_modifier;3504 struct res_cq *cq;3505 int err;3506 3507 err = get_res(dev, slave, cqn, RES_CQ, &cq);3508 if (err)3509 return err;3510 3511 if (cq->com.from_state != RES_CQ_HW)3512 goto ex_put;3513 3514 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3515ex_put:3516 put_res(dev, slave, cqn, RES_CQ);3517 3518 return err;3519}3520 3521static int handle_resize(struct mlx4_dev *dev, int slave,3522 struct mlx4_vhcr *vhcr,3523 struct mlx4_cmd_mailbox *inbox,3524 struct mlx4_cmd_mailbox *outbox,3525 struct mlx4_cmd_info *cmd,3526 struct res_cq *cq)3527{3528 int err;3529 struct res_mtt *orig_mtt;3530 struct res_mtt *mtt;3531 struct mlx4_cq_context *cqc = inbox->buf;3532 int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;3533 3534 err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt);3535 if (err)3536 return err;3537 3538 if (orig_mtt != cq->mtt) {3539 err = -EINVAL;3540 goto ex_put;3541 }3542 3543 err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);3544 if (err)3545 goto ex_put;3546 3547 err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt);3548 if (err)3549 goto ex_put1;3550 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3551 if (err)3552 goto ex_put1;3553 atomic_dec(&orig_mtt->ref_count);3554 put_res(dev, slave, orig_mtt->com.res_id, RES_MTT);3555 atomic_inc(&mtt->ref_count);3556 cq->mtt = mtt;3557 put_res(dev, slave, mtt->com.res_id, RES_MTT);3558 return 0;3559 3560ex_put1:3561 put_res(dev, slave, mtt->com.res_id, RES_MTT);3562ex_put:3563 put_res(dev, slave, orig_mtt->com.res_id, RES_MTT);3564 3565 return err;3566 3567}3568 3569int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave,3570 struct mlx4_vhcr *vhcr,3571 struct mlx4_cmd_mailbox *inbox,3572 struct mlx4_cmd_mailbox *outbox,3573 struct mlx4_cmd_info *cmd)3574{3575 int cqn = vhcr->in_modifier;3576 struct res_cq *cq;3577 int err;3578 3579 err = get_res(dev, slave, cqn, RES_CQ, &cq);3580 if (err)3581 return err;3582 3583 if (cq->com.from_state != RES_CQ_HW)3584 goto ex_put;3585 3586 if (vhcr->op_modifier == 0) {3587 err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq);3588 goto ex_put;3589 }3590 3591 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3592ex_put:3593 put_res(dev, slave, cqn, RES_CQ);3594 3595 return err;3596}3597 3598static int srq_get_mtt_size(struct mlx4_srq_context *srqc)3599{3600 int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf;3601 int log_rq_stride = srqc->logstride & 7;3602 int page_shift = (srqc->log_page_size & 0x3f) + 12;3603 3604 if (log_srq_size + log_rq_stride + 4 < page_shift)3605 return 1;3606 3607 return 1 << (log_srq_size + log_rq_stride + 4 - page_shift);3608}3609 3610int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave,3611 struct mlx4_vhcr *vhcr,3612 struct mlx4_cmd_mailbox *inbox,3613 struct mlx4_cmd_mailbox *outbox,3614 struct mlx4_cmd_info *cmd)3615{3616 int err;3617 int srqn = vhcr->in_modifier;3618 struct res_mtt *mtt;3619 struct res_srq *srq = NULL;3620 struct mlx4_srq_context *srqc = inbox->buf;3621 int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz;3622 3623 if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff))3624 return -EINVAL;3625 3626 err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq);3627 if (err)3628 return err;3629 err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);3630 if (err)3631 goto ex_abort;3632 err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc),3633 mtt);3634 if (err)3635 goto ex_put_mtt;3636 3637 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3638 if (err)3639 goto ex_put_mtt;3640 3641 atomic_inc(&mtt->ref_count);3642 srq->mtt = mtt;3643 put_res(dev, slave, mtt->com.res_id, RES_MTT);3644 res_end_move(dev, slave, RES_SRQ, srqn);3645 return 0;3646 3647ex_put_mtt:3648 put_res(dev, slave, mtt->com.res_id, RES_MTT);3649ex_abort:3650 res_abort_move(dev, slave, RES_SRQ, srqn);3651 3652 return err;3653}3654 3655int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave,3656 struct mlx4_vhcr *vhcr,3657 struct mlx4_cmd_mailbox *inbox,3658 struct mlx4_cmd_mailbox *outbox,3659 struct mlx4_cmd_info *cmd)3660{3661 int err;3662 int srqn = vhcr->in_modifier;3663 struct res_srq *srq = NULL;3664 3665 err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq);3666 if (err)3667 return err;3668 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3669 if (err)3670 goto ex_abort;3671 atomic_dec(&srq->mtt->ref_count);3672 if (srq->cq)3673 atomic_dec(&srq->cq->ref_count);3674 res_end_move(dev, slave, RES_SRQ, srqn);3675 3676 return 0;3677 3678ex_abort:3679 res_abort_move(dev, slave, RES_SRQ, srqn);3680 3681 return err;3682}3683 3684int mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave,3685 struct mlx4_vhcr *vhcr,3686 struct mlx4_cmd_mailbox *inbox,3687 struct mlx4_cmd_mailbox *outbox,3688 struct mlx4_cmd_info *cmd)3689{3690 int err;3691 int srqn = vhcr->in_modifier;3692 struct res_srq *srq;3693 3694 err = get_res(dev, slave, srqn, RES_SRQ, &srq);3695 if (err)3696 return err;3697 if (srq->com.from_state != RES_SRQ_HW) {3698 err = -EBUSY;3699 goto out;3700 }3701 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3702out:3703 put_res(dev, slave, srqn, RES_SRQ);3704 return err;3705}3706 3707int mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave,3708 struct mlx4_vhcr *vhcr,3709 struct mlx4_cmd_mailbox *inbox,3710 struct mlx4_cmd_mailbox *outbox,3711 struct mlx4_cmd_info *cmd)3712{3713 int err;3714 int srqn = vhcr->in_modifier;3715 struct res_srq *srq;3716 3717 err = get_res(dev, slave, srqn, RES_SRQ, &srq);3718 if (err)3719 return err;3720 3721 if (srq->com.from_state != RES_SRQ_HW) {3722 err = -EBUSY;3723 goto out;3724 }3725 3726 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3727out:3728 put_res(dev, slave, srqn, RES_SRQ);3729 return err;3730}3731 3732int mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave,3733 struct mlx4_vhcr *vhcr,3734 struct mlx4_cmd_mailbox *inbox,3735 struct mlx4_cmd_mailbox *outbox,3736 struct mlx4_cmd_info *cmd)3737{3738 int err;3739 int qpn = vhcr->in_modifier & 0x7fffff;3740 struct res_qp *qp;3741 3742 err = get_res(dev, slave, qpn, RES_QP, &qp);3743 if (err)3744 return err;3745 if (qp->com.from_state != RES_QP_HW) {3746 err = -EBUSY;3747 goto out;3748 }3749 3750 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3751out:3752 put_res(dev, slave, qpn, RES_QP);3753 return err;3754}3755 3756int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,3757 struct mlx4_vhcr *vhcr,3758 struct mlx4_cmd_mailbox *inbox,3759 struct mlx4_cmd_mailbox *outbox,3760 struct mlx4_cmd_info *cmd)3761{3762 struct mlx4_qp_context *context = inbox->buf + 8;3763 adjust_proxy_tun_qkey(dev, vhcr, context);3764 update_pkey_index(dev, slave, inbox);3765 return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3766}3767 3768static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,3769 struct mlx4_qp_context *qpc,3770 struct mlx4_cmd_mailbox *inbox)3771{3772 enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf);3773 u8 pri_sched_queue;3774 int port = mlx4_slave_convert_port(3775 dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1;3776 3777 if (port < 0)3778 return -EINVAL;3779 3780 pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) |3781 ((port & 1) << 6);3782 3783 if (optpar & (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | MLX4_QP_OPTPAR_SCHED_QUEUE) ||3784 qpc->pri_path.sched_queue || mlx4_is_eth(dev, port + 1)) {3785 qpc->pri_path.sched_queue = pri_sched_queue;3786 }3787 3788 if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {3789 port = mlx4_slave_convert_port(3790 dev, slave, (qpc->alt_path.sched_queue >> 6 & 1)3791 + 1) - 1;3792 if (port < 0)3793 return -EINVAL;3794 qpc->alt_path.sched_queue =3795 (qpc->alt_path.sched_queue & ~(1 << 6)) |3796 (port & 1) << 6;3797 }3798 return 0;3799}3800 3801static int roce_verify_mac(struct mlx4_dev *dev, int slave,3802 struct mlx4_qp_context *qpc,3803 struct mlx4_cmd_mailbox *inbox)3804{3805 u64 mac;3806 int port;3807 u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;3808 u8 sched = *(u8 *)(inbox->buf + 64);3809 u8 smac_ix;3810 3811 port = (sched >> 6 & 1) + 1;3812 if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {3813 smac_ix = qpc->pri_path.grh_mylmc & 0x7f;3814 if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))3815 return -ENOENT;3816 }3817 return 0;3818}3819 3820int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,3821 struct mlx4_vhcr *vhcr,3822 struct mlx4_cmd_mailbox *inbox,3823 struct mlx4_cmd_mailbox *outbox,3824 struct mlx4_cmd_info *cmd)3825{3826 int err;3827 struct mlx4_qp_context *qpc = inbox->buf + 8;3828 int qpn = vhcr->in_modifier & 0x7fffff;3829 struct res_qp *qp;3830 u8 orig_sched_queue;3831 u8 orig_vlan_control = qpc->pri_path.vlan_control;3832 u8 orig_fvl_rx = qpc->pri_path.fvl_rx;3833 u8 orig_pri_path_fl = qpc->pri_path.fl;3834 u8 orig_vlan_index = qpc->pri_path.vlan_index;3835 u8 orig_feup = qpc->pri_path.feup;3836 3837 err = adjust_qp_sched_queue(dev, slave, qpc, inbox);3838 if (err)3839 return err;3840 err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave);3841 if (err)3842 return err;3843 3844 if (roce_verify_mac(dev, slave, qpc, inbox))3845 return -EINVAL;3846 3847 update_pkey_index(dev, slave, inbox);3848 update_gid(dev, inbox, (u8)slave);3849 adjust_proxy_tun_qkey(dev, vhcr, qpc);3850 orig_sched_queue = qpc->pri_path.sched_queue;3851 3852 err = get_res(dev, slave, qpn, RES_QP, &qp);3853 if (err)3854 return err;3855 if (qp->com.from_state != RES_QP_HW) {3856 err = -EBUSY;3857 goto out;3858 }3859 3860 err = update_vport_qp_param(dev, inbox, slave, qpn);3861 if (err)3862 goto out;3863 3864 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3865out:3866 /* if no error, save sched queue value passed in by VF. This is3867 * essentially the QOS value provided by the VF. This will be useful3868 * if we allow dynamic changes from VST back to VGT3869 */3870 if (!err) {3871 qp->sched_queue = orig_sched_queue;3872 qp->vlan_control = orig_vlan_control;3873 qp->fvl_rx = orig_fvl_rx;3874 qp->pri_path_fl = orig_pri_path_fl;3875 qp->vlan_index = orig_vlan_index;3876 qp->feup = orig_feup;3877 }3878 put_res(dev, slave, qpn, RES_QP);3879 return err;3880}3881 3882int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,3883 struct mlx4_vhcr *vhcr,3884 struct mlx4_cmd_mailbox *inbox,3885 struct mlx4_cmd_mailbox *outbox,3886 struct mlx4_cmd_info *cmd)3887{3888 int err;3889 struct mlx4_qp_context *context = inbox->buf + 8;3890 3891 err = adjust_qp_sched_queue(dev, slave, context, inbox);3892 if (err)3893 return err;3894 err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave);3895 if (err)3896 return err;3897 3898 update_pkey_index(dev, slave, inbox);3899 update_gid(dev, inbox, (u8)slave);3900 adjust_proxy_tun_qkey(dev, vhcr, context);3901 return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3902}3903 3904int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,3905 struct mlx4_vhcr *vhcr,3906 struct mlx4_cmd_mailbox *inbox,3907 struct mlx4_cmd_mailbox *outbox,3908 struct mlx4_cmd_info *cmd)3909{3910 int err;3911 struct mlx4_qp_context *context = inbox->buf + 8;3912 3913 err = adjust_qp_sched_queue(dev, slave, context, inbox);3914 if (err)3915 return err;3916 err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave);3917 if (err)3918 return err;3919 3920 update_pkey_index(dev, slave, inbox);3921 update_gid(dev, inbox, (u8)slave);3922 adjust_proxy_tun_qkey(dev, vhcr, context);3923 return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3924}3925 3926 3927int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,3928 struct mlx4_vhcr *vhcr,3929 struct mlx4_cmd_mailbox *inbox,3930 struct mlx4_cmd_mailbox *outbox,3931 struct mlx4_cmd_info *cmd)3932{3933 struct mlx4_qp_context *context = inbox->buf + 8;3934 int err = adjust_qp_sched_queue(dev, slave, context, inbox);3935 if (err)3936 return err;3937 adjust_proxy_tun_qkey(dev, vhcr, context);3938 return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3939}3940 3941int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,3942 struct mlx4_vhcr *vhcr,3943 struct mlx4_cmd_mailbox *inbox,3944 struct mlx4_cmd_mailbox *outbox,3945 struct mlx4_cmd_info *cmd)3946{3947 int err;3948 struct mlx4_qp_context *context = inbox->buf + 8;3949 3950 err = adjust_qp_sched_queue(dev, slave, context, inbox);3951 if (err)3952 return err;3953 err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave);3954 if (err)3955 return err;3956 3957 adjust_proxy_tun_qkey(dev, vhcr, context);3958 update_gid(dev, inbox, (u8)slave);3959 update_pkey_index(dev, slave, inbox);3960 return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3961}3962 3963int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,3964 struct mlx4_vhcr *vhcr,3965 struct mlx4_cmd_mailbox *inbox,3966 struct mlx4_cmd_mailbox *outbox,3967 struct mlx4_cmd_info *cmd)3968{3969 int err;3970 struct mlx4_qp_context *context = inbox->buf + 8;3971 3972 err = adjust_qp_sched_queue(dev, slave, context, inbox);3973 if (err)3974 return err;3975 err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave);3976 if (err)3977 return err;3978 3979 adjust_proxy_tun_qkey(dev, vhcr, context);3980 update_gid(dev, inbox, (u8)slave);3981 update_pkey_index(dev, slave, inbox);3982 return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3983}3984 3985int mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave,3986 struct mlx4_vhcr *vhcr,3987 struct mlx4_cmd_mailbox *inbox,3988 struct mlx4_cmd_mailbox *outbox,3989 struct mlx4_cmd_info *cmd)3990{3991 int err;3992 int qpn = vhcr->in_modifier & 0x7fffff;3993 struct res_qp *qp;3994 3995 err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0);3996 if (err)3997 return err;3998 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);3999 if (err)4000 goto ex_abort;4001 4002 atomic_dec(&qp->mtt->ref_count);4003 atomic_dec(&qp->rcq->ref_count);4004 atomic_dec(&qp->scq->ref_count);4005 if (qp->srq)4006 atomic_dec(&qp->srq->ref_count);4007 res_end_move(dev, slave, RES_QP, qpn);4008 return 0;4009 4010ex_abort:4011 res_abort_move(dev, slave, RES_QP, qpn);4012 4013 return err;4014}4015 4016static struct res_gid *find_gid(struct mlx4_dev *dev, int slave,4017 struct res_qp *rqp, u8 *gid)4018{4019 struct res_gid *res;4020 4021 list_for_each_entry(res, &rqp->mcg_list, list) {4022 if (!memcmp(res->gid, gid, 16))4023 return res;4024 }4025 return NULL;4026}4027 4028static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,4029 u8 *gid, enum mlx4_protocol prot,4030 enum mlx4_steer_type steer, u64 reg_id)4031{4032 struct res_gid *res;4033 int err;4034 4035 res = kzalloc(sizeof(*res), GFP_KERNEL);4036 if (!res)4037 return -ENOMEM;4038 4039 spin_lock_irq(&rqp->mcg_spl);4040 if (find_gid(dev, slave, rqp, gid)) {4041 kfree(res);4042 err = -EEXIST;4043 } else {4044 memcpy(res->gid, gid, 16);4045 res->prot = prot;4046 res->steer = steer;4047 res->reg_id = reg_id;4048 list_add_tail(&res->list, &rqp->mcg_list);4049 err = 0;4050 }4051 spin_unlock_irq(&rqp->mcg_spl);4052 4053 return err;4054}4055 4056static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,4057 u8 *gid, enum mlx4_protocol prot,4058 enum mlx4_steer_type steer, u64 *reg_id)4059{4060 struct res_gid *res;4061 int err;4062 4063 spin_lock_irq(&rqp->mcg_spl);4064 res = find_gid(dev, slave, rqp, gid);4065 if (!res || res->prot != prot || res->steer != steer)4066 err = -EINVAL;4067 else {4068 *reg_id = res->reg_id;4069 list_del(&res->list);4070 kfree(res);4071 err = 0;4072 }4073 spin_unlock_irq(&rqp->mcg_spl);4074 4075 return err;4076}4077 4078static int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp,4079 u8 gid[16], int block_loopback, enum mlx4_protocol prot,4080 enum mlx4_steer_type type, u64 *reg_id)4081{4082 switch (dev->caps.steering_mode) {4083 case MLX4_STEERING_MODE_DEVICE_MANAGED: {4084 int port = mlx4_slave_convert_port(dev, slave, gid[5]);4085 if (port < 0)4086 return port;4087 return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,4088 block_loopback, prot,4089 reg_id);4090 }4091 case MLX4_STEERING_MODE_B0:4092 if (prot == MLX4_PROT_ETH) {4093 int port = mlx4_slave_convert_port(dev, slave, gid[5]);4094 if (port < 0)4095 return port;4096 gid[5] = port;4097 }4098 return mlx4_qp_attach_common(dev, qp, gid,4099 block_loopback, prot, type);4100 default:4101 return -EINVAL;4102 }4103}4104 4105static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,4106 u8 gid[16], enum mlx4_protocol prot,4107 enum mlx4_steer_type type, u64 reg_id)4108{4109 switch (dev->caps.steering_mode) {4110 case MLX4_STEERING_MODE_DEVICE_MANAGED:4111 return mlx4_flow_detach(dev, reg_id);4112 case MLX4_STEERING_MODE_B0:4113 return mlx4_qp_detach_common(dev, qp, gid, prot, type);4114 default:4115 return -EINVAL;4116 }4117}4118 4119static int mlx4_adjust_port(struct mlx4_dev *dev, int slave,4120 u8 *gid, enum mlx4_protocol prot)4121{4122 int real_port;4123 4124 if (prot != MLX4_PROT_ETH)4125 return 0;4126 4127 if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 ||4128 dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {4129 real_port = mlx4_slave_convert_port(dev, slave, gid[5]);4130 if (real_port < 0)4131 return -EINVAL;4132 gid[5] = real_port;4133 }4134 4135 return 0;4136}4137 4138int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,4139 struct mlx4_vhcr *vhcr,4140 struct mlx4_cmd_mailbox *inbox,4141 struct mlx4_cmd_mailbox *outbox,4142 struct mlx4_cmd_info *cmd)4143{4144 struct mlx4_qp qp; /* dummy for calling attach/detach */4145 u8 *gid = inbox->buf;4146 enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7;4147 int err;4148 int qpn;4149 struct res_qp *rqp;4150 u64 reg_id = 0;4151 int attach = vhcr->op_modifier;4152 int block_loopback = vhcr->in_modifier >> 31;4153 u8 steer_type_mask = 2;4154 enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1;4155 4156 qpn = vhcr->in_modifier & 0xffffff;4157 err = get_res(dev, slave, qpn, RES_QP, &rqp);4158 if (err)4159 return err;4160 4161 qp.qpn = qpn;4162 if (attach) {4163 err = qp_attach(dev, slave, &qp, gid, block_loopback, prot,4164 type, ®_id);4165 if (err) {4166 pr_err("Fail to attach rule to qp 0x%x\n", qpn);4167 goto ex_put;4168 }4169 err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id);4170 if (err)4171 goto ex_detach;4172 } else {4173 err = mlx4_adjust_port(dev, slave, gid, prot);4174 if (err)4175 goto ex_put;4176 4177 err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id);4178 if (err)4179 goto ex_put;4180 4181 err = qp_detach(dev, &qp, gid, prot, type, reg_id);4182 if (err)4183 pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n",4184 qpn, reg_id);4185 }4186 put_res(dev, slave, qpn, RES_QP);4187 return err;4188 4189ex_detach:4190 qp_detach(dev, &qp, gid, prot, type, reg_id);4191ex_put:4192 put_res(dev, slave, qpn, RES_QP);4193 return err;4194}4195 4196/*4197 * MAC validation for Flow Steering rules.4198 * VF can attach rules only with a mac address which is assigned to it.4199 */4200static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header,4201 struct list_head *rlist)4202{4203 struct mac_res *res, *tmp;4204 __be64 be_mac;4205 4206 /* make sure it isn't multicast or broadcast mac*/4207 if (!is_multicast_ether_addr(eth_header->eth.dst_mac) &&4208 !is_broadcast_ether_addr(eth_header->eth.dst_mac)) {4209 list_for_each_entry_safe(res, tmp, rlist, list) {4210 be_mac = cpu_to_be64(res->mac << 16);4211 if (ether_addr_equal((u8 *)&be_mac, eth_header->eth.dst_mac))4212 return 0;4213 }4214 pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n",4215 eth_header->eth.dst_mac, slave);4216 return -EINVAL;4217 }4218 return 0;4219}4220 4221/*4222 * In case of missing eth header, append eth header with a MAC address4223 * assigned to the VF.4224 */4225static int add_eth_header(struct mlx4_dev *dev, int slave,4226 struct mlx4_cmd_mailbox *inbox,4227 struct list_head *rlist, int header_id)4228{4229 struct mac_res *res, *tmp;4230 u8 port;4231 struct mlx4_net_trans_rule_hw_ctrl *ctrl;4232 struct mlx4_net_trans_rule_hw_eth *eth_header;4233 struct mlx4_net_trans_rule_hw_ipv4 *ip_header;4234 struct mlx4_net_trans_rule_hw_tcp_udp *l4_header;4235 __be64 be_mac = 0;4236 __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);4237 4238 ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;4239 port = ctrl->port;4240 eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1);4241 4242 /* Clear a space in the inbox for eth header */4243 switch (header_id) {4244 case MLX4_NET_TRANS_RULE_ID_IPV4:4245 ip_header =4246 (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1);4247 memmove(ip_header, eth_header,4248 sizeof(*ip_header) + sizeof(*l4_header));4249 break;4250 case MLX4_NET_TRANS_RULE_ID_TCP:4251 case MLX4_NET_TRANS_RULE_ID_UDP:4252 l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *)4253 (eth_header + 1);4254 memmove(l4_header, eth_header, sizeof(*l4_header));4255 break;4256 default:4257 return -EINVAL;4258 }4259 list_for_each_entry_safe(res, tmp, rlist, list) {4260 if (port == res->port) {4261 be_mac = cpu_to_be64(res->mac << 16);4262 break;4263 }4264 }4265 if (!be_mac) {4266 pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d\n",4267 port);4268 return -EINVAL;4269 }4270 4271 memset(eth_header, 0, sizeof(*eth_header));4272 eth_header->size = sizeof(*eth_header) >> 2;4273 eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]);4274 memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN);4275 memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN);4276 4277 return 0;4278 4279}4280 4281#define MLX4_UPD_QP_PATH_MASK_SUPPORTED ( \4282 1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX |\4283 1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)4284int mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,4285 struct mlx4_vhcr *vhcr,4286 struct mlx4_cmd_mailbox *inbox,4287 struct mlx4_cmd_mailbox *outbox,4288 struct mlx4_cmd_info *cmd_info)4289{4290 int err;4291 u32 qpn = vhcr->in_modifier & 0xffffff;4292 struct res_qp *rqp;4293 u64 mac;4294 unsigned port;4295 u64 pri_addr_path_mask;4296 struct mlx4_update_qp_context *cmd;4297 int smac_index;4298 4299 cmd = (struct mlx4_update_qp_context *)inbox->buf;4300 4301 pri_addr_path_mask = be64_to_cpu(cmd->primary_addr_path_mask);4302 if (cmd->qp_mask || cmd->secondary_addr_path_mask ||4303 (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED))4304 return -EPERM;4305 4306 if ((pri_addr_path_mask &4307 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) &&4308 !(dev->caps.flags2 &4309 MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {4310 mlx4_warn(dev, "Src check LB for slave %d isn't supported\n",4311 slave);4312 return -EOPNOTSUPP;4313 }4314 4315 /* Just change the smac for the QP */4316 err = get_res(dev, slave, qpn, RES_QP, &rqp);4317 if (err) {4318 mlx4_err(dev, "Updating qpn 0x%x for slave %d rejected\n", qpn, slave);4319 return err;4320 }4321 4322 port = (rqp->sched_queue >> 6 & 1) + 1;4323 4324 if (pri_addr_path_mask & (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)) {4325 smac_index = cmd->qp_context.pri_path.grh_mylmc;4326 err = mac_find_smac_ix_in_slave(dev, slave, port,4327 smac_index, &mac);4328 4329 if (err) {4330 mlx4_err(dev, "Failed to update qpn 0x%x, MAC is invalid. smac_ix: %d\n",4331 qpn, smac_index);4332 goto err_mac;4333 }4334 }4335 4336 err = mlx4_cmd(dev, inbox->dma,4337 vhcr->in_modifier, 0,4338 MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A,4339 MLX4_CMD_NATIVE);4340 if (err) {4341 mlx4_err(dev, "Failed to update qpn on qpn 0x%x, command failed\n", qpn);4342 goto err_mac;4343 }4344 4345err_mac:4346 put_res(dev, slave, qpn, RES_QP);4347 return err;4348}4349 4350static u32 qp_attach_mbox_size(void *mbox)4351{4352 u32 size = sizeof(struct mlx4_net_trans_rule_hw_ctrl);4353 struct _rule_hw *rule_header;4354 4355 rule_header = (struct _rule_hw *)(mbox + size);4356 4357 while (rule_header->size) {4358 size += rule_header->size * sizeof(u32);4359 rule_header += 1;4360 }4361 return size;4362}4363 4364static int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule);4365 4366int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,4367 struct mlx4_vhcr *vhcr,4368 struct mlx4_cmd_mailbox *inbox,4369 struct mlx4_cmd_mailbox *outbox,4370 struct mlx4_cmd_info *cmd)4371{4372 4373 struct mlx4_priv *priv = mlx4_priv(dev);4374 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;4375 struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];4376 int err;4377 int qpn;4378 struct res_qp *rqp;4379 struct mlx4_net_trans_rule_hw_ctrl *ctrl;4380 struct _rule_hw *rule_header;4381 int header_id;4382 struct res_fs_rule *rrule;4383 u32 mbox_size;4384 4385 if (dev->caps.steering_mode !=4386 MLX4_STEERING_MODE_DEVICE_MANAGED)4387 return -EOPNOTSUPP;4388 4389 ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;4390 err = mlx4_slave_convert_port(dev, slave, ctrl->port);4391 if (err <= 0)4392 return -EINVAL;4393 ctrl->port = err;4394 qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;4395 err = get_res(dev, slave, qpn, RES_QP, &rqp);4396 if (err) {4397 pr_err("Steering rule with qpn 0x%x rejected\n", qpn);4398 return err;4399 }4400 rule_header = (struct _rule_hw *)(ctrl + 1);4401 header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));4402 4403 if (header_id == MLX4_NET_TRANS_RULE_ID_ETH)4404 mlx4_handle_eth_header_mcast_prio(ctrl, rule_header);4405 4406 switch (header_id) {4407 case MLX4_NET_TRANS_RULE_ID_ETH:4408 if (validate_eth_header_mac(slave, rule_header, rlist)) {4409 err = -EINVAL;4410 goto err_put_qp;4411 }4412 break;4413 case MLX4_NET_TRANS_RULE_ID_IB:4414 break;4415 case MLX4_NET_TRANS_RULE_ID_IPV4:4416 case MLX4_NET_TRANS_RULE_ID_TCP:4417 case MLX4_NET_TRANS_RULE_ID_UDP:4418 pr_warn("Can't attach FS rule without L2 headers, adding L2 header\n");4419 if (add_eth_header(dev, slave, inbox, rlist, header_id)) {4420 err = -EINVAL;4421 goto err_put_qp;4422 }4423 vhcr->in_modifier +=4424 sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2;4425 break;4426 default:4427 pr_err("Corrupted mailbox\n");4428 err = -EINVAL;4429 goto err_put_qp;4430 }4431 4432 err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,4433 vhcr->in_modifier, 0,4434 MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,4435 MLX4_CMD_NATIVE);4436 if (err)4437 goto err_put_qp;4438 4439 4440 err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);4441 if (err) {4442 mlx4_err(dev, "Fail to add flow steering resources\n");4443 goto err_detach;4444 }4445 4446 err = get_res(dev, slave, vhcr->out_param, RES_FS_RULE, &rrule);4447 if (err)4448 goto err_detach;4449 4450 mbox_size = qp_attach_mbox_size(inbox->buf);4451 rrule->mirr_mbox = kmalloc(mbox_size, GFP_KERNEL);4452 if (!rrule->mirr_mbox) {4453 err = -ENOMEM;4454 goto err_put_rule;4455 }4456 rrule->mirr_mbox_size = mbox_size;4457 rrule->mirr_rule_id = 0;4458 memcpy(rrule->mirr_mbox, inbox->buf, mbox_size);4459 4460 /* set different port */4461 ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)rrule->mirr_mbox;4462 if (ctrl->port == 1)4463 ctrl->port = 2;4464 else4465 ctrl->port = 1;4466 4467 if (mlx4_is_bonded(dev))4468 mlx4_do_mirror_rule(dev, rrule);4469 4470 atomic_inc(&rqp->ref_count);4471 4472err_put_rule:4473 put_res(dev, slave, vhcr->out_param, RES_FS_RULE);4474err_detach:4475 /* detach rule on error */4476 if (err)4477 mlx4_cmd(dev, vhcr->out_param, 0, 0,4478 MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,4479 MLX4_CMD_NATIVE);4480err_put_qp:4481 put_res(dev, slave, qpn, RES_QP);4482 return err;4483}4484 4485static int mlx4_undo_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)4486{4487 int err;4488 4489 err = rem_res_range(dev, fs_rule->com.owner, fs_rule->com.res_id, 1, RES_FS_RULE, 0);4490 if (err) {4491 mlx4_err(dev, "Fail to remove flow steering resources\n");4492 return err;4493 }4494 4495 mlx4_cmd(dev, fs_rule->com.res_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,4496 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);4497 return 0;4498}4499 4500int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,4501 struct mlx4_vhcr *vhcr,4502 struct mlx4_cmd_mailbox *inbox,4503 struct mlx4_cmd_mailbox *outbox,4504 struct mlx4_cmd_info *cmd)4505{4506 int err;4507 struct res_qp *rqp;4508 struct res_fs_rule *rrule;4509 u64 mirr_reg_id;4510 int qpn;4511 4512 if (dev->caps.steering_mode !=4513 MLX4_STEERING_MODE_DEVICE_MANAGED)4514 return -EOPNOTSUPP;4515 4516 err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule);4517 if (err)4518 return err;4519 4520 if (!rrule->mirr_mbox) {4521 mlx4_err(dev, "Mirror rules cannot be removed explicitly\n");4522 put_res(dev, slave, vhcr->in_param, RES_FS_RULE);4523 return -EINVAL;4524 }4525 mirr_reg_id = rrule->mirr_rule_id;4526 kfree(rrule->mirr_mbox);4527 qpn = rrule->qpn;4528 4529 /* Release the rule form busy state before removal */4530 put_res(dev, slave, vhcr->in_param, RES_FS_RULE);4531 err = get_res(dev, slave, qpn, RES_QP, &rqp);4532 if (err)4533 return err;4534 4535 if (mirr_reg_id && mlx4_is_bonded(dev)) {4536 err = get_res(dev, slave, mirr_reg_id, RES_FS_RULE, &rrule);4537 if (err) {4538 mlx4_err(dev, "Fail to get resource of mirror rule\n");4539 } else {4540 put_res(dev, slave, mirr_reg_id, RES_FS_RULE);4541 mlx4_undo_mirror_rule(dev, rrule);4542 }4543 }4544 err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);4545 if (err) {4546 mlx4_err(dev, "Fail to remove flow steering resources\n");4547 goto out;4548 }4549 4550 err = mlx4_cmd(dev, vhcr->in_param, 0, 0,4551 MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,4552 MLX4_CMD_NATIVE);4553 if (!err)4554 atomic_dec(&rqp->ref_count);4555out:4556 put_res(dev, slave, qpn, RES_QP);4557 return err;4558}4559 4560enum {4561 BUSY_MAX_RETRIES = 104562};4563 4564int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave,4565 struct mlx4_vhcr *vhcr,4566 struct mlx4_cmd_mailbox *inbox,4567 struct mlx4_cmd_mailbox *outbox,4568 struct mlx4_cmd_info *cmd)4569{4570 int err;4571 int index = vhcr->in_modifier & 0xffff;4572 4573 err = get_res(dev, slave, index, RES_COUNTER, NULL);4574 if (err)4575 return err;4576 4577 err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);4578 put_res(dev, slave, index, RES_COUNTER);4579 return err;4580}4581 4582static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)4583{4584 struct res_gid *rgid;4585 struct res_gid *tmp;4586 struct mlx4_qp qp; /* dummy for calling attach/detach */4587 4588 list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) {4589 switch (dev->caps.steering_mode) {4590 case MLX4_STEERING_MODE_DEVICE_MANAGED:4591 mlx4_flow_detach(dev, rgid->reg_id);4592 break;4593 case MLX4_STEERING_MODE_B0:4594 qp.qpn = rqp->local_qpn;4595 (void) mlx4_qp_detach_common(dev, &qp, rgid->gid,4596 rgid->prot, rgid->steer);4597 break;4598 }4599 list_del(&rgid->list);4600 kfree(rgid);4601 }4602}4603 4604static int _move_all_busy(struct mlx4_dev *dev, int slave,4605 enum mlx4_resource type, int print)4606{4607 struct mlx4_priv *priv = mlx4_priv(dev);4608 struct mlx4_resource_tracker *tracker =4609 &priv->mfunc.master.res_tracker;4610 struct list_head *rlist = &tracker->slave_list[slave].res_list[type];4611 struct res_common *r;4612 struct res_common *tmp;4613 int busy;4614 4615 busy = 0;4616 spin_lock_irq(mlx4_tlock(dev));4617 list_for_each_entry_safe(r, tmp, rlist, list) {4618 if (r->owner == slave) {4619 if (!r->removing) {4620 if (r->state == RES_ANY_BUSY) {4621 if (print)4622 mlx4_dbg(dev,4623 "%s id 0x%llx is busy\n",4624 resource_str(type),4625 r->res_id);4626 ++busy;4627 } else {4628 r->from_state = r->state;4629 r->state = RES_ANY_BUSY;4630 r->removing = 1;4631 }4632 }4633 }4634 }4635 spin_unlock_irq(mlx4_tlock(dev));4636 4637 return busy;4638}4639 4640static int move_all_busy(struct mlx4_dev *dev, int slave,4641 enum mlx4_resource type)4642{4643 unsigned long begin;4644 int busy;4645 4646 begin = jiffies;4647 do {4648 busy = _move_all_busy(dev, slave, type, 0);4649 if (time_after(jiffies, begin + 5 * HZ))4650 break;4651 if (busy)4652 cond_resched();4653 } while (busy);4654 4655 if (busy)4656 busy = _move_all_busy(dev, slave, type, 1);4657 4658 return busy;4659}4660static void rem_slave_qps(struct mlx4_dev *dev, int slave)4661{4662 struct mlx4_priv *priv = mlx4_priv(dev);4663 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;4664 struct list_head *qp_list =4665 &tracker->slave_list[slave].res_list[RES_QP];4666 struct res_qp *qp;4667 struct res_qp *tmp;4668 int state;4669 u64 in_param;4670 int qpn;4671 int err;4672 4673 err = move_all_busy(dev, slave, RES_QP);4674 if (err)4675 mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy for slave %d\n",4676 slave);4677 4678 spin_lock_irq(mlx4_tlock(dev));4679 list_for_each_entry_safe(qp, tmp, qp_list, com.list) {4680 spin_unlock_irq(mlx4_tlock(dev));4681 if (qp->com.owner == slave) {4682 qpn = qp->com.res_id;4683 detach_qp(dev, slave, qp);4684 state = qp->com.from_state;4685 while (state != 0) {4686 switch (state) {4687 case RES_QP_RESERVED:4688 spin_lock_irq(mlx4_tlock(dev));4689 rb_erase(&qp->com.node,4690 &tracker->res_tree[RES_QP]);4691 list_del(&qp->com.list);4692 spin_unlock_irq(mlx4_tlock(dev));4693 if (!valid_reserved(dev, slave, qpn)) {4694 __mlx4_qp_release_range(dev, qpn, 1);4695 mlx4_release_resource(dev, slave,4696 RES_QP, 1, 0);4697 }4698 kfree(qp);4699 state = 0;4700 break;4701 case RES_QP_MAPPED:4702 if (!valid_reserved(dev, slave, qpn))4703 __mlx4_qp_free_icm(dev, qpn);4704 state = RES_QP_RESERVED;4705 break;4706 case RES_QP_HW:4707 in_param = slave;4708 err = mlx4_cmd(dev, in_param,4709 qp->local_qpn, 2,4710 MLX4_CMD_2RST_QP,4711 MLX4_CMD_TIME_CLASS_A,4712 MLX4_CMD_NATIVE);4713 if (err)4714 mlx4_dbg(dev, "rem_slave_qps: failed to move slave %d qpn %d to reset\n",4715 slave, qp->local_qpn);4716 atomic_dec(&qp->rcq->ref_count);4717 atomic_dec(&qp->scq->ref_count);4718 atomic_dec(&qp->mtt->ref_count);4719 if (qp->srq)4720 atomic_dec(&qp->srq->ref_count);4721 state = RES_QP_MAPPED;4722 break;4723 default:4724 state = 0;4725 }4726 }4727 }4728 spin_lock_irq(mlx4_tlock(dev));4729 }4730 spin_unlock_irq(mlx4_tlock(dev));4731}4732 4733static void rem_slave_srqs(struct mlx4_dev *dev, int slave)4734{4735 struct mlx4_priv *priv = mlx4_priv(dev);4736 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;4737 struct list_head *srq_list =4738 &tracker->slave_list[slave].res_list[RES_SRQ];4739 struct res_srq *srq;4740 struct res_srq *tmp;4741 int state;4742 u64 in_param;4743 int srqn;4744 int err;4745 4746 err = move_all_busy(dev, slave, RES_SRQ);4747 if (err)4748 mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs - too busy for slave %d\n",4749 slave);4750 4751 spin_lock_irq(mlx4_tlock(dev));4752 list_for_each_entry_safe(srq, tmp, srq_list, com.list) {4753 spin_unlock_irq(mlx4_tlock(dev));4754 if (srq->com.owner == slave) {4755 srqn = srq->com.res_id;4756 state = srq->com.from_state;4757 while (state != 0) {4758 switch (state) {4759 case RES_SRQ_ALLOCATED:4760 __mlx4_srq_free_icm(dev, srqn);4761 spin_lock_irq(mlx4_tlock(dev));4762 rb_erase(&srq->com.node,4763 &tracker->res_tree[RES_SRQ]);4764 list_del(&srq->com.list);4765 spin_unlock_irq(mlx4_tlock(dev));4766 mlx4_release_resource(dev, slave,4767 RES_SRQ, 1, 0);4768 kfree(srq);4769 state = 0;4770 break;4771 4772 case RES_SRQ_HW:4773 in_param = slave;4774 err = mlx4_cmd(dev, in_param, srqn, 1,4775 MLX4_CMD_HW2SW_SRQ,4776 MLX4_CMD_TIME_CLASS_A,4777 MLX4_CMD_NATIVE);4778 if (err)4779 mlx4_dbg(dev, "rem_slave_srqs: failed to move slave %d srq %d to SW ownership\n",4780 slave, srqn);4781 4782 atomic_dec(&srq->mtt->ref_count);4783 if (srq->cq)4784 atomic_dec(&srq->cq->ref_count);4785 state = RES_SRQ_ALLOCATED;4786 break;4787 4788 default:4789 state = 0;4790 }4791 }4792 }4793 spin_lock_irq(mlx4_tlock(dev));4794 }4795 spin_unlock_irq(mlx4_tlock(dev));4796}4797 4798static void rem_slave_cqs(struct mlx4_dev *dev, int slave)4799{4800 struct mlx4_priv *priv = mlx4_priv(dev);4801 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;4802 struct list_head *cq_list =4803 &tracker->slave_list[slave].res_list[RES_CQ];4804 struct res_cq *cq;4805 struct res_cq *tmp;4806 int state;4807 u64 in_param;4808 int cqn;4809 int err;4810 4811 err = move_all_busy(dev, slave, RES_CQ);4812 if (err)4813 mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs - too busy for slave %d\n",4814 slave);4815 4816 spin_lock_irq(mlx4_tlock(dev));4817 list_for_each_entry_safe(cq, tmp, cq_list, com.list) {4818 spin_unlock_irq(mlx4_tlock(dev));4819 if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) {4820 cqn = cq->com.res_id;4821 state = cq->com.from_state;4822 while (state != 0) {4823 switch (state) {4824 case RES_CQ_ALLOCATED:4825 __mlx4_cq_free_icm(dev, cqn);4826 spin_lock_irq(mlx4_tlock(dev));4827 rb_erase(&cq->com.node,4828 &tracker->res_tree[RES_CQ]);4829 list_del(&cq->com.list);4830 spin_unlock_irq(mlx4_tlock(dev));4831 mlx4_release_resource(dev, slave,4832 RES_CQ, 1, 0);4833 kfree(cq);4834 state = 0;4835 break;4836 4837 case RES_CQ_HW:4838 in_param = slave;4839 err = mlx4_cmd(dev, in_param, cqn, 1,4840 MLX4_CMD_HW2SW_CQ,4841 MLX4_CMD_TIME_CLASS_A,4842 MLX4_CMD_NATIVE);4843 if (err)4844 mlx4_dbg(dev, "rem_slave_cqs: failed to move slave %d cq %d to SW ownership\n",4845 slave, cqn);4846 atomic_dec(&cq->mtt->ref_count);4847 state = RES_CQ_ALLOCATED;4848 break;4849 4850 default:4851 state = 0;4852 }4853 }4854 }4855 spin_lock_irq(mlx4_tlock(dev));4856 }4857 spin_unlock_irq(mlx4_tlock(dev));4858}4859 4860static void rem_slave_mrs(struct mlx4_dev *dev, int slave)4861{4862 struct mlx4_priv *priv = mlx4_priv(dev);4863 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;4864 struct list_head *mpt_list =4865 &tracker->slave_list[slave].res_list[RES_MPT];4866 struct res_mpt *mpt;4867 struct res_mpt *tmp;4868 int state;4869 u64 in_param;4870 int mptn;4871 int err;4872 4873 err = move_all_busy(dev, slave, RES_MPT);4874 if (err)4875 mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts - too busy for slave %d\n",4876 slave);4877 4878 spin_lock_irq(mlx4_tlock(dev));4879 list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) {4880 spin_unlock_irq(mlx4_tlock(dev));4881 if (mpt->com.owner == slave) {4882 mptn = mpt->com.res_id;4883 state = mpt->com.from_state;4884 while (state != 0) {4885 switch (state) {4886 case RES_MPT_RESERVED:4887 __mlx4_mpt_release(dev, mpt->key);4888 spin_lock_irq(mlx4_tlock(dev));4889 rb_erase(&mpt->com.node,4890 &tracker->res_tree[RES_MPT]);4891 list_del(&mpt->com.list);4892 spin_unlock_irq(mlx4_tlock(dev));4893 mlx4_release_resource(dev, slave,4894 RES_MPT, 1, 0);4895 kfree(mpt);4896 state = 0;4897 break;4898 4899 case RES_MPT_MAPPED:4900 __mlx4_mpt_free_icm(dev, mpt->key);4901 state = RES_MPT_RESERVED;4902 break;4903 4904 case RES_MPT_HW:4905 in_param = slave;4906 err = mlx4_cmd(dev, in_param, mptn, 0,4907 MLX4_CMD_HW2SW_MPT,4908 MLX4_CMD_TIME_CLASS_A,4909 MLX4_CMD_NATIVE);4910 if (err)4911 mlx4_dbg(dev, "rem_slave_mrs: failed to move slave %d mpt %d to SW ownership\n",4912 slave, mptn);4913 if (mpt->mtt)4914 atomic_dec(&mpt->mtt->ref_count);4915 state = RES_MPT_MAPPED;4916 break;4917 default:4918 state = 0;4919 }4920 }4921 }4922 spin_lock_irq(mlx4_tlock(dev));4923 }4924 spin_unlock_irq(mlx4_tlock(dev));4925}4926 4927static void rem_slave_mtts(struct mlx4_dev *dev, int slave)4928{4929 struct mlx4_priv *priv = mlx4_priv(dev);4930 struct mlx4_resource_tracker *tracker =4931 &priv->mfunc.master.res_tracker;4932 struct list_head *mtt_list =4933 &tracker->slave_list[slave].res_list[RES_MTT];4934 struct res_mtt *mtt;4935 struct res_mtt *tmp;4936 int state;4937 int base;4938 int err;4939 4940 err = move_all_busy(dev, slave, RES_MTT);4941 if (err)4942 mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts - too busy for slave %d\n",4943 slave);4944 4945 spin_lock_irq(mlx4_tlock(dev));4946 list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) {4947 spin_unlock_irq(mlx4_tlock(dev));4948 if (mtt->com.owner == slave) {4949 base = mtt->com.res_id;4950 state = mtt->com.from_state;4951 while (state != 0) {4952 switch (state) {4953 case RES_MTT_ALLOCATED:4954 __mlx4_free_mtt_range(dev, base,4955 mtt->order);4956 spin_lock_irq(mlx4_tlock(dev));4957 rb_erase(&mtt->com.node,4958 &tracker->res_tree[RES_MTT]);4959 list_del(&mtt->com.list);4960 spin_unlock_irq(mlx4_tlock(dev));4961 mlx4_release_resource(dev, slave, RES_MTT,4962 1 << mtt->order, 0);4963 kfree(mtt);4964 state = 0;4965 break;4966 4967 default:4968 state = 0;4969 }4970 }4971 }4972 spin_lock_irq(mlx4_tlock(dev));4973 }4974 spin_unlock_irq(mlx4_tlock(dev));4975}4976 4977static int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)4978{4979 struct mlx4_cmd_mailbox *mailbox;4980 int err;4981 struct res_fs_rule *mirr_rule;4982 u64 reg_id;4983 4984 mailbox = mlx4_alloc_cmd_mailbox(dev);4985 if (IS_ERR(mailbox))4986 return PTR_ERR(mailbox);4987 4988 if (!fs_rule->mirr_mbox) {4989 mlx4_err(dev, "rule mirroring mailbox is null\n");4990 mlx4_free_cmd_mailbox(dev, mailbox);4991 return -EINVAL;4992 }4993 memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size);4994 err = mlx4_cmd_imm(dev, mailbox->dma, ®_id, fs_rule->mirr_mbox_size >> 2, 0,4995 MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,4996 MLX4_CMD_NATIVE);4997 mlx4_free_cmd_mailbox(dev, mailbox);4998 4999 if (err)5000 goto err;5001 5002 err = add_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, fs_rule->qpn);5003 if (err)5004 goto err_detach;5005 5006 err = get_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE, &mirr_rule);5007 if (err)5008 goto err_rem;5009 5010 fs_rule->mirr_rule_id = reg_id;5011 mirr_rule->mirr_rule_id = 0;5012 mirr_rule->mirr_mbox_size = 0;5013 mirr_rule->mirr_mbox = NULL;5014 put_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE);5015 5016 return 0;5017err_rem:5018 rem_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, 0);5019err_detach:5020 mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,5021 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);5022err:5023 return err;5024}5025 5026static int mlx4_mirror_fs_rules(struct mlx4_dev *dev, bool bond)5027{5028 struct mlx4_priv *priv = mlx4_priv(dev);5029 struct mlx4_resource_tracker *tracker =5030 &priv->mfunc.master.res_tracker;5031 struct rb_root *root = &tracker->res_tree[RES_FS_RULE];5032 struct rb_node *p;5033 struct res_fs_rule *fs_rule;5034 int err = 0;5035 LIST_HEAD(mirr_list);5036 5037 for (p = rb_first(root); p; p = rb_next(p)) {5038 fs_rule = rb_entry(p, struct res_fs_rule, com.node);5039 if ((bond && fs_rule->mirr_mbox_size) ||5040 (!bond && !fs_rule->mirr_mbox_size))5041 list_add_tail(&fs_rule->mirr_list, &mirr_list);5042 }5043 5044 list_for_each_entry(fs_rule, &mirr_list, mirr_list) {5045 if (bond)5046 err += mlx4_do_mirror_rule(dev, fs_rule);5047 else5048 err += mlx4_undo_mirror_rule(dev, fs_rule);5049 }5050 return err;5051}5052 5053int mlx4_bond_fs_rules(struct mlx4_dev *dev)5054{5055 return mlx4_mirror_fs_rules(dev, true);5056}5057 5058int mlx4_unbond_fs_rules(struct mlx4_dev *dev)5059{5060 return mlx4_mirror_fs_rules(dev, false);5061}5062 5063static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave)5064{5065 struct mlx4_priv *priv = mlx4_priv(dev);5066 struct mlx4_resource_tracker *tracker =5067 &priv->mfunc.master.res_tracker;5068 struct list_head *fs_rule_list =5069 &tracker->slave_list[slave].res_list[RES_FS_RULE];5070 struct res_fs_rule *fs_rule;5071 struct res_fs_rule *tmp;5072 int state;5073 u64 base;5074 int err;5075 5076 err = move_all_busy(dev, slave, RES_FS_RULE);5077 if (err)5078 mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n",5079 slave);5080 5081 spin_lock_irq(mlx4_tlock(dev));5082 list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) {5083 spin_unlock_irq(mlx4_tlock(dev));5084 if (fs_rule->com.owner == slave) {5085 base = fs_rule->com.res_id;5086 state = fs_rule->com.from_state;5087 while (state != 0) {5088 switch (state) {5089 case RES_FS_RULE_ALLOCATED:5090 /* detach rule */5091 err = mlx4_cmd(dev, base, 0, 0,5092 MLX4_QP_FLOW_STEERING_DETACH,5093 MLX4_CMD_TIME_CLASS_A,5094 MLX4_CMD_NATIVE);5095 5096 spin_lock_irq(mlx4_tlock(dev));5097 rb_erase(&fs_rule->com.node,5098 &tracker->res_tree[RES_FS_RULE]);5099 list_del(&fs_rule->com.list);5100 spin_unlock_irq(mlx4_tlock(dev));5101 kfree(fs_rule->mirr_mbox);5102 kfree(fs_rule);5103 state = 0;5104 break;5105 5106 default:5107 state = 0;5108 }5109 }5110 }5111 spin_lock_irq(mlx4_tlock(dev));5112 }5113 spin_unlock_irq(mlx4_tlock(dev));5114}5115 5116static void rem_slave_eqs(struct mlx4_dev *dev, int slave)5117{5118 struct mlx4_priv *priv = mlx4_priv(dev);5119 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;5120 struct list_head *eq_list =5121 &tracker->slave_list[slave].res_list[RES_EQ];5122 struct res_eq *eq;5123 struct res_eq *tmp;5124 int err;5125 int state;5126 int eqn;5127 5128 err = move_all_busy(dev, slave, RES_EQ);5129 if (err)5130 mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs - too busy for slave %d\n",5131 slave);5132 5133 spin_lock_irq(mlx4_tlock(dev));5134 list_for_each_entry_safe(eq, tmp, eq_list, com.list) {5135 spin_unlock_irq(mlx4_tlock(dev));5136 if (eq->com.owner == slave) {5137 eqn = eq->com.res_id;5138 state = eq->com.from_state;5139 while (state != 0) {5140 switch (state) {5141 case RES_EQ_RESERVED:5142 spin_lock_irq(mlx4_tlock(dev));5143 rb_erase(&eq->com.node,5144 &tracker->res_tree[RES_EQ]);5145 list_del(&eq->com.list);5146 spin_unlock_irq(mlx4_tlock(dev));5147 kfree(eq);5148 state = 0;5149 break;5150 5151 case RES_EQ_HW:5152 err = mlx4_cmd(dev, slave, eqn & 0x3ff,5153 1, MLX4_CMD_HW2SW_EQ,5154 MLX4_CMD_TIME_CLASS_A,5155 MLX4_CMD_NATIVE);5156 if (err)5157 mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n",5158 slave, eqn & 0x3ff);5159 atomic_dec(&eq->mtt->ref_count);5160 state = RES_EQ_RESERVED;5161 break;5162 5163 default:5164 state = 0;5165 }5166 }5167 }5168 spin_lock_irq(mlx4_tlock(dev));5169 }5170 spin_unlock_irq(mlx4_tlock(dev));5171}5172 5173static void rem_slave_counters(struct mlx4_dev *dev, int slave)5174{5175 struct mlx4_priv *priv = mlx4_priv(dev);5176 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;5177 struct list_head *counter_list =5178 &tracker->slave_list[slave].res_list[RES_COUNTER];5179 struct res_counter *counter;5180 struct res_counter *tmp;5181 int err;5182 int *counters_arr = NULL;5183 int i, j;5184 5185 err = move_all_busy(dev, slave, RES_COUNTER);5186 if (err)5187 mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n",5188 slave);5189 5190 counters_arr = kmalloc_array(dev->caps.max_counters,5191 sizeof(*counters_arr), GFP_KERNEL);5192 if (!counters_arr)5193 return;5194 5195 do {5196 i = 0;5197 j = 0;5198 spin_lock_irq(mlx4_tlock(dev));5199 list_for_each_entry_safe(counter, tmp, counter_list, com.list) {5200 if (counter->com.owner == slave) {5201 counters_arr[i++] = counter->com.res_id;5202 rb_erase(&counter->com.node,5203 &tracker->res_tree[RES_COUNTER]);5204 list_del(&counter->com.list);5205 kfree(counter);5206 }5207 }5208 spin_unlock_irq(mlx4_tlock(dev));5209 5210 while (j < i) {5211 __mlx4_counter_free(dev, counters_arr[j++]);5212 mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);5213 }5214 } while (i);5215 5216 kfree(counters_arr);5217}5218 5219static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave)5220{5221 struct mlx4_priv *priv = mlx4_priv(dev);5222 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;5223 struct list_head *xrcdn_list =5224 &tracker->slave_list[slave].res_list[RES_XRCD];5225 struct res_xrcdn *xrcd;5226 struct res_xrcdn *tmp;5227 int err;5228 int xrcdn;5229 5230 err = move_all_busy(dev, slave, RES_XRCD);5231 if (err)5232 mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns - too busy for slave %d\n",5233 slave);5234 5235 spin_lock_irq(mlx4_tlock(dev));5236 list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) {5237 if (xrcd->com.owner == slave) {5238 xrcdn = xrcd->com.res_id;5239 rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]);5240 list_del(&xrcd->com.list);5241 kfree(xrcd);5242 __mlx4_xrcd_free(dev, xrcdn);5243 }5244 }5245 spin_unlock_irq(mlx4_tlock(dev));5246}5247 5248void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)5249{5250 struct mlx4_priv *priv = mlx4_priv(dev);5251 mlx4_reset_roce_gids(dev, slave);5252 mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);5253 rem_slave_vlans(dev, slave);5254 rem_slave_macs(dev, slave);5255 rem_slave_fs_rule(dev, slave);5256 rem_slave_qps(dev, slave);5257 rem_slave_srqs(dev, slave);5258 rem_slave_cqs(dev, slave);5259 rem_slave_mrs(dev, slave);5260 rem_slave_eqs(dev, slave);5261 rem_slave_mtts(dev, slave);5262 rem_slave_counters(dev, slave);5263 rem_slave_xrcdns(dev, slave);5264 mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);5265}5266 5267static void update_qos_vpp(struct mlx4_update_qp_context *ctx,5268 struct mlx4_vf_immed_vlan_work *work)5269{5270 ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP);5271 ctx->qp_context.qos_vport = work->qos_vport;5272}5273 5274void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)5275{5276 struct mlx4_vf_immed_vlan_work *work =5277 container_of(_work, struct mlx4_vf_immed_vlan_work, work);5278 struct mlx4_cmd_mailbox *mailbox;5279 struct mlx4_update_qp_context *upd_context;5280 struct mlx4_dev *dev = &work->priv->dev;5281 struct mlx4_resource_tracker *tracker =5282 &work->priv->mfunc.master.res_tracker;5283 struct list_head *qp_list =5284 &tracker->slave_list[work->slave].res_list[RES_QP];5285 struct res_qp *qp;5286 struct res_qp *tmp;5287 u64 qp_path_mask_vlan_ctrl =5288 ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) |5289 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) |5290 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) |5291 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) |5292 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) |5293 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED));5294 5295 u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) |5296 (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) |5297 (1ULL << MLX4_UPD_QP_PATH_MASK_CV) |5298 (1ULL << MLX4_UPD_QP_PATH_MASK_SV) |5299 (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) |5300 (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) |5301 (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) |5302 (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE));5303 5304 int err;5305 int port, errors = 0;5306 u8 vlan_control;5307 5308 if (mlx4_is_slave(dev)) {5309 mlx4_warn(dev, "Trying to update-qp in slave %d\n",5310 work->slave);5311 goto out;5312 }5313 5314 mailbox = mlx4_alloc_cmd_mailbox(dev);5315 if (IS_ERR(mailbox))5316 goto out;5317 if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE) /* block all */5318 vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |5319 MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |5320 MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |5321 MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |5322 MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |5323 MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;5324 else if (!work->vlan_id)5325 vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |5326 MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;5327 else if (work->vlan_proto == htons(ETH_P_8021AD))5328 vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |5329 MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |5330 MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |5331 MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;5332 else /* vst 802.1Q */5333 vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |5334 MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |5335 MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;5336 5337 upd_context = mailbox->buf;5338 upd_context->qp_mask = cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_VSD);5339 5340 spin_lock_irq(mlx4_tlock(dev));5341 list_for_each_entry_safe(qp, tmp, qp_list, com.list) {5342 spin_unlock_irq(mlx4_tlock(dev));5343 if (qp->com.owner == work->slave) {5344 if (qp->com.from_state != RES_QP_HW ||5345 !qp->sched_queue || /* no INIT2RTR trans yet */5346 mlx4_is_qp_reserved(dev, qp->local_qpn) ||5347 qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) {5348 spin_lock_irq(mlx4_tlock(dev));5349 continue;5350 }5351 port = (qp->sched_queue >> 6 & 1) + 1;5352 if (port != work->port) {5353 spin_lock_irq(mlx4_tlock(dev));5354 continue;5355 }5356 if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff))5357 upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask);5358 else5359 upd_context->primary_addr_path_mask =5360 cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl);5361 if (work->vlan_id == MLX4_VGT) {5362 upd_context->qp_context.param3 = qp->param3;5363 upd_context->qp_context.pri_path.vlan_control = qp->vlan_control;5364 upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx;5365 upd_context->qp_context.pri_path.vlan_index = qp->vlan_index;5366 upd_context->qp_context.pri_path.fl = qp->pri_path_fl;5367 upd_context->qp_context.pri_path.feup = qp->feup;5368 upd_context->qp_context.pri_path.sched_queue =5369 qp->sched_queue;5370 } else {5371 upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN);5372 upd_context->qp_context.pri_path.vlan_control = vlan_control;5373 upd_context->qp_context.pri_path.vlan_index = work->vlan_ix;5374 upd_context->qp_context.pri_path.fvl_rx =5375 qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN;5376 upd_context->qp_context.pri_path.fl =5377 qp->pri_path_fl | MLX4_FL_ETH_HIDE_CQE_VLAN;5378 if (work->vlan_proto == htons(ETH_P_8021AD))5379 upd_context->qp_context.pri_path.fl |= MLX4_FL_SV;5380 else5381 upd_context->qp_context.pri_path.fl |= MLX4_FL_CV;5382 upd_context->qp_context.pri_path.feup =5383 qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;5384 upd_context->qp_context.pri_path.sched_queue =5385 qp->sched_queue & 0xC7;5386 upd_context->qp_context.pri_path.sched_queue |=5387 ((work->qos & 0x7) << 3);5388 5389 if (dev->caps.flags2 &5390 MLX4_DEV_CAP_FLAG2_QOS_VPP)5391 update_qos_vpp(upd_context, work);5392 }5393 5394 err = mlx4_cmd(dev, mailbox->dma,5395 qp->local_qpn & 0xffffff,5396 0, MLX4_CMD_UPDATE_QP,5397 MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);5398 if (err) {5399 mlx4_info(dev, "UPDATE_QP failed for slave %d, port %d, qpn %d (%d)\n",5400 work->slave, port, qp->local_qpn, err);5401 errors++;5402 }5403 }5404 spin_lock_irq(mlx4_tlock(dev));5405 }5406 spin_unlock_irq(mlx4_tlock(dev));5407 mlx4_free_cmd_mailbox(dev, mailbox);5408 5409 if (errors)5410 mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n",5411 errors, work->slave, work->port);5412 5413 /* unregister previous vlan_id if needed and we had no errors5414 * while updating the QPs5415 */5416 if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors &&5417 NO_INDX != work->orig_vlan_ix)5418 __mlx4_unregister_vlan(&work->priv->dev, work->port,5419 work->orig_vlan_id);5420out:5421 kfree(work);5422 return;5423}5424