Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/mellanox/mlx4/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 132 kB image not shown  

Quelle  resource_tracker.c   Sprache: C

 
/*
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies.
 * All rights reserved.
 * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/mlx4/cmd.h>
#include <linux/mlx4/qp.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>

#include "mlx4.h"
#include "fw.h"
#include "mlx4_stats.h"

#define MLX4_MAC_VALID  (1ull << 63)
#define MLX4_PF_COUNTERS_PER_PORT 2
#define MLX4_VF_COUNTERS_PER_PORT 1

struct mac_res {
 struct list_head list;
 u64 mac;
 int ref_count;
 u8 smac_index;
 u8 port;
};

struct vlan_res {
 struct list_head list;
 u16 vlan;
 int ref_count;
 int vlan_index;
 u8 port;
};

struct res_common {
 struct list_head list;
 struct rb_node  node;
 u64          res_id;
 int   owner;
 int   state;
 int   from_state;
 int   to_state;
 int   removing;
 const char  *func_name;
};

enum {
 RES_ANY_BUSY = 1
};

struct res_gid {
 struct list_head list;
 u8   gid[16];
 enum mlx4_protocol prot;
 enum mlx4_steer_type steer;
 u64   reg_id;
};

enum res_qp_states {
 RES_QP_BUSY = RES_ANY_BUSY,

 /* QP number was allocated */
 RES_QP_RESERVED,

 /* ICM memory for QP context was mapped */
 RES_QP_MAPPED,

 /* QP is in hw ownership */
 RES_QP_HW
};

struct res_qp {
 struct res_common com;
 struct res_mtt        *mtt;
 struct res_cq        *rcq;
 struct res_cq        *scq;
 struct res_srq        *srq;
 struct list_head mcg_list;
 spinlock_t  mcg_spl;
 int   local_qpn;
 atomic_t  ref_count;
 u32   qpc_flags;
 /* saved qp params before VST enforcement in order to restore on VGT */
 u8   sched_queue;
 __be32   param3;
 u8   vlan_control;
 u8   fvl_rx;
 u8   pri_path_fl;
 u8   vlan_index;
 u8   feup;
};

enum res_mtt_states {
 RES_MTT_BUSY = RES_ANY_BUSY,
 RES_MTT_ALLOCATED,
};

static inline const char *mtt_states_str(enum res_mtt_states state)
{
 switch (state) {
 case RES_MTT_BUSY: return "RES_MTT_BUSY";
 case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED";
 defaultreturn "Unknown";
 }
}

struct res_mtt {
 struct res_common com;
 int   order;
 atomic_t  ref_count;
};

enum res_mpt_states {
 RES_MPT_BUSY = RES_ANY_BUSY,
 RES_MPT_RESERVED,
 RES_MPT_MAPPED,
 RES_MPT_HW,
};

struct res_mpt {
 struct res_common com;
 struct res_mtt        *mtt;
 int   key;
};

enum res_eq_states {
 RES_EQ_BUSY = RES_ANY_BUSY,
 RES_EQ_RESERVED,
 RES_EQ_HW,
};

struct res_eq {
 struct res_common com;
 struct res_mtt        *mtt;
};

enum res_cq_states {
 RES_CQ_BUSY = RES_ANY_BUSY,
 RES_CQ_ALLOCATED,
 RES_CQ_HW,
};

struct res_cq {
 struct res_common com;
 struct res_mtt        *mtt;
 atomic_t  ref_count;
};

enum res_srq_states {
 RES_SRQ_BUSY = RES_ANY_BUSY,
 RES_SRQ_ALLOCATED,
 RES_SRQ_HW,
};

struct res_srq {
 struct res_common com;
 struct res_mtt        *mtt;
 struct res_cq        *cq;
 atomic_t  ref_count;
};

enum res_counter_states {
 RES_COUNTER_BUSY = RES_ANY_BUSY,
 RES_COUNTER_ALLOCATED,
};

struct res_counter {
 struct res_common com;
 int   port;
};

enum res_xrcdn_states {
 RES_XRCD_BUSY = RES_ANY_BUSY,
 RES_XRCD_ALLOCATED,
};

struct res_xrcdn {
 struct res_common com;
 int   port;
};

enum res_fs_rule_states {
 RES_FS_RULE_BUSY = RES_ANY_BUSY,
 RES_FS_RULE_ALLOCATED,
};

struct res_fs_rule {
 struct res_common com;
 int   qpn;
 /* VF DMFS mbox with port flipped */
 void   *mirr_mbox;
 /* > 0 --> apply mirror when getting into HA mode      */
 /* = 0 --> un-apply mirror when getting out of HA mode */
 u32   mirr_mbox_size;
 struct list_head mirr_list;
 u64   mirr_rule_id;
};

static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
{
 struct rb_node *node = root->rb_node;

 while (node) {
  struct res_common *res = rb_entry(node, struct res_common,
        node);

  if (res_id < res->res_id)
   node = node->rb_left;
  else if (res_id > res->res_id)
   node = node->rb_right;
  else
   return res;
 }
 return NULL;
}

static int res_tracker_insert(struct rb_root *root, struct res_common *res)
{
 struct rb_node **new = &(root->rb_node), *parent = NULL;

 /* Figure out where to put new node */
 while (*new) {
  struct res_common *this = rb_entry(*newstruct res_common,
         node);

  parent = *new;
  if (res->res_id < this->res_id)
   new = &((*new)->rb_left);
  else if (res->res_id > this->res_id)
   new = &((*new)->rb_right);
  else
   return -EEXIST;
 }

 /* Add new node and rebalance tree. */
 rb_link_node(&res->node, parent, new);
 rb_insert_color(&res->node, root);

 return 0;
}

enum qp_transition {
 QP_TRANS_INIT2RTR,
 QP_TRANS_RTR2RTS,
 QP_TRANS_RTS2RTS,
 QP_TRANS_SQERR2RTS,
 QP_TRANS_SQD2SQD,
 QP_TRANS_SQD2RTS
};

/* For Debug uses */
static const char *resource_str(enum mlx4_resource rt)
{
 switch (rt) {
 case RES_QP: return "RES_QP";
 case RES_CQ: return "RES_CQ";
 case RES_SRQ: return "RES_SRQ";
 case RES_MPT: return "RES_MPT";
 case RES_MTT: return "RES_MTT";
 case RES_MAC: return  "RES_MAC";
 case RES_VLAN: return  "RES_VLAN";
 case RES_EQ: return "RES_EQ";
 case RES_COUNTER: return "RES_COUNTER";
 case RES_FS_RULE: return "RES_FS_RULE";
 case RES_XRCD: return "RES_XRCD";
 defaultreturn "Unknown resource type !!!";
 }
}

static void rem_slave_vlans(struct mlx4_dev *dev, int slave);
static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
          enum mlx4_resource res_type, int count,
          int port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct resource_allocator *res_alloc =
  &priv->mfunc.master.res_tracker.res_alloc[res_type];
 int err = -EDQUOT;
 int allocated, free, reserved, guaranteed, from_free;
 int from_rsvd;

 if (slave > dev->persist->num_vfs)
  return -EINVAL;

 spin_lock(&res_alloc->alloc_lock);
 allocated = (port > 0) ?
  res_alloc->allocated[(port - 1) *
  (dev->persist->num_vfs + 1) + slave] :
  res_alloc->allocated[slave];
 free = (port > 0) ? res_alloc->res_port_free[port - 1] :
  res_alloc->res_free;
 reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] :
  res_alloc->res_reserved;
 guaranteed = res_alloc->guaranteed[slave];

 if (allocated + count > res_alloc->quota[slave]) {
  mlx4_warn(dev, "VF %d port %d res %s: quota exceeded, count %d alloc %d quota %d\n",
     slave, port, resource_str(res_type), count,
     allocated, res_alloc->quota[slave]);
  goto out;
 }

 if (allocated + count <= guaranteed) {
  err = 0;
  from_rsvd = count;
 } else {
  /* portion may need to be obtained from free area */
  if (guaranteed - allocated > 0)
   from_free = count - (guaranteed - allocated);
  else
   from_free = count;

  from_rsvd = count - from_free;

  if (free - from_free >= reserved)
   err = 0;
  else
   mlx4_warn(dev, "VF %d port %d res %s: free pool empty, free %d from_free %d rsvd %d\n",
      slave, port, resource_str(res_type), free,
      from_free, reserved);
 }

 if (!err) {
  /* grant the request */
  if (port > 0) {
   res_alloc->allocated[(port - 1) *
   (dev->persist->num_vfs + 1) + slave] += count;
   res_alloc->res_port_free[port - 1] -= count;
   res_alloc->res_port_rsvd[port - 1] -= from_rsvd;
  } else {
   res_alloc->allocated[slave] += count;
   res_alloc->res_free -= count;
   res_alloc->res_reserved -= from_rsvd;
  }
 }

