Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 1 Nov 2011 17:51:38 +0000 (10:51 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 1 Nov 2011 17:51:38 +0000 (10:51 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: (62 commits)
  mlx4_core: Deprecate log_num_vlan module param
  IB/mlx4: Don't set VLAN in IBoE WQEs' control segment
  IB/mlx4: Enable 4K mtu for IBoE
  RDMA/cxgb4: Mark QP in error before disabling the queue in firmware
  RDMA/cxgb4: Serialize calls to CQ's comp_handler
  RDMA/cxgb3: Serialize calls to CQ's comp_handler
  IB/qib: Fix issue with link states and QSFP cables
  IB/mlx4: Configure extended active speeds
  mlx4_core: Add extended port capabilities support
  IB/qib: Hold links until tuning data is available
  IB/qib: Clean up checkpatch issue
  IB/qib: Remove s_lock around header validation
  IB/qib: Precompute timeout jiffies to optimize latency
  IB/qib: Use RCU for qpn lookup
  IB/qib: Eliminate divide/mod in converting idx to egr buf pointer
  IB/qib: Decode path MTU optimization
  IB/qib: Optimize RC/UC code by IB operation
  IPoIB: Use the right function to do DMA unmap pages
  RDMA/cxgb4: Use correct QID in insert_recv_cqe()
  RDMA/cxgb4: Make sure flush CQ entries are collected on connection close
  ...

13 files changed:
1  2 
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/fw.h
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/mellanox/mlx4/pd.c
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/srq.c
include/linux/mlx4/device.h

Simple merge
index 1ad1f6029af80a3fd84dd0071fbdefb57de2892a,0000000000000000000000000000000000000000..869a2c220a7b4b7c6b727a1696ea94070edab334
mode 100644,000000..100644
--- /dev/null
@@@ -1,842 -1,0 +1,842 @@@
-               pci_free_consistent(dev->pdev, PAGE_SIZE,
 +/*
 + * 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/interrupt.h>
 +#include <linux/slab.h>
 +#include <linux/mm.h>
 +#include <linux/dma-mapping.h>
 +
 +#include <linux/mlx4/cmd.h>
 +
 +#include "mlx4.h"
 +#include "fw.h"
 +
 +enum {
 +      MLX4_IRQNAME_SIZE       = 32
 +};
 +
 +enum {
 +      MLX4_NUM_ASYNC_EQE      = 0x100,
 +      MLX4_NUM_SPARE_EQE      = 0x80,
 +      MLX4_EQ_ENTRY_SIZE      = 0x20
 +};
 +
 +/*
 + * Must be packed because start is 64 bits but only aligned to 32 bits.
 + */
 +struct mlx4_eq_context {
 +      __be32                  flags;
 +      u16                     reserved1[3];
 +      __be16                  page_offset;
 +      u8                      log_eq_size;
 +      u8                      reserved2[4];
 +      u8                      eq_period;
 +      u8                      reserved3;
 +      u8                      eq_max_count;
 +      u8                      reserved4[3];
 +      u8                      intr;
 +      u8                      log_page_size;
 +      u8                      reserved5[2];
 +      u8                      mtt_base_addr_h;
 +      __be32                  mtt_base_addr_l;
 +      u32                     reserved6[2];
 +      __be32                  consumer_index;
 +      __be32                  producer_index;
 +      u32                     reserved7[4];
 +};
 +
 +#define MLX4_EQ_STATUS_OK        ( 0 << 28)
 +#define MLX4_EQ_STATUS_WRITE_FAIL  (10 << 28)
 +#define MLX4_EQ_OWNER_SW         ( 0 << 24)
 +#define MLX4_EQ_OWNER_HW         ( 1 << 24)
 +#define MLX4_EQ_FLAG_EC                  ( 1 << 18)
 +#define MLX4_EQ_FLAG_OI                  ( 1 << 17)
 +#define MLX4_EQ_STATE_ARMED      ( 9 <<  8)
 +#define MLX4_EQ_STATE_FIRED      (10 <<  8)
 +#define MLX4_EQ_STATE_ALWAYS_ARMED (11 <<  8)
 +
 +#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG)         | \
 +                             (1ull << MLX4_EVENT_TYPE_COMM_EST)           | \
 +                             (1ull << MLX4_EVENT_TYPE_SQ_DRAINED)         | \
 +                             (1ull << MLX4_EVENT_TYPE_CQ_ERROR)           | \
 +                             (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR)     | \
 +                             (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR)    | \
 +                             (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED)    | \
 +                             (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
 +                             (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
 +                             (1ull << MLX4_EVENT_TYPE_PORT_CHANGE)        | \
 +                             (1ull << MLX4_EVENT_TYPE_ECC_DETECT)         | \
 +                             (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
 +                             (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
 +                             (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)          | \
 +                             (1ull << MLX4_EVENT_TYPE_CMD))
 +
 +struct mlx4_eqe {
 +      u8                      reserved1;
 +      u8                      type;
 +      u8                      reserved2;
 +      u8                      subtype;
 +      union {
 +              u32             raw[6];
 +              struct {
 +                      __be32  cqn;
 +              } __packed comp;
 +              struct {
 +                      u16     reserved1;
 +                      __be16  token;
 +                      u32     reserved2;
 +                      u8      reserved3[3];
 +                      u8      status;
 +                      __be64  out_param;
 +              } __packed cmd;
 +              struct {
 +                      __be32  qpn;
 +              } __packed qp;
 +              struct {
 +                      __be32  srqn;
 +              } __packed srq;
 +              struct {
 +                      __be32  cqn;
 +                      u32     reserved1;
 +                      u8      reserved2[3];
 +                      u8      syndrome;
 +              } __packed cq_err;
 +              struct {
 +                      u32     reserved1[2];
 +                      __be32  port;
 +              } __packed port_change;
 +      }                       event;
 +      u8                      reserved3[3];
 +      u8                      owner;
 +} __packed;
 +
 +static void eq_set_ci(struct mlx4_eq *eq, int req_not)
 +{
 +      __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) |
 +                                             req_not << 31),
 +                   eq->doorbell);
 +      /* We still want ordering, just not swabbing, so add a barrier */
 +      mb();
 +}
 +
 +static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry)
 +{
 +      unsigned long off = (entry & (eq->nent - 1)) * MLX4_EQ_ENTRY_SIZE;
 +      return eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE;
 +}
 +
 +static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq)
 +{
 +      struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index);
 +      return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe;
 +}
 +
 +static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
 +{
 +      struct mlx4_eqe *eqe;
 +      int cqn;
 +      int eqes_found = 0;
 +      int set_ci = 0;
 +      int port;
 +
 +      while ((eqe = next_eqe_sw(eq))) {
 +              /*
 +               * Make sure we read EQ entry contents after we've
 +               * checked the ownership bit.
 +               */
 +              rmb();
 +
 +              switch (eqe->type) {
 +              case MLX4_EVENT_TYPE_COMP:
 +                      cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff;
 +                      mlx4_cq_completion(dev, cqn);
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_PATH_MIG:
 +              case MLX4_EVENT_TYPE_COMM_EST:
 +              case MLX4_EVENT_TYPE_SQ_DRAINED:
 +              case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE:
 +              case MLX4_EVENT_TYPE_WQ_CATAS_ERROR:
 +              case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
 +              case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
 +              case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
 +                      mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
 +                                    eqe->type);
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_SRQ_LIMIT:
 +              case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
 +                      mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff,
 +                                    eqe->type);
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_CMD:
 +                      mlx4_cmd_event(dev,
 +                                     be16_to_cpu(eqe->event.cmd.token),
 +                                     eqe->event.cmd.status,
 +                                     be64_to_cpu(eqe->event.cmd.out_param));
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_PORT_CHANGE:
 +                      port = be32_to_cpu(eqe->event.port_change.port) >> 28;
 +                      if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
 +                              mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
 +                                                  port);
 +                              mlx4_priv(dev)->sense.do_sense_port[port] = 1;
 +                      } else {
 +                              mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP,
 +                                                  port);
 +                              mlx4_priv(dev)->sense.do_sense_port[port] = 0;
 +                      }
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_CQ_ERROR:
 +                      mlx4_warn(dev, "CQ %s on CQN %06x\n",
 +                                eqe->event.cq_err.syndrome == 1 ?
 +                                "overrun" : "access violation",
 +                                be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff);
 +                      mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn),
 +                                    eqe->type);
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_EQ_OVERFLOW:
 +                      mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn);
 +                      break;
 +
 +              case MLX4_EVENT_TYPE_EEC_CATAS_ERROR:
 +              case MLX4_EVENT_TYPE_ECC_DETECT:
 +              default:
 +                      mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at index %u\n",
 +                                eqe->type, eqe->subtype, eq->eqn, eq->cons_index);
 +                      break;
 +              }
 +
 +              ++eq->cons_index;
 +              eqes_found = 1;
 +              ++set_ci;
 +
 +              /*
 +               * The HCA will think the queue has overflowed if we
 +               * don't tell it we've been processing events.  We
 +               * create our EQs with MLX4_NUM_SPARE_EQE extra
 +               * entries, so we must update our consumer index at
 +               * least that often.
 +               */
 +              if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) {
 +                      eq_set_ci(eq, 0);
 +                      set_ci = 0;
 +              }
 +      }
 +
 +      eq_set_ci(eq, 1);
 +
 +      return eqes_found;
 +}
 +
 +static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr)
 +{
 +      struct mlx4_dev *dev = dev_ptr;
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int work = 0;
 +      int i;
 +
 +      writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
 +
 +      for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 +              work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
 +
 +      return IRQ_RETVAL(work);
 +}
 +
 +static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
 +{
 +      struct mlx4_eq  *eq  = eq_ptr;
 +      struct mlx4_dev *dev = eq->dev;
 +
 +      mlx4_eq_int(dev, eq);
 +
 +      /* MSI-X vectors always belong to us */
 +      return IRQ_HANDLED;
 +}
 +
 +static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
 +                      int eq_num)
 +{
 +      return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num,
 +                      0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B);
 +}
 +
 +static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                       int eq_num)
 +{
 +      return mlx4_cmd(dev, mailbox->dma, eq_num, 0, MLX4_CMD_SW2HW_EQ,
 +                      MLX4_CMD_TIME_CLASS_A);
 +}
 +
 +static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                       int eq_num)
 +{
 +      return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, 0, MLX4_CMD_HW2SW_EQ,
 +                          MLX4_CMD_TIME_CLASS_A);
 +}
 +
 +static int mlx4_num_eq_uar(struct mlx4_dev *dev)
 +{
 +      /*
 +       * Each UAR holds 4 EQ doorbells.  To figure out how many UARs
 +       * we need to map, take the difference of highest index and
 +       * the lowest index we'll use and add 1.
 +       */
 +      return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs +
 +               dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1;
 +}
 +
 +static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int index;
 +
 +      index = eq->eqn / 4 - dev->caps.reserved_eqs / 4;
 +
 +      if (!priv->eq_table.uar_map[index]) {
 +              priv->eq_table.uar_map[index] =
 +                      ioremap(pci_resource_start(dev->pdev, 2) +
 +                              ((eq->eqn / 4) << PAGE_SHIFT),
 +                              PAGE_SIZE);
 +              if (!priv->eq_table.uar_map[index]) {
 +                      mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n",
 +                               eq->eqn);
 +                      return NULL;
 +              }
 +      }
 +
 +      return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
 +}
 +
 +static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
 +                        u8 intr, struct mlx4_eq *eq)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_cmd_mailbox *mailbox;
 +      struct mlx4_eq_context *eq_context;
 +      int npages;
 +      u64 *dma_list = NULL;
 +      dma_addr_t t;
 +      u64 mtt_addr;
 +      int err = -ENOMEM;
 +      int i;
 +
 +      eq->dev   = dev;
 +      eq->nent  = roundup_pow_of_two(max(nent, 2));
 +      npages = PAGE_ALIGN(eq->nent * MLX4_EQ_ENTRY_SIZE) / PAGE_SIZE;
 +
 +      eq->page_list = kmalloc(npages * sizeof *eq->page_list,
 +                              GFP_KERNEL);
 +      if (!eq->page_list)
 +              goto err_out;
 +
 +      for (i = 0; i < npages; ++i)
 +              eq->page_list[i].buf = NULL;
 +
 +      dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
 +      if (!dma_list)
 +              goto err_out_free;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              goto err_out_free;
 +      eq_context = mailbox->buf;
 +
 +      for (i = 0; i < npages; ++i) {
 +              eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
 +                                                        PAGE_SIZE, &t, GFP_KERNEL);
 +              if (!eq->page_list[i].buf)
 +                      goto err_out_free_pages;
 +
 +              dma_list[i] = t;
 +              eq->page_list[i].map = t;
 +
 +              memset(eq->page_list[i].buf, 0, PAGE_SIZE);
 +      }
 +
 +      eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap);
 +      if (eq->eqn == -1)
 +              goto err_out_free_pages;
 +
 +      eq->doorbell = mlx4_get_eq_uar(dev, eq);
 +      if (!eq->doorbell) {
 +              err = -ENOMEM;
 +              goto err_out_free_eq;
 +      }
 +
 +      err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt);
 +      if (err)
 +              goto err_out_free_eq;
 +
 +      err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list);
 +      if (err)
 +              goto err_out_free_mtt;
 +
 +      memset(eq_context, 0, sizeof *eq_context);
 +      eq_context->flags         = cpu_to_be32(MLX4_EQ_STATUS_OK   |
 +                                              MLX4_EQ_STATE_ARMED);
 +      eq_context->log_eq_size   = ilog2(eq->nent);
 +      eq_context->intr          = intr;
 +      eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT;
 +
 +      mtt_addr = mlx4_mtt_addr(dev, &eq->mtt);
 +      eq_context->mtt_base_addr_h = mtt_addr >> 32;
 +      eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
 +
 +      err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn);
 +      if (err) {
 +              mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err);
 +              goto err_out_free_mtt;
 +      }
 +
 +      kfree(dma_list);
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +
 +      eq->cons_index = 0;
 +
 +      return err;
 +
 +err_out_free_mtt:
 +      mlx4_mtt_cleanup(dev, &eq->mtt);
 +
 +err_out_free_eq:
 +      mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn);
 +
 +err_out_free_pages:
 +      for (i = 0; i < npages; ++i)
 +              if (eq->page_list[i].buf)
 +                      dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 +                                        eq->page_list[i].buf,
 +                                        eq->page_list[i].map);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +
 +err_out_free:
 +      kfree(eq->page_list);
 +      kfree(dma_list);
 +
 +err_out:
 +      return err;
 +}
 +
 +static void mlx4_free_eq(struct mlx4_dev *dev,
 +                       struct mlx4_eq *eq)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_cmd_mailbox *mailbox;
 +      int err;
 +      int npages = PAGE_ALIGN(MLX4_EQ_ENTRY_SIZE * eq->nent) / PAGE_SIZE;
 +      int i;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return;
 +
 +      err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn);
 +      if (err)
 +              mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err);
 +
 +      if (0) {
 +              mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
 +              for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) {
 +                      if (i % 4 == 0)
 +                              pr_cont("[%02x] ", i * 4);
 +                      pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4));
 +                      if ((i + 1) % 4 == 0)
 +                              pr_cont("\n");
 +              }
 +      }
 +
 +      mlx4_mtt_cleanup(dev, &eq->mtt);
 +      for (i = 0; i < npages; ++i)
++              dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 +                                  eq->page_list[i].buf,
 +                                  eq->page_list[i].map);
 +
 +      kfree(eq->page_list);
 +      mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn);
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +}
 +
 +static void mlx4_free_irqs(struct mlx4_dev *dev)
 +{
 +      struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table;
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int     i, vec;
 +
 +      if (eq_table->have_irq)
 +              free_irq(dev->pdev->irq, dev);
 +
 +      for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 +              if (eq_table->eq[i].have_irq) {
 +                      free_irq(eq_table->eq[i].irq, eq_table->eq + i);
 +                      eq_table->eq[i].have_irq = 0;
 +              }
 +
 +      for (i = 0; i < dev->caps.comp_pool; i++) {
 +              /*
 +               * Freeing the assigned irq's
 +               * all bits should be 0, but we need to validate
 +               */
 +              if (priv->msix_ctl.pool_bm & 1ULL << i) {
 +                      /* NO need protecting*/
 +                      vec = dev->caps.num_comp_vectors + 1 + i;
 +                      free_irq(priv->eq_table.eq[vec].irq,
 +                               &priv->eq_table.eq[vec]);
 +              }
 +      }
 +
 +
 +      kfree(eq_table->irq_names);
 +}
 +
 +static int mlx4_map_clr_int(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) +
 +                               priv->fw.clr_int_base, MLX4_CLR_INT_SIZE);
 +      if (!priv->clr_base) {
 +              mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n");
 +              return -ENOMEM;
 +      }
 +
 +      return 0;
 +}
 +
 +static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      iounmap(priv->clr_base);
 +}
 +
 +int mlx4_alloc_eq_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs,
 +                                  sizeof *priv->eq_table.eq, GFP_KERNEL);
 +      if (!priv->eq_table.eq)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +
 +void mlx4_free_eq_table(struct mlx4_dev *dev)
 +{
 +      kfree(mlx4_priv(dev)->eq_table.eq);
 +}
 +
 +int mlx4_init_eq_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int err;
 +      int i;
 +
 +      priv->eq_table.uar_map = kcalloc(sizeof *priv->eq_table.uar_map,
 +                                       mlx4_num_eq_uar(dev), GFP_KERNEL);
 +      if (!priv->eq_table.uar_map) {
 +              err = -ENOMEM;
 +              goto err_out_free;
 +      }
 +
 +      err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs,
 +                             dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0);
 +      if (err)
 +              goto err_out_free;
 +
 +      for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
 +              priv->eq_table.uar_map[i] = NULL;
 +
 +      err = mlx4_map_clr_int(dev);
 +      if (err)
 +              goto err_out_bitmap;
 +
 +      priv->eq_table.clr_mask =
 +              swab32(1 << (priv->eq_table.inta_pin & 31));
 +      priv->eq_table.clr_int  = priv->clr_base +
 +              (priv->eq_table.inta_pin < 32 ? 4 : 0);
 +
 +      priv->eq_table.irq_names =
 +              kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 +
 +                                           dev->caps.comp_pool),
 +                      GFP_KERNEL);
 +      if (!priv->eq_table.irq_names) {
 +              err = -ENOMEM;
 +              goto err_out_bitmap;
 +      }
 +
 +      for (i = 0; i < dev->caps.num_comp_vectors; ++i) {
 +              err = mlx4_create_eq(dev, dev->caps.num_cqs -
 +                                        dev->caps.reserved_cqs +
 +                                        MLX4_NUM_SPARE_EQE,
 +                                   (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
 +                                   &priv->eq_table.eq[i]);
 +              if (err) {
 +                      --i;
 +                      goto err_out_unmap;
 +              }
 +      }
 +
 +      err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
 +                           (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0,
 +                           &priv->eq_table.eq[dev->caps.num_comp_vectors]);
 +      if (err)
 +              goto err_out_comp;
 +
 +      /*if additional completion vectors poolsize is 0 this loop will not run*/
 +      for (i = dev->caps.num_comp_vectors + 1;
 +            i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) {
 +
 +              err = mlx4_create_eq(dev, dev->caps.num_cqs -
 +                                        dev->caps.reserved_cqs +
 +                                        MLX4_NUM_SPARE_EQE,
 +                                   (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
 +                                   &priv->eq_table.eq[i]);
 +              if (err) {
 +                      --i;
 +                      goto err_out_unmap;
 +              }
 +      }
 +
 +
 +      if (dev->flags & MLX4_FLAG_MSI_X) {
 +              const char *eq_name;
 +
 +              for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) {
 +                      if (i < dev->caps.num_comp_vectors) {
 +                              snprintf(priv->eq_table.irq_names +
 +                                       i * MLX4_IRQNAME_SIZE,
 +                                       MLX4_IRQNAME_SIZE,
 +                                       "mlx4-comp-%d@pci:%s", i,
 +                                       pci_name(dev->pdev));
 +                      } else {
 +                              snprintf(priv->eq_table.irq_names +
 +                                       i * MLX4_IRQNAME_SIZE,
 +                                       MLX4_IRQNAME_SIZE,
 +                                       "mlx4-async@pci:%s",
 +                                       pci_name(dev->pdev));
 +                      }
 +
 +                      eq_name = priv->eq_table.irq_names +
 +                                i * MLX4_IRQNAME_SIZE;
 +                      err = request_irq(priv->eq_table.eq[i].irq,
 +                                        mlx4_msi_x_interrupt, 0, eq_name,
 +                                        priv->eq_table.eq + i);
 +                      if (err)
 +                              goto err_out_async;
 +
 +                      priv->eq_table.eq[i].have_irq = 1;
 +              }
 +      } else {
 +              snprintf(priv->eq_table.irq_names,
 +                       MLX4_IRQNAME_SIZE,
 +                       DRV_NAME "@pci:%s",
 +                       pci_name(dev->pdev));
 +              err = request_irq(dev->pdev->irq, mlx4_interrupt,
 +                                IRQF_SHARED, priv->eq_table.irq_names, dev);
 +              if (err)
 +                      goto err_out_async;
 +
 +              priv->eq_table.have_irq = 1;
 +      }
 +
 +      err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
 +                        priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
 +      if (err)
 +              mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
 +                         priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err);
 +
 +      for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 +              eq_set_ci(&priv->eq_table.eq[i], 1);
 +
 +      return 0;
 +
 +err_out_async:
 +      mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]);
 +
 +err_out_comp:
 +      i = dev->caps.num_comp_vectors - 1;
 +
 +err_out_unmap:
 +      while (i >= 0) {
 +              mlx4_free_eq(dev, &priv->eq_table.eq[i]);
 +              --i;
 +      }
 +      mlx4_unmap_clr_int(dev);
 +      mlx4_free_irqs(dev);
 +
 +err_out_bitmap:
 +      mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
 +
 +err_out_free:
 +      kfree(priv->eq_table.uar_map);
 +
 +      return err;
 +}
 +
 +void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int i;
 +
 +      mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
 +                  priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
 +
 +      mlx4_free_irqs(dev);
 +
 +      for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i)
 +              mlx4_free_eq(dev, &priv->eq_table.eq[i]);
 +
 +      mlx4_unmap_clr_int(dev);
 +
 +      for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
 +              if (priv->eq_table.uar_map[i])
 +                      iounmap(priv->eq_table.uar_map[i]);
 +
 +      mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
 +
 +      kfree(priv->eq_table.uar_map);
 +}
 +
 +/* A test that verifies that we can accept interrupts on all
 + * the irq vectors of the device.
 + * Interrupts are checked using the NOP command.
 + */
 +int mlx4_test_interrupts(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int i;
 +      int err;
 +
 +      err = mlx4_NOP(dev);
 +      /* When not in MSI_X, there is only one irq to check */
 +      if (!(dev->flags & MLX4_FLAG_MSI_X))
 +              return err;
 +
 +      /* A loop over all completion vectors, for each vector we will check
 +       * whether it works by mapping command completions to that vector
 +       * and performing a NOP command
 +       */
 +      for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) {
 +              /* Temporary use polling for command completions */
 +              mlx4_cmd_use_polling(dev);
 +
 +              /* Map the new eq to handle all asyncronous events */
 +              err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
 +                                priv->eq_table.eq[i].eqn);
 +              if (err) {
 +                      mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
 +                      mlx4_cmd_use_events(dev);
 +                      break;
 +              }
 +
 +              /* Go back to using events */
 +              mlx4_cmd_use_events(dev);
 +              err = mlx4_NOP(dev);
 +      }
 +
 +      /* Return to default */
 +      mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
 +                  priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
 +      return err;
 +}
 +EXPORT_SYMBOL(mlx4_test_interrupts);
 +
 +int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector)
 +{
 +
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int vec = 0, err = 0, i;
 +
 +      spin_lock(&priv->msix_ctl.pool_lock);
 +      for (i = 0; !vec && i < dev->caps.comp_pool; i++) {
 +              if (~priv->msix_ctl.pool_bm & 1ULL << i) {
 +                      priv->msix_ctl.pool_bm |= 1ULL << i;
 +                      vec = dev->caps.num_comp_vectors + 1 + i;
 +                      snprintf(priv->eq_table.irq_names +
 +                                      vec * MLX4_IRQNAME_SIZE,
 +                                      MLX4_IRQNAME_SIZE, "%s", name);
 +                      err = request_irq(priv->eq_table.eq[vec].irq,
 +                                        mlx4_msi_x_interrupt, 0,
 +                                        &priv->eq_table.irq_names[vec<<5],
 +                                        priv->eq_table.eq + vec);
 +                      if (err) {
 +                              /*zero out bit by fliping it*/
 +                              priv->msix_ctl.pool_bm ^= 1 << i;
 +                              vec = 0;
 +                              continue;
 +                              /*we dont want to break here*/
 +                      }
 +                      eq_set_ci(&priv->eq_table.eq[vec], 1);
 +              }
 +      }
 +      spin_unlock(&priv->msix_ctl.pool_lock);
 +
 +      if (vec) {
 +              *vector = vec;
 +      } else {
 +              *vector = 0;
 +              err = (i == dev->caps.comp_pool) ? -ENOSPC : err;
 +      }
 +      return err;
 +}
 +EXPORT_SYMBOL(mlx4_assign_eq);
 +
 +void mlx4_release_eq(struct mlx4_dev *dev, int vec)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      /*bm index*/
 +      int i = vec - dev->caps.num_comp_vectors - 1;
 +
 +      if (likely(i >= 0)) {
 +              /*sanity check , making sure were not trying to free irq's
 +                Belonging to a legacy EQ*/
 +              spin_lock(&priv->msix_ctl.pool_lock);
 +              if (priv->msix_ctl.pool_bm & 1ULL << i) {
 +                      free_irq(priv->eq_table.eq[vec].irq,
 +                               &priv->eq_table.eq[vec]);
 +                      priv->msix_ctl.pool_bm &= ~(1ULL << i);
 +              }
 +              spin_unlock(&priv->msix_ctl.pool_lock);
 +      }
 +
 +}
 +EXPORT_SYMBOL(mlx4_release_eq);
 +