out:
 spin_unlock(&res_alloc->alloc_lock);
 return err;
}

static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
        enum mlx4_resource res_type, int count,
        int port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct resource_allocator *res_alloc =
  &priv->mfunc.master.res_tracker.res_alloc[res_type];
 int allocated, guaranteed, from_rsvd;

 if (slave > dev->persist->num_vfs)
  return;

 spin_lock(&res_alloc->alloc_lock);

 allocated = (port > 0) ?
  res_alloc->allocated[(port - 1) *
  (dev->persist->num_vfs + 1) + slave] :
  res_alloc->allocated[slave];
 guaranteed = res_alloc->guaranteed[slave];

 if (allocated - count >= guaranteed) {
  from_rsvd = 0;
 } else {
  /* portion may need to be returned to reserved area */
  if (allocated - guaranteed > 0)
   from_rsvd = count - (allocated - guaranteed);
  else
   from_rsvd = count;
 }

 if (port > 0) {
  res_alloc->allocated[(port - 1) *
  (dev->persist->num_vfs + 1) + slave] -= count;
  res_alloc->res_port_free[port - 1] += count;
  res_alloc->res_port_rsvd[port - 1] += from_rsvd;
 } else {
  res_alloc->allocated[slave] -= count;
  res_alloc->res_free += count;
  res_alloc->res_reserved += from_rsvd;
 }

 spin_unlock(&res_alloc->alloc_lock);
 return;
}

static inline void initialize_res_quotas(struct mlx4_dev *dev,
      struct resource_allocator *res_alloc,
      enum mlx4_resource res_type,
      int vf, int num_instances)
{
 res_alloc->guaranteed[vf] = num_instances /
        (2 * (dev->persist->num_vfs + 1));
 res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf];
 if (vf == mlx4_master_func_num(dev)) {
  res_alloc->res_free = num_instances;
  if (res_type == RES_MTT) {
   /* reserved mtts will be taken out of the PF allocation */
   res_alloc->res_free += dev->caps.reserved_mtts;
   res_alloc->guaranteed[vf] += dev->caps.reserved_mtts;
   res_alloc->quota[vf] += dev->caps.reserved_mtts;
  }
 }
}

void mlx4_init_quotas(struct mlx4_dev *dev)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 int pf;

 /* quotas for VFs are initialized in mlx4_slave_cap */
 if (mlx4_is_slave(dev))
  return;

 if (!mlx4_is_mfunc(dev)) {
  dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps -
   mlx4_num_reserved_sqps(dev);
  dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs;
  dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs;
  dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts;
  dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws;
  return;
 }

 pf = mlx4_master_func_num(dev);
 dev->quotas.qp =
  priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf];
 dev->quotas.cq =
  priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf];
 dev->quotas.srq =
  priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf];
 dev->quotas.mtt =
  priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf];
 dev->quotas.mpt =
  priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
}

static int
mlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev,
     struct resource_allocator *res_alloc,
     int vf)
{
 struct mlx4_active_ports actv_ports;
 int ports, counters_guaranteed;

 /* For master, only allocate according to the number of phys ports */
 if (vf == mlx4_master_func_num(dev))
  return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports;

 /* calculate real number of ports for the VF */
 actv_ports = mlx4_get_active_ports(dev, vf);
 ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
 counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT;

 /* If we do not have enough counters for this VF, do not
 * allocate any for it. '-1' to reduce the sink counter.
 */

 if ((res_alloc->res_reserved + counters_guaranteed) >
     (dev->caps.max_counters - 1))
  return 0;

 return counters_guaranteed;
}

int mlx4_init_resource_tracker(struct mlx4_dev *dev)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 int i, j;
 int t;

 priv->mfunc.master.res_tracker.slave_list =
  kcalloc(dev->num_slaves, sizeof(struct slave_list),
   GFP_KERNEL);
 if (!priv->mfunc.master.res_tracker.slave_list)
  return -ENOMEM;

 for (i = 0 ; i < dev->num_slaves; i++) {
  for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t)
   INIT_LIST_HEAD(&priv->mfunc.master.res_tracker.
           slave_list[i].res_list[t]);
  mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
 }

 mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n",
   dev->num_slaves);
 for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++)
  priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT;

 for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
  struct resource_allocator *res_alloc =
   &priv->mfunc.master.res_tracker.res_alloc[i];
  res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1,
       sizeof(int),
       GFP_KERNEL);
  res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1,
            sizeof(int),
            GFP_KERNEL);
  if (i == RES_MAC || i == RES_VLAN)
   res_alloc->allocated =
    kcalloc(MLX4_MAX_PORTS *
      (dev->persist->num_vfs + 1),
     sizeof(int), GFP_KERNEL);
  else
   res_alloc->allocated =
    kcalloc(dev->persist->num_vfs + 1,
     sizeof(int), GFP_KERNEL);
  /* Reduce the sink counter */
  if (i == RES_COUNTER)
   res_alloc->res_free = dev->caps.max_counters - 1;

  if (!res_alloc->quota || !res_alloc->guaranteed ||
      !res_alloc->allocated)
   goto no_mem_err;

  spin_lock_init(&res_alloc->alloc_lock);
  for (t = 0; t < dev->persist->num_vfs + 1; t++) {
   struct mlx4_active_ports actv_ports =
    mlx4_get_active_ports(dev, t);
   switch (i) {
   case RES_QP:
    initialize_res_quotas(dev, res_alloc, RES_QP,
            t, dev->caps.num_qps -
            dev->caps.reserved_qps -
            mlx4_num_reserved_sqps(dev));
    break;
   case RES_CQ:
    initialize_res_quotas(dev, res_alloc, RES_CQ,
            t, dev->caps.num_cqs -
            dev->caps.reserved_cqs);
    break;
   case RES_SRQ:
    initialize_res_quotas(dev, res_alloc, RES_SRQ,
            t, dev->caps.num_srqs -
            dev->caps.reserved_srqs);
    break;
   case RES_MPT:
    initialize_res_quotas(dev, res_alloc, RES_MPT,
            t, dev->caps.num_mpts -
            dev->caps.reserved_mrws);
    break;
   case RES_MTT:
    initialize_res_quotas(dev, res_alloc, RES_MTT,
            t, dev->caps.num_mtts -
            dev->caps.reserved_mtts);
    break;
   case RES_MAC:
    if (t == mlx4_master_func_num(dev)) {
     int max_vfs_pport = 0;
     /* Calculate the max vfs per port for */
     /* both ports.       */
     for (j = 0; j < dev->caps.num_ports;
          j++) {
      struct mlx4_slaves_pport slaves_pport =
       mlx4_phys_to_slaves_pport(dev, j + 1);
      unsigned current_slaves =
       bitmap_weight(slaves_pport.slaves,
              dev->caps.num_ports) - 1;
      if (max_vfs_pport < current_slaves)
       max_vfs_pport =
        current_slaves;
     }
     res_alloc->quota[t] =
      MLX4_MAX_MAC_NUM -
      2 * max_vfs_pport;
     res_alloc->guaranteed[t] = 2;
     for (j = 0; j < MLX4_MAX_PORTS; j++)
      res_alloc->res_port_free[j] =
       MLX4_MAX_MAC_NUM;
    } else {
     res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
     res_alloc->guaranteed[t] = 2;
    }
    break;
   case RES_VLAN:
    if (t == mlx4_master_func_num(dev)) {
     res_alloc->quota[t] = MLX4_MAX_VLAN_NUM;
     res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2;
     for (j = 0; j < MLX4_MAX_PORTS; j++)
      res_alloc->res_port_free[j] =
       res_alloc->quota[t];
    } else {
     res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2;
     res_alloc->guaranteed[t] = 0;
    }
    break;
   case RES_COUNTER:
    res_alloc->quota[t] = dev->caps.max_counters;
    res_alloc->guaranteed[t] =
     mlx4_calc_res_counter_guaranteed(dev, res_alloc, t);
    break;
   default:
    break;
   }
   if (i == RES_MAC || i == RES_VLAN) {
    for (j = 0; j < dev->caps.num_ports; j++)
     if (test_bit(j, actv_ports.ports))
      res_alloc->res_port_rsvd[j] +=
       res_alloc->guaranteed[t];
   } else {
    res_alloc->res_reserved += res_alloc->guaranteed[t];
   }
  }
 }
 spin_lock_init(&priv->mfunc.master.res_tracker.lock);
 return 0;