index ed452ddfe3426606ac651cf22d6136f77e364857,0000000000000000000000000000000000000000..abdfbacab4a68eba2a32b1cf104f448cb09247af
mode 100644,000000..100644
--- /dev/null
@@@ -1,945 -1,0 +1,951 @@@
 +/*
 + * 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/mlx4/cmd.h>
 +#include <linux/cache.h>
 +
 +#include "fw.h"
 +#include "icm.h"
 +
 +enum {
 +      MLX4_COMMAND_INTERFACE_MIN_REV          = 2,
 +      MLX4_COMMAND_INTERFACE_MAX_REV          = 3,
 +      MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS    = 3,
 +};
 +
 +extern void __buggy_use_of_MLX4_GET(void);
 +extern void __buggy_use_of_MLX4_PUT(void);
 +
 +static int enable_qos;
 +module_param(enable_qos, bool, 0444);
 +MODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)");
 +
 +#define MLX4_GET(dest, source, offset)                                      \
 +      do {                                                          \
 +              void *__p = (char *) (source) + (offset);             \
 +              switch (sizeof (dest)) {                              \
 +              case 1: (dest) = *(u8 *) __p;       break;            \
 +              case 2: (dest) = be16_to_cpup(__p); break;            \
 +              case 4: (dest) = be32_to_cpup(__p); break;            \
 +              case 8: (dest) = be64_to_cpup(__p); break;            \
 +              default: __buggy_use_of_MLX4_GET();                   \
 +              }                                                     \
 +      } while (0)
 +
 +#define MLX4_PUT(dest, source, offset)                                      \
 +      do {                                                          \
 +              void *__d = ((char *) (dest) + (offset));             \
 +              switch (sizeof(source)) {                             \
 +              case 1: *(u8 *) __d = (source);                break; \
 +              case 2: *(__be16 *) __d = cpu_to_be16(source); break; \
 +              case 4: *(__be32 *) __d = cpu_to_be32(source); break; \
 +              case 8: *(__be64 *) __d = cpu_to_be64(source); break; \
 +              default: __buggy_use_of_MLX4_PUT();                   \
 +              }                                                     \
 +      } while (0)
 +
 +static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
 +{
 +      static const char *fname[] = {
 +              [ 0] = "RC transport",
 +              [ 1] = "UC transport",
 +              [ 2] = "UD transport",
 +              [ 3] = "XRC transport",
 +              [ 4] = "reliable multicast",
 +              [ 5] = "FCoIB support",
 +              [ 6] = "SRQ support",
 +              [ 7] = "IPoIB checksum offload",
 +              [ 8] = "P_Key violation counter",
 +              [ 9] = "Q_Key violation counter",
 +              [10] = "VMM",
 +              [12] = "DPDP",
 +              [15] = "Big LSO headers",
 +              [16] = "MW support",
 +              [17] = "APM support",
 +              [18] = "Atomic ops support",
 +              [19] = "Raw multicast support",
 +              [20] = "Address vector port checking support",
 +              [21] = "UD multicast support",
 +              [24] = "Demand paging support",
 +              [25] = "Router support",
 +              [30] = "IBoE support",
 +              [32] = "Unicast loopback support",
 +              [34] = "FCS header control",
 +              [38] = "Wake On LAN support",
 +              [40] = "UDP RSS support",
 +              [41] = "Unicast VEP steering support",
 +              [42] = "Multicast VEP steering support",
 +              [48] = "Counters support",
 +      };
 +      int i;
 +
 +      mlx4_dbg(dev, "DEV_CAP flags:\n");
 +      for (i = 0; i < ARRAY_SIZE(fname); ++i)
 +              if (fname[i] && (flags & (1LL << i)))
 +                      mlx4_dbg(dev, "    %s\n", fname[i]);
 +}
 +
 +int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 *inbox;
 +      int err = 0;
 +
 +#define MOD_STAT_CFG_IN_SIZE          0x100
 +
 +#define MOD_STAT_CFG_PG_SZ_M_OFFSET   0x002
 +#define MOD_STAT_CFG_PG_SZ_OFFSET     0x003
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +      inbox = mailbox->buf;
 +
 +      memset(inbox, 0, MOD_STAT_CFG_IN_SIZE);
 +
 +      MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET);
 +      MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET);
 +
 +      err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG,
 +                      MLX4_CMD_TIME_CLASS_A);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 *outbox;
 +      u8 field;
 +      u32 field32, flags, ext_flags;
 +      u16 size;
 +      u16 stat_rate;
 +      int err;
 +      int i;
 +
 +#define QUERY_DEV_CAP_OUT_SIZE                       0x100
 +#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET               0x10
 +#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET                0x11
 +#define QUERY_DEV_CAP_RSVD_QP_OFFSET          0x12
 +#define QUERY_DEV_CAP_MAX_QP_OFFSET           0x13
 +#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET         0x14
 +#define QUERY_DEV_CAP_MAX_SRQ_OFFSET          0x15
 +#define QUERY_DEV_CAP_RSVD_EEC_OFFSET         0x16
 +#define QUERY_DEV_CAP_MAX_EEC_OFFSET          0x17
 +#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET                0x19
 +#define QUERY_DEV_CAP_RSVD_CQ_OFFSET          0x1a
 +#define QUERY_DEV_CAP_MAX_CQ_OFFSET           0x1b
 +#define QUERY_DEV_CAP_MAX_MPT_OFFSET          0x1d
 +#define QUERY_DEV_CAP_RSVD_EQ_OFFSET          0x1e
 +#define QUERY_DEV_CAP_MAX_EQ_OFFSET           0x1f
 +#define QUERY_DEV_CAP_RSVD_MTT_OFFSET         0x20
 +#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET               0x21
 +#define QUERY_DEV_CAP_RSVD_MRW_OFFSET         0x22
 +#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET      0x23
 +#define QUERY_DEV_CAP_MAX_AV_OFFSET           0x27
 +#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET               0x29
 +#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET               0x2b
 +#define QUERY_DEV_CAP_MAX_GSO_OFFSET          0x2d
 +#define QUERY_DEV_CAP_MAX_RDMA_OFFSET         0x2f
 +#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET          0x33
 +#define QUERY_DEV_CAP_ACK_DELAY_OFFSET                0x35
 +#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET                0x36
 +#define QUERY_DEV_CAP_VL_PORT_OFFSET          0x37
 +#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET               0x38
 +#define QUERY_DEV_CAP_MAX_GID_OFFSET          0x3b
 +#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET     0x3c
 +#define QUERY_DEV_CAP_MAX_PKEY_OFFSET         0x3f
 +#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET                0x40
 +#define QUERY_DEV_CAP_FLAGS_OFFSET            0x44
 +#define QUERY_DEV_CAP_RSVD_UAR_OFFSET         0x48
 +#define QUERY_DEV_CAP_UAR_SZ_OFFSET           0x49
 +#define QUERY_DEV_CAP_PAGE_SZ_OFFSET          0x4b
 +#define QUERY_DEV_CAP_BF_OFFSET                       0x4c
 +#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET    0x4d
 +#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET 0x4e
 +#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET 0x4f
 +#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET                0x51
 +#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET   0x52
 +#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET                0x55
 +#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET   0x56
 +#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET               0x61
 +#define QUERY_DEV_CAP_RSVD_MCG_OFFSET         0x62
 +#define QUERY_DEV_CAP_MAX_MCG_OFFSET          0x63
 +#define QUERY_DEV_CAP_RSVD_PD_OFFSET          0x64
 +#define QUERY_DEV_CAP_MAX_PD_OFFSET           0x65
++#define QUERY_DEV_CAP_RSVD_XRC_OFFSET         0x66
++#define QUERY_DEV_CAP_MAX_XRC_OFFSET          0x67
 +#define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET     0x68
 +#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET  0x80
 +#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET     0x82
 +#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET     0x84
 +#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET    0x86
 +#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET     0x88
 +#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET     0x8a
 +#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET     0x8c
 +#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET   0x8e
 +#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET     0x90
 +#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET   0x92
 +#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET               0x94
 +#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET                0x98
 +#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET               0xa0
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +      outbox = mailbox->buf;
 +
 +      err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
 +                         MLX4_CMD_TIME_CLASS_A);
 +      if (err)
 +              goto out;
 +
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET);
 +      dev_cap->reserved_qps = 1 << (field & 0xf);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET);
 +      dev_cap->max_qps = 1 << (field & 0x1f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET);
 +      dev_cap->reserved_srqs = 1 << (field >> 4);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET);
 +      dev_cap->max_srqs = 1 << (field & 0x1f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET);
 +      dev_cap->max_cq_sz = 1 << field;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET);
 +      dev_cap->reserved_cqs = 1 << (field & 0xf);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET);
 +      dev_cap->max_cqs = 1 << (field & 0x1f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET);
 +      dev_cap->max_mpts = 1 << (field & 0x3f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
 +      dev_cap->reserved_eqs = field & 0xf;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
 +      dev_cap->max_eqs = 1 << (field & 0xf);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
 +      dev_cap->reserved_mtts = 1 << (field >> 4);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
 +      dev_cap->max_mrw_sz = 1 << field;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET);
 +      dev_cap->reserved_mrws = 1 << (field & 0xf);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET);
 +      dev_cap->max_mtt_seg = 1 << (field & 0x3f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
 +      dev_cap->max_requester_per_qp = 1 << (field & 0x3f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET);
 +      dev_cap->max_responder_per_qp = 1 << (field & 0x3f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET);
 +      field &= 0x1f;
 +      if (!field)
 +              dev_cap->max_gso_sz = 0;
 +      else
 +              dev_cap->max_gso_sz = 1 << field;
 +
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET);
 +      dev_cap->max_rdma_global = 1 << (field & 0x3f);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
 +      dev_cap->local_ca_ack_delay = field & 0x1f;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
 +      dev_cap->num_ports = field & 0xf;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET);
 +      dev_cap->max_msg_sz = 1 << (field & 0x1f);
 +      MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
 +      dev_cap->stat_rate_support = stat_rate;
 +      MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
 +      MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
 +      dev_cap->flags = flags | (u64)ext_flags << 32;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
 +      dev_cap->reserved_uars = field >> 4;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET);
 +      dev_cap->uar_size = 1 << ((field & 0x3f) + 20);
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET);
 +      dev_cap->min_page_sz = 1 << field;
 +
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET);
 +      if (field & 0x80) {
 +              MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET);
 +              dev_cap->bf_reg_size = 1 << (field & 0x1f);
 +              MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET);
 +              if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size))
 +                      field = 3;
 +              dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
 +              mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
 +                       dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
 +      } else {
 +              dev_cap->bf_reg_size = 0;
 +              mlx4_dbg(dev, "BlueFlame not available\n");
 +      }
 +
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET);
 +      dev_cap->max_sq_sg = field;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET);
 +      dev_cap->max_sq_desc_sz = size;
 +
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET);
 +      dev_cap->max_qp_per_mcg = 1 << field;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET);
 +      dev_cap->reserved_mgms = field & 0xf;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET);
 +      dev_cap->max_mcgs = 1 << field;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET);
 +      dev_cap->reserved_pds = field >> 4;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET);
 +      dev_cap->max_pds = 1 << (field & 0x3f);
++      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET);
++      dev_cap->reserved_xrcds = field >> 4;
++      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET);
++      dev_cap->max_xrcds = 1 << (field & 0x1f);
 +
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET);
 +      dev_cap->rdmarc_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET);
 +      dev_cap->qpc_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET);
 +      dev_cap->aux_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET);
 +      dev_cap->altc_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET);
 +      dev_cap->eqc_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET);
 +      dev_cap->cqc_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET);
 +      dev_cap->srq_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET);
 +      dev_cap->cmpt_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET);
 +      dev_cap->mtt_entry_sz = size;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET);
 +      dev_cap->dmpt_entry_sz = size;
 +
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET);
 +      dev_cap->max_srq_sz = 1 << field;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET);
 +      dev_cap->max_qp_sz = 1 << field;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET);
 +      dev_cap->resize_srq = field & 1;
 +      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET);
 +      dev_cap->max_rq_sg = field;
 +      MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET);
 +      dev_cap->max_rq_desc_sz = size;
 +
 +      MLX4_GET(dev_cap->bmme_flags, outbox,
 +               QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
 +      MLX4_GET(dev_cap->reserved_lkey, outbox,
 +               QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
 +      MLX4_GET(dev_cap->max_icm_sz, outbox,
 +               QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
 +      if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
 +              MLX4_GET(dev_cap->max_counters, outbox,
 +                       QUERY_DEV_CAP_MAX_COUNTERS_OFFSET);
 +
 +      if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
 +              for (i = 1; i <= dev_cap->num_ports; ++i) {
 +                      MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
 +                      dev_cap->max_vl[i]         = field >> 4;
 +                      MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
 +                      dev_cap->ib_mtu[i]         = field >> 4;
 +                      dev_cap->max_port_width[i] = field & 0xf;
 +                      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
 +                      dev_cap->max_gids[i]       = 1 << (field & 0xf);
 +                      MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
 +                      dev_cap->max_pkeys[i]      = 1 << (field & 0xf);
 +              }
 +      } else {
 +#define QUERY_PORT_SUPPORTED_TYPE_OFFSET      0x00
 +#define QUERY_PORT_MTU_OFFSET                 0x01
 +#define QUERY_PORT_ETH_MTU_OFFSET             0x02
 +#define QUERY_PORT_WIDTH_OFFSET                       0x06
 +#define QUERY_PORT_MAX_GID_PKEY_OFFSET                0x07
 +#define QUERY_PORT_MAX_MACVLAN_OFFSET         0x0a
 +#define QUERY_PORT_MAX_VL_OFFSET              0x0b
 +#define QUERY_PORT_MAC_OFFSET                 0x10
 +#define QUERY_PORT_TRANS_VENDOR_OFFSET                0x18
 +#define QUERY_PORT_WAVELENGTH_OFFSET          0x1c
 +#define QUERY_PORT_TRANS_CODE_OFFSET          0x20
 +
 +              for (i = 1; i <= dev_cap->num_ports; ++i) {
 +                      err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT,
 +                                         MLX4_CMD_TIME_CLASS_B);
 +                      if (err)
 +                              goto out;
 +
 +                      MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
 +                      dev_cap->supported_port_types[i] = field & 3;
 +                      MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
 +                      dev_cap->ib_mtu[i]         = field & 0xf;
 +                      MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
 +                      dev_cap->max_port_width[i] = field & 0xf;
 +                      MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
 +                      dev_cap->max_gids[i]       = 1 << (field >> 4);
 +                      dev_cap->max_pkeys[i]      = 1 << (field & 0xf);
 +                      MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
 +                      dev_cap->max_vl[i]         = field & 0xf;
 +                      MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
 +                      dev_cap->log_max_macs[i]  = field & 0xf;
 +                      dev_cap->log_max_vlans[i] = field >> 4;
 +                      MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
 +                      MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
 +                      MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
 +                      dev_cap->trans_type[i] = field32 >> 24;
 +                      dev_cap->vendor_oui[i] = field32 & 0xffffff;
 +                      MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET);
 +                      MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET);
 +              }
 +      }
 +
 +      mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
 +               dev_cap->bmme_flags, dev_cap->reserved_lkey);
 +
 +      /*
 +       * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then
 +       * we can't use any EQs whose doorbell falls on that page,
 +       * even if the EQ itself isn't reserved.
 +       */
 +      dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
 +                                  dev_cap->reserved_eqs);
 +
 +      mlx4_dbg(dev, "Max ICM size %lld MB\n",
 +               (unsigned long long) dev_cap->max_icm_sz >> 20);
 +      mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
 +               dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz);
 +      mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n",
 +               dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz);
 +      mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
 +               dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz);
 +      mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n",
 +               dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz);
 +      mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
 +               dev_cap->reserved_mrws, dev_cap->reserved_mtts);
 +      mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
 +               dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars);
 +      mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n",
 +               dev_cap->max_pds, dev_cap->reserved_mgms);
 +      mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
 +               dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
 +      mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
 +               dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1],
 +               dev_cap->max_port_width[1]);
 +      mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
 +               dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
 +      mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
 +               dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
 +      mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
 +      mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
 +
 +      dump_dev_cap_flags(dev, dev_cap->flags);
 +
 +out:
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      struct mlx4_icm_iter iter;
 +      __be64 *pages;
 +      int lg;
 +      int nent = 0;
 +      int i;
 +      int err = 0;
 +      int ts = 0, tc = 0;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +      memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
 +      pages = mailbox->buf;
 +
 +      for (mlx4_icm_first(icm, &iter);
 +           !mlx4_icm_last(&iter);
 +           mlx4_icm_next(&iter)) {
 +              /*
 +               * We have to pass pages that are aligned to their
 +               * size, so find the least significant 1 in the
 +               * address or size and use that as our log2 size.
 +               */
 +              lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1;
 +              if (lg < MLX4_ICM_PAGE_SHIFT) {
 +                      mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
 +                                 MLX4_ICM_PAGE_SIZE,
 +                                 (unsigned long long) mlx4_icm_addr(&iter),
 +                                 mlx4_icm_size(&iter));
 +                      err = -EINVAL;
 +                      goto out;
 +              }
 +
 +              for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) {
 +                      if (virt != -1) {
 +                              pages[nent * 2] = cpu_to_be64(virt);
 +                              virt += 1 << lg;
 +                      }
 +
 +                      pages[nent * 2 + 1] =
 +                              cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) |
 +                                          (lg - MLX4_ICM_PAGE_SHIFT));
 +                      ts += 1 << (lg - 10);
 +                      ++tc;
 +
 +                      if (++nent == MLX4_MAILBOX_SIZE / 16) {
 +                              err = mlx4_cmd(dev, mailbox->dma, nent, 0, op,
 +                                              MLX4_CMD_TIME_CLASS_B);
 +                              if (err)
 +                                      goto out;
 +                              nent = 0;
 +                      }
 +              }
 +      }
 +
 +      if (nent)
 +              err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, MLX4_CMD_TIME_CLASS_B);
 +      if (err)
 +              goto out;
 +
 +      switch (op) {
 +      case MLX4_CMD_MAP_FA:
 +              mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts);
 +              break;
 +      case MLX4_CMD_MAP_ICM_AUX:
 +              mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts);
 +              break;
 +      case MLX4_CMD_MAP_ICM:
 +              mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n",
 +                        tc, ts, (unsigned long long) virt - (ts << 10));
 +              break;
 +      }
 +
 +out:
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm)
 +{
 +      return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1);
 +}
 +
 +int mlx4_UNMAP_FA(struct mlx4_dev *dev)
 +{
 +      return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, MLX4_CMD_TIME_CLASS_B);
 +}
 +
 +
 +int mlx4_RUN_FW(struct mlx4_dev *dev)
 +{
 +      return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, MLX4_CMD_TIME_CLASS_A);
 +}
 +
 +int mlx4_QUERY_FW(struct mlx4_dev *dev)
 +{
 +      struct mlx4_fw  *fw  = &mlx4_priv(dev)->fw;
 +      struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 *outbox;
 +      int err = 0;
 +      u64 fw_ver;
 +      u16 cmd_if_rev;
 +      u8 lg;
 +
 +#define QUERY_FW_OUT_SIZE             0x100
 +#define QUERY_FW_VER_OFFSET            0x00
 +#define QUERY_FW_CMD_IF_REV_OFFSET     0x0a
 +#define QUERY_FW_MAX_CMD_OFFSET        0x0f
 +#define QUERY_FW_ERR_START_OFFSET      0x30
 +#define QUERY_FW_ERR_SIZE_OFFSET       0x38
 +#define QUERY_FW_ERR_BAR_OFFSET        0x3c
 +
 +#define QUERY_FW_SIZE_OFFSET           0x00
 +#define QUERY_FW_CLR_INT_BASE_OFFSET   0x20
 +#define QUERY_FW_CLR_INT_BAR_OFFSET    0x28
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +      outbox = mailbox->buf;
 +
 +      err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW,
 +                          MLX4_CMD_TIME_CLASS_A);
 +      if (err)
 +              goto out;
 +
 +      MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET);
 +      /*
 +       * FW subminor version is at more significant bits than minor
 +       * version, so swap here.
 +       */
 +      dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) |
 +              ((fw_ver & 0xffff0000ull) >> 16) |
 +              ((fw_ver & 0x0000ffffull) << 16);
 +
 +      MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET);
 +      if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV ||
 +          cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) {
 +              mlx4_err(dev, "Installed FW has unsupported "
 +                       "command interface revision %d.\n",
 +                       cmd_if_rev);
 +              mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n",
 +                       (int) (dev->caps.fw_ver >> 32),
 +                       (int) (dev->caps.fw_ver >> 16) & 0xffff,
 +                       (int) dev->caps.fw_ver & 0xffff);
 +              mlx4_err(dev, "This driver version supports only revisions %d to %d.\n",
 +                       MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV);
 +              err = -ENODEV;
 +              goto out;
 +      }
 +
 +      if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS)
 +              dev->flags |= MLX4_FLAG_OLD_PORT_CMDS;
 +
 +      MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
 +      cmd->max_cmds = 1 << lg;
 +
 +      mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n",
 +               (int) (dev->caps.fw_ver >> 32),
 +               (int) (dev->caps.fw_ver >> 16) & 0xffff,
 +               (int) dev->caps.fw_ver & 0xffff,
 +               cmd_if_rev, cmd->max_cmds);
 +
 +      MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET);
 +      MLX4_GET(fw->catas_size,   outbox, QUERY_FW_ERR_SIZE_OFFSET);
 +      MLX4_GET(fw->catas_bar,    outbox, QUERY_FW_ERR_BAR_OFFSET);
 +      fw->catas_bar = (fw->catas_bar >> 6) * 2;
 +
 +      mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n",
 +               (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar);
 +
 +      MLX4_GET(fw->fw_pages,     outbox, QUERY_FW_SIZE_OFFSET);
 +      MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
 +      MLX4_GET(fw->clr_int_bar,  outbox, QUERY_FW_CLR_INT_BAR_OFFSET);
 +      fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2;
 +
 +      mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2);
 +
 +      /*
 +       * Round up number of system pages needed in case
 +       * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
 +       */
 +      fw->fw_pages =
 +              ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
 +              (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
 +
 +      mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n",
 +               (unsigned long long) fw->clr_int_base, fw->clr_int_bar);
 +
 +out:
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +static void get_board_id(void *vsd, char *board_id)
 +{
 +      int i;
 +
 +#define VSD_OFFSET_SIG1               0x00
 +#define VSD_OFFSET_SIG2               0xde
 +#define VSD_OFFSET_MLX_BOARD_ID       0xd0
 +#define VSD_OFFSET_TS_BOARD_ID        0x20
 +
 +#define VSD_SIGNATURE_TOPSPIN 0x5ad
 +
 +      memset(board_id, 0, MLX4_BOARD_ID_LEN);
 +
 +      if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN &&
 +          be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) {
 +              strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN);
 +      } else {
 +              /*
 +               * The board ID is a string but the firmware byte
 +               * swaps each 4-byte word before passing it back to
 +               * us.  Therefore we need to swab it before printing.
 +               */
 +              for (i = 0; i < 4; ++i)
 +                      ((u32 *) board_id)[i] =
 +                              swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4));
 +      }
 +}
 +
 +int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 *outbox;
 +      int err;
 +
 +#define QUERY_ADAPTER_OUT_SIZE             0x100
 +#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 +#define QUERY_ADAPTER_VSD_OFFSET           0x20
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +      outbox = mailbox->buf;
 +
 +      err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER,
 +                         MLX4_CMD_TIME_CLASS_A);
 +      if (err)
 +              goto out;
 +
 +      MLX4_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 +
 +      get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
 +                   adapter->board_id);
 +
 +out:
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      __be32 *inbox;
 +      int err;
 +
 +#define INIT_HCA_IN_SIZE               0x200
 +#define INIT_HCA_VERSION_OFFSET                0x000
 +#define        INIT_HCA_VERSION                2
 +#define INIT_HCA_CACHELINE_SZ_OFFSET   0x0e
 +#define INIT_HCA_FLAGS_OFFSET          0x014
 +#define INIT_HCA_QPC_OFFSET            0x020
 +#define        INIT_HCA_QPC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x10)
 +#define        INIT_HCA_LOG_QP_OFFSET          (INIT_HCA_QPC_OFFSET + 0x17)
 +#define        INIT_HCA_SRQC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x28)
 +#define        INIT_HCA_LOG_SRQ_OFFSET         (INIT_HCA_QPC_OFFSET + 0x2f)
 +#define        INIT_HCA_CQC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x30)
 +#define        INIT_HCA_LOG_CQ_OFFSET          (INIT_HCA_QPC_OFFSET + 0x37)
 +#define        INIT_HCA_ALTC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x40)
 +#define        INIT_HCA_AUXC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x50)
 +#define        INIT_HCA_EQC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x60)
 +#define        INIT_HCA_LOG_EQ_OFFSET          (INIT_HCA_QPC_OFFSET + 0x67)
 +#define        INIT_HCA_RDMARC_BASE_OFFSET     (INIT_HCA_QPC_OFFSET + 0x70)
 +#define        INIT_HCA_LOG_RD_OFFSET          (INIT_HCA_QPC_OFFSET + 0x77)
 +#define INIT_HCA_MCAST_OFFSET          0x0c0
 +#define        INIT_HCA_MC_BASE_OFFSET         (INIT_HCA_MCAST_OFFSET + 0x00)
 +#define        INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12)
 +#define        INIT_HCA_LOG_MC_HASH_SZ_OFFSET  (INIT_HCA_MCAST_OFFSET + 0x16)
 +#define  INIT_HCA_UC_STEERING_OFFSET   (INIT_HCA_MCAST_OFFSET + 0x18)
 +#define        INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b)
 +#define INIT_HCA_TPT_OFFSET            0x0f0
 +#define        INIT_HCA_DMPT_BASE_OFFSET       (INIT_HCA_TPT_OFFSET + 0x00)
 +#define        INIT_HCA_LOG_MPT_SZ_OFFSET      (INIT_HCA_TPT_OFFSET + 0x0b)
 +#define        INIT_HCA_MTT_BASE_OFFSET        (INIT_HCA_TPT_OFFSET + 0x10)
 +#define        INIT_HCA_CMPT_BASE_OFFSET       (INIT_HCA_TPT_OFFSET + 0x18)
 +#define INIT_HCA_UAR_OFFSET            0x120
 +#define        INIT_HCA_LOG_UAR_SZ_OFFSET      (INIT_HCA_UAR_OFFSET + 0x0a)
 +#define  INIT_HCA_UAR_PAGE_SZ_OFFSET     (INIT_HCA_UAR_OFFSET + 0x0b)
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +      inbox = mailbox->buf;
 +
 +      memset(inbox, 0, INIT_HCA_IN_SIZE);
 +
 +      *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION;
 +
 +      *((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) =
 +              (ilog2(cache_line_size()) - 4) << 5;
 +
 +#if defined(__LITTLE_ENDIAN)
 +      *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
 +#elif defined(__BIG_ENDIAN)
 +      *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
 +#else
 +#error Host endianness not defined
 +#endif
 +      /* Check port for UD address vector: */
 +      *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
 +
 +      /* Enable IPoIB checksumming if we can: */
 +      if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM)
 +              *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3);
 +
 +      /* Enable QoS support if module parameter set */
 +      if (enable_qos)
 +              *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2);
 +
 +      /* enable counters */
 +      if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)
 +              *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4);
 +
 +      /* QPC/EEC/CQC/EQC/RDMARC attributes */
 +
 +      MLX4_PUT(inbox, param->qpc_base,      INIT_HCA_QPC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_num_qps,   INIT_HCA_LOG_QP_OFFSET);
 +      MLX4_PUT(inbox, param->srqc_base,     INIT_HCA_SRQC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_num_srqs,  INIT_HCA_LOG_SRQ_OFFSET);
 +      MLX4_PUT(inbox, param->cqc_base,      INIT_HCA_CQC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_num_cqs,   INIT_HCA_LOG_CQ_OFFSET);
 +      MLX4_PUT(inbox, param->altc_base,     INIT_HCA_ALTC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->auxc_base,     INIT_HCA_AUXC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->eqc_base,      INIT_HCA_EQC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_num_eqs,   INIT_HCA_LOG_EQ_OFFSET);
 +      MLX4_PUT(inbox, param->rdmarc_base,   INIT_HCA_RDMARC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET);
 +
 +      /* multicast attributes */
 +
 +      MLX4_PUT(inbox, param->mc_base,         INIT_HCA_MC_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
 +      MLX4_PUT(inbox, param->log_mc_hash_sz,  INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
 +      if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
 +              MLX4_PUT(inbox, (u8) (1 << 3),  INIT_HCA_UC_STEERING_OFFSET);
 +      MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
 +
 +      /* TPT attributes */
 +
 +      MLX4_PUT(inbox, param->dmpt_base,  INIT_HCA_DMPT_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET);
 +      MLX4_PUT(inbox, param->mtt_base,   INIT_HCA_MTT_BASE_OFFSET);
 +      MLX4_PUT(inbox, param->cmpt_base,  INIT_HCA_CMPT_BASE_OFFSET);
 +
 +      /* UAR attributes */
 +
 +      MLX4_PUT(inbox, (u8) (PAGE_SHIFT - 12), INIT_HCA_UAR_PAGE_SZ_OFFSET);
 +      MLX4_PUT(inbox, param->log_uar_sz,      INIT_HCA_LOG_UAR_SZ_OFFSET);
 +
 +      err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000);
 +
 +      if (err)
 +              mlx4_err(dev, "INIT_HCA returns %d\n", err);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +int mlx4_INIT_PORT(struct mlx4_dev *dev, int port)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 *inbox;
 +      int err;
 +      u32 flags;
 +      u16 field;
 +
 +      if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
 +#define INIT_PORT_IN_SIZE          256
 +#define INIT_PORT_FLAGS_OFFSET     0x00
 +#define INIT_PORT_FLAG_SIG         (1 << 18)
 +#define INIT_PORT_FLAG_NG          (1 << 17)
 +#define INIT_PORT_FLAG_G0          (1 << 16)
 +#define INIT_PORT_VL_SHIFT         4
 +#define INIT_PORT_PORT_WIDTH_SHIFT 8
 +#define INIT_PORT_MTU_OFFSET       0x04
 +#define INIT_PORT_MAX_GID_OFFSET   0x06
 +#define INIT_PORT_MAX_PKEY_OFFSET  0x0a
 +#define INIT_PORT_GUID0_OFFSET     0x10
 +#define INIT_PORT_NODE_GUID_OFFSET 0x18
 +#define INIT_PORT_SI_GUID_OFFSET   0x20
 +
 +              mailbox = mlx4_alloc_cmd_mailbox(dev);
 +              if (IS_ERR(mailbox))
 +                      return PTR_ERR(mailbox);
 +              inbox = mailbox->buf;
 +
 +              memset(inbox, 0, INIT_PORT_IN_SIZE);
 +
 +              flags = 0;
 +              flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT;
 +              flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT;
 +              MLX4_PUT(inbox, flags,            INIT_PORT_FLAGS_OFFSET);
 +
 +              field = 128 << dev->caps.ib_mtu_cap[port];
 +              MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET);
 +              field = dev->caps.gid_table_len[port];
 +              MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET);
 +              field = dev->caps.pkey_table_len[port];
 +              MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET);
 +
 +              err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT,
 +                             MLX4_CMD_TIME_CLASS_A);
 +
 +              mlx4_free_cmd_mailbox(dev, mailbox);
 +      } else
 +              err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
 +                             MLX4_CMD_TIME_CLASS_A);
 +
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_INIT_PORT);
 +
 +int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port)
 +{
 +      return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT);
 +
 +int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
 +{
 +      return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000);
 +}
 +
 +int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
 +{
 +      int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
 +                             MLX4_CMD_SET_ICM_SIZE,
 +                             MLX4_CMD_TIME_CLASS_A);
 +      if (ret)
 +              return ret;
 +
 +      /*
 +       * Round up number of system pages needed in case
 +       * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
 +       */
 +      *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
 +              (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
 +
 +      return 0;
 +}
 +
 +int mlx4_NOP(struct mlx4_dev *dev)
 +{
 +      /* Input modifier of 0x1f means "finish as soon as possible." */
 +      return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100);
 +}
 +
 +#define MLX4_WOL_SETUP_MODE (5 << 28)
 +int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port)
 +{
 +      u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
 +
 +      return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3,
 +                          MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_wol_read);
 +
 +int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port)
 +{
 +      u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
 +
 +      return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG,
 +                                      MLX4_CMD_TIME_CLASS_A);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_wol_write);
index 1e8ecc3708e22eff9f33d5326af850d9a4c4c7da,0000000000000000000000000000000000000000..bf5ec2286528ca9bbf239c126dd3f706c5b2a55b
mode 100644,000000..100644
--- /dev/null
@@@ -1,182 -1,0 +1,184 @@@
 +/*
 + * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
 + * Copyright (c) 2006, 2007 Cisco Systems.  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.
 + */
 +
 +#ifndef MLX4_FW_H
 +#define MLX4_FW_H
 +
 +#include "mlx4.h"
 +#include "icm.h"
 +
 +struct mlx4_mod_stat_cfg {
 +      u8 log_pg_sz;
 +      u8 log_pg_sz_m;
 +};
 +
 +struct mlx4_dev_cap {
 +      int max_srq_sz;
 +      int max_qp_sz;
 +      int reserved_qps;
 +      int max_qps;
 +      int reserved_srqs;
 +      int max_srqs;
 +      int max_cq_sz;
 +      int reserved_cqs;
 +      int max_cqs;
 +      int max_mpts;
 +      int reserved_eqs;
 +      int max_eqs;
 +      int reserved_mtts;
 +      int max_mrw_sz;
 +      int reserved_mrws;
 +      int max_mtt_seg;
 +      int max_requester_per_qp;
 +      int max_responder_per_qp;
 +      int max_rdma_global;
 +      int local_ca_ack_delay;
 +      int num_ports;
 +      u32 max_msg_sz;
 +      int ib_mtu[MLX4_MAX_PORTS + 1];
 +      int max_port_width[MLX4_MAX_PORTS + 1];
 +      int max_vl[MLX4_MAX_PORTS + 1];
 +      int max_gids[MLX4_MAX_PORTS + 1];
 +      int max_pkeys[MLX4_MAX_PORTS + 1];
 +      u64 def_mac[MLX4_MAX_PORTS + 1];
 +      u16 eth_mtu[MLX4_MAX_PORTS + 1];
 +      int trans_type[MLX4_MAX_PORTS + 1];
 +      int vendor_oui[MLX4_MAX_PORTS + 1];
 +      u16 wavelength[MLX4_MAX_PORTS + 1];
 +      u64 trans_code[MLX4_MAX_PORTS + 1];
 +      u16 stat_rate_support;
 +      u64 flags;
 +      int reserved_uars;
 +      int uar_size;
 +      int min_page_sz;
 +      int bf_reg_size;
 +      int bf_regs_per_page;
 +      int max_sq_sg;
 +      int max_sq_desc_sz;
 +      int max_rq_sg;
 +      int max_rq_desc_sz;
 +      int max_qp_per_mcg;
 +      int reserved_mgms;
 +      int max_mcgs;
 +      int reserved_pds;
 +      int max_pds;
++      int reserved_xrcds;
++      int max_xrcds;
 +      int qpc_entry_sz;
 +      int rdmarc_entry_sz;
 +      int altc_entry_sz;
 +      int aux_entry_sz;
 +      int srq_entry_sz;
 +      int cqc_entry_sz;
 +      int eqc_entry_sz;
 +      int dmpt_entry_sz;
 +      int cmpt_entry_sz;
 +      int mtt_entry_sz;
 +      int resize_srq;
 +      u32 bmme_flags;
 +      u32 reserved_lkey;
 +      u64 max_icm_sz;
 +      int max_gso_sz;
 +      u8  supported_port_types[MLX4_MAX_PORTS + 1];
 +      u8  log_max_macs[MLX4_MAX_PORTS + 1];
 +      u8  log_max_vlans[MLX4_MAX_PORTS + 1];
 +      u32 max_counters;
 +};
 +
 +struct mlx4_adapter {
 +      char board_id[MLX4_BOARD_ID_LEN];
 +      u8   inta_pin;
 +};
 +
 +struct mlx4_init_hca_param {
 +      u64 qpc_base;
 +      u64 rdmarc_base;
 +      u64 auxc_base;
 +      u64 altc_base;
 +      u64 srqc_base;
 +      u64 cqc_base;
 +      u64 eqc_base;
 +      u64 mc_base;
 +      u64 dmpt_base;
 +      u64 cmpt_base;
 +      u64 mtt_base;
 +      u16 log_mc_entry_sz;
 +      u16 log_mc_hash_sz;
 +      u8  log_num_qps;
 +      u8  log_num_srqs;
 +      u8  log_num_cqs;
 +      u8  log_num_eqs;
 +      u8  log_rd_per_qp;
 +      u8  log_mc_table_sz;
 +      u8  log_mpt_sz;
 +      u8  log_uar_sz;
 +};
 +
 +struct mlx4_init_ib_param {
 +      int port_width;
 +      int vl_cap;
 +      int mtu_cap;
 +      u16 gid_cap;
 +      u16 pkey_cap;
 +      int set_guid0;
 +      u64 guid0;
 +      int set_node_guid;
 +      u64 node_guid;
 +      int set_si_guid;
 +      u64 si_guid;
 +};
 +
 +struct mlx4_set_ib_param {
 +      int set_si_guid;
 +      int reset_qkey_viol;
 +      u64 si_guid;
 +      u32 cap_mask;
 +};
 +
 +int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
 +int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm);
 +int mlx4_UNMAP_FA(struct mlx4_dev *dev);
 +int mlx4_RUN_FW(struct mlx4_dev *dev);
 +int mlx4_QUERY_FW(struct mlx4_dev *dev);
 +int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter);
 +int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param);
 +int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic);
 +int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt);
 +int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages);
 +int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm);
 +int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
 +int mlx4_NOP(struct mlx4_dev *dev);
 +int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg);
 +
 +#endif /* MLX4_FW_H */
index f0ee35df4dd7779aa971fec3d7fa7555d9bc058a,0000000000000000000000000000000000000000..94bbc85a532d18d2fd67caf5406bcd2a6baac26d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1529 -1,0 +1,1553 @@@
-       dev->caps.log_num_vlans = log_num_vlan;
 +/*
 + * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
 + * Copyright (c) 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/module.h>
 +#include <linux/init.h>
 +#include <linux/errno.h>
 +#include <linux/pci.h>
 +#include <linux/dma-mapping.h>
 +#include <linux/slab.h>
 +#include <linux/io-mapping.h>
 +
 +#include <linux/mlx4/device.h>
 +#include <linux/mlx4/doorbell.h>
 +
 +#include "mlx4.h"
 +#include "fw.h"
 +#include "icm.h"
 +
 +MODULE_AUTHOR("Roland Dreier");
 +MODULE_DESCRIPTION("Mellanox ConnectX HCA low-level driver");
 +MODULE_LICENSE("Dual BSD/GPL");
 +MODULE_VERSION(DRV_VERSION);
 +
 +struct workqueue_struct *mlx4_wq;
 +
 +#ifdef CONFIG_MLX4_DEBUG
 +
 +int mlx4_debug_level = 0;
 +module_param_named(debug_level, mlx4_debug_level, int, 0644);
 +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
 +
 +#endif /* CONFIG_MLX4_DEBUG */
 +
 +#ifdef CONFIG_PCI_MSI
 +
 +static int msi_x = 1;
 +module_param(msi_x, int, 0444);
 +MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 +
 +#else /* CONFIG_PCI_MSI */
 +
 +#define msi_x (0)
 +
 +#endif /* CONFIG_PCI_MSI */
 +
 +static char mlx4_version[] __devinitdata =
 +      DRV_NAME ": Mellanox ConnectX core driver v"
 +      DRV_VERSION " (" DRV_RELDATE ")\n";
 +
 +static struct mlx4_profile default_profile = {
 +      .num_qp         = 1 << 17,
 +      .num_srq        = 1 << 16,
 +      .rdmarc_per_qp  = 1 << 4,
 +      .num_cq         = 1 << 16,
 +      .num_mcg        = 1 << 13,
 +      .num_mpt        = 1 << 17,
 +      .num_mtt        = 1 << 20,
 +};
 +
 +static int log_num_mac = 2;
 +module_param_named(log_num_mac, log_num_mac, int, 0444);
 +MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)");
 +
 +static int log_num_vlan;
 +module_param_named(log_num_vlan, log_num_vlan, int, 0444);
 +MODULE_PARM_DESC(log_num_vlan, "Log2 max number of VLANs per ETH port (0-7)");