no_mem_err:
 for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
  kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
  priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
  kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
  priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
  kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
  priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
 }
 return -ENOMEM;
}

void mlx4_free_resource_tracker(struct mlx4_dev *dev,
    enum mlx4_res_tracker_free_type type)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 int i;

 if (priv->mfunc.master.res_tracker.slave_list) {
  if (type != RES_TR_FREE_STRUCTS_ONLY) {
   for (i = 0; i < dev->num_slaves; i++) {
    if (type == RES_TR_FREE_ALL ||
        dev->caps.function != i)
     mlx4_delete_all_resources_for_slave(dev, i);
   }
   /* free master's vlans */
   i = dev->caps.function;
   mlx4_reset_roce_gids(dev, i);
   mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
   rem_slave_vlans(dev, i);
   mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
  }

  if (type != RES_TR_FREE_SLAVES_ONLY) {
   for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
    kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
    priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
    kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
    priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
    kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
    priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
   }
   kfree(priv->mfunc.master.res_tracker.slave_list);
   priv->mfunc.master.res_tracker.slave_list = NULL;
  }
 }
}

static void update_pkey_index(struct mlx4_dev *dev, int slave,
         struct mlx4_cmd_mailbox *inbox)
{
 u8 sched = *(u8 *)(inbox->buf + 64);
 u8 orig_index = *(u8 *)(inbox->buf + 35);
 u8 new_index;
 struct mlx4_priv *priv = mlx4_priv(dev);
 int port;

 port = (sched >> 6 & 1) + 1;

 new_index = priv->virt2phys_pkey[slave][port - 1][orig_index];
 *(u8 *)(inbox->buf + 35) = new_index;
}

static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
         u8 slave)
{
 struct mlx4_qp_context *qp_ctx = inbox->buf + 8;
 enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf);
 u32   ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
 int port;

 if (MLX4_QP_ST_UD == ts) {
  port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
  if (mlx4_is_eth(dev, port))
   qp_ctx->pri_path.mgid_index =
    mlx4_get_base_gid_ix(dev, slave, port) | 0x80;
  else
   qp_ctx->pri_path.mgid_index = slave | 0x80;

 } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {
  if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
   port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
   if (mlx4_is_eth(dev, port)) {
    qp_ctx->pri_path.mgid_index +=
     mlx4_get_base_gid_ix(dev, slave, port);
    qp_ctx->pri_path.mgid_index &= 0x7f;
   } else {
    qp_ctx->pri_path.mgid_index = slave & 0x7F;
   }
  }
  if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
   port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
   if (mlx4_is_eth(dev, port)) {
    qp_ctx->alt_path.mgid_index +=
     mlx4_get_base_gid_ix(dev, slave, port);
    qp_ctx->alt_path.mgid_index &= 0x7f;
   } else {
    qp_ctx->alt_path.mgid_index = slave & 0x7F;
   }
  }
 }
}

static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
     u8 slave, int port);

static int update_vport_qp_param(struct mlx4_dev *dev,
     struct mlx4_cmd_mailbox *inbox,
     u8 slave, u32 qpn)
{
 struct mlx4_qp_context *qpc = inbox->buf + 8;
 struct mlx4_vport_oper_state *vp_oper;
 struct mlx4_priv *priv;
 u32 qp_type;
 int port, err = 0;

 port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
 priv = mlx4_priv(dev);
 vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
 qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;

 err = handle_counter(dev, qpc, slave, port);
 if (err)
  goto out;

 if (MLX4_VGT != vp_oper->state.default_vlan) {
  /* the reserved QPs (special, proxy, tunnel)
 * do not operate over vlans
 */

  if (mlx4_is_qp_reserved(dev, qpn))
   return 0;

  /* force strip vlan by clear vsd, MLX QP refers to Raw Ethernet */
  if (qp_type == MLX4_QP_ST_UD ||
      (qp_type == MLX4_QP_ST_MLX && mlx4_is_eth(dev, port))) {
   if (dev->caps.bmme_flags & MLX4_BMME_FLAG_VSD_INIT2RTR) {
    *(__be32 *)inbox->buf =
     cpu_to_be32(be32_to_cpu(*(__be32 *)inbox->buf) |
     MLX4_QP_OPTPAR_VLAN_STRIPPING);
    qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN);
   } else {
    struct mlx4_update_qp_params params = {.flags = 0};

    err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, ¶ms);
    if (err)
     goto out;
   }
  }

  /* preserve IF_COUNTER flag */
  qpc->pri_path.vlan_control &=
   MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
  if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&
      dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {
   qpc->pri_path.vlan_control |=
    MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
    MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
    MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
    MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
    MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
    MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
  } else if (0 != vp_oper->state.default_vlan) {
   if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) {
    /* vst QinQ should block untagged on TX,
 * but cvlan is in payload and phv is set so
 * hw see it as untagged. Block tagged instead.
 */

    qpc->pri_path.vlan_control |=
     MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
     MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
     MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
     MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
   } else { /* vst 802.1Q */
    qpc->pri_path.vlan_control |=
     MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
     MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
     MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
   }
  } else { /* priority tagged */
   qpc->pri_path.vlan_control |=
    MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
    MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
  }

  qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN;
  qpc->pri_path.vlan_index = vp_oper->vlan_idx;
  qpc->pri_path.fl |= MLX4_FL_ETH_HIDE_CQE_VLAN;
  if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD))
   qpc->pri_path.fl |= MLX4_FL_SV;
  else
   qpc->pri_path.fl |= MLX4_FL_CV;
  qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
  qpc->pri_path.sched_queue &= 0xC7;
  qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
  qpc->qos_vport = vp_oper->state.qos_vport;
 }
 if (vp_oper->state.spoofchk) {
  qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;
  qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
 }
out:
 return err;
}

static int mpt_mask(struct mlx4_dev *dev)
{
 return dev->caps.num_mpts - 1;
}

static const char *mlx4_resource_type_to_str(enum mlx4_resource t)
{
 switch (t) {
 case RES_QP:
  return "QP";
 case RES_CQ:
  return "CQ";
 case RES_SRQ:
  return "SRQ";
 case RES_XRCD:
  return "XRCD";
 case RES_MPT:
  return "MPT";
 case RES_MTT:
  return "MTT";
 case RES_MAC:
  return "MAC";
 case RES_VLAN:
  return "VLAN";
 case RES_COUNTER:
  return "COUNTER";
 case RES_FS_RULE:
  return "FS_RULE";
 case RES_EQ:
  return "EQ";
 default:
  return "INVALID RESOURCE";
 }
}

static void *find_res(struct mlx4_dev *dev, u64 res_id,
        enum mlx4_resource type)
{
 struct mlx4_priv *priv = mlx4_priv(dev);

 return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type],
      res_id);
}

static int _get_res(struct mlx4_dev *dev, int slave, u64 res_id,
      enum mlx4_resource type,
      void *res, const char *func_name)
{
 struct res_common *r;
 int err = 0;

 spin_lock_irq(mlx4_tlock(dev));
 r = find_res(dev, res_id, type);
 if (!r) {
  err = -ENONET;
  goto exit;
 }

 if (r->state == RES_ANY_BUSY) {
  mlx4_warn(dev,
     "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n",
     func_name, slave, res_id, mlx4_resource_type_to_str(type),
     r->func_name);
  err = -EBUSY;
  goto exit;
 }

 if (r->owner != slave) {
  err = -EPERM;
  goto exit;
 }

 r->from_state = r->state;
 r->state = RES_ANY_BUSY;
 r->func_name = func_name;

 if (res)
  *((struct res_common **)res) = r;

exit:
 spin_unlock_irq(mlx4_tlock(dev));
 return err;
}

#define get_res(dev, slave, res_id, type, res) \
 _get_res((dev), (slave), (res_id), (type), (res), __func__)

int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev,
        enum mlx4_resource type,
        u64 res_id, int *slave)
{

 struct res_common *r;
 int err = -ENOENT;
 int id = res_id;

 if (type == RES_QP)
  id &= 0x7fffff;
 spin_lock(mlx4_tlock(dev));

 r = find_res(dev, id, type);
 if (r) {
  *slave = r->owner;
  err = 0;
 }
 spin_unlock(mlx4_tlock(dev));

 return err;
}

static void put_res(struct mlx4_dev *dev, int slave, u64 res_id,
      enum mlx4_resource type)
{
 struct res_common *r;

 spin_lock_irq(mlx4_tlock(dev));
 r = find_res(dev, res_id, type);
 if (r) {
  r->state = r->from_state;
  r->func_name = "";
 }
 spin_unlock_irq(mlx4_tlock(dev));
}

static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        u64 in_param, u64 *out_param, int port);

static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,
       int counter_index)
{
 struct res_common *r;
 struct res_counter *counter;
 int ret = 0;

 if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
  return ret;

 spin_lock_irq(mlx4_tlock(dev));
 r = find_res(dev, counter_index, RES_COUNTER);
 if (!r || r->owner != slave) {
  ret = -EINVAL;
 } else {
  counter = container_of(r, struct res_counter, com);
  if (!counter->port)
   counter->port = port;
 }

 spin_unlock_irq(mlx4_tlock(dev));
 return ret;
}

static int handle_unexisting_counter(struct mlx4_dev *dev,
         struct mlx4_qp_context *qpc, u8 slave,
         int port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_common *tmp;
 struct res_counter *counter;
 u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev);
 int err = 0;

 spin_lock_irq(mlx4_tlock(dev));
 list_for_each_entry(tmp,
       &tracker->slave_list[slave].res_list[RES_COUNTER],
       list) {
  counter = container_of(tmp, struct res_counter, com);
  if (port == counter->port) {
   qpc->pri_path.counter_index  = counter->com.res_id;
   spin_unlock_irq(mlx4_tlock(dev));
   return 0;
  }
 }
 spin_unlock_irq(mlx4_tlock(dev));

 /* No existing counter, need to allocate a new counter */
 err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx,
    port);
 if (err == -ENOENT) {
  err = 0;
 } else if (err && err != -ENOSPC) {
  mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n",
    __func__, slave, err);
 } else {
  qpc->pri_path.counter_index = counter_idx;
  mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n",
    __func__, slave, qpc->pri_path.counter_index);
  err = 0;
 }

 return err;
}

static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
     u8 slave, int port)
{
 if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev))
  return handle_existing_counter(dev, slave, port,
            qpc->pri_path.counter_index);

 return handle_unexisting_counter(dev, qpc, slave, port);
}

static struct res_common *alloc_qp_tr(int id)
{
 struct res_qp *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_QP_RESERVED;
 ret->local_qpn = id;
 INIT_LIST_HEAD(&ret->mcg_list);
 spin_lock_init(&ret->mcg_spl);
 atomic_set(&ret->ref_count, 0);

 return &ret->com;
}

static struct res_common *alloc_mtt_tr(int id, int order)
{
 struct res_mtt *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->order = order;
 ret->com.state = RES_MTT_ALLOCATED;
 atomic_set(&ret->ref_count, 0);

 return &ret->com;
}

static struct res_common *alloc_mpt_tr(int id, int key)
{
 struct res_mpt *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_MPT_RESERVED;
 ret->key = key;

 return &ret->com;
}

static struct res_common *alloc_eq_tr(int id)
{
 struct res_eq *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_EQ_RESERVED;

 return &ret->com;
}

static struct res_common *alloc_cq_tr(int id)
{
 struct res_cq *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_CQ_ALLOCATED;
 atomic_set(&ret->ref_count, 0);

 return &ret->com;
}

static struct res_common *alloc_srq_tr(int id)
{
 struct res_srq *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_SRQ_ALLOCATED;
 atomic_set(&ret->ref_count, 0);

 return &ret->com;
}

static struct res_common *alloc_counter_tr(int id, int port)
{
 struct res_counter *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_COUNTER_ALLOCATED;
 ret->port = port;

 return &ret->com;
}

static struct res_common *alloc_xrcdn_tr(int id)
{
 struct res_xrcdn *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_XRCD_ALLOCATED;

 return &ret->com;
}

static struct res_common *alloc_fs_rule_tr(u64 id, int qpn)
{
 struct res_fs_rule *ret;

 ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 if (!ret)
  return NULL;

 ret->com.res_id = id;
 ret->com.state = RES_FS_RULE_ALLOCATED;
 ret->qpn = qpn;
 return &ret->com;
}

static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
       int extra)
{
 struct res_common *ret;

 switch (type) {
 case RES_QP:
  ret = alloc_qp_tr(id);
  break;
 case RES_MPT:
  ret = alloc_mpt_tr(id, extra);
  break;
 case RES_MTT:
  ret = alloc_mtt_tr(id, extra);
  break;
 case RES_EQ:
  ret = alloc_eq_tr(id);
  break;
 case RES_CQ:
  ret = alloc_cq_tr(id);
  break;
 case RES_SRQ:
  ret = alloc_srq_tr(id);
  break;
 case RES_MAC:
  pr_err("implementation missing\n");
  return NULL;
 case RES_COUNTER:
  ret = alloc_counter_tr(id, extra);
  break;
 case RES_XRCD:
  ret = alloc_xrcdn_tr(id);
  break;
 case RES_FS_RULE:
  ret = alloc_fs_rule_tr(id, extra);
  break;
 default:
  return NULL;
 }
 if (ret)
  ret->owner = slave;

 return ret;
}

int mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,
     struct mlx4_counter *data)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_common *tmp;
 struct res_counter *counter;
 int *counters_arr;
 int i = 0, err = 0;

 memset(data, 0, sizeof(*data));

 counters_arr = kmalloc_array(dev->caps.max_counters,
         sizeof(*counters_arr), GFP_KERNEL);
 if (!counters_arr)
  return -ENOMEM;

 spin_lock_irq(mlx4_tlock(dev));
 list_for_each_entry(tmp,
       &tracker->slave_list[slave].res_list[RES_COUNTER],
       list) {
  counter = container_of(tmp, struct res_counter, com);
  if (counter->port == port) {
   counters_arr[i] = (int)tmp->res_id;
   i++;
  }
 }
 spin_unlock_irq(mlx4_tlock(dev));
 counters_arr[i] = -1;

 i = 0;

 while (counters_arr[i] != -1) {
  err = mlx4_get_counter_stats(dev, counters_arr[i], data,
          0);
  if (err) {
   memset(data, 0, sizeof(*data));
   goto table_changed;
  }
  i++;
 }

table_changed:
 kfree(counters_arr);
 return 0;
}

static int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
    enum mlx4_resource type, int extra)
{
 int i;
 int err;
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct res_common **res_arr;
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct rb_root *root = &tracker->res_tree[type];

 res_arr = kcalloc(count, sizeof(*res_arr), GFP_KERNEL);
 if (!res_arr)
  return -ENOMEM;