++/* Log2 max number of VLANs per ETH port (0-7) */
++#define MLX4_LOG_NUM_VLANS 7
 +
 +static int use_prio;
 +module_param_named(use_prio, use_prio, bool, 0444);
 +MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
 +                "(0/1, default 0)");
 +
 +static int log_mtts_per_seg = ilog2(MLX4_MTT_ENTRY_PER_SEG);
 +module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);
 +MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-7)");
 +
 +int mlx4_check_port_params(struct mlx4_dev *dev,
 +                         enum mlx4_port_type *port_type)
 +{
 +      int i;
 +
 +      for (i = 0; i < dev->caps.num_ports - 1; i++) {
 +              if (port_type[i] != port_type[i + 1]) {
 +                      if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) {
 +                              mlx4_err(dev, "Only same port types supported "
 +                                       "on this HCA, aborting.\n");
 +                              return -EINVAL;
 +                      }
 +                      if (port_type[i] == MLX4_PORT_TYPE_ETH &&
 +                          port_type[i + 1] == MLX4_PORT_TYPE_IB)
 +                              return -EINVAL;
 +              }
 +      }
 +
 +      for (i = 0; i < dev->caps.num_ports; i++) {
 +              if (!(port_type[i] & dev->caps.supported_type[i+1])) {
 +                      mlx4_err(dev, "Requested port type for port %d is not "
 +                                    "supported on this HCA\n", i + 1);
 +                      return -EINVAL;
 +              }
 +      }
 +      return 0;
 +}
 +
 +static void mlx4_set_port_mask(struct mlx4_dev *dev)
 +{
 +      int i;
 +
 +      dev->caps.port_mask = 0;
 +      for (i = 1; i <= dev->caps.num_ports; ++i)
 +              if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB)
 +                      dev->caps.port_mask |= 1 << (i - 1);
 +}
 +
 +static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 +{
 +      int err;
 +      int i;
 +
 +      err = mlx4_QUERY_DEV_CAP(dev, dev_cap);
 +      if (err) {
 +              mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
 +              return err;
 +      }
 +
 +      if (dev_cap->min_page_sz > PAGE_SIZE) {
 +              mlx4_err(dev, "HCA minimum page size of %d bigger than "
 +                       "kernel PAGE_SIZE of %ld, aborting.\n",
 +                       dev_cap->min_page_sz, PAGE_SIZE);
 +              return -ENODEV;
 +      }
 +      if (dev_cap->num_ports > MLX4_MAX_PORTS) {
 +              mlx4_err(dev, "HCA has %d ports, but we only support %d, "
 +                       "aborting.\n",
 +                       dev_cap->num_ports, MLX4_MAX_PORTS);
 +              return -ENODEV;
 +      }
 +
 +      if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) {
 +              mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than "
 +                       "PCI resource 2 size of 0x%llx, aborting.\n",
 +                       dev_cap->uar_size,
 +                       (unsigned long long) pci_resource_len(dev->pdev, 2));
 +              return -ENODEV;
 +      }
 +
 +      dev->caps.num_ports          = dev_cap->num_ports;
 +      for (i = 1; i <= dev->caps.num_ports; ++i) {
 +              dev->caps.vl_cap[i]         = dev_cap->max_vl[i];
 +              dev->caps.ib_mtu_cap[i]     = dev_cap->ib_mtu[i];
 +              dev->caps.gid_table_len[i]  = dev_cap->max_gids[i];
 +              dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i];
 +              dev->caps.port_width_cap[i] = dev_cap->max_port_width[i];
 +              dev->caps.eth_mtu_cap[i]    = dev_cap->eth_mtu[i];
 +              dev->caps.def_mac[i]        = dev_cap->def_mac[i];
 +              dev->caps.supported_type[i] = dev_cap->supported_port_types[i];
 +              dev->caps.trans_type[i]     = dev_cap->trans_type[i];
 +              dev->caps.vendor_oui[i]     = dev_cap->vendor_oui[i];
 +              dev->caps.wavelength[i]     = dev_cap->wavelength[i];
 +              dev->caps.trans_code[i]     = dev_cap->trans_code[i];
 +      }
 +
 +      dev->caps.num_uars           = dev_cap->uar_size / PAGE_SIZE;
 +      dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay;
 +      dev->caps.bf_reg_size        = dev_cap->bf_reg_size;
 +      dev->caps.bf_regs_per_page   = dev_cap->bf_regs_per_page;
 +      dev->caps.max_sq_sg          = dev_cap->max_sq_sg;
 +      dev->caps.max_rq_sg          = dev_cap->max_rq_sg;
 +      dev->caps.max_wqes           = dev_cap->max_qp_sz;
 +      dev->caps.max_qp_init_rdma   = dev_cap->max_requester_per_qp;
 +      dev->caps.max_srq_wqes       = dev_cap->max_srq_sz;
 +      dev->caps.max_srq_sge        = dev_cap->max_rq_sg - 1;
 +      dev->caps.reserved_srqs      = dev_cap->reserved_srqs;
 +      dev->caps.max_sq_desc_sz     = dev_cap->max_sq_desc_sz;
 +      dev->caps.max_rq_desc_sz     = dev_cap->max_rq_desc_sz;
 +      dev->caps.num_qp_per_mgm     = MLX4_QP_PER_MGM;
 +      /*
 +       * Subtract 1 from the limit because we need to allocate a
 +       * spare CQE so the HCA HW can tell the difference between an
 +       * empty CQ and a full CQ.
 +       */
 +      dev->caps.max_cqes           = dev_cap->max_cq_sz - 1;
 +      dev->caps.reserved_cqs       = dev_cap->reserved_cqs;
 +      dev->caps.reserved_eqs       = dev_cap->reserved_eqs;
 +      dev->caps.mtts_per_seg       = 1 << log_mtts_per_seg;
 +      dev->caps.reserved_mtts      = DIV_ROUND_UP(dev_cap->reserved_mtts,
 +                                                  dev->caps.mtts_per_seg);
 +      dev->caps.reserved_mrws      = dev_cap->reserved_mrws;
 +      dev->caps.reserved_uars      = dev_cap->reserved_uars;
 +      dev->caps.reserved_pds       = dev_cap->reserved_pds;
++      dev->caps.reserved_xrcds     = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ?
++                                      dev_cap->reserved_xrcds : 0;
++      dev->caps.max_xrcds          = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ?
++                                      dev_cap->max_xrcds : 0;
 +      dev->caps.mtt_entry_sz       = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz;
 +      dev->caps.max_msg_sz         = dev_cap->max_msg_sz;
 +      dev->caps.page_size_cap      = ~(u32) (dev_cap->min_page_sz - 1);
 +      dev->caps.flags              = dev_cap->flags;
 +      dev->caps.bmme_flags         = dev_cap->bmme_flags;
 +      dev->caps.reserved_lkey      = dev_cap->reserved_lkey;
 +      dev->caps.stat_rate_support  = dev_cap->stat_rate_support;
 +      dev->caps.max_gso_sz         = dev_cap->max_gso_sz;
 +
 +      dev->caps.log_num_macs  = log_num_mac;
-               goto err_pd_table_free;
++      dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS;
 +      dev->caps.log_num_prios = use_prio ? 3 : 0;
 +
 +      for (i = 1; i <= dev->caps.num_ports; ++i) {
 +              if (dev->caps.supported_type[i] != MLX4_PORT_TYPE_ETH)
 +                      dev->caps.port_type[i] = MLX4_PORT_TYPE_IB;
 +              else
 +                      dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH;
 +              dev->caps.possible_type[i] = dev->caps.port_type[i];
 +              mlx4_priv(dev)->sense.sense_allowed[i] =
 +                      dev->caps.supported_type[i] == MLX4_PORT_TYPE_AUTO;
 +
 +              if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) {
 +                      dev->caps.log_num_macs = dev_cap->log_max_macs[i];
 +                      mlx4_warn(dev, "Requested number of MACs is too much "
 +                                "for port %d, reducing to %d.\n",
 +                                i, 1 << dev->caps.log_num_macs);
 +              }
 +              if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) {
 +                      dev->caps.log_num_vlans = dev_cap->log_max_vlans[i];
 +                      mlx4_warn(dev, "Requested number of VLANs is too much "
 +                                "for port %d, reducing to %d.\n",
 +                                i, 1 << dev->caps.log_num_vlans);
 +              }
 +      }
 +
 +      mlx4_set_port_mask(dev);
 +
 +      dev->caps.max_counters = 1 << ilog2(dev_cap->max_counters);
 +
 +      dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps;
 +      dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] =
 +              dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] =
 +              (1 << dev->caps.log_num_macs) *
 +              (1 << dev->caps.log_num_vlans) *
 +              (1 << dev->caps.log_num_prios) *
 +              dev->caps.num_ports;
 +      dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = MLX4_NUM_FEXCH;
 +
 +      dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] +
 +              dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] +
 +              dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] +
 +              dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH];
 +
 +      return 0;
 +}
 +
 +/*
 + * Change the port configuration of the device.
 + * Every user of this function must hold the port mutex.
 + */
 +int mlx4_change_port_types(struct mlx4_dev *dev,
 +                         enum mlx4_port_type *port_types)
 +{
 +      int err = 0;
 +      int change = 0;
 +      int port;
 +
 +      for (port = 0; port <  dev->caps.num_ports; port++) {
 +              /* Change the port type only if the new type is different
 +               * from the current, and not set to Auto */
 +              if (port_types[port] != dev->caps.port_type[port + 1]) {
 +                      change = 1;
 +                      dev->caps.port_type[port + 1] = port_types[port];
 +              }
 +      }
 +      if (change) {
 +              mlx4_unregister_device(dev);
 +              for (port = 1; port <= dev->caps.num_ports; port++) {
 +                      mlx4_CLOSE_PORT(dev, port);
 +                      err = mlx4_SET_PORT(dev, port);
 +                      if (err) {
 +                              mlx4_err(dev, "Failed to set port %d, "
 +                                            "aborting\n", port);
 +                              goto out;
 +                      }
 +              }
 +              mlx4_set_port_mask(dev);
 +              err = mlx4_register_device(dev);
 +      }
 +
 +out:
 +      return err;
 +}
 +
 +static ssize_t show_port_type(struct device *dev,
 +                            struct device_attribute *attr,
 +                            char *buf)
 +{
 +      struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
 +                                                 port_attr);
 +      struct mlx4_dev *mdev = info->dev;
 +      char type[8];
 +
 +      sprintf(type, "%s",
 +              (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB) ?
 +              "ib" : "eth");
 +      if (mdev->caps.possible_type[info->port] == MLX4_PORT_TYPE_AUTO)
 +              sprintf(buf, "auto (%s)\n", type);
 +      else
 +              sprintf(buf, "%s\n", type);
 +
 +      return strlen(buf);
 +}
 +
 +static ssize_t set_port_type(struct device *dev,
 +                           struct device_attribute *attr,
 +                           const char *buf, size_t count)
 +{
 +      struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
 +                                                 port_attr);
 +      struct mlx4_dev *mdev = info->dev;
 +      struct mlx4_priv *priv = mlx4_priv(mdev);
 +      enum mlx4_port_type types[MLX4_MAX_PORTS];
 +      enum mlx4_port_type new_types[MLX4_MAX_PORTS];
 +      int i;
 +      int err = 0;
 +
 +      if (!strcmp(buf, "ib\n"))
 +              info->tmp_type = MLX4_PORT_TYPE_IB;
 +      else if (!strcmp(buf, "eth\n"))
 +              info->tmp_type = MLX4_PORT_TYPE_ETH;
 +      else if (!strcmp(buf, "auto\n"))
 +              info->tmp_type = MLX4_PORT_TYPE_AUTO;
 +      else {
 +              mlx4_err(mdev, "%s is not supported port type\n", buf);
 +              return -EINVAL;
 +      }
 +
 +      mlx4_stop_sense(mdev);
 +      mutex_lock(&priv->port_mutex);
 +      /* Possible type is always the one that was delivered */
 +      mdev->caps.possible_type[info->port] = info->tmp_type;
 +
 +      for (i = 0; i < mdev->caps.num_ports; i++) {
 +              types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type :
 +                                      mdev->caps.possible_type[i+1];
 +              if (types[i] == MLX4_PORT_TYPE_AUTO)
 +                      types[i] = mdev->caps.port_type[i+1];
 +      }
 +
 +      if (!(mdev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) {
 +              for (i = 1; i <= mdev->caps.num_ports; i++) {
 +                      if (mdev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) {
 +                              mdev->caps.possible_type[i] = mdev->caps.port_type[i];
 +                              err = -EINVAL;
 +                      }
 +              }
 +      }
 +      if (err) {
 +              mlx4_err(mdev, "Auto sensing is not supported on this HCA. "
 +                             "Set only 'eth' or 'ib' for both ports "
 +                             "(should be the same)\n");
 +              goto out;
 +      }
 +
 +      mlx4_do_sense_ports(mdev, new_types, types);
 +
 +      err = mlx4_check_port_params(mdev, new_types);
 +      if (err)
 +              goto out;
 +
 +      /* We are about to apply the changes after the configuration
 +       * was verified, no need to remember the temporary types
 +       * any more */
 +      for (i = 0; i < mdev->caps.num_ports; i++)
 +              priv->port[i + 1].tmp_type = 0;
 +
 +      err = mlx4_change_port_types(mdev, new_types);
 +
 +out:
 +      mlx4_start_sense(mdev);
 +      mutex_unlock(&priv->port_mutex);
 +      return err ? err : count;
 +}
 +
 +static int mlx4_load_fw(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int err;
 +
 +      priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages,
 +                                       GFP_HIGHUSER | __GFP_NOWARN, 0);
 +      if (!priv->fw.fw_icm) {
 +              mlx4_err(dev, "Couldn't allocate FW area, aborting.\n");
 +              return -ENOMEM;
 +      }
 +
 +      err = mlx4_MAP_FA(dev, priv->fw.fw_icm);
 +      if (err) {
 +              mlx4_err(dev, "MAP_FA command failed, aborting.\n");
 +              goto err_free;
 +      }
 +
 +      err = mlx4_RUN_FW(dev);
 +      if (err) {
 +              mlx4_err(dev, "RUN_FW command failed, aborting.\n");
 +              goto err_unmap_fa;
 +      }
 +
 +      return 0;
 +
 +err_unmap_fa:
 +      mlx4_UNMAP_FA(dev);
 +
 +err_free:
 +      mlx4_free_icm(dev, priv->fw.fw_icm, 0);
 +      return err;
 +}
 +
 +static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
 +                              int cmpt_entry_sz)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int err;
 +
 +      err = mlx4_init_icm_table(dev, &priv->qp_table.cmpt_table,
 +                                cmpt_base +
 +                                ((u64) (MLX4_CMPT_TYPE_QP *
 +                                        cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 +                                cmpt_entry_sz, dev->caps.num_qps,
 +                                dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
 +                                0, 0);
 +      if (err)
 +              goto err;
 +
 +      err = mlx4_init_icm_table(dev, &priv->srq_table.cmpt_table,
 +                                cmpt_base +
 +                                ((u64) (MLX4_CMPT_TYPE_SRQ *
 +                                        cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 +                                cmpt_entry_sz, dev->caps.num_srqs,
 +                                dev->caps.reserved_srqs, 0, 0);
 +      if (err)
 +              goto err_qp;
 +
 +      err = mlx4_init_icm_table(dev, &priv->cq_table.cmpt_table,
 +                                cmpt_base +
 +                                ((u64) (MLX4_CMPT_TYPE_CQ *
 +                                        cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 +                                cmpt_entry_sz, dev->caps.num_cqs,
 +                                dev->caps.reserved_cqs, 0, 0);
 +      if (err)
 +              goto err_srq;
 +
 +      err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table,
 +                                cmpt_base +
 +                                ((u64) (MLX4_CMPT_TYPE_EQ *
 +                                        cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 +                                cmpt_entry_sz,
 +                                dev->caps.num_eqs, dev->caps.num_eqs, 0, 0);
 +      if (err)
 +              goto err_cq;
 +
 +      return 0;
 +
 +err_cq:
 +      mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
 +
 +err_srq:
 +      mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
 +
 +err_qp:
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
 +
 +err:
 +      return err;
 +}
 +
 +static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
 +                       struct mlx4_init_hca_param *init_hca, u64 icm_size)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      u64 aux_pages;
 +      int err;
 +
 +      err = mlx4_SET_ICM_SIZE(dev, icm_size, &aux_pages);
 +      if (err) {
 +              mlx4_err(dev, "SET_ICM_SIZE command failed, aborting.\n");
 +              return err;
 +      }
 +
 +      mlx4_dbg(dev, "%lld KB of HCA context requires %lld KB aux memory.\n",
 +               (unsigned long long) icm_size >> 10,
 +               (unsigned long long) aux_pages << 2);
 +
 +      priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages,
 +                                        GFP_HIGHUSER | __GFP_NOWARN, 0);
 +      if (!priv->fw.aux_icm) {
 +              mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n");
 +              return -ENOMEM;
 +      }
 +
 +      err = mlx4_MAP_ICM_AUX(dev, priv->fw.aux_icm);
 +      if (err) {
 +              mlx4_err(dev, "MAP_ICM_AUX command failed, aborting.\n");
 +              goto err_free_aux;
 +      }
 +
 +      err = mlx4_init_cmpt_table(dev, init_hca->cmpt_base, dev_cap->cmpt_entry_sz);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map cMPT context memory, aborting.\n");
 +              goto err_unmap_aux;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->eq_table.table,
 +                                init_hca->eqc_base, dev_cap->eqc_entry_sz,
 +                                dev->caps.num_eqs, dev->caps.num_eqs,
 +                                0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map EQ context memory, aborting.\n");
 +              goto err_unmap_cmpt;
 +      }
 +
 +      /*
 +       * Reserved MTT entries must be aligned up to a cacheline
 +       * boundary, since the FW will write to them, while the driver
 +       * writes to all other MTT entries. (The variable
 +       * dev->caps.mtt_entry_sz below is really the MTT segment
 +       * size, not the raw entry size)
 +       */
 +      dev->caps.reserved_mtts =
 +              ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz,
 +                    dma_get_cache_alignment()) / dev->caps.mtt_entry_sz;
 +
 +      err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table,
 +                                init_hca->mtt_base,
 +                                dev->caps.mtt_entry_sz,
 +                                dev->caps.num_mtt_segs,
 +                                dev->caps.reserved_mtts, 1, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map MTT context memory, aborting.\n");
 +              goto err_unmap_eq;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->mr_table.dmpt_table,
 +                                init_hca->dmpt_base,
 +                                dev_cap->dmpt_entry_sz,
 +                                dev->caps.num_mpts,
 +                                dev->caps.reserved_mrws, 1, 1);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n");
 +              goto err_unmap_mtt;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->qp_table.qp_table,
 +                                init_hca->qpc_base,
 +                                dev_cap->qpc_entry_sz,
 +                                dev->caps.num_qps,
 +                                dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
 +                                0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map QP context memory, aborting.\n");
 +              goto err_unmap_dmpt;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->qp_table.auxc_table,
 +                                init_hca->auxc_base,
 +                                dev_cap->aux_entry_sz,
 +                                dev->caps.num_qps,
 +                                dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
 +                                0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n");
 +              goto err_unmap_qp;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->qp_table.altc_table,
 +                                init_hca->altc_base,
 +                                dev_cap->altc_entry_sz,
 +                                dev->caps.num_qps,
 +                                dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
 +                                0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n");
 +              goto err_unmap_auxc;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->qp_table.rdmarc_table,
 +                                init_hca->rdmarc_base,
 +                                dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift,
 +                                dev->caps.num_qps,
 +                                dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW],
 +                                0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n");
 +              goto err_unmap_altc;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->cq_table.table,
 +                                init_hca->cqc_base,
 +                                dev_cap->cqc_entry_sz,
 +                                dev->caps.num_cqs,
 +                                dev->caps.reserved_cqs, 0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map CQ context memory, aborting.\n");
 +              goto err_unmap_rdmarc;
 +      }
 +
 +      err = mlx4_init_icm_table(dev, &priv->srq_table.table,
 +                                init_hca->srqc_base,
 +                                dev_cap->srq_entry_sz,
 +                                dev->caps.num_srqs,
 +                                dev->caps.reserved_srqs, 0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n");
 +              goto err_unmap_cq;
 +      }
 +
 +      /*
 +       * It's not strictly required, but for simplicity just map the
 +       * whole multicast group table now.  The table isn't very big
 +       * and it's a lot easier than trying to track ref counts.
 +       */
 +      err = mlx4_init_icm_table(dev, &priv->mcg_table.table,
 +                                init_hca->mc_base, MLX4_MGM_ENTRY_SIZE,
 +                                dev->caps.num_mgms + dev->caps.num_amgms,
 +                                dev->caps.num_mgms + dev->caps.num_amgms,
 +                                0, 0);
 +      if (err) {
 +              mlx4_err(dev, "Failed to map MCG context memory, aborting.\n");
 +              goto err_unmap_srq;
 +      }
 +
 +      return 0;
 +
 +err_unmap_srq:
 +      mlx4_cleanup_icm_table(dev, &priv->srq_table.table);
 +
 +err_unmap_cq:
 +      mlx4_cleanup_icm_table(dev, &priv->cq_table.table);
 +
 +err_unmap_rdmarc:
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table);
 +
 +err_unmap_altc:
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table);
 +
 +err_unmap_auxc:
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table);
 +
 +err_unmap_qp:
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table);
 +
 +err_unmap_dmpt:
 +      mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table);
 +
 +err_unmap_mtt:
 +      mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
 +
 +err_unmap_eq:
 +      mlx4_cleanup_icm_table(dev, &priv->eq_table.table);
 +
 +err_unmap_cmpt:
 +      mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
 +
 +err_unmap_aux:
 +      mlx4_UNMAP_ICM_AUX(dev);
 +
 +err_free_aux:
 +      mlx4_free_icm(dev, priv->fw.aux_icm, 0);
 +
 +      return err;
 +}
 +
 +static void mlx4_free_icms(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      mlx4_cleanup_icm_table(dev, &priv->mcg_table.table);
 +      mlx4_cleanup_icm_table(dev, &priv->srq_table.table);
 +      mlx4_cleanup_icm_table(dev, &priv->cq_table.table);
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table);
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table);
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table);
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table);
 +      mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->eq_table.table);
 +      mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
 +      mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
 +
 +      mlx4_UNMAP_ICM_AUX(dev);
 +      mlx4_free_icm(dev, priv->fw.aux_icm, 0);
 +}
 +
 +static int map_bf_area(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      resource_size_t bf_start;
 +      resource_size_t bf_len;
 +      int err = 0;
 +
 +      bf_start = pci_resource_start(dev->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT);
 +      bf_len = pci_resource_len(dev->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT);
 +      priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len);
 +      if (!priv->bf_mapping)
 +              err = -ENOMEM;
 +
 +      return err;
 +}
 +
 +static void unmap_bf_area(struct mlx4_dev *dev)
 +{
 +      if (mlx4_priv(dev)->bf_mapping)
 +              io_mapping_free(mlx4_priv(dev)->bf_mapping);
 +}
 +
 +static void mlx4_close_hca(struct mlx4_dev *dev)
 +{
 +      unmap_bf_area(dev);
 +      mlx4_CLOSE_HCA(dev, 0);
 +      mlx4_free_icms(dev);
 +      mlx4_UNMAP_FA(dev);
 +      mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0);
 +}
 +
 +static int mlx4_init_hca(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv          *priv = mlx4_priv(dev);
 +      struct mlx4_adapter        adapter;
 +      struct mlx4_dev_cap        dev_cap;
 +      struct mlx4_mod_stat_cfg   mlx4_cfg;
 +      struct mlx4_profile        profile;
 +      struct mlx4_init_hca_param init_hca;
 +      u64 icm_size;
 +      int err;
 +
 +      err = mlx4_QUERY_FW(dev);
 +      if (err) {
 +              if (err == -EACCES)
 +                      mlx4_info(dev, "non-primary physical function, skipping.\n");
 +              else
 +                      mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
 +              return err;
 +      }
 +
 +      err = mlx4_load_fw(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to start FW, aborting.\n");
 +              return err;
 +      }
 +
 +      mlx4_cfg.log_pg_sz_m = 1;
 +      mlx4_cfg.log_pg_sz = 0;
 +      err = mlx4_MOD_STAT_CFG(dev, &mlx4_cfg);
 +      if (err)
 +              mlx4_warn(dev, "Failed to override log_pg_sz parameter\n");
 +
 +      err = mlx4_dev_cap(dev, &dev_cap);
 +      if (err) {
 +              mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
 +              goto err_stop_fw;
 +      }
 +
 +      profile = default_profile;
 +
 +      icm_size = mlx4_make_profile(dev, &profile, &dev_cap, &init_hca);
 +      if ((long long) icm_size < 0) {
 +              err = icm_size;
 +              goto err_stop_fw;
 +      }
 +
 +      if (map_bf_area(dev))
 +              mlx4_dbg(dev, "Failed to map blue flame area\n");
 +
 +      init_hca.log_uar_sz = ilog2(dev->caps.num_uars);
 +
 +      err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size);
 +      if (err)
 +              goto err_stop_fw;
 +
 +      err = mlx4_INIT_HCA(dev, &init_hca);
 +      if (err) {
 +              mlx4_err(dev, "INIT_HCA command failed, aborting.\n");
 +              goto err_free_icm;
 +      }
 +
 +      err = mlx4_QUERY_ADAPTER(dev, &adapter);
 +      if (err) {
 +              mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n");
 +              goto err_close;
 +      }
 +
 +      priv->eq_table.inta_pin = adapter.inta_pin;
 +      memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
 +
 +      return 0;
 +
 +err_close:
 +      mlx4_CLOSE_HCA(dev, 0);
 +
 +err_free_icm:
 +      mlx4_free_icms(dev);
 +
 +err_stop_fw:
 +      unmap_bf_area(dev);
 +      mlx4_UNMAP_FA(dev);
 +      mlx4_free_icm(dev, priv->fw.fw_icm, 0);
 +
 +      return err;
 +}
 +
 +static int mlx4_init_counters_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int nent;
 +
 +      if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
 +              return -ENOENT;
 +
 +      nent = dev->caps.max_counters;
 +      return mlx4_bitmap_init(&priv->counters_bitmap, nent, nent - 1, 0, 0);
 +}
 +
 +static void mlx4_cleanup_counters_table(struct mlx4_dev *dev)
 +{
 +      mlx4_bitmap_cleanup(&mlx4_priv(dev)->counters_bitmap);
 +}
 +
 +int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
 +              return -ENOENT;
 +
 +      *idx = mlx4_bitmap_alloc(&priv->counters_bitmap);
 +      if (*idx == -1)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_counter_alloc);
 +
 +void mlx4_counter_free(struct mlx4_dev *dev, u32 idx)
 +{
 +      mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx);
 +      return;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_counter_free);
 +
 +static int mlx4_setup_hca(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int err;
 +      int port;
 +      __be32 ib_port_default_caps;
 +
 +      err = mlx4_init_uar_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "user access region table, aborting.\n");
 +              return err;
 +      }
 +
 +      err = mlx4_uar_alloc(dev, &priv->driver_uar);
 +      if (err) {
 +              mlx4_err(dev, "Failed to allocate driver access region, "
 +                       "aborting.\n");
 +              goto err_uar_table_free;
 +      }
 +
 +      priv->kar = ioremap((phys_addr_t) priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
 +      if (!priv->kar) {
 +              mlx4_err(dev, "Couldn't map kernel access region, "
 +                       "aborting.\n");
 +              err = -ENOMEM;
 +              goto err_uar_free;
 +      }
 +
 +      err = mlx4_init_pd_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "protection domain table, aborting.\n");
 +              goto err_kar_unmap;
 +      }
 +
++      err = mlx4_init_xrcd_table(dev);
++      if (err) {
++              mlx4_err(dev, "Failed to initialize "
++                       "reliable connection domain table, aborting.\n");
++              goto err_pd_table_free;
++      }
++
 +      err = mlx4_init_mr_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "memory region table, aborting.\n");
-       if ((log_num_vlan < 0) || (log_num_vlan > 7)) {
-               pr_warning("mlx4_core: bad num_vlan: %d\n", log_num_vlan);
-               return -1;
-       }
++              goto err_xrcd_table_free;
 +      }
 +
 +      err = mlx4_init_eq_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "event queue table, aborting.\n");
 +              goto err_mr_table_free;
 +      }
 +
 +      err = mlx4_cmd_use_events(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to switch to event-driven "
 +                       "firmware commands, aborting.\n");
 +              goto err_eq_table_free;
 +      }
 +
 +      err = mlx4_NOP(dev);
 +      if (err) {
 +              if (dev->flags & MLX4_FLAG_MSI_X) {
 +                      mlx4_warn(dev, "NOP command failed to generate MSI-X "
 +                                "interrupt IRQ %d).\n",
 +                                priv->eq_table.eq[dev->caps.num_comp_vectors].irq);
 +                      mlx4_warn(dev, "Trying again without MSI-X.\n");
 +              } else {
 +                      mlx4_err(dev, "NOP command failed to generate interrupt "
 +                               "(IRQ %d), aborting.\n",
 +                               priv->eq_table.eq[dev->caps.num_comp_vectors].irq);
 +                      mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
 +              }
 +
 +              goto err_cmd_poll;
 +      }
 +
 +      mlx4_dbg(dev, "NOP command IRQ test passed\n");
 +
 +      err = mlx4_init_cq_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "completion queue table, aborting.\n");
 +              goto err_cmd_poll;
 +      }
 +
 +      err = mlx4_init_srq_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "shared receive queue table, aborting.\n");
 +              goto err_cq_table_free;
 +      }
 +
 +      err = mlx4_init_qp_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "queue pair table, aborting.\n");
 +              goto err_srq_table_free;
 +      }
 +
 +      err = mlx4_init_mcg_table(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to initialize "
 +                       "multicast group table, aborting.\n");
 +              goto err_qp_table_free;
 +      }
 +
 +      err = mlx4_init_counters_table(dev);
 +      if (err && err != -ENOENT) {
 +              mlx4_err(dev, "Failed to initialize counters table, aborting.\n");
 +              goto err_counters_table_free;
 +      }
 +
 +      for (port = 1; port <= dev->caps.num_ports; port++) {
 +              enum mlx4_port_type port_type = 0;
 +              mlx4_SENSE_PORT(dev, port, &port_type);
 +              if (port_type)
 +                      dev->caps.port_type[port] = port_type;
 +              ib_port_default_caps = 0;
 +              err = mlx4_get_port_ib_caps(dev, port, &ib_port_default_caps);
 +              if (err)
 +                      mlx4_warn(dev, "failed to get port %d default "
 +                                "ib capabilities (%d). Continuing with "
 +                                "caps = 0\n", port, err);
 +              dev->caps.ib_port_def_cap[port] = ib_port_default_caps;
++
++              err = mlx4_check_ext_port_caps(dev, port);
++              if (err)
++                      mlx4_warn(dev, "failed to get port %d extended "
++                                "port capabilities support info (%d)."
++                                " Assuming not supported\n", port, err);
++
 +              err = mlx4_SET_PORT(dev, port);
 +              if (err) {
 +                      mlx4_err(dev, "Failed to set port %d, aborting\n",
 +                              port);
 +                      goto err_mcg_table_free;
 +              }
 +      }
 +      mlx4_set_port_mask(dev);
 +
 +      return 0;
 +
 +err_mcg_table_free:
 +      mlx4_cleanup_mcg_table(dev);
 +
 +err_counters_table_free:
 +      mlx4_cleanup_counters_table(dev);
 +
 +err_qp_table_free:
 +      mlx4_cleanup_qp_table(dev);
 +
 +err_srq_table_free:
 +      mlx4_cleanup_srq_table(dev);
 +
 +err_cq_table_free:
 +      mlx4_cleanup_cq_table(dev);
 +
 +err_cmd_poll:
 +      mlx4_cmd_use_polling(dev);
 +
 +err_eq_table_free:
 +      mlx4_cleanup_eq_table(dev);
 +
 +err_mr_table_free:
 +      mlx4_cleanup_mr_table(dev);
 +
++err_xrcd_table_free:
++      mlx4_cleanup_xrcd_table(dev);
++
 +err_pd_table_free:
 +      mlx4_cleanup_pd_table(dev);
 +
 +err_kar_unmap:
 +      iounmap(priv->kar);
 +
 +err_uar_free:
 +      mlx4_uar_free(dev, &priv->driver_uar);
 +
 +err_uar_table_free:
 +      mlx4_cleanup_uar_table(dev);
 +      return err;
 +}
 +
 +static void mlx4_enable_msi_x(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct msix_entry *entries;
 +      int nreq = min_t(int, dev->caps.num_ports *
 +                       min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT)
 +                              + MSIX_LEGACY_SZ, MAX_MSIX);
 +      int err;
 +      int i;
 +
 +      if (msi_x) {
 +              nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
 +                           nreq);
 +              entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL);
 +              if (!entries)
 +                      goto no_msi;
 +
 +              for (i = 0; i < nreq; ++i)
 +                      entries[i].entry = i;
 +
 +      retry:
 +              err = pci_enable_msix(dev->pdev, entries, nreq);
 +              if (err) {
 +                      /* Try again if at least 2 vectors are available */
 +                      if (err > 1) {
 +                              mlx4_info(dev, "Requested %d vectors, "
 +                                        "but only %d MSI-X vectors available, "
 +                                        "trying again\n", nreq, err);
 +                              nreq = err;
 +                              goto retry;
 +                      }
 +                      kfree(entries);
 +                      goto no_msi;
 +              }
 +
 +              if (nreq <
 +                  MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) {
 +                      /*Working in legacy mode , all EQ's shared*/
 +                      dev->caps.comp_pool           = 0;
 +                      dev->caps.num_comp_vectors = nreq - 1;
 +              } else {
 +                      dev->caps.comp_pool           = nreq - MSIX_LEGACY_SZ;
 +                      dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1;
 +              }
 +              for (i = 0; i < nreq; ++i)
 +                      priv->eq_table.eq[i].irq = entries[i].vector;
 +
 +              dev->flags |= MLX4_FLAG_MSI_X;
 +
 +              kfree(entries);
 +              return;
 +      }
 +
 +no_msi:
 +      dev->caps.num_comp_vectors = 1;
 +      dev->caps.comp_pool        = 0;
 +
 +      for (i = 0; i < 2; ++i)
 +              priv->eq_table.eq[i].irq = dev->pdev->irq;
 +}
 +
 +static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
 +{
 +      struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
 +      int err = 0;
 +
 +      info->dev = dev;
 +      info->port = port;
 +      mlx4_init_mac_table(dev, &info->mac_table);
 +      mlx4_init_vlan_table(dev, &info->vlan_table);
 +      info->base_qpn = dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
 +                      (port - 1) * (1 << log_num_mac);
 +
 +      sprintf(info->dev_name, "mlx4_port%d", port);
 +      info->port_attr.attr.name = info->dev_name;
 +      info->port_attr.attr.mode = S_IRUGO | S_IWUSR;
 +      info->port_attr.show      = show_port_type;
 +      info->port_attr.store     = set_port_type;
 +      sysfs_attr_init(&info->port_attr.attr);
 +
 +      err = device_create_file(&dev->pdev->dev, &info->port_attr);
 +      if (err) {
 +              mlx4_err(dev, "Failed to create file for port %d\n", port);
 +              info->port = -1;
 +      }
 +
 +      return err;
 +}
 +
 +static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
 +{
 +      if (info->port < 0)
 +              return;
 +
 +      device_remove_file(&info->dev->pdev->dev, &info->port_attr);
 +}
 +
 +static int mlx4_init_steering(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int num_entries = dev->caps.num_ports;
 +      int i, j;
 +
 +      priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL);
 +      if (!priv->steer)
 +              return -ENOMEM;
 +
 +      for (i = 0; i < num_entries; i++) {
 +              for (j = 0; j < MLX4_NUM_STEERS; j++) {
 +                      INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]);
 +                      INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]);
 +              }
 +              INIT_LIST_HEAD(&priv->steer[i].high_prios);
 +      }
 +      return 0;
 +}
 +
 +static void mlx4_clear_steering(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_steer_index *entry, *tmp_entry;
 +      struct mlx4_promisc_qp *pqp, *tmp_pqp;
 +      int num_entries = dev->caps.num_ports;
 +      int i, j;
 +
 +      for (i = 0; i < num_entries; i++) {
 +              for (j = 0; j < MLX4_NUM_STEERS; j++) {
 +                      list_for_each_entry_safe(pqp, tmp_pqp,
 +                                               &priv->steer[i].promisc_qps[j],
 +                                               list) {
 +                              list_del(&pqp->list);
 +                              kfree(pqp);
 +                      }
 +                      list_for_each_entry_safe(entry, tmp_entry,
 +                                               &priv->steer[i].steer_entries[j],
 +                                               list) {
 +                              list_del(&entry->list);
 +                              list_for_each_entry_safe(pqp, tmp_pqp,
 +                                                       &entry->duplicates,
 +                                                       list) {
 +                                      list_del(&pqp->list);
 +                                      kfree(pqp);
 +                              }
 +                              kfree(entry);
 +                      }
 +              }
 +      }
 +      kfree(priv->steer);
 +}
 +
 +static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 +{
 +      struct mlx4_priv *priv;
 +      struct mlx4_dev *dev;
 +      int err;
 +      int port;
 +
 +      pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
 +
 +      err = pci_enable_device(pdev);
 +      if (err) {
 +              dev_err(&pdev->dev, "Cannot enable PCI device, "
 +                      "aborting.\n");
 +              return err;
 +      }
 +
 +      /*
 +       * Check for BARs.  We expect 0: 1MB
 +       */
 +      if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
 +          pci_resource_len(pdev, 0) != 1 << 20) {
 +              dev_err(&pdev->dev, "Missing DCS, aborting.\n");
 +              err = -ENODEV;
 +              goto err_disable_pdev;
 +      }
 +      if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
 +              dev_err(&pdev->dev, "Missing UAR, aborting.\n");
 +              err = -ENODEV;
 +              goto err_disable_pdev;
 +      }
 +
 +      err = pci_request_regions(pdev, DRV_NAME);
 +      if (err) {
 +              dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n");
 +              goto err_disable_pdev;
 +      }
 +
 +      pci_set_master(pdev);
 +
 +      err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
 +      if (err) {
 +              dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n");
 +              err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 +              if (err) {
 +                      dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n");
 +                      goto err_release_regions;
 +              }
 +      }
 +      err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
 +      if (err) {
 +              dev_warn(&pdev->dev, "Warning: couldn't set 64-bit "
 +                       "consistent PCI DMA mask.\n");
 +              err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 +              if (err) {
 +                      dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, "
 +                              "aborting.\n");
 +                      goto err_release_regions;
 +              }
 +      }
 +
 +      /* Allow large DMA segments, up to the firmware limit of 1 GB */
 +      dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
 +
 +      priv = kzalloc(sizeof *priv, GFP_KERNEL);
 +      if (!priv) {
 +              dev_err(&pdev->dev, "Device struct alloc failed, "
 +                      "aborting.\n");
 +              err = -ENOMEM;
 +              goto err_release_regions;
 +      }
 +
 +      dev       = &priv->dev;
 +      dev->pdev = pdev;
 +      INIT_LIST_HEAD(&priv->ctx_list);
 +      spin_lock_init(&priv->ctx_lock);
 +
 +      mutex_init(&priv->port_mutex);
 +
 +      INIT_LIST_HEAD(&priv->pgdir_list);
 +      mutex_init(&priv->pgdir_mutex);
 +
 +      INIT_LIST_HEAD(&priv->bf_list);
 +      mutex_init(&priv->bf_mutex);
 +
 +      dev->rev_id = pdev->revision;
 +
 +      /*
 +       * Now reset the HCA before we touch the PCI capabilities or
 +       * attempt a firmware command, since a boot ROM may have left
 +       * the HCA in an undefined state.
 +       */
 +      err = mlx4_reset(dev);
 +      if (err) {
 +              mlx4_err(dev, "Failed to reset HCA, aborting.\n");
 +              goto err_free_dev;
 +      }
 +
 +      if (mlx4_cmd_init(dev)) {
 +              mlx4_err(dev, "Failed to init command interface, aborting.\n");
 +              goto err_free_dev;
 +      }
 +
 +      err = mlx4_init_hca(dev);
 +      if (err)
 +              goto err_cmd;
 +
 +      err = mlx4_alloc_eq_table(dev);
 +      if (err)
 +              goto err_close;
 +
 +      priv->msix_ctl.pool_bm = 0;
 +      spin_lock_init(&priv->msix_ctl.pool_lock);
 +
 +      mlx4_enable_msi_x(dev);
 +
 +      err = mlx4_init_steering(dev);
 +      if (err)
 +              goto err_free_eq;
 +
 +      err = mlx4_setup_hca(dev);
 +      if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) {
 +              dev->flags &= ~MLX4_FLAG_MSI_X;
 +              pci_disable_msix(pdev);
 +              err = mlx4_setup_hca(dev);
 +      }
 +
 +      if (err)
 +              goto err_steer;
 +
 +      for (port = 1; port <= dev->caps.num_ports; port++) {
 +              err = mlx4_init_port_info(dev, port);
 +              if (err)
 +                      goto err_port;
 +      }
 +
 +      err = mlx4_register_device(dev);
 +      if (err)
 +              goto err_port;
 +
 +      mlx4_sense_init(dev);
 +      mlx4_start_sense(dev);
 +
 +      pci_set_drvdata(pdev, dev);
 +
 +      return 0;
 +
 +err_port:
 +      for (--port; port >= 1; --port)
 +              mlx4_cleanup_port_info(&priv->port[port]);
 +
 +      mlx4_cleanup_counters_table(dev);
 +      mlx4_cleanup_mcg_table(dev);
 +      mlx4_cleanup_qp_table(dev);
 +      mlx4_cleanup_srq_table(dev);
 +      mlx4_cleanup_cq_table(dev);
 +      mlx4_cmd_use_polling(dev);
 +      mlx4_cleanup_eq_table(dev);
 +      mlx4_cleanup_mr_table(dev);