 for (i = 0; i < count; ++i) {
  res_arr[i] = alloc_tr(base + i, type, slave, extra);
  if (!res_arr[i]) {
   for (--i; i >= 0; --i)
    kfree(res_arr[i]);

   kfree(res_arr);
   return -ENOMEM;
  }
 }

 spin_lock_irq(mlx4_tlock(dev));
 for (i = 0; i < count; ++i) {
  if (find_res(dev, base + i, type)) {
   err = -EEXIST;
   goto undo;
  }
  err = res_tracker_insert(root, res_arr[i]);
  if (err)
   goto undo;
  list_add_tail(&res_arr[i]->list,
         &tracker->slave_list[slave].res_list[type]);
 }
 spin_unlock_irq(mlx4_tlock(dev));
 kfree(res_arr);

 return 0;

undo:
 for (--i; i >= 0; --i) {
  rb_erase(&res_arr[i]->node, root);
  list_del_init(&res_arr[i]->list);
 }

 spin_unlock_irq(mlx4_tlock(dev));

 for (i = 0; i < count; ++i)
  kfree(res_arr[i]);

 kfree(res_arr);

 return err;
}

static int remove_qp_ok(struct res_qp *res)
{
 if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) ||
     !list_empty(&res->mcg_list)) {
  pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n",
         res->com.state, atomic_read(&res->ref_count));
  return -EBUSY;
 } else if (res->com.state != RES_QP_RESERVED) {
  return -EPERM;
 }

 return 0;
}

static int remove_mtt_ok(struct res_mtt *res, int order)
{
 if (res->com.state == RES_MTT_BUSY ||
     atomic_read(&res->ref_count)) {
  pr_devel("%s-%d: state %s, ref_count %d\n",
    __func__, __LINE__,
    mtt_states_str(res->com.state),
    atomic_read(&res->ref_count));
  return -EBUSY;
 } else if (res->com.state != RES_MTT_ALLOCATED)
  return -EPERM;
 else if (res->order != order)
  return -EINVAL;

 return 0;
}

static int remove_mpt_ok(struct res_mpt *res)
{
 if (res->com.state == RES_MPT_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_MPT_RESERVED)
  return -EPERM;

 return 0;
}

static int remove_eq_ok(struct res_eq *res)
{
 if (res->com.state == RES_MPT_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_MPT_RESERVED)
  return -EPERM;

 return 0;
}

static int remove_counter_ok(struct res_counter *res)
{
 if (res->com.state == RES_COUNTER_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_COUNTER_ALLOCATED)
  return -EPERM;

 return 0;
}

static int remove_xrcdn_ok(struct res_xrcdn *res)
{
 if (res->com.state == RES_XRCD_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_XRCD_ALLOCATED)
  return -EPERM;

 return 0;
}

static int remove_fs_rule_ok(struct res_fs_rule *res)
{
 if (res->com.state == RES_FS_RULE_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_FS_RULE_ALLOCATED)
  return -EPERM;

 return 0;
}

static int remove_cq_ok(struct res_cq *res)
{
 if (res->com.state == RES_CQ_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_CQ_ALLOCATED)
  return -EPERM;

 return 0;
}

static int remove_srq_ok(struct res_srq *res)
{
 if (res->com.state == RES_SRQ_BUSY)
  return -EBUSY;
 else if (res->com.state != RES_SRQ_ALLOCATED)
  return -EPERM;

 return 0;
}

static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra)
{
 switch (type) {
 case RES_QP:
  return remove_qp_ok((struct res_qp *)res);
 case RES_CQ:
  return remove_cq_ok((struct res_cq *)res);
 case RES_SRQ:
  return remove_srq_ok((struct res_srq *)res);
 case RES_MPT:
  return remove_mpt_ok((struct res_mpt *)res);
 case RES_MTT:
  return remove_mtt_ok((struct res_mtt *)res, extra);
 case RES_MAC:
  return -EOPNOTSUPP;
 case RES_EQ:
  return remove_eq_ok((struct res_eq *)res);
 case RES_COUNTER:
  return remove_counter_ok((struct res_counter *)res);
 case RES_XRCD:
  return remove_xrcdn_ok((struct res_xrcdn *)res);
 case RES_FS_RULE:
  return remove_fs_rule_ok((struct res_fs_rule *)res);
 default:
  return -EINVAL;
 }
}

static int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
    enum mlx4_resource type, int extra)
{
 u64 i;
 int err;
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_common *r;

 spin_lock_irq(mlx4_tlock(dev));
 for (i = base; i < base + count; ++i) {
  r = res_tracker_lookup(&tracker->res_tree[type], i);
  if (!r) {
   err = -ENOENT;
   goto out;
  }
  if (r->owner != slave) {
   err = -EPERM;
   goto out;
  }
  err = remove_ok(r, type, extra);
  if (err)
   goto out;
 }

 for (i = base; i < base + count; ++i) {
  r = res_tracker_lookup(&tracker->res_tree[type], i);
  rb_erase(&r->node, &tracker->res_tree[type]);
  list_del(&r->list);
  kfree(r);
 }
 err = 0;

out:
 spin_unlock_irq(mlx4_tlock(dev));

 return err;
}

static int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn,
    enum res_qp_states state, struct res_qp **qp,
    int alloc)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_qp *r;
 int err = 0;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn);
 if (!r)
  err = -ENOENT;
 else if (r->com.owner != slave)
  err = -EPERM;
 else {
  switch (state) {
  case RES_QP_BUSY:
   mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n",
     __func__, r->com.res_id);
   err = -EBUSY;
   break;

  case RES_QP_RESERVED:
   if (r->com.state == RES_QP_MAPPED && !alloc)
    break;

   mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id);
   err = -EINVAL;
   break;

  case RES_QP_MAPPED:
   if ((r->com.state == RES_QP_RESERVED && alloc) ||
       r->com.state == RES_QP_HW)
    break;
   else {
    mlx4_dbg(dev, "failed RES_QP, 0x%llx\n",
       r->com.res_id);
    err = -EINVAL;
   }

   break;

  case RES_QP_HW:
   if (r->com.state != RES_QP_MAPPED)
    err = -EINVAL;
   break;
  default:
   err = -EINVAL;
  }

  if (!err) {
   r->com.from_state = r->com.state;
   r->com.to_state = state;
   r->com.state = RES_QP_BUSY;
   if (qp)
    *qp = r;
  }
 }

 spin_unlock_irq(mlx4_tlock(dev));

 return err;
}

static int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
    enum res_mpt_states state, struct res_mpt **mpt)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_mpt *r;
 int err = 0;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index);
 if (!r)
  err = -ENOENT;
 else if (r->com.owner != slave)
  err = -EPERM;
 else {
  switch (state) {
  case RES_MPT_BUSY:
   err = -EINVAL;
   break;

  case RES_MPT_RESERVED:
   if (r->com.state != RES_MPT_MAPPED)
    err = -EINVAL;
   break;

  case RES_MPT_MAPPED:
   if (r->com.state != RES_MPT_RESERVED &&
       r->com.state != RES_MPT_HW)
    err = -EINVAL;
   break;

  case RES_MPT_HW:
   if (r->com.state != RES_MPT_MAPPED)
    err = -EINVAL;
   break;
  default:
   err = -EINVAL;
  }

  if (!err) {
   r->com.from_state = r->com.state;
   r->com.to_state = state;
   r->com.state = RES_MPT_BUSY;
   if (mpt)
    *mpt = r;
  }
 }

 spin_unlock_irq(mlx4_tlock(dev));

 return err;
}

static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
    enum res_eq_states state, struct res_eq **eq)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_eq *r;
 int err = 0;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index);
 if (!r)
  err = -ENOENT;
 else if (r->com.owner != slave)
  err = -EPERM;
 else {
  switch (state) {
  case RES_EQ_BUSY:
   err = -EINVAL;
   break;

  case RES_EQ_RESERVED:
   if (r->com.state != RES_EQ_HW)
    err = -EINVAL;
   break;

  case RES_EQ_HW:
   if (r->com.state != RES_EQ_RESERVED)
    err = -EINVAL;
   break;

  default:
   err = -EINVAL;
  }

  if (!err) {
   r->com.from_state = r->com.state;
   r->com.to_state = state;
   r->com.state = RES_EQ_BUSY;
  }
 }

 spin_unlock_irq(mlx4_tlock(dev));

 if (!err && eq)
  *eq = r;

 return err;
}