++      mlx4_cleanup_xrcd_table(dev);
 +      mlx4_cleanup_pd_table(dev);
 +      mlx4_cleanup_uar_table(dev);
 +
 +err_steer:
 +      mlx4_clear_steering(dev);
 +
 +err_free_eq:
 +      mlx4_free_eq_table(dev);
 +
 +err_close:
 +      if (dev->flags & MLX4_FLAG_MSI_X)
 +              pci_disable_msix(pdev);
 +
 +      mlx4_close_hca(dev);
 +
 +err_cmd:
 +      mlx4_cmd_cleanup(dev);
 +
 +err_free_dev:
 +      kfree(priv);
 +
 +err_release_regions:
 +      pci_release_regions(pdev);
 +
 +err_disable_pdev:
 +      pci_disable_device(pdev);
 +      pci_set_drvdata(pdev, NULL);
 +      return err;
 +}
 +
 +static int __devinit mlx4_init_one(struct pci_dev *pdev,
 +                                 const struct pci_device_id *id)
 +{
 +      printk_once(KERN_INFO "%s", mlx4_version);
 +
 +      return __mlx4_init_one(pdev, id);
 +}
 +
 +static void mlx4_remove_one(struct pci_dev *pdev)
 +{
 +      struct mlx4_dev  *dev  = pci_get_drvdata(pdev);
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int p;
 +
 +      if (dev) {
 +              mlx4_stop_sense(dev);
 +              mlx4_unregister_device(dev);
 +
 +              for (p = 1; p <= dev->caps.num_ports; p++) {
 +                      mlx4_cleanup_port_info(&priv->port[p]);
 +                      mlx4_CLOSE_PORT(dev, p);
 +              }
 +
 +              mlx4_cleanup_counters_table(dev);
 +              mlx4_cleanup_mcg_table(dev);
 +              mlx4_cleanup_qp_table(dev);
 +              mlx4_cleanup_srq_table(dev);
 +              mlx4_cleanup_cq_table(dev);
 +              mlx4_cmd_use_polling(dev);
 +              mlx4_cleanup_eq_table(dev);
 +              mlx4_cleanup_mr_table(dev);
++              mlx4_cleanup_xrcd_table(dev);
 +              mlx4_cleanup_pd_table(dev);
 +
 +              iounmap(priv->kar);
 +              mlx4_uar_free(dev, &priv->driver_uar);
 +              mlx4_cleanup_uar_table(dev);
 +              mlx4_clear_steering(dev);
 +              mlx4_free_eq_table(dev);
 +              mlx4_close_hca(dev);
 +              mlx4_cmd_cleanup(dev);
 +
 +              if (dev->flags & MLX4_FLAG_MSI_X)
 +                      pci_disable_msix(pdev);
 +
 +              kfree(priv);
 +              pci_release_regions(pdev);
 +              pci_disable_device(pdev);
 +              pci_set_drvdata(pdev, NULL);
 +      }
 +}
 +
 +int mlx4_restart_one(struct pci_dev *pdev)
 +{
 +      mlx4_remove_one(pdev);
 +      return __mlx4_init_one(pdev, NULL);
 +}
 +
 +static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
 +      { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
 +      { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
 +      { PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */
 +      { PCI_VDEVICE(MELLANOX, 0x6732) }, /* MT25408 "Hermon" DDR PCIe gen2 */
 +      { PCI_VDEVICE(MELLANOX, 0x673c) }, /* MT25408 "Hermon" QDR PCIe gen2 */
 +      { PCI_VDEVICE(MELLANOX, 0x6368) }, /* MT25408 "Hermon" EN 10GigE */
 +      { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */
 +      { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */
 +      { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */
 +      { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/
 +      { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */
 +      { PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX2 40GigE PCIe gen2 */
 +      { PCI_VDEVICE(MELLANOX, 0x1002) }, /* MT25400 Family [ConnectX-2 Virtual Function] */
 +      { PCI_VDEVICE(MELLANOX, 0x1003) }, /* MT27500 Family [ConnectX-3] */
 +      { PCI_VDEVICE(MELLANOX, 0x1004) }, /* MT27500 Family [ConnectX-3 Virtual Function] */
 +      { PCI_VDEVICE(MELLANOX, 0x1005) }, /* MT27510 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x1006) }, /* MT27511 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x1007) }, /* MT27520 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x1008) }, /* MT27521 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x1009) }, /* MT27530 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x100a) }, /* MT27531 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x100b) }, /* MT27540 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x100c) }, /* MT27541 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x100d) }, /* MT27550 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x100e) }, /* MT27551 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x100f) }, /* MT27560 Family */
 +      { PCI_VDEVICE(MELLANOX, 0x1010) }, /* MT27561 Family */
 +      { 0, }
 +};
 +
 +MODULE_DEVICE_TABLE(pci, mlx4_pci_table);
 +
 +static struct pci_driver mlx4_driver = {
 +      .name           = DRV_NAME,
 +      .id_table       = mlx4_pci_table,
 +      .probe          = mlx4_init_one,
 +      .remove         = __devexit_p(mlx4_remove_one)
 +};
 +
 +static int __init mlx4_verify_params(void)
 +{
 +      if ((log_num_mac < 0) || (log_num_mac > 7)) {
 +              pr_warning("mlx4_core: bad num_mac: %d\n", log_num_mac);
 +              return -1;
 +      }
 +
++      if (log_num_vlan != 0)
++              pr_warning("mlx4_core: log_num_vlan - obsolete module param, using %d\n",
++                         MLX4_LOG_NUM_VLANS);
 +
 +      if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 7)) {
 +              pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +static int __init mlx4_init(void)
 +{
 +      int ret;
 +
 +      if (mlx4_verify_params())
 +              return -EINVAL;
 +
 +      mlx4_catas_init();
 +
 +      mlx4_wq = create_singlethread_workqueue("mlx4");
 +      if (!mlx4_wq)
 +              return -ENOMEM;
 +
 +      ret = pci_register_driver(&mlx4_driver);
 +      return ret < 0 ? ret : 0;
 +}
 +
 +static void __exit mlx4_cleanup(void)
 +{
 +      pci_unregister_driver(&mlx4_driver);
 +      destroy_workqueue(mlx4_wq);
 +}
 +
 +module_init(mlx4_init);
 +module_exit(mlx4_cleanup);
index a2fcd8402d37295a04474e502a8594dfb8a4a188,0000000000000000000000000000000000000000..5dfa68ffc11c4ea9bacb8b8bdfff94299fd630c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,459 -1,0 +1,463 @@@
 +/*
 + * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 + * Copyright (c) 2005, 2006, 2007 Cisco Systems.  All rights reserved.
 + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
 + * Copyright (c) 2004 Voltaire, 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.
 + */
 +
 +#ifndef MLX4_H
 +#define MLX4_H
 +
 +#include <linux/mutex.h>
 +#include <linux/radix-tree.h>
 +#include <linux/timer.h>
 +#include <linux/semaphore.h>
 +#include <linux/workqueue.h>
 +
 +#include <linux/mlx4/device.h>
 +#include <linux/mlx4/driver.h>
 +#include <linux/mlx4/doorbell.h>
 +
 +#define DRV_NAME      "mlx4_core"
 +#define DRV_VERSION   "1.0"
 +#define DRV_RELDATE   "July 14, 2011"
 +
 +enum {
 +      MLX4_HCR_BASE           = 0x80680,
 +      MLX4_HCR_SIZE           = 0x0001c,
 +      MLX4_CLR_INT_SIZE       = 0x00008
 +};
 +
 +enum {
 +      MLX4_MGM_ENTRY_SIZE     =  0x100,
 +      MLX4_QP_PER_MGM         = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2),
 +      MLX4_MTT_ENTRY_PER_SEG  = 8
 +};
 +
 +enum {
 +      MLX4_NUM_PDS            = 1 << 15
 +};
 +
 +enum {
 +      MLX4_CMPT_TYPE_QP       = 0,
 +      MLX4_CMPT_TYPE_SRQ      = 1,
 +      MLX4_CMPT_TYPE_CQ       = 2,
 +      MLX4_CMPT_TYPE_EQ       = 3,
 +      MLX4_CMPT_NUM_TYPE
 +};
 +
 +enum {
 +      MLX4_CMPT_SHIFT         = 24,
 +      MLX4_NUM_CMPTS          = MLX4_CMPT_NUM_TYPE << MLX4_CMPT_SHIFT
 +};
 +
 +#ifdef CONFIG_MLX4_DEBUG
 +extern int mlx4_debug_level;
 +#else /* CONFIG_MLX4_DEBUG */
 +#define mlx4_debug_level      (0)
 +#endif /* CONFIG_MLX4_DEBUG */
 +
 +#define mlx4_dbg(mdev, format, arg...)                                        \
 +do {                                                                  \
 +      if (mlx4_debug_level)                                           \
 +              dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ##arg); \
 +} while (0)
 +
 +#define mlx4_err(mdev, format, arg...) \
 +      dev_err(&mdev->pdev->dev, format, ##arg)
 +#define mlx4_info(mdev, format, arg...) \
 +      dev_info(&mdev->pdev->dev, format, ##arg)
 +#define mlx4_warn(mdev, format, arg...) \
 +      dev_warn(&mdev->pdev->dev, format, ##arg)
 +
 +struct mlx4_bitmap {
 +      u32                     last;
 +      u32                     top;
 +      u32                     max;
 +      u32                     reserved_top;
 +      u32                     mask;
 +      u32                     avail;
 +      spinlock_t              lock;
 +      unsigned long          *table;
 +};
 +
 +struct mlx4_buddy {
 +      unsigned long         **bits;
 +      unsigned int           *num_free;
 +      int                     max_order;
 +      spinlock_t              lock;
 +};
 +
 +struct mlx4_icm;
 +
 +struct mlx4_icm_table {
 +      u64                     virt;
 +      int                     num_icm;
 +      int                     num_obj;
 +      int                     obj_size;
 +      int                     lowmem;
 +      int                     coherent;
 +      struct mutex            mutex;
 +      struct mlx4_icm       **icm;
 +};
 +
 +struct mlx4_eq {
 +      struct mlx4_dev        *dev;
 +      void __iomem           *doorbell;
 +      int                     eqn;
 +      u32                     cons_index;
 +      u16                     irq;
 +      u16                     have_irq;
 +      int                     nent;
 +      struct mlx4_buf_list   *page_list;
 +      struct mlx4_mtt         mtt;
 +};
 +
 +struct mlx4_profile {
 +      int                     num_qp;
 +      int                     rdmarc_per_qp;
 +      int                     num_srq;
 +      int                     num_cq;
 +      int                     num_mcg;
 +      int                     num_mpt;
 +      int                     num_mtt;
 +};
 +
 +struct mlx4_fw {
 +      u64                     clr_int_base;
 +      u64                     catas_offset;
 +      struct mlx4_icm        *fw_icm;
 +      struct mlx4_icm        *aux_icm;
 +      u32                     catas_size;
 +      u16                     fw_pages;
 +      u8                      clr_int_bar;
 +      u8                      catas_bar;
 +};
 +
 +#define MGM_QPN_MASK       0x00FFFFFF
 +#define MGM_BLCK_LB_BIT    30
 +
 +struct mlx4_promisc_qp {
 +      struct list_head list;
 +      u32 qpn;
 +};
 +
 +struct mlx4_steer_index {
 +      struct list_head list;
 +      unsigned int index;
 +      struct list_head duplicates;
 +};
 +
 +struct mlx4_mgm {
 +      __be32                  next_gid_index;
 +      __be32                  members_count;
 +      u32                     reserved[2];
 +      u8                      gid[16];
 +      __be32                  qp[MLX4_QP_PER_MGM];
 +};
 +struct mlx4_cmd {
 +      struct pci_pool        *pool;
 +      void __iomem           *hcr;
 +      struct mutex            hcr_mutex;
 +      struct semaphore        poll_sem;
 +      struct semaphore        event_sem;
 +      int                     max_cmds;
 +      spinlock_t              context_lock;
 +      int                     free_head;
 +      struct mlx4_cmd_context *context;
 +      u16                     token_mask;
 +      u8                      use_events;
 +      u8                      toggle;
 +};
 +
 +struct mlx4_uar_table {
 +      struct mlx4_bitmap      bitmap;
 +};
 +
 +struct mlx4_mr_table {
 +      struct mlx4_bitmap      mpt_bitmap;
 +      struct mlx4_buddy       mtt_buddy;
 +      u64                     mtt_base;
 +      u64                     mpt_base;
 +      struct mlx4_icm_table   mtt_table;
 +      struct mlx4_icm_table   dmpt_table;
 +};
 +
 +struct mlx4_cq_table {
 +      struct mlx4_bitmap      bitmap;
 +      spinlock_t              lock;
 +      struct radix_tree_root  tree;
 +      struct mlx4_icm_table   table;
 +      struct mlx4_icm_table   cmpt_table;
 +};
 +
 +struct mlx4_eq_table {
 +      struct mlx4_bitmap      bitmap;
 +      char                   *irq_names;
 +      void __iomem           *clr_int;
 +      void __iomem          **uar_map;
 +      u32                     clr_mask;
 +      struct mlx4_eq         *eq;
 +      struct mlx4_icm_table   table;
 +      struct mlx4_icm_table   cmpt_table;
 +      int                     have_irq;
 +      u8                      inta_pin;
 +};
 +
 +struct mlx4_srq_table {
 +      struct mlx4_bitmap      bitmap;
 +      spinlock_t              lock;
 +      struct radix_tree_root  tree;
 +      struct mlx4_icm_table   table;
 +      struct mlx4_icm_table   cmpt_table;
 +};
 +
 +struct mlx4_qp_table {
 +      struct mlx4_bitmap      bitmap;
 +      u32                     rdmarc_base;
 +      int                     rdmarc_shift;
 +      spinlock_t              lock;
 +      struct mlx4_icm_table   qp_table;
 +      struct mlx4_icm_table   auxc_table;
 +      struct mlx4_icm_table   altc_table;
 +      struct mlx4_icm_table   rdmarc_table;
 +      struct mlx4_icm_table   cmpt_table;
 +};
 +
 +struct mlx4_mcg_table {
 +      struct mutex            mutex;
 +      struct mlx4_bitmap      bitmap;
 +      struct mlx4_icm_table   table;
 +};
 +
 +struct mlx4_catas_err {
 +      u32 __iomem            *map;
 +      struct timer_list       timer;
 +      struct list_head        list;
 +};
 +
 +#define MLX4_MAX_MAC_NUM      128
 +#define MLX4_MAC_TABLE_SIZE   (MLX4_MAX_MAC_NUM << 3)
 +
 +struct mlx4_mac_table {
 +      __be64                  entries[MLX4_MAX_MAC_NUM];
 +      int                     refs[MLX4_MAX_MAC_NUM];
 +      struct mutex            mutex;
 +      int                     total;
 +      int                     max;
 +};
 +
 +#define MLX4_MAX_VLAN_NUM     128
 +#define MLX4_VLAN_TABLE_SIZE  (MLX4_MAX_VLAN_NUM << 2)
 +
 +struct mlx4_vlan_table {
 +      __be32                  entries[MLX4_MAX_VLAN_NUM];
 +      int                     refs[MLX4_MAX_VLAN_NUM];
 +      struct mutex            mutex;
 +      int                     total;
 +      int                     max;
 +};
 +
 +struct mlx4_mac_entry {
 +      u64 mac;
 +};
 +
 +struct mlx4_port_info {
 +      struct mlx4_dev        *dev;
 +      int                     port;
 +      char                    dev_name[16];
 +      struct device_attribute port_attr;
 +      enum mlx4_port_type     tmp_type;
 +      struct mlx4_mac_table   mac_table;
 +      struct radix_tree_root  mac_tree;
 +      struct mlx4_vlan_table  vlan_table;
 +      int                     base_qpn;
 +};
 +
 +struct mlx4_sense {
 +      struct mlx4_dev         *dev;
 +      u8                      do_sense_port[MLX4_MAX_PORTS + 1];
 +      u8                      sense_allowed[MLX4_MAX_PORTS + 1];
 +      struct delayed_work     sense_poll;
 +};
 +
 +struct mlx4_msix_ctl {
 +      u64             pool_bm;
 +      spinlock_t      pool_lock;
 +};
 +
 +struct mlx4_steer {
 +      struct list_head promisc_qps[MLX4_NUM_STEERS];
 +      struct list_head steer_entries[MLX4_NUM_STEERS];
 +      struct list_head high_prios;
 +};
 +
 +struct mlx4_priv {
 +      struct mlx4_dev         dev;
 +
 +      struct list_head        dev_list;
 +      struct list_head        ctx_list;
 +      spinlock_t              ctx_lock;
 +
 +      struct list_head        pgdir_list;
 +      struct mutex            pgdir_mutex;
 +
 +      struct mlx4_fw          fw;
 +      struct mlx4_cmd         cmd;
 +
 +      struct mlx4_bitmap      pd_bitmap;
++      struct mlx4_bitmap      xrcd_bitmap;
 +      struct mlx4_uar_table   uar_table;
 +      struct mlx4_mr_table    mr_table;
 +      struct mlx4_cq_table    cq_table;
 +      struct mlx4_eq_table    eq_table;
 +      struct mlx4_srq_table   srq_table;
 +      struct mlx4_qp_table    qp_table;
 +      struct mlx4_mcg_table   mcg_table;
 +      struct mlx4_bitmap      counters_bitmap;
 +
 +      struct mlx4_catas_err   catas_err;
 +
 +      void __iomem           *clr_base;
 +
 +      struct mlx4_uar         driver_uar;
 +      void __iomem           *kar;
 +      struct mlx4_port_info   port[MLX4_MAX_PORTS + 1];
 +      struct mlx4_sense       sense;
 +      struct mutex            port_mutex;
 +      struct mlx4_msix_ctl    msix_ctl;
 +      struct mlx4_steer       *steer;
 +      struct list_head        bf_list;
 +      struct mutex            bf_mutex;
 +      struct io_mapping       *bf_mapping;
 +};
 +
 +static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
 +{
 +      return container_of(dev, struct mlx4_priv, dev);
 +}
 +
 +#define MLX4_SENSE_RANGE      (HZ * 3)
 +
 +extern struct workqueue_struct *mlx4_wq;
 +
 +u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
 +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj);
 +u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align);
 +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt);
 +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap);
 +int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
 +                   u32 reserved_bot, u32 resetrved_top);
 +void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap);
 +
 +int mlx4_reset(struct mlx4_dev *dev);
 +
 +int mlx4_alloc_eq_table(struct mlx4_dev *dev);
 +void mlx4_free_eq_table(struct mlx4_dev *dev);
 +
 +int mlx4_init_pd_table(struct mlx4_dev *dev);
++int mlx4_init_xrcd_table(struct mlx4_dev *dev);
 +int mlx4_init_uar_table(struct mlx4_dev *dev);
 +int mlx4_init_mr_table(struct mlx4_dev *dev);
 +int mlx4_init_eq_table(struct mlx4_dev *dev);
 +int mlx4_init_cq_table(struct mlx4_dev *dev);
 +int mlx4_init_qp_table(struct mlx4_dev *dev);
 +int mlx4_init_srq_table(struct mlx4_dev *dev);
 +int mlx4_init_mcg_table(struct mlx4_dev *dev);
 +
 +void mlx4_cleanup_pd_table(struct mlx4_dev *dev);
++void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_uar_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_mr_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_eq_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_cq_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
 +void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
 +
 +void mlx4_start_catas_poll(struct mlx4_dev *dev);
 +void mlx4_stop_catas_poll(struct mlx4_dev *dev);
 +void mlx4_catas_init(void);
 +int mlx4_restart_one(struct pci_dev *pdev);
 +int mlx4_register_device(struct mlx4_dev *dev);
 +void mlx4_unregister_device(struct mlx4_dev *dev);
 +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, int port);
 +
 +struct mlx4_dev_cap;
 +struct mlx4_init_hca_param;
 +
 +u64 mlx4_make_profile(struct mlx4_dev *dev,
 +                    struct mlx4_profile *request,
 +                    struct mlx4_dev_cap *dev_cap,
 +                    struct mlx4_init_hca_param *init_hca);
 +
 +int mlx4_cmd_init(struct mlx4_dev *dev);
 +void mlx4_cmd_cleanup(struct mlx4_dev *dev);
 +void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param);
 +int mlx4_cmd_use_events(struct mlx4_dev *dev);
 +void mlx4_cmd_use_polling(struct mlx4_dev *dev);
 +
 +void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn);
 +void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type);
 +
 +void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type);
 +
 +void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
 +
 +void mlx4_handle_catas_err(struct mlx4_dev *dev);
 +
 +int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port,
 +                  enum mlx4_port_type *type);
 +void mlx4_do_sense_ports(struct mlx4_dev *dev,
 +                       enum mlx4_port_type *stype,
 +                       enum mlx4_port_type *defaults);
 +void mlx4_start_sense(struct mlx4_dev *dev);
 +void mlx4_stop_sense(struct mlx4_dev *dev);
 +void mlx4_sense_init(struct mlx4_dev *dev);
 +int mlx4_check_port_params(struct mlx4_dev *dev,
 +                         enum mlx4_port_type *port_type);
 +int mlx4_change_port_types(struct mlx4_dev *dev,
 +                         enum mlx4_port_type *port_types);
 +
 +void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
 +void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
 +
 +int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port);
 +int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps);
++int mlx4_check_ext_port_caps(struct mlx4_dev *dev, u8 port);
 +
 +int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 +                        enum mlx4_protocol prot, enum mlx4_steer_type steer);
 +int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 +                        int block_mcast_loopback, enum mlx4_protocol prot,
 +                        enum mlx4_steer_type steer);
 +#endif /* MLX4_H */
index 9c188bdd7f4f2c5a6a3a124749d513c4d6b77958,0000000000000000000000000000000000000000..ab639cfef78ea8005f39beccd6a8f71a92ed96c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,667 -1,0 +1,667 @@@
-       buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof (int *),
 +/*
 + * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
 + * Copyright (c) 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/errno.h>
 +#include <linux/slab.h>
 +
 +#include <linux/mlx4/cmd.h>
 +
 +#include "mlx4.h"
 +#include "icm.h"
 +
 +/*
 + * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
 + */
 +struct mlx4_mpt_entry {
 +      __be32 flags;
 +      __be32 qpn;
 +      __be32 key;
 +      __be32 pd_flags;
 +      __be64 start;
 +      __be64 length;
 +      __be32 lkey;
 +      __be32 win_cnt;
 +      u8      reserved1[3];
 +      u8      mtt_rep;
 +      __be64 mtt_seg;
 +      __be32 mtt_sz;
 +      __be32 entity_size;
 +      __be32 first_byte_offset;
 +} __packed;
 +
 +#define MLX4_MPT_FLAG_SW_OWNS     (0xfUL << 28)
 +#define MLX4_MPT_FLAG_FREE        (0x3UL << 28)
 +#define MLX4_MPT_FLAG_MIO         (1 << 17)
 +#define MLX4_MPT_FLAG_BIND_ENABLE   (1 << 15)
 +#define MLX4_MPT_FLAG_PHYSICAL            (1 <<  9)
 +#define MLX4_MPT_FLAG_REGION      (1 <<  8)
 +
 +#define MLX4_MPT_PD_FLAG_FAST_REG   (1 << 27)
 +#define MLX4_MPT_PD_FLAG_RAE      (1 << 28)
 +#define MLX4_MPT_PD_FLAG_EN_INV           (3 << 24)
 +
 +#define MLX4_MPT_STATUS_SW            0xF0
 +#define MLX4_MPT_STATUS_HW            0x00
 +
 +static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order)
 +{
 +      int o;
 +      int m;
 +      u32 seg;
 +
 +      spin_lock(&buddy->lock);
 +
 +      for (o = order; o <= buddy->max_order; ++o)
 +              if (buddy->num_free[o]) {
 +                      m = 1 << (buddy->max_order - o);
 +                      seg = find_first_bit(buddy->bits[o], m);
 +                      if (seg < m)
 +                              goto found;
 +              }
 +
 +      spin_unlock(&buddy->lock);
 +      return -1;
 +
 + found:
 +      clear_bit(seg, buddy->bits[o]);
 +      --buddy->num_free[o];
 +
 +      while (o > order) {
 +              --o;
 +              seg <<= 1;
 +              set_bit(seg ^ 1, buddy->bits[o]);
 +              ++buddy->num_free[o];
 +      }
 +
 +      spin_unlock(&buddy->lock);
 +
 +      seg <<= order;
 +
 +      return seg;
 +}
 +
 +static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order)
 +{
 +      seg >>= order;
 +
 +      spin_lock(&buddy->lock);
 +
 +      while (test_bit(seg ^ 1, buddy->bits[order])) {
 +              clear_bit(seg ^ 1, buddy->bits[order]);
 +              --buddy->num_free[order];
 +              seg >>= 1;
 +              ++order;
 +      }
 +
 +      set_bit(seg, buddy->bits[order]);
 +      ++buddy->num_free[order];
 +
 +      spin_unlock(&buddy->lock);
 +}
 +
 +static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 +{
 +      int i, s;
 +
 +      buddy->max_order = max_order;
 +      spin_lock_init(&buddy->lock);
 +
 +      buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *),
 +                            GFP_KERNEL);
++      buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free,
 +                                GFP_KERNEL);
 +      if (!buddy->bits || !buddy->num_free)
 +              goto err_out;
 +
 +      for (i = 0; i <= buddy->max_order; ++i) {
 +              s = BITS_TO_LONGS(1 << (buddy->max_order - i));
 +              buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
 +              if (!buddy->bits[i])
 +                      goto err_out_free;
 +              bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i));
 +      }
 +
 +      set_bit(0, buddy->bits[buddy->max_order]);
 +      buddy->num_free[buddy->max_order] = 1;
 +
 +      return 0;
 +
 +err_out_free:
 +      for (i = 0; i <= buddy->max_order; ++i)
 +              kfree(buddy->bits[i]);
 +
 +err_out:
 +      kfree(buddy->bits);
 +      kfree(buddy->num_free);
 +
 +      return -ENOMEM;
 +}
 +
 +static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy)
 +{
 +      int i;
 +
 +      for (i = 0; i <= buddy->max_order; ++i)
 +              kfree(buddy->bits[i]);
 +
 +      kfree(buddy->bits);
 +      kfree(buddy->num_free);
 +}
 +
 +static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order)
 +{
 +      struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 +      u32 seg;
 +
 +      seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, order);
 +      if (seg == -1)
 +              return -1;
 +
 +      if (mlx4_table_get_range(dev, &mr_table->mtt_table, seg,
 +                               seg + (1 << order) - 1)) {
 +              mlx4_buddy_free(&mr_table->mtt_buddy, seg, order);
 +              return -1;
 +      }
 +
 +      return seg;
 +}
 +
 +int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift,
 +                struct mlx4_mtt *mtt)
 +{
 +      int i;
 +
 +      if (!npages) {
 +              mtt->order      = -1;
 +              mtt->page_shift = MLX4_ICM_PAGE_SHIFT;
 +              return 0;
 +      } else
 +              mtt->page_shift = page_shift;
 +
 +      for (mtt->order = 0, i = dev->caps.mtts_per_seg; i < npages; i <<= 1)
 +              ++mtt->order;
 +
 +      mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order);
 +      if (mtt->first_seg == -1)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_mtt_init);
 +
 +void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt)
 +{
 +      struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 +
 +      if (mtt->order < 0)
 +              return;
 +
 +      mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order);
 +      mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg,
 +                           mtt->first_seg + (1 << mtt->order) - 1);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup);
 +
 +u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt)
 +{
 +      return (u64) mtt->first_seg * dev->caps.mtt_entry_sz;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_mtt_addr);
 +
 +static u32 hw_index_to_key(u32 ind)
 +{
 +      return (ind >> 24) | (ind << 8);
 +}
 +
 +static u32 key_to_hw_index(u32 key)
 +{
 +      return (key << 24) | (key >> 8);
 +}
 +
 +static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                        int mpt_index)
 +{
 +      return mlx4_cmd(dev, mailbox->dma, mpt_index, 0, MLX4_CMD_SW2HW_MPT,
 +                      MLX4_CMD_TIME_CLASS_B);
 +}
 +
 +static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                        int mpt_index)
 +{
 +      return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
 +                          !mailbox, MLX4_CMD_HW2SW_MPT, MLX4_CMD_TIME_CLASS_B);
 +}
 +
 +int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
 +                int npages, int page_shift, struct mlx4_mr *mr)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      u32 index;
 +      int err;
 +
 +      index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap);
 +      if (index == -1)
 +              return -ENOMEM;
 +
 +      mr->iova       = iova;
 +      mr->size       = size;
 +      mr->pd         = pd;
 +      mr->access     = access;
 +      mr->enabled    = 0;
 +      mr->key        = hw_index_to_key(index);
 +
 +      err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
 +      if (err)
 +              mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
 +
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_mr_alloc);
 +
 +void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int err;
 +
 +      if (mr->enabled) {
 +              err = mlx4_HW2SW_MPT(dev, NULL,
 +                                   key_to_hw_index(mr->key) &
 +                                   (dev->caps.num_mpts - 1));
 +              if (err)
 +                      mlx4_warn(dev, "HW2SW_MPT failed (%d)\n", err);
 +      }
 +
 +      mlx4_mtt_cleanup(dev, &mr->mtt);
 +      mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key));
 +}
 +EXPORT_SYMBOL_GPL(mlx4_mr_free);
 +
 +int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
 +{
 +      struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 +      struct mlx4_cmd_mailbox *mailbox;
 +      struct mlx4_mpt_entry *mpt_entry;
 +      int err;
 +
 +      err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key));
 +      if (err)
 +              return err;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox)) {
 +              err = PTR_ERR(mailbox);
 +              goto err_table;
 +      }
 +      mpt_entry = mailbox->buf;
 +
 +      memset(mpt_entry, 0, sizeof *mpt_entry);
 +
 +      mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_MIO         |
 +                                     MLX4_MPT_FLAG_REGION      |
 +                                     mr->access);
 +
 +      mpt_entry->key         = cpu_to_be32(key_to_hw_index(mr->key));
 +      mpt_entry->pd_flags    = cpu_to_be32(mr->pd | MLX4_MPT_PD_FLAG_EN_INV);
 +      mpt_entry->start       = cpu_to_be64(mr->iova);
 +      mpt_entry->length      = cpu_to_be64(mr->size);
 +      mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift);
 +
 +      if (mr->mtt.order < 0) {
 +              mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL);
 +              mpt_entry->mtt_seg = 0;
 +      } else {
 +              mpt_entry->mtt_seg = cpu_to_be64(mlx4_mtt_addr(dev, &mr->mtt));
 +      }
 +
 +      if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) {
 +              /* fast register MR in free state */
 +              mpt_entry->flags    |= cpu_to_be32(MLX4_MPT_FLAG_FREE);
 +              mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG |
 +                                                 MLX4_MPT_PD_FLAG_RAE);
 +              mpt_entry->mtt_sz    = cpu_to_be32((1 << mr->mtt.order) *
 +                                                 dev->caps.mtts_per_seg);
 +      } else {
 +              mpt_entry->flags    |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS);
 +      }
 +
 +      err = mlx4_SW2HW_MPT(dev, mailbox,
 +                           key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1));
 +      if (err) {
 +              mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err);
 +              goto err_cmd;
 +      }
 +
 +      mr->enabled = 1;
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +
 +      return 0;
 +
 +err_cmd:
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +
 +err_table:
 +      mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key));
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_mr_enable);
 +
 +static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 +                              int start_index, int npages, u64 *page_list)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      __be64 *mtts;
 +      dma_addr_t dma_handle;
 +      int i;
 +      int s = start_index * sizeof (u64);
 +
 +      /* All MTTs must fit in the same page */
 +      if (start_index / (PAGE_SIZE / sizeof (u64)) !=
 +          (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64)))
 +              return -EINVAL;
 +
 +      if (start_index & (dev->caps.mtts_per_seg - 1))
 +              return -EINVAL;
 +
 +      mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg +
 +                              s / dev->caps.mtt_entry_sz, &dma_handle);
 +      if (!mtts)
 +              return -ENOMEM;
 +
 +      dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle,
 +                              npages * sizeof (u64), DMA_TO_DEVICE);
 +
 +      for (i = 0; i < npages; ++i)
 +              mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
 +
 +      dma_sync_single_for_device(&dev->pdev->dev, dma_handle,
 +                                 npages * sizeof (u64), DMA_TO_DEVICE);
 +
 +      return 0;
 +}
 +
 +int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 +                 int start_index, int npages, u64 *page_list)
 +{
 +      int chunk;
 +      int err;
 +
 +      if (mtt->order < 0)
 +              return -EINVAL;
 +
 +      while (npages > 0) {
 +              chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
 +              err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list);
 +              if (err)
 +                      return err;
 +
 +              npages      -= chunk;
 +              start_index += chunk;
 +              page_list   += chunk;
 +      }
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_write_mtt);
 +
 +int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 +                     struct mlx4_buf *buf)
 +{
 +      u64 *page_list;
 +      int err;
 +      int i;
 +
 +      page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL);
 +      if (!page_list)
 +              return -ENOMEM;
 +
 +      for (i = 0; i < buf->npages; ++i)
 +              if (buf->nbufs == 1)
 +                      page_list[i] = buf->direct.map + (i << buf->page_shift);
 +              else
 +                      page_list[i] = buf->page_list[i].map;
 +
 +      err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list);
 +
 +      kfree(page_list);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt);
 +
 +int mlx4_init_mr_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 +      int err;
 +
 +      err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts,
 +                             ~0, dev->caps.reserved_mrws, 0);
 +      if (err)
 +              return err;
 +
 +      err = mlx4_buddy_init(&mr_table->mtt_buddy,
 +                            ilog2(dev->caps.num_mtt_segs));
 +      if (err)
 +              goto err_buddy;
 +
 +      if (dev->caps.reserved_mtts) {
 +              if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) {
 +                      mlx4_warn(dev, "MTT table of order %d is too small.\n",
 +                                mr_table->mtt_buddy.max_order);
 +                      err = -ENOMEM;
 +                      goto err_reserve_mtts;
 +              }
 +      }
 +
 +      return 0;
 +
 +err_reserve_mtts:
 +      mlx4_buddy_cleanup(&mr_table->mtt_buddy);
 +
 +err_buddy:
 +      mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
 +
 +      return err;
 +}
 +
 +void mlx4_cleanup_mr_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 +
 +      mlx4_buddy_cleanup(&mr_table->mtt_buddy);
 +      mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
 +}
 +
 +static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list,
 +                                int npages, u64 iova)
 +{
 +      int i, page_mask;
 +
 +      if (npages > fmr->max_pages)
 +              return -EINVAL;
 +
 +      page_mask = (1 << fmr->page_shift) - 1;
 +
 +      /* We are getting page lists, so va must be page aligned. */
 +      if (iova & page_mask)
 +              return -EINVAL;
 +
 +      /* Trust the user not to pass misaligned data in page_list */
 +      if (0)
 +              for (i = 0; i < npages; ++i) {
 +                      if (page_list[i] & ~page_mask)
 +                              return -EINVAL;
 +              }
 +
 +      if (fmr->maps >= fmr->max_maps)
 +              return -EINVAL;
 +
 +      return 0;
 +}
 +
 +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list,
 +                    int npages, u64 iova, u32 *lkey, u32 *rkey)
 +{
 +      u32 key;
 +      int i, err;
 +
 +      err = mlx4_check_fmr(fmr, page_list, npages, iova);
 +      if (err)
 +              return err;
 +
 +      ++fmr->maps;
 +
 +      key = key_to_hw_index(fmr->mr.key);
 +      key += dev->caps.num_mpts;
 +      *lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
 +
 +      *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
 +
 +      /* Make sure MPT status is visible before writing MTT entries */
 +      wmb();
 +
 +      dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle,
 +                              npages * sizeof(u64), DMA_TO_DEVICE);
 +
 +      for (i = 0; i < npages; ++i)
 +              fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
 +
 +      dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle,
 +                                 npages * sizeof(u64), DMA_TO_DEVICE);
 +
 +      fmr->mpt->key    = cpu_to_be32(key);
 +      fmr->mpt->lkey   = cpu_to_be32(key);
 +      fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift));
 +      fmr->mpt->start  = cpu_to_be64(iova);
 +
 +      /* Make MTT entries are visible before setting MPT status */
 +      wmb();
 +
 +      *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW;
 +
 +      /* Make sure MPT status is visible before consumer can use FMR */
 +      wmb();
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr);
 +
 +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages,
 +                 int max_maps, u8 page_shift, struct mlx4_fmr *fmr)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      u64 mtt_seg;
 +      int err = -ENOMEM;
 +
 +      if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32)
 +              return -EINVAL;
 +
 +      /* All MTTs must fit in the same page */
 +      if (max_pages * sizeof *fmr->mtts > PAGE_SIZE)
 +              return -EINVAL;
 +
 +      fmr->page_shift = page_shift;
 +      fmr->max_pages  = max_pages;
 +      fmr->max_maps   = max_maps;
 +      fmr->maps = 0;
 +
 +      err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages,
 +                          page_shift, &fmr->mr);
 +      if (err)
 +              return err;
 +
 +      mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz;
 +
 +      fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table,
 +                                  fmr->mr.mtt.first_seg,
 +                                  &fmr->dma_handle);
 +      if (!fmr->mtts) {
 +              err = -ENOMEM;
 +              goto err_free;
 +      }
 +
 +      return 0;
 +
 +err_free:
 +      mlx4_mr_free(dev, &fmr->mr);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_fmr_alloc);
 +
 +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int err;
 +
 +      err = mlx4_mr_enable(dev, &fmr->mr);
 +      if (err)
 +              return err;
 +
 +      fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table,
 +                                  key_to_hw_index(fmr->mr.key), NULL);
 +      if (!fmr->mpt)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_fmr_enable);
 +
 +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
 +                  u32 *lkey, u32 *rkey)
 +{
 +      if (!fmr->maps)
 +              return;
 +
 +      fmr->maps = 0;
 +
 +      *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_fmr_unmap);
 +
 +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
 +{
 +      if (fmr->maps)
 +              return -EBUSY;
 +
 +      fmr->mr.enabled = 0;
 +      mlx4_mr_free(dev, &fmr->mr);
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_fmr_free);
 +
 +int mlx4_SYNC_TPT(struct mlx4_dev *dev)
 +{
 +      return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT);
index 1286b886dcea5d6f54f32f7e22374ee600fd36ca,0000000000000000000000000000000000000000..3736163e30e9a6d9296e541d4756b3925c51a5df
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,240 @@@
 +/*
 + * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
 + * Copyright (c) 2005 Mellanox Technologies. 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/errno.h>
 +#include <linux/io-mapping.h>
 +
 +#include <asm/page.h>
 +
 +#include "mlx4.h"
 +#include "icm.h"
 +
 +enum {
 +      MLX4_NUM_RESERVED_UARS = 8
 +};
 +
 +int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap);
 +      if (*pdn == -1)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_pd_alloc);
 +
 +void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn)
 +{
 +      mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_pd_free);
 +
++int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn)
++{
++      struct mlx4_priv *priv = mlx4_priv(dev);
++
++      *xrcdn = mlx4_bitmap_alloc(&priv->xrcd_bitmap);
++      if (*xrcdn == -1)
++              return -ENOMEM;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc);
++
++void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn)
++{
++      mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn);
++}
++EXPORT_SYMBOL_GPL(mlx4_xrcd_free);
++
 +int mlx4_init_pd_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +
 +      return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds,
 +                              (1 << 24) - 1, dev->caps.reserved_pds, 0);
 +}
 +
 +void mlx4_cleanup_pd_table(struct mlx4_dev *dev)
 +{
 +      mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap);
 +}
 +
++int mlx4_init_xrcd_table(struct mlx4_dev *dev)
++{
++      struct mlx4_priv *priv = mlx4_priv(dev);
++
++      return mlx4_bitmap_init(&priv->xrcd_bitmap, (1 << 16),
++                              (1 << 16) - 1, dev->caps.reserved_xrcds + 1, 0);
++}
++
++void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev)
++{
++      mlx4_bitmap_cleanup(&mlx4_priv(dev)->xrcd_bitmap);
++}
 +
 +int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar)
 +{
 +      uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap);
 +      if (uar->index == -1)
 +              return -ENOMEM;
 +
 +      uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index;
 +      uar->map = NULL;
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_uar_alloc);
 +
 +void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar)
 +{
 +      mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_uar_free);
 +
 +int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_uar *uar;
 +      int err = 0;
 +      int idx;
 +
 +      if (!priv->bf_mapping)
 +              return -ENOMEM;
 +
 +      mutex_lock(&priv->bf_mutex);
 +      if (!list_empty(&priv->bf_list))
 +              uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list);
 +      else {
 +              if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) {
 +                      err = -ENOMEM;
 +                      goto out;
 +              }
 +              uar = kmalloc(sizeof *uar, GFP_KERNEL);
 +              if (!uar) {
 +                      err = -ENOMEM;
 +                      goto out;
 +              }
 +              err = mlx4_uar_alloc(dev, uar);
 +              if (err)
 +                      goto free_kmalloc;
 +
 +              uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE);
 +              if (!uar->map) {
 +                      err = -ENOMEM;
 +                      goto free_uar;
 +              }
 +
 +              uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT);
 +              if (!uar->bf_map) {
 +                      err = -ENOMEM;
 +                      goto unamp_uar;
 +              }
 +              uar->free_bf_bmap = 0;
 +              list_add(&uar->bf_list, &priv->bf_list);
 +      }
 +
 +      bf->uar = uar;
 +      idx = ffz(uar->free_bf_bmap);
 +      uar->free_bf_bmap |= 1 << idx;
 +      bf->uar = uar;
 +      bf->offset = 0;
 +      bf->buf_size = dev->caps.bf_reg_size / 2;
 +      bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size;
 +      if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1)
 +              list_del_init(&uar->bf_list);
 +
 +      goto out;
 +
 +unamp_uar:
 +      bf->uar = NULL;
 +      iounmap(uar->map);
 +
 +free_uar:
 +      mlx4_uar_free(dev, uar);
 +
 +free_kmalloc:
 +      kfree(uar);
 +
 +out:
 +      mutex_unlock(&priv->bf_mutex);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_bf_alloc);
 +
 +void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      int idx;
 +
 +      if (!bf->uar || !bf->uar->bf_map)
 +              return;
 +
 +      mutex_lock(&priv->bf_mutex);
 +      idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size;
 +      bf->uar->free_bf_bmap &= ~(1 << idx);
 +      if (!bf->uar->free_bf_bmap) {
 +              if (!list_empty(&bf->uar->bf_list))
 +                      list_del(&bf->uar->bf_list);
 +
 +              io_mapping_unmap(bf->uar->bf_map);
 +              iounmap(bf->uar->map);
 +              mlx4_uar_free(dev, bf->uar);
 +              kfree(bf->uar);
 +      } else if (list_empty(&bf->uar->bf_list))
 +              list_add(&bf->uar->bf_list, &priv->bf_list);
 +
 +      mutex_unlock(&priv->bf_mutex);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_bf_free);
 +
 +int mlx4_init_uar_table(struct mlx4_dev *dev)
 +{
 +      if (dev->caps.num_uars <= 128) {
 +              mlx4_err(dev, "Only %d UAR pages (need more than 128)\n",
 +                       dev->caps.num_uars);
 +              mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n");
 +              return -ENODEV;
 +      }
 +
 +      return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap,
 +                              dev->caps.num_uars, dev->caps.num_uars - 1,
 +                              max(128, dev->caps.reserved_uars), 0);
 +}
 +
 +void mlx4_cleanup_uar_table(struct mlx4_dev *dev)
 +{
 +      mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap);
 +}
index 163a314c148f1ada4286003838830d08c688bdeb,0000000000000000000000000000000000000000..a44f080fdfe59899c6d06639a63dfe43bfea8ba4
mode 100644,000000..100644
--- /dev/null
@@@ -1,488 -1,0 +1,534 @@@
-               if (!err) {
-                       entry = kmalloc(sizeof *entry, GFP_KERNEL);
-                       if (!entry) {
-                               mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
-                               return -ENOMEM;
-                       }
-                       entry->mac = mac;
-                       err = radix_tree_insert(&info->mac_tree, *qpn, entry);
-                       if (err) {
-                               mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
-                               return err;
-                       }
-               } else
 +/*
 + * Copyright (c) 2007 Mellanox Technologies. 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/errno.h>
 +#include <linux/if_ether.h>
 +
 +#include <linux/mlx4/cmd.h>
 +
 +#include "mlx4.h"
 +
 +#define MLX4_MAC_VALID                (1ull << 63)
 +#define MLX4_MAC_MASK         0xffffffffffffULL
 +
 +#define MLX4_VLAN_VALID               (1u << 31)
 +#define MLX4_VLAN_MASK                0xfff
 +
 +void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
 +{
 +      int i;
 +
 +      mutex_init(&table->mutex);
 +      for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
 +              table->entries[i] = 0;
 +              table->refs[i]   = 0;
 +      }
 +      table->max   = 1 << dev->caps.log_num_macs;
 +      table->total = 0;
 +}
 +
 +void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
 +{
 +      int i;
 +
 +      mutex_init(&table->mutex);
 +      for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
 +              table->entries[i] = 0;
 +              table->refs[i]   = 0;
 +      }
 +      table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
 +      table->total = 0;
 +}
 +
 +static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
 +                                 __be64 *entries)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 in_mod;
 +      int err;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +
 +      memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
 +
 +      in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
 +      err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
 +                     MLX4_CMD_TIME_CLASS_B);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +
 +static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
 +                           u64 mac, int *qpn, u8 reserve)
 +{
 +      struct mlx4_qp qp;
 +      u8 gid[16] = {0};
 +      int err;
 +
 +      if (reserve) {
 +              err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
 +              if (err) {
 +                      mlx4_err(dev, "Failed to reserve qp for mac registration\n");
 +                      return err;
 +              }
 +      }
 +      qp.qpn = *qpn;
 +
 +      mac &= 0xffffffffffffULL;
 +      mac = cpu_to_be64(mac << 16);
 +      memcpy(&gid[10], &mac, ETH_ALEN);
 +      gid[5] = port;
 +      gid[7] = MLX4_UC_STEER << 1;
 +
 +      err = mlx4_qp_attach_common(dev, &qp, gid, 0,
 +                                  MLX4_PROT_ETH, MLX4_UC_STEER);
 +      if (err && reserve)
 +              mlx4_qp_release_range(dev, *qpn, 1);
 +
 +      return err;
 +}
 +
 +static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
 +                                u64 mac, int qpn, u8 free)
 +{
 +      struct mlx4_qp qp;
 +      u8 gid[16] = {0};
 +
 +      qp.qpn = qpn;
 +      mac &= 0xffffffffffffULL;
 +      mac = cpu_to_be64(mac << 16);
 +      memcpy(&gid[10], &mac, ETH_ALEN);
 +      gid[5] = port;
 +      gid[7] = MLX4_UC_STEER << 1;
 +
 +      mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER);
 +      if (free)
 +              mlx4_qp_release_range(dev, qpn, 1);
 +}
 +
 +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap)
 +{
 +      struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
 +      struct mlx4_mac_table *table = &info->mac_table;
 +      struct mlx4_mac_entry *entry;
 +      int i, err = 0;
 +      int free = -1;
 +
 +      if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
 +              err = mlx4_uc_steer_add(dev, port, mac, qpn, 1);
++              if (err)
 +                      return err;
++
++              entry = kmalloc(sizeof *entry, GFP_KERNEL);
++              if (!entry) {
++                      mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
++                      return -ENOMEM;
++              }
++
++              entry->mac = mac;
++              err = radix_tree_insert(&info->mac_tree, *qpn, entry);
++              if (err) {
++                      kfree(entry);
++                      mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
++                      return err;
++              }
 +      }
++
 +      mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac);
++
 +      mutex_lock(&table->mutex);
 +      for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) {
 +              if (free < 0 && !table->refs[i]) {
 +                      free = i;
 +                      continue;
 +              }
 +
 +              if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
 +                      /* MAC already registered, increase references count */
 +                      ++table->refs[i];
 +                      goto out;
 +              }
 +      }
 +
 +      if (free < 0) {
 +              err = -ENOMEM;
 +              goto out;
 +      }
 +
 +      mlx4_dbg(dev, "Free MAC index is %d\n", free);
 +
 +      if (table->total == table->max) {
 +              /* No free mac entries */
 +              err = -ENOSPC;
 +              goto out;
 +      }
 +
 +      /* Register new MAC */
 +      table->refs[free] = 1;
 +      table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
 +
 +      err = mlx4_set_port_mac_table(dev, port, table->entries);
 +      if (unlikely(err)) {
 +              mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) mac);
 +              table->refs[free] = 0;
 +              table->entries[free] = 0;
 +              goto out;
 +      }
 +
 +      if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
 +              *qpn = info->base_qpn + free;
 +      ++table->total;
 +out:
 +      mutex_unlock(&table->mutex);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_register_mac);
 +
 +static int validate_index(struct mlx4_dev *dev,
 +                        struct mlx4_mac_table *table, int index)
 +{
 +      int err = 0;
 +
 +      if (index < 0 || index >= table->max || !table->entries[index]) {
 +              mlx4_warn(dev, "No valid Mac entry for the given index\n");
 +              err = -EINVAL;
 +      }
 +      return err;
 +}
 +
 +static int find_index(struct mlx4_dev *dev,
 +                    struct mlx4_mac_table *table, u64 mac)
 +{
 +      int i;
 +      for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
 +              if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
 +                      return i;
 +      }
 +      /* Mac not found */
 +      return -EINVAL;
 +}
 +
 +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn)
 +{
 +      struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
 +      struct mlx4_mac_table *table = &info->mac_table;
 +      int index = qpn - info->base_qpn;
 +      struct mlx4_mac_entry *entry;
 +
 +      if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
 +              entry = radix_tree_lookup(&info->mac_tree, qpn);
 +              if (entry) {
 +                      mlx4_uc_steer_release(dev, port, entry->mac, qpn, 1);
 +                      radix_tree_delete(&info->mac_tree, qpn);
 +                      index = find_index(dev, table, entry->mac);
 +                      kfree(entry);
 +              }
 +      }
 +
 +      mutex_lock(&table->mutex);
 +
 +      if (validate_index(dev, table, index))
 +              goto out;
 +
 +      /* Check whether this address has reference count */
 +      if (!(--table->refs[index])) {
 +              table->entries[index] = 0;
 +              mlx4_set_port_mac_table(dev, port, table->entries);
 +              --table->total;
 +      }
 +out:
 +      mutex_unlock(&table->mutex);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
 +
 +int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap)
 +{
 +      struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
 +      struct mlx4_mac_table *table = &info->mac_table;
 +      int index = qpn - info->base_qpn;
 +      struct mlx4_mac_entry *entry;
 +      int err;
 +
 +      if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
 +              entry = radix_tree_lookup(&info->mac_tree, qpn);
 +              if (!entry)
 +                      return -EINVAL;
 +              index = find_index(dev, table, entry->mac);
 +              mlx4_uc_steer_release(dev, port, entry->mac, qpn, 0);
 +              entry->mac = new_mac;
 +              err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn, 0);
 +              if (err || index < 0)
 +                      return err;
 +      }
 +
 +      mutex_lock(&table->mutex);
 +
 +      err = validate_index(dev, table, index);
 +      if (err)
 +              goto out;
 +
 +      table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
 +
 +      err = mlx4_set_port_mac_table(dev, port, table->entries);
 +      if (unlikely(err)) {
 +              mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) new_mac);
 +              table->entries[index] = 0;
 +      }
 +out:
 +      mutex_unlock(&table->mutex);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_replace_mac);
 +static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
 +                                  __be32 *entries)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      u32 in_mod;
 +      int err;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +
 +      memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
 +      in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
 +      err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
 +                     MLX4_CMD_TIME_CLASS_B);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +
 +      return err;
 +}
 +
 +int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
 +{
 +      struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 +      int i;
 +
 +      for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
 +              if (table->refs[i] &&
 +                  (vid == (MLX4_VLAN_MASK &
 +                            be32_to_cpu(table->entries[i])))) {
 +                      /* VLAN already registered, increase reference count */
 +                      *idx = i;
 +                      return 0;
 +              }
 +      }
 +
 +      return -ENOENT;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
 +
 +int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
 +{
 +      struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 +      int i, err = 0;
 +      int free = -1;
 +
 +      mutex_lock(&table->mutex);
 +
 +      if (table->total == table->max) {
 +              /* No free vlan entries */
 +              err = -ENOSPC;
 +              goto out;
 +      }
 +
 +      for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
 +              if (free < 0 && (table->refs[i] == 0)) {
 +                      free = i;
 +                      continue;
 +              }
 +
 +              if (table->refs[i] &&
 +                  (vlan == (MLX4_VLAN_MASK &
 +                            be32_to_cpu(table->entries[i])))) {
 +                      /* Vlan already registered, increase references count */
 +                      *index = i;
 +                      ++table->refs[i];
 +                      goto out;
 +              }
 +      }
 +
 +      if (free < 0) {
 +              err = -ENOMEM;
 +              goto out;
 +      }
 +
 +      /* Register new MAC */
 +      table->refs[free] = 1;
 +      table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
 +
 +      err = mlx4_set_port_vlan_table(dev, port, table->entries);
 +      if (unlikely(err)) {
 +              mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
 +              table->refs[free] = 0;
 +              table->entries[free] = 0;
 +              goto out;
 +      }
 +
 +      *index = free;
 +      ++table->total;
 +out:
 +      mutex_unlock(&table->mutex);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_register_vlan);
 +
 +void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
 +{
 +      struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 +
 +      if (index < MLX4_VLAN_REGULAR) {
 +              mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
 +              return;
 +      }
 +
 +      mutex_lock(&table->mutex);
 +      if (!table->refs[index]) {
 +              mlx4_warn(dev, "No vlan entry for index %d\n", index);
 +              goto out;
 +      }
 +      if (--table->refs[index]) {
 +              mlx4_dbg(dev, "Have more references for index %d,"
 +                       "no need to modify vlan table\n", index);
 +              goto out;
 +      }
 +      table->entries[index] = 0;
 +      mlx4_set_port_vlan_table(dev, port, table->entries);
 +      --table->total;
 +out:
 +      mutex_unlock(&table->mutex);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
 +
 +int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
 +{
 +      struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
 +      u8 *inbuf, *outbuf;
 +      int err;
 +
 +      inmailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(inmailbox))
 +              return PTR_ERR(inmailbox);
 +
 +      outmailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(outmailbox)) {
 +              mlx4_free_cmd_mailbox(dev, inmailbox);
 +              return PTR_ERR(outmailbox);
 +      }
 +
 +      inbuf = inmailbox->buf;
 +      outbuf = outmailbox->buf;
 +      memset(inbuf, 0, 256);
 +      memset(outbuf, 0, 256);
 +      inbuf[0] = 1;
 +      inbuf[1] = 1;
 +      inbuf[2] = 1;
 +      inbuf[3] = 1;
 +      *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
 +      *(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
 +
 +      err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
 +                         MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
 +      if (!err)
 +              *caps = *(__be32 *) (outbuf + 84);
 +      mlx4_free_cmd_mailbox(dev, inmailbox);
 +      mlx4_free_cmd_mailbox(dev, outmailbox);
 +      return err;
 +}
 +