static int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn,
    enum res_cq_states state, struct res_cq **cq)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_cq *r;
 int err;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn);
 if (!r) {
  err = -ENOENT;
 } else if (r->com.owner != slave) {
  err = -EPERM;
 } else if (state == RES_CQ_ALLOCATED) {
  if (r->com.state != RES_CQ_HW)
   err = -EINVAL;
  else if (atomic_read(&r->ref_count))
   err = -EBUSY;
  else
   err = 0;
 } else if (state != RES_CQ_HW || r->com.state != RES_CQ_ALLOCATED) {
  err = -EINVAL;
 } else {
  err = 0;
 }

 if (!err) {
  r->com.from_state = r->com.state;
  r->com.to_state = state;
  r->com.state = RES_CQ_BUSY;
  if (cq)
   *cq = r;
 }

 spin_unlock_irq(mlx4_tlock(dev));

 return err;
}

static int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
     enum res_srq_states state, struct res_srq **srq)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_srq *r;
 int err = 0;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index);
 if (!r) {
  err = -ENOENT;
 } else if (r->com.owner != slave) {
  err = -EPERM;
 } else if (state == RES_SRQ_ALLOCATED) {
  if (r->com.state != RES_SRQ_HW)
   err = -EINVAL;
  else if (atomic_read(&r->ref_count))
   err = -EBUSY;
 } else if (state != RES_SRQ_HW || r->com.state != RES_SRQ_ALLOCATED) {
  err = -EINVAL;
 }

 if (!err) {
  r->com.from_state = r->com.state;
  r->com.to_state = state;
  r->com.state = RES_SRQ_BUSY;
  if (srq)
   *srq = r;
 }

 spin_unlock_irq(mlx4_tlock(dev));

 return err;
}

static void res_abort_move(struct mlx4_dev *dev, int slave,
      enum mlx4_resource type, int id)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_common *r;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[type], id);
 if (r && (r->owner == slave))
  r->state = r->from_state;
 spin_unlock_irq(mlx4_tlock(dev));
}

static void res_end_move(struct mlx4_dev *dev, int slave,
    enum mlx4_resource type, int id)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct res_common *r;

 spin_lock_irq(mlx4_tlock(dev));
 r = res_tracker_lookup(&tracker->res_tree[type], id);
 if (r && (r->owner == slave))
  r->state = r->to_state;
 spin_unlock_irq(mlx4_tlock(dev));
}

static int valid_reserved(struct mlx4_dev *dev, int slave, int qpn)
{
 return mlx4_is_qp_reserved(dev, qpn) &&
  (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn));
}

static int fw_reserved(struct mlx4_dev *dev, int qpn)
{
 return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
}

static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
   u64 in_param, u64 *out_param)
{
 int err;
 int count;
 int align;
 int base;
 int qpn;
 u8 flags;

 switch (op) {
 case RES_OP_RESERVE:
  count = get_param_l(&in_param) & 0xffffff;
  /* Turn off all unsupported QP allocation flags that the
 * slave tries to set.
 */

  flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask;
  align = get_param_h(&in_param);
  err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
  if (err)
   return err;

  err = __mlx4_qp_reserve_range(dev, count, align, &base, flags);
  if (err) {
   mlx4_release_resource(dev, slave, RES_QP, count, 0);
   return err;
  }

  err = add_res_range(dev, slave, base, count, RES_QP, 0);
  if (err) {
   mlx4_release_resource(dev, slave, RES_QP, count, 0);
   __mlx4_qp_release_range(dev, base, count);
   return err;
  }
  set_param_l(out_param, base);
  break;
 case RES_OP_MAP_ICM:
  qpn = get_param_l(&in_param) & 0x7fffff;
  if (valid_reserved(dev, slave, qpn)) {
   err = add_res_range(dev, slave, qpn, 1, RES_QP, 0);
   if (err)
    return err;
  }

  err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED,
        NULL, 1);
  if (err)
   return err;

  if (!fw_reserved(dev, qpn)) {
   err = __mlx4_qp_alloc_icm(dev, qpn);
   if (err) {
    res_abort_move(dev, slave, RES_QP, qpn);
    return err;
   }
  }

  res_end_move(dev, slave, RES_QP, qpn);
  break;

 default:
  err = -EINVAL;
  break;
 }
 return err;
}

static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
    u64 in_param, u64 *out_param)
{
 int err = -EINVAL;
 int base;
 int order;

 if (op != RES_OP_RESERVE_AND_MAP)
  return err;

 order = get_param_l(&in_param);

 err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0);
 if (err)
  return err;

 base = __mlx4_alloc_mtt_range(dev, order);
 if (base == -1) {
  mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
  return -ENOMEM;
 }

 err = add_res_range(dev, slave, base, 1, RES_MTT, order);
 if (err) {
  mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
  __mlx4_free_mtt_range(dev, base, order);
 } else {
  set_param_l(out_param, base);
 }

 return err;
}

static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
    u64 in_param, u64 *out_param)
{
 int err = -EINVAL;
 int index;
 int id;
 struct res_mpt *mpt;

 switch (op) {
 case RES_OP_RESERVE:
  err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0);
  if (err)
   break;

  index = __mlx4_mpt_reserve(dev);
  if (index == -1) {
   mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
   break;
  }
  id = index & mpt_mask(dev);

  err = add_res_range(dev, slave, id, 1, RES_MPT, index);
  if (err) {
   mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
   __mlx4_mpt_release(dev, index);
   break;
  }
  set_param_l(out_param, index);
  break;
 case RES_OP_MAP_ICM:
  index = get_param_l(&in_param);
  id = index & mpt_mask(dev);
  err = mr_res_start_move_to(dev, slave, id,
        RES_MPT_MAPPED, &mpt);
  if (err)
   return err;

  err = __mlx4_mpt_alloc_icm(dev, mpt->key);
  if (err) {
   res_abort_move(dev, slave, RES_MPT, id);
   return err;
  }

  res_end_move(dev, slave, RES_MPT, id);
  break;
 }
 return err;
}

static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
   u64 in_param, u64 *out_param)
{
 int cqn;
 int err;

 switch (op) {
 case RES_OP_RESERVE_AND_MAP:
  err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0);
  if (err)
   break;

  err = __mlx4_cq_alloc_icm(dev, &cqn);
  if (err) {
   mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
   break;
  }

  err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0);
  if (err) {
   mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
   __mlx4_cq_free_icm(dev, cqn);
   break;
  }

  set_param_l(out_param, cqn);
  break;

 default:
  err = -EINVAL;
 }

 return err;
}

static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
    u64 in_param, u64 *out_param)
{
 int srqn;
 int err;

 switch (op) {
 case RES_OP_RESERVE_AND_MAP:
  err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0);
  if (err)
   break;

  err = __mlx4_srq_alloc_icm(dev, &srqn);
  if (err) {
   mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
   break;
  }

  err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
  if (err) {
   mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
   __mlx4_srq_free_icm(dev, srqn);
   break;
  }

  set_param_l(out_param, srqn);
  break;

 default:
  err = -EINVAL;
 }

 return err;
}

static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
         u8 smac_index, u64 *mac)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *mac_list =
  &tracker->slave_list[slave].res_list[RES_MAC];
 struct mac_res *res, *tmp;

 list_for_each_entry_safe(res, tmp, mac_list, list) {
  if (res->smac_index == smac_index && res->port == (u8) port) {
   *mac = res->mac;
   return 0;
  }
 }
 return -ENOENT;
}