++int mlx4_check_ext_port_caps(struct mlx4_dev *dev, u8 port)
++{
++      struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
++      u8 *inbuf, *outbuf;
++      int err, packet_error;
++
++      inmailbox = mlx4_alloc_cmd_mailbox(dev);
++      if (IS_ERR(inmailbox))
++              return PTR_ERR(inmailbox);
++
++      outmailbox = mlx4_alloc_cmd_mailbox(dev);
++      if (IS_ERR(outmailbox)) {
++              mlx4_free_cmd_mailbox(dev, inmailbox);
++              return PTR_ERR(outmailbox);
++      }
++
++      inbuf = inmailbox->buf;
++      outbuf = outmailbox->buf;
++      memset(inbuf, 0, 256);
++      memset(outbuf, 0, 256);
++      inbuf[0] = 1;
++      inbuf[1] = 1;
++      inbuf[2] = 1;
++      inbuf[3] = 1;
++
++      *(__be16 *) (&inbuf[16]) = MLX4_ATTR_EXTENDED_PORT_INFO;
++      *(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
++
++      err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
++                         MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
++
++      packet_error = be16_to_cpu(*(__be16 *) (outbuf + 4));
++
++      dev->caps.ext_port_cap[port] = (!err && !packet_error) ?
++                                     MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO
++                                     : 0;
++
++      mlx4_free_cmd_mailbox(dev, inmailbox);
++      mlx4_free_cmd_mailbox(dev, outmailbox);
++      return err;
++}
++
 +int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      int err;
 +
 +      if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
 +              return 0;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +
 +      memset(mailbox->buf, 0, 256);
 +
 +      ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
 +      err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
 +                     MLX4_CMD_TIME_CLASS_B);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
index ec9350e5f21ab7072dc00a062b28cb9781af2d7b,0000000000000000000000000000000000000000..51c53898c35f89f3529e866fea994e001a828a85
mode 100644,000000..100644
--- /dev/null
@@@ -1,380 -1,0 +1,383 @@@
 +/*
 + * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved.
 + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
 + * Copyright (c) 2004 Voltaire, 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/gfp.h>
 +#include <linux/mlx4/cmd.h>
 +#include <linux/mlx4/qp.h>
 +
 +#include "mlx4.h"
 +#include "icm.h"
 +
 +void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
 +{
 +      struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
 +      struct mlx4_qp *qp;
 +
 +      spin_lock(&qp_table->lock);
 +
 +      qp = __mlx4_qp_lookup(dev, qpn);
 +      if (qp)
 +              atomic_inc(&qp->refcount);
 +
 +      spin_unlock(&qp_table->lock);
 +
 +      if (!qp) {
 +              mlx4_warn(dev, "Async event for bogus QP %08x\n", qpn);
 +              return;
 +      }
 +
 +      qp->event(qp, event_type);
 +
 +      if (atomic_dec_and_test(&qp->refcount))
 +              complete(&qp->free);
 +}
 +
 +int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 +                 enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state,
 +                 struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar,
 +                 int sqd_event, struct mlx4_qp *qp)
 +{
 +      static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = {
 +              [MLX4_QP_STATE_RST] = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +                      [MLX4_QP_STATE_INIT]    = MLX4_CMD_RST2INIT_QP,
 +              },
 +              [MLX4_QP_STATE_INIT]  = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +                      [MLX4_QP_STATE_INIT]    = MLX4_CMD_INIT2INIT_QP,
 +                      [MLX4_QP_STATE_RTR]     = MLX4_CMD_INIT2RTR_QP,
 +              },
 +              [MLX4_QP_STATE_RTR]   = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +                      [MLX4_QP_STATE_RTS]     = MLX4_CMD_RTR2RTS_QP,
 +              },
 +              [MLX4_QP_STATE_RTS]   = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +                      [MLX4_QP_STATE_RTS]     = MLX4_CMD_RTS2RTS_QP,
 +                      [MLX4_QP_STATE_SQD]     = MLX4_CMD_RTS2SQD_QP,
 +              },
 +              [MLX4_QP_STATE_SQD] = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +                      [MLX4_QP_STATE_RTS]     = MLX4_CMD_SQD2RTS_QP,
 +                      [MLX4_QP_STATE_SQD]     = MLX4_CMD_SQD2SQD_QP,
 +              },
 +              [MLX4_QP_STATE_SQER] = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +                      [MLX4_QP_STATE_RTS]     = MLX4_CMD_SQERR2RTS_QP,
 +              },
 +              [MLX4_QP_STATE_ERR] = {
 +                      [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
 +                      [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
 +              }
 +      };
 +
 +      struct mlx4_cmd_mailbox *mailbox;
 +      int ret = 0;
 +
 +      if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE ||
 +          !op[cur_state][new_state])
 +              return -EINVAL;
 +
 +      if (op[cur_state][new_state] == MLX4_CMD_2RST_QP)
 +              return mlx4_cmd(dev, 0, qp->qpn, 2,
 +                              MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A);
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +
 +      if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) {
 +              u64 mtt_addr = mlx4_mtt_addr(dev, mtt);
 +              context->mtt_base_addr_h = mtt_addr >> 32;
 +              context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
 +              context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
 +      }
 +
 +      *(__be32 *) mailbox->buf = cpu_to_be32(optpar);
 +      memcpy(mailbox->buf + 8, context, sizeof *context);
 +
 +      ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn =
 +              cpu_to_be32(qp->qpn);
 +
 +      ret = mlx4_cmd(dev, mailbox->dma, qp->qpn | (!!sqd_event << 31),
 +                     new_state == MLX4_QP_STATE_RST ? 2 : 0,
 +                     op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_modify);
 +
 +int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_qp_table *qp_table = &priv->qp_table;
 +      int qpn;
 +
 +      qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align);
 +      if (qpn == -1)
 +              return -ENOMEM;
 +
 +      *base = qpn;
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range);
 +
 +void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_qp_table *qp_table = &priv->qp_table;
 +      if (base_qpn < dev->caps.sqp_start + 8)
 +              return;
 +
 +      mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_release_range);
 +
 +int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
 +{
 +      struct mlx4_priv *priv = mlx4_priv(dev);
 +      struct mlx4_qp_table *qp_table = &priv->qp_table;
 +      int err;
 +
 +      if (!qpn)
 +              return -EINVAL;
 +
 +      qp->qpn = qpn;
 +
 +      err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn);
 +      if (err)
 +              goto err_out;
 +
 +      err = mlx4_table_get(dev, &qp_table->auxc_table, qp->qpn);
 +      if (err)
 +              goto err_put_qp;
 +
 +      err = mlx4_table_get(dev, &qp_table->altc_table, qp->qpn);
 +      if (err)
 +              goto err_put_auxc;
 +
 +      err = mlx4_table_get(dev, &qp_table->rdmarc_table, qp->qpn);
 +      if (err)
 +              goto err_put_altc;
 +
 +      err = mlx4_table_get(dev, &qp_table->cmpt_table, qp->qpn);
 +      if (err)
 +              goto err_put_rdmarc;
 +
 +      spin_lock_irq(&qp_table->lock);
 +      err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp);
 +      spin_unlock_irq(&qp_table->lock);
 +      if (err)
 +              goto err_put_cmpt;
 +
 +      atomic_set(&qp->refcount, 1);
 +      init_completion(&qp->free);
 +
 +      return 0;
 +
 +err_put_cmpt:
 +      mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn);
 +
 +err_put_rdmarc:
 +      mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn);
 +
 +err_put_altc:
 +      mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
 +
 +err_put_auxc:
 +      mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
 +
 +err_put_qp:
 +      mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
 +
 +err_out:
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
 +
 +void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp)
 +{
 +      struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&qp_table->lock, flags);
 +      radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1));
 +      spin_unlock_irqrestore(&qp_table->lock, flags);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_remove);
 +
 +void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
 +{
 +      struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
 +
 +      if (atomic_dec_and_test(&qp->refcount))
 +              complete(&qp->free);
 +      wait_for_completion(&qp->free);
 +
 +      mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn);
 +      mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn);
 +      mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
 +      mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
 +      mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_free);
 +
 +static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn)
 +{
 +      return mlx4_cmd(dev, 0, base_qpn, 0, MLX4_CMD_CONF_SPECIAL_QP,
 +                      MLX4_CMD_TIME_CLASS_B);
 +}
 +
 +int mlx4_init_qp_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
 +      int err;
 +      int reserved_from_top = 0;
 +
 +      spin_lock_init(&qp_table->lock);
 +      INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
 +
 +      /*
 +       * We reserve 2 extra QPs per port for the special QPs.  The
 +       * block of special QPs must be aligned to a multiple of 8, so
 +       * round up.
++       *
++       * We also reserve the MSB of the 24-bit QP number to indicate
++       * that a QP is an XRC QP.
 +       */
 +      dev->caps.sqp_start =
 +              ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
 +
 +      {
 +              int sort[MLX4_NUM_QP_REGION];
 +              int i, j, tmp;
 +              int last_base = dev->caps.num_qps;
 +
 +              for (i = 1; i < MLX4_NUM_QP_REGION; ++i)
 +                      sort[i] = i;
 +
 +              for (i = MLX4_NUM_QP_REGION; i > 0; --i) {
 +                      for (j = 2; j < i; ++j) {
 +                              if (dev->caps.reserved_qps_cnt[sort[j]] >
 +                                  dev->caps.reserved_qps_cnt[sort[j - 1]]) {
 +                                      tmp             = sort[j];
 +                                      sort[j]         = sort[j - 1];
 +                                      sort[j - 1]     = tmp;
 +                              }
 +                      }
 +              }
 +
 +              for (i = 1; i < MLX4_NUM_QP_REGION; ++i) {
 +                      last_base -= dev->caps.reserved_qps_cnt[sort[i]];
 +                      dev->caps.reserved_qps_base[sort[i]] = last_base;
 +                      reserved_from_top +=
 +                              dev->caps.reserved_qps_cnt[sort[i]];
 +              }
 +
 +      }
 +
 +      err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps,
 +                             (1 << 23) - 1, dev->caps.sqp_start + 8,
 +                             reserved_from_top);
 +      if (err)
 +              return err;
 +
 +      return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start);
 +}
 +
 +void mlx4_cleanup_qp_table(struct mlx4_dev *dev)
 +{
 +      mlx4_CONF_SPECIAL_QP(dev, 0);
 +      mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap);
 +}
 +
 +int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
 +                struct mlx4_qp_context *context)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      int err;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +
 +      err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0,
 +                         MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A);
 +      if (!err)
 +              memcpy(context, mailbox->buf + 8, sizeof *context);
 +
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_query);
 +
 +int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 +                   struct mlx4_qp_context *context,
 +                   struct mlx4_qp *qp, enum mlx4_qp_state *qp_state)
 +{
 +      int err;
 +      int i;
 +      enum mlx4_qp_state states[] = {
 +              MLX4_QP_STATE_RST,
 +              MLX4_QP_STATE_INIT,
 +              MLX4_QP_STATE_RTR,
 +              MLX4_QP_STATE_RTS
 +      };
 +
 +      for (i = 0; i < ARRAY_SIZE(states) - 1; i++) {
 +              context->flags &= cpu_to_be32(~(0xf << 28));
 +              context->flags |= cpu_to_be32(states[i + 1] << 28);
 +              err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1],
 +                                   context, 0, 0, qp);
 +              if (err) {
 +                      mlx4_err(dev, "Failed to bring QP to state: "
 +                               "%d with error: %d\n",
 +                               states[i + 1], err);
 +                      return err;
 +              }
 +
 +              *qp_state = states[i + 1];
 +      }
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_qp_to_ready);
index 3b07b80a0456baec10d02146c1a71aa1feed872e,0000000000000000000000000000000000000000..a20b141dbb5cf3a1ee3b8910624b9c0b58740a08
mode 100644,000000..100644
--- /dev/null
@@@ -1,257 -1,0 +1,259 @@@
-       u8                      reserved1[3];
-       u8                      pg_offset;
-       u8                      reserved2[3];
-       u32                     reserved3;
 +/*
 + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
 + * Copyright (c) 2007, 2008 Mellanox Technologies. 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/mlx4/cmd.h>
 +#include <linux/gfp.h>
 +
 +#include "mlx4.h"
 +#include "icm.h"
 +
 +struct mlx4_srq_context {
 +      __be32                  state_logsize_srqn;
 +      u8                      logstride;
-       u8                      reserved4[2];
++      u8                      reserved1;
++      __be16                  xrcd;
++      __be32                  pg_offset_cqn;
++      u32                     reserved2;
 +      u8                      log_page_size;
-       u16                     reserved5;
++      u8                      reserved3[2];
 +      u8                      mtt_base_addr_h;
 +      __be32                  mtt_base_addr_l;
 +      __be32                  pd;
 +      __be16                  limit_watermark;
 +      __be16                  wqe_cnt;
-       u32                     reserved6;
++      u16                     reserved4;
 +      __be16                  wqe_counter;
- int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
-                  u64 db_rec, struct mlx4_srq *srq)
++      u32                     reserved5;
 +      __be64                  db_rec_addr;
 +};
 +
 +void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
 +{
 +      struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 +      struct mlx4_srq *srq;
 +
 +      spin_lock(&srq_table->lock);
 +
 +      srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
 +      if (srq)
 +              atomic_inc(&srq->refcount);
 +
 +      spin_unlock(&srq_table->lock);
 +
 +      if (!srq) {
 +              mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
 +              return;
 +      }
 +
 +      srq->event(srq, event_type);
 +
 +      if (atomic_dec_and_test(&srq->refcount))
 +              complete(&srq->free);
 +}
 +
 +static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                        int srq_num)
 +{
 +      return mlx4_cmd(dev, mailbox->dma, srq_num, 0, MLX4_CMD_SW2HW_SRQ,
 +                      MLX4_CMD_TIME_CLASS_A);
 +}
 +
 +static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                        int srq_num)
 +{
 +      return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num,
 +                          mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ,
 +                          MLX4_CMD_TIME_CLASS_A);
 +}
 +
 +static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark)
 +{
 +      return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ,
 +                      MLX4_CMD_TIME_CLASS_B);
 +}
 +
 +static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
 +                        int srq_num)
 +{
 +      return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ,
 +                          MLX4_CMD_TIME_CLASS_A);
 +}
 +
++int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
++                 struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq)
 +{
 +      struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 +      struct mlx4_cmd_mailbox *mailbox;
 +      struct mlx4_srq_context *srq_context;
 +      u64 mtt_addr;
 +      int err;
 +
 +      srq->srqn = mlx4_bitmap_alloc(&srq_table->bitmap);
 +      if (srq->srqn == -1)
 +              return -ENOMEM;
 +
 +      err = mlx4_table_get(dev, &srq_table->table, srq->srqn);
 +      if (err)
 +              goto err_out;
 +
 +      err = mlx4_table_get(dev, &srq_table->cmpt_table, srq->srqn);
 +      if (err)
 +              goto err_put;
 +
 +      spin_lock_irq(&srq_table->lock);
 +      err = radix_tree_insert(&srq_table->tree, srq->srqn, srq);
 +      spin_unlock_irq(&srq_table->lock);
 +      if (err)
 +              goto err_cmpt_put;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox)) {
 +              err = PTR_ERR(mailbox);
 +              goto err_radix;
 +      }
 +
 +      srq_context = mailbox->buf;
 +      memset(srq_context, 0, sizeof *srq_context);
 +
 +      srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) |
 +                                                    srq->srqn);
 +      srq_context->logstride          = srq->wqe_shift - 4;
++      srq_context->xrcd               = cpu_to_be16(xrcd);
++      srq_context->pg_offset_cqn      = cpu_to_be32(cqn & 0xffffff);
 +      srq_context->log_page_size      = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
 +
 +      mtt_addr = mlx4_mtt_addr(dev, mtt);
 +      srq_context->mtt_base_addr_h    = mtt_addr >> 32;
 +      srq_context->mtt_base_addr_l    = cpu_to_be32(mtt_addr & 0xffffffff);
 +      srq_context->pd                 = cpu_to_be32(pdn);
 +      srq_context->db_rec_addr        = cpu_to_be64(db_rec);
 +
 +      err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn);
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      if (err)
 +              goto err_radix;
 +
 +      atomic_set(&srq->refcount, 1);
 +      init_completion(&srq->free);
 +
 +      return 0;
 +
 +err_radix:
 +      spin_lock_irq(&srq_table->lock);
 +      radix_tree_delete(&srq_table->tree, srq->srqn);
 +      spin_unlock_irq(&srq_table->lock);
 +
 +err_cmpt_put:
 +      mlx4_table_put(dev, &srq_table->cmpt_table, srq->srqn);
 +
 +err_put:
 +      mlx4_table_put(dev, &srq_table->table, srq->srqn);
 +
 +err_out:
 +      mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
 +
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_srq_alloc);
 +
 +void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq)
 +{
 +      struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 +      int err;
 +
 +      err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn);
 +      if (err)
 +              mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn);
 +
 +      spin_lock_irq(&srq_table->lock);
 +      radix_tree_delete(&srq_table->tree, srq->srqn);
 +      spin_unlock_irq(&srq_table->lock);
 +
 +      if (atomic_dec_and_test(&srq->refcount))
 +              complete(&srq->free);
 +      wait_for_completion(&srq->free);
 +
 +      mlx4_table_put(dev, &srq_table->table, srq->srqn);
 +      mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_srq_free);
 +
 +int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark)
 +{
 +      return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark);
 +}
 +EXPORT_SYMBOL_GPL(mlx4_srq_arm);
 +
 +int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark)
 +{
 +      struct mlx4_cmd_mailbox *mailbox;
 +      struct mlx4_srq_context *srq_context;
 +      int err;
 +
 +      mailbox = mlx4_alloc_cmd_mailbox(dev);
 +      if (IS_ERR(mailbox))
 +              return PTR_ERR(mailbox);
 +
 +      srq_context = mailbox->buf;
 +
 +      err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
 +      if (err)
 +              goto err_out;
 +      *limit_watermark = be16_to_cpu(srq_context->limit_watermark);
 +
 +err_out:
 +      mlx4_free_cmd_mailbox(dev, mailbox);
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(mlx4_srq_query);
 +
 +int mlx4_init_srq_table(struct mlx4_dev *dev)
 +{
 +      struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 +      int err;
 +
 +      spin_lock_init(&srq_table->lock);
 +      INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
 +
 +      err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs,
 +                             dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0);
 +      if (err)
 +              return err;
 +
 +      return 0;
 +}
 +
 +void mlx4_cleanup_srq_table(struct mlx4_dev *dev)
 +{
 +      mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap);
 +}
Simple merge