static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *mac_list =
  &tracker->slave_list[slave].res_list[RES_MAC];
 struct mac_res *res, *tmp;

 list_for_each_entry_safe(res, tmp, mac_list, list) {
  if (res->mac == mac && res->port == (u8) port) {
   /* mac found. update ref count */
   ++res->ref_count;
   return 0;
  }
 }

 if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
  return -EINVAL;
 res = kzalloc(sizeof(*res), GFP_KERNEL);
 if (!res) {
  mlx4_release_resource(dev, slave, RES_MAC, 1, port);
  return -ENOMEM;
 }
 res->mac = mac;
 res->port = (u8) port;
 res->smac_index = smac_index;
 res->ref_count = 1;
 list_add_tail(&res->list,
        &tracker->slave_list[slave].res_list[RES_MAC]);
 return 0;
}

static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
          int port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *mac_list =
  &tracker->slave_list[slave].res_list[RES_MAC];
 struct mac_res *res, *tmp;

 list_for_each_entry_safe(res, tmp, mac_list, list) {
  if (res->mac == mac && res->port == (u8) port) {
   if (!--res->ref_count) {
    list_del(&res->list);
    mlx4_release_resource(dev, slave, RES_MAC, 1, port);
    kfree(res);
   }
   break;
  }
 }
}

static void rem_slave_macs(struct mlx4_dev *dev, int slave)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *mac_list =
  &tracker->slave_list[slave].res_list[RES_MAC];
 struct mac_res *res, *tmp;
 int i;

 list_for_each_entry_safe(res, tmp, mac_list, list) {
  list_del(&res->list);
  /* dereference the mac the num times the slave referenced it */
  for (i = 0; i < res->ref_count; i++)
   __mlx4_unregister_mac(dev, res->port, res->mac);
  mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
  kfree(res);
 }
}

static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
    u64 in_param, u64 *out_param, int in_port)
{
 int err = -EINVAL;
 int port;
 u64 mac;
 u8 smac_index;

 if (op != RES_OP_RESERVE_AND_MAP)
  return err;

 port = !in_port ? get_param_l(out_param) : in_port;
 port = mlx4_slave_convert_port(
   dev, slave, port);

 if (port < 0)
  return -EINVAL;
 mac = in_param;

 err = __mlx4_register_mac(dev, port, mac);
 if (err >= 0) {
  smac_index = err;
  set_param_l(out_param, err);
  err = 0;
 }

 if (!err) {
  err = mac_add_to_slave(dev, slave, mac, port, smac_index);
  if (err)
   __mlx4_unregister_mac(dev, port, mac);
 }
 return err;
}

static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan,
        int port, int vlan_index)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *vlan_list =
  &tracker->slave_list[slave].res_list[RES_VLAN];
 struct vlan_res *res, *tmp;

 list_for_each_entry_safe(res, tmp, vlan_list, list) {
  if (res->vlan == vlan && res->port == (u8) port) {
   /* vlan found. update ref count */
   ++res->ref_count;
   return 0;
  }
 }

 if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port))
  return -EINVAL;
 res = kzalloc(sizeof(*res), GFP_KERNEL);
 if (!res) {
  mlx4_release_resource(dev, slave, RES_VLAN, 1, port);
  return -ENOMEM;
 }
 res->vlan = vlan;
 res->port = (u8) port;
 res->vlan_index = vlan_index;
 res->ref_count = 1;
 list_add_tail(&res->list,
        &tracker->slave_list[slave].res_list[RES_VLAN]);
 return 0;
}


static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan,
    int port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *vlan_list =
  &tracker->slave_list[slave].res_list[RES_VLAN];
 struct vlan_res *res, *tmp;

 list_for_each_entry_safe(res, tmp, vlan_list, list) {
  if (res->vlan == vlan && res->port == (u8) port) {
   if (!--res->ref_count) {
    list_del(&res->list);
    mlx4_release_resource(dev, slave, RES_VLAN,
            1, port);
    kfree(res);
   }
   break;
  }
 }
}

static void rem_slave_vlans(struct mlx4_dev *dev, int slave)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
 struct list_head *vlan_list =
  &tracker->slave_list[slave].res_list[RES_VLAN];
 struct vlan_res *res, *tmp;
 int i;

 list_for_each_entry_safe(res, tmp, vlan_list, list) {
  list_del(&res->list);
  /* dereference the vlan the num times the slave referenced it */
  for (i = 0; i < res->ref_count; i++)
   __mlx4_unregister_vlan(dev, res->port, res->vlan);
  mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port);
  kfree(res);
 }
}

static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
     u64 in_param, u64 *out_param, int in_port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
 int err;
 u16 vlan;
 int vlan_index;
 int port;

 port = !in_port ? get_param_l(out_param) : in_port;

 if (!port || op != RES_OP_RESERVE_AND_MAP)
  return -EINVAL;

 port = mlx4_slave_convert_port(
   dev, slave, port);

 if (port < 0)
  return -EINVAL;
 /* upstream kernels had NOP for reg/unreg vlan. Continue this. */
 if (!in_port && port > 0 && port <= dev->caps.num_ports) {
  slave_state[slave].old_vlan_api = true;
  return 0;
 }

 vlan = (u16) in_param;

 err = __mlx4_register_vlan(dev, port, vlan, &vlan_index);
 if (!err) {
  set_param_l(out_param, (u32) vlan_index);
  err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index);
  if (err)
   __mlx4_unregister_vlan(dev, port, vlan);
 }
 return err;
}

static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        u64 in_param, u64 *out_param, int port)
{
 u32 index;
 int err;

 if (op != RES_OP_RESERVE)
  return -EINVAL;

 err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0);
 if (err)
  return err;

 err = __mlx4_counter_alloc(dev, &index);
 if (err) {
  mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
  return err;
 }

 err = add_res_range(dev, slave, index, 1, RES_COUNTER, port);
 if (err) {
  __mlx4_counter_free(dev, index);
  mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
 } else {
  set_param_l(out_param, index);
 }

 return err;
}

static int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
      u64 in_param, u64 *out_param)
{
 u32 xrcdn;
 int err;

 if (op != RES_OP_RESERVE)
  return -EINVAL;

 err = __mlx4_xrcd_alloc(dev, &xrcdn);
 if (err)
  return err;

 err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);
 if (err)
  __mlx4_xrcd_free(dev, xrcdn);
 else
  set_param_l(out_param, xrcdn);

 return err;
}

int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,
      struct mlx4_vhcr *vhcr,
      struct mlx4_cmd_mailbox *inbox,
      struct mlx4_cmd_mailbox *outbox,
      struct mlx4_cmd_info *cmd)
{
 int err;
 int alop = vhcr->op_modifier;

 switch (vhcr->in_modifier & 0xFF) {
 case RES_QP:
  err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop,
       vhcr->in_param, &vhcr->out_param);
  break;

 case RES_MTT:
  err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop,
        vhcr->in_param, &vhcr->out_param);
  break;

 case RES_MPT:
  err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop,
        vhcr->in_param, &vhcr->out_param);
  break;

 case RES_CQ:
  err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop,
       vhcr->in_param, &vhcr->out_param);
  break;

 case RES_SRQ:
  err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop,
        vhcr->in_param, &vhcr->out_param);
  break;

 case RES_MAC:
  err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop,
        vhcr->in_param, &vhcr->out_param,
        (vhcr->in_modifier >> 8) & 0xFF);
  break;

 case RES_VLAN:
  err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop,
         vhcr->in_param, &vhcr->out_param,
         (vhcr->in_modifier >> 8) & 0xFF);
  break;

 case RES_COUNTER:
  err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop,
     vhcr->in_param, &vhcr->out_param, 0);
  break;

 case RES_XRCD:
  err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop,
          vhcr->in_param, &vhcr->out_param);
  break;

 default:
  err = -EINVAL;
  break;
 }

 return err;
}

static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
         u64 in_param)
{
 int err;
 int count;
 int base;
 int qpn;

 switch (op) {
 case RES_OP_RESERVE:
  base = get_param_l(&in_param) & 0x7fffff;
  count = get_param_h(&in_param);
  err = rem_res_range(dev, slave, base, count, RES_QP, 0);
  if (err)
   break;
  mlx4_release_resource(dev, slave, RES_QP, count, 0);
  __mlx4_qp_release_range(dev, base, count);
  break;
 case RES_OP_MAP_ICM:
  qpn = get_param_l(&in_param) & 0x7fffff;
  err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED,
        NULL, 0);
  if (err)
   return err;

  if (!fw_reserved(dev, qpn))
   __mlx4_qp_free_icm(dev, qpn);

  res_end_move(dev, slave, RES_QP, qpn);

  if (valid_reserved(dev, slave, qpn))
   err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0);
  break;
 default:
  err = -EINVAL;
  break;
 }
 return err;
}

static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
   u64 in_param, u64 *out_param)
{
 int err = -EINVAL;
 int base;
 int order;

 if (op != RES_OP_RESERVE_AND_MAP)
  return err;

 base = get_param_l(&in_param);
 order = get_param_h(&in_param);
 err = rem_res_range(dev, slave, base, 1, RES_MTT, order);
 if (!err) {
  mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
  __mlx4_free_mtt_range(dev, base, order);
 }
 return err;
}

static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
   u64 in_param)
{
 int err = -EINVAL;
 int index;
 int id;
 struct res_mpt *mpt;

 switch (op) {
 case RES_OP_RESERVE:
  index = get_param_l(&in_param);
  id = index & mpt_mask(dev);
  err = get_res(dev, slave, id, RES_MPT, &mpt);
  if (err)
   break;
  index = mpt->key;
  put_res(dev, slave, id, RES_MPT);

  err = rem_res_range(dev, slave, id, 1, RES_MPT, 0);
  if (err)
   break;
  mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
  __mlx4_mpt_release(dev, index);
  break;
 case RES_OP_MAP_ICM:
  index = get_param_l(&in_param);
  id = index & mpt_mask(dev);
  err = mr_res_start_move_to(dev, slave, id,
        RES_MPT_RESERVED, &mpt);
  if (err)
   return err;

  __mlx4_mpt_free_icm(dev, mpt->key);
  res_end_move(dev, slave, RES_MPT, id);
  break;
 default:
  err = -EINVAL;
  break;
 }
 return err;
}

static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
         u64 in_param, u64 *out_param)
{
 int cqn;
 int err;

 switch (op) {
 case RES_OP_RESERVE_AND_MAP:
  cqn = get_param_l(&in_param);
  err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0);
  if (err)
   break;

  mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
  __mlx4_cq_free_icm(dev, cqn);
  break;

 default:
  err = -EINVAL;
  break;
 }

 return err;
}

static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
   u64 in_param, u64 *out_param)
{
 int srqn;
 int err;

 switch (op) {
 case RES_OP_RESERVE_AND_MAP:
  srqn = get_param_l(&in_param);
  err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
  if (err)
   break;

  mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
  __mlx4_srq_free_icm(dev, srqn);
  break;

 default:
  err = -EINVAL;
  break;
 }

 return err;
}

static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
       u64 in_param, u64 *out_param, int in_port)
{
 int port;
 int err = 0;

 switch (op) {
 case RES_OP_RESERVE_AND_MAP:
  port = !in_port ? get_param_l(out_param) : in_port;
  port = mlx4_slave_convert_port(
    dev, slave, port);

  if (port < 0)
   return -EINVAL;
  mac_del_from_slave(dev, slave, in_param, port);
  __mlx4_unregister_mac(dev, port, in_param);
  break;
 default:
  err = -EINVAL;
  break;
 }

 return err;

}

static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
       u64 in_param, u64 *out_param, int port)
{
 struct mlx4_priv *priv = mlx4_priv(dev);
 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
 int err = 0;

 port = mlx4_slave_convert_port(
   dev, slave, port);

 if (port < 0)
  return -EINVAL;
 switch (op) {
 case RES_OP_RESERVE_AND_MAP:
  if (slave_state[slave].old_vlan_api)
   return 0;
  if (!port)
   return -EINVAL;
  vlan_del_from_slave(dev, slave, in_param, port);
  __mlx4_unregister_vlan(dev, port, in_param);
  break;
 default:
  err = -EINVAL;
  break;
 }

 return err;
}

static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
       u64 in_param, u64 *out_param)
{
 int index;
 int err;

 if (op != RES_OP_RESERVE)
  return -EINVAL;

 index = get_param_l(&in_param);
 if (index == MLX4_SINK_COUNTER_INDEX(dev))
  return 0;

 err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0);
 if (err)
  return err;

 __mlx4_counter_free(dev, index);
 mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);

 return err;
}

static int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
     u64 in_param, u64 *out_param)
{
 int xrcdn;
 int err;

 if (op != RES_OP_RESERVE)
  return -EINVAL;

 xrcdn = get_param_l(&in_param);
 err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);
 if (err)
  return err;

 __mlx4_xrcd_free(dev, xrcdn);

 return err;
}

int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,
     struct mlx4_vhcr *vhcr,
     struct mlx4_cmd_mailbox *inbox,
     struct mlx4_cmd_mailbox *outbox,
     struct mlx4_cmd_info *cmd)
{
 int err = -EINVAL;
 int alop = vhcr->op_modifier;

 switch (vhcr->in_modifier & 0xFF) {
 case RES_QP:
  err = qp_free_res(dev, slave, vhcr->op_modifier, alop,
      vhcr->in_param);
  break;

 case RES_MTT:
  err = mtt_free_res(dev, slave, vhcr->op_modifier, alop,
       vhcr->in_param, &vhcr->out_param);
  break;

 case RES_MPT:
  err = mpt_free_res(dev, slave, vhcr->op_modifier, alop,
       vhcr->in_param);
  break;

 case RES_CQ:
  err = cq_free_res(dev, slave, vhcr->op_modifier, alop,
      vhcr->in_param, &vhcr->out_param);
  break;

 case RES_SRQ:
  err = srq_free_res(dev, slave, vhcr->op_modifier, alop,
       vhcr->in_param, &vhcr->out_param);
  break;

 case RES_MAC:
  err = mac_free_res(dev, slave, vhcr->op_modifier, alop,
       vhcr->in_param, &vhcr->out_param,
       (vhcr->in_modifier >> 8) & 0xFF);
  break;

 case RES_VLAN:
  err = vlan_free_res(dev, slave, vhcr->op_modifier, alop,
        vhcr->in_param, &vhcr->out_param,
        (vhcr->in_modifier >> 8) & 0xFF);
  break;

 case RES_COUNTER:
  err = counter_free_res(dev, slave, vhcr->op_modifier, alop,
           vhcr->in_param, &vhcr->out_param);
  break;

 case RES_XRCD:
  err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop,
         vhcr->in_param, &vhcr->out_param);
  break;

 default:
  break;
 }
 return err;
}

/* ugly but other choices are uglier */
static int mr_phys_mpt(struct mlx4_mpt_entry *mpt)
{
 return (be32_to_cpu(mpt->flags) >> 9) & 1;
}

static int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt)
{
 return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8;
}

static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt)
{
 return be32_to_cpu(mpt->mtt_sz);
}

static u32 mr_get_pd(struct mlx4_mpt_entry *mpt)
{
 return be32_to_cpu(mpt->pd_flags) & 0x00ffffff;
}

static int mr_is_fmr(struct mlx4_mpt_entry *mpt)
{
 return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG;
}

static int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt)
{
 return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE;
}

static int mr_is_region(struct mlx4_mpt_entry *mpt)
{
 return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION;
}

static int qp_get_mtt_addr(struct mlx4_qp_context *qpc)
{
 return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8;
}

static int srq_get_mtt_addr(struct mlx4_srq_context *srqc)
{
 return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8;
}

static int qp_get_mtt_size(struct mlx4_qp_context *qpc)
{
 int page_shift = (qpc->log_page_size & 0x3f) + 12;
 int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf;
 int log_sq_sride = qpc->sq_size_stride & 7;
 int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf;
 int log_rq_stride = qpc->rq_size_stride & 7;
 int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1;
 int rss = (be32_to_cpu(qpc->flags) >> 13) & 1;
 u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
 int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0;
 int sq_size;
 int rq_size;
 int total_pages;
 int total_mem;
 int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f;
 int tot;

 sq_size = 1 << (log_sq_size + log_sq_sride + 4);
 rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4));
 total_mem = sq_size + rq_size;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=99 H=96 G=97

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.