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

@@@ -441,13 -441,13 +441,13 @@@ static int nes_nic_send(struct sk_buff 
                nesnic->tx_skb[nesnic->sq_head] = skb;
                for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;
                                skb_fragment_index++) {
 -                      bus_address = pci_map_page( nesdev->pcidev,
 -                                      skb_shinfo(skb)->frags[skb_fragment_index].page,
 -                                      skb_shinfo(skb)->frags[skb_fragment_index].page_offset,
 -                                      skb_shinfo(skb)->frags[skb_fragment_index].size,
 -                                      PCI_DMA_TODEVICE);
 +                      skb_frag_t *frag =
 +                              &skb_shinfo(skb)->frags[skb_fragment_index];
 +                      bus_address = skb_frag_dma_map(&nesdev->pcidev->dev,
 +                                                     frag, 0, skb_frag_size(frag),
 +                                                     DMA_TO_DEVICE);
                        wqe_fragment_length[wqe_fragment_index] =
 -                                      cpu_to_le16(skb_shinfo(skb)->frags[skb_fragment_index].size);
 +                                      cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[skb_fragment_index]));
                        set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
                                bus_address);
                        wqe_fragment_index++;
@@@ -561,12 -561,11 +561,12 @@@ tso_sq_no_longer_full
                        /* Map all the buffers */
                        for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
                                        tso_frag_count++) {
 -                              tso_bus_address[tso_frag_count] = pci_map_page( nesdev->pcidev,
 -                                              skb_shinfo(skb)->frags[tso_frag_count].page,
 -                                              skb_shinfo(skb)->frags[tso_frag_count].page_offset,
 -                                              skb_shinfo(skb)->frags[tso_frag_count].size,
 -                                              PCI_DMA_TODEVICE);
 +                              skb_frag_t *frag =
 +                                      &skb_shinfo(skb)->frags[tso_frag_count];
 +                              tso_bus_address[tso_frag_count] =
 +                                      skb_frag_dma_map(&nesdev->pcidev->dev,
 +                                                       frag, 0, skb_frag_size(frag),
 +                                                       DMA_TO_DEVICE);
                        }
  
                        tso_frag_index = 0;
                                }
                                while (wqe_fragment_index < 5) {
                                        wqe_fragment_length[wqe_fragment_index] =
 -                                                      cpu_to_le16(skb_shinfo(skb)->frags[tso_frag_index].size);
 +                                                      cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index]));
                                        set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
                                                (u64)tso_bus_address[tso_frag_index]);
                                        wqe_fragment_index++;
 -                                      tso_wqe_length += skb_shinfo(skb)->frags[tso_frag_index++].size;
 +                                      tso_wqe_length += skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index++]);
                                        if (wqe_fragment_index < 5)
                                                wqe_fragment_length[wqe_fragment_index] = 0;
                                        if (tso_frag_index == tso_frag_count)
@@@ -1091,6 -1090,8 +1091,8 @@@ static const char nes_ethtool_stringset
        "LRO aggregated",
        "LRO flushed",
        "LRO no_desc",
+       "PAU CreateQPs",
+       "PAU DestroyQPs",
  };
  #define NES_ETHTOOL_STAT_COUNT  ARRAY_SIZE(nes_ethtool_stringset)
  
@@@ -1306,6 -1307,8 +1308,8 @@@ static void nes_netdev_get_ethtool_stat
        target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated;
        target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed;
        target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc;
+       target_stat_values[++index] = atomic_read(&pau_qps_created);
+       target_stat_values[++index] = atomic_read(&pau_qps_destroyed);
  }
  
  /**
@@@ -1639,7 -1642,7 +1643,7 @@@ static const struct net_device_ops nes_
        .ndo_get_stats          = nes_netdev_get_stats,
        .ndo_tx_timeout         = nes_netdev_tx_timeout,
        .ndo_set_mac_address    = nes_netdev_set_mac_address,
 -      .ndo_set_multicast_list = nes_netdev_set_multicast_list,
 +      .ndo_set_rx_mode        = nes_netdev_set_multicast_list,
        .ndo_change_mtu         = nes_netdev_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_fix_features       = nes_fix_features,
@@@ -84,7 -84,7 +84,7 @@@ static void ipoib_cm_dma_unmap_rx(struc
        ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE);
  
        for (i = 0; i < frags; ++i)
-               ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
+               ib_dma_unmap_page(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
  }
  
  static int ipoib_cm_post_receive_srq(struct net_device *dev, int id)
@@@ -169,7 -169,7 +169,7 @@@ static struct sk_buff *ipoib_cm_alloc_r
                        goto partial_error;
                skb_fill_page_desc(skb, i, page, 0, PAGE_SIZE);
  
 -              mapping[i + 1] = ib_dma_map_page(priv->ca, skb_shinfo(skb)->frags[i].page,
 +              mapping[i + 1] = ib_dma_map_page(priv->ca, page,
                                                 0, PAGE_SIZE, DMA_FROM_DEVICE);
                if (unlikely(ib_dma_mapping_error(priv->ca, mapping[i + 1])))
                        goto partial_error;
@@@ -183,7 -183,7 +183,7 @@@ partial_error
        ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE);
  
        for (; i > 0; --i)
-               ib_dma_unmap_single(priv->ca, mapping[i], PAGE_SIZE, DMA_FROM_DEVICE);
+               ib_dma_unmap_page(priv->ca, mapping[i], PAGE_SIZE, DMA_FROM_DEVICE);
  
        dev_kfree_skb_any(skb);
        return NULL;
@@@ -537,13 -537,12 +537,13 @@@ static void skb_put_frags(struct sk_buf
  
                if (length == 0) {
                        /* don't need this page */
 -                      skb_fill_page_desc(toskb, i, frag->page, 0, PAGE_SIZE);
 +                      skb_fill_page_desc(toskb, i, skb_frag_page(frag),
 +                                         0, PAGE_SIZE);
                        --skb_shinfo(skb)->nr_frags;
                } else {
                        size = min(length, (unsigned) PAGE_SIZE);
  
 -                      frag->size = size;
 +                      skb_frag_size_set(frag, size);
                        skb->data_len += size;
                        skb->truesize += size;
                        skb->len += size;
@@@ -1497,6 -1496,7 +1497,7 @@@ static void ipoib_cm_create_srq(struct 
  {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_srq_init_attr srq_init_attr = {
+               .srq_type = IB_SRQT_BASIC,
                .attr = {
                        .max_wr  = ipoib_recvq_size,
                        .max_sge = max_sge
@@@ -484,7 -484,7 +484,7 @@@ static void mlx4_free_eq(struct mlx4_de
  
        mlx4_mtt_cleanup(dev, &eq->mtt);
        for (i = 0; i < npages; ++i)
-               pci_free_consistent(dev->pdev, PAGE_SIZE,
+               dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
                                    eq->page_list[i].buf,
                                    eq->page_list[i].map);
  
@@@ -101,7 -101,6 +101,7 @@@ static void dump_dev_cap_flags(struct m
                [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",
@@@ -205,6 -204,8 +205,8 @@@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev 
  #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
        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;
@@@ -93,6 -93,8 +93,8 @@@ struct mlx4_dev_cap 
        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;
@@@ -96,6 -96,8 +96,8 @@@ MODULE_PARM_DESC(log_num_mac, "Log2 ma
  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);
@@@ -220,6 -222,10 +222,10 @@@ static int mlx4_dev_cap(struct mlx4_de
        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.max_gso_sz         = dev_cap->max_gso_sz;
  
        dev->caps.log_num_macs  = log_num_mac;
-       dev->caps.log_num_vlans = log_num_vlan;
+       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) {
@@@ -912,11 -918,18 +918,18 @@@ static int mlx4_setup_hca(struct mlx4_d
                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");
-               goto err_pd_table_free;
+               goto err_xrcd_table_free;
        }
  
        err = mlx4_init_eq_table(dev);
                                  "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",
@@@ -1033,6 -1053,9 +1053,9 @@@ err_eq_table_free
  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);
  
@@@ -1355,6 -1378,7 +1378,7 @@@ err_port
        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);
  
@@@ -1416,6 -1440,7 +1440,7 @@@ static void mlx4_remove_one(struct pci_
                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);
@@@ -1489,10 -1514,9 +1514,9 @@@ static int __init mlx4_verify_params(vo
                return -1;
        }
  
-       if ((log_num_vlan < 0) || (log_num_vlan > 7)) {
-               pr_warning("mlx4_core: bad num_vlan: %d\n", log_num_vlan);
-               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);
@@@ -335,6 -335,7 +335,7 @@@ struct mlx4_priv 
        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;
@@@ -384,6 -385,7 +385,7 @@@ int mlx4_alloc_eq_table(struct mlx4_de
  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);
@@@ -393,6 -395,7 +395,7 @@@ int mlx4_init_srq_table(struct mlx4_de
  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);
@@@ -450,6 -453,7 +453,7 @@@ void mlx4_init_vlan_table(struct mlx4_d
  
  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);
@@@ -139,7 -139,7 +139,7 @@@ static int mlx4_buddy_init(struct mlx4_
  
        buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *),
                              GFP_KERNEL);
-       buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof (int *),
+       buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free,
                                  GFP_KERNEL);
        if (!buddy->bits || !buddy->num_free)
                goto err_out;
@@@ -61,6 -61,24 +61,24 @@@ void mlx4_pd_free(struct mlx4_dev *dev
  }
  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);
@@@ -74,6 -92,18 +92,18 @@@ void mlx4_cleanup_pd_table(struct mlx4_
        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)
  {
@@@ -65,7 -65,7 +65,7 @@@ void mlx4_init_vlan_table(struct mlx4_d
                table->entries[i] = 0;
                table->refs[i]   = 0;
        }
 -      table->max   = 1 << dev->caps.log_num_vlans;
 +      table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
        table->total = 0;
  }
  
@@@ -148,22 -148,26 +148,26 @@@ int mlx4_register_mac(struct mlx4_dev *
  
        if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
                err = mlx4_uc_steer_add(dev, port, mac, qpn, 1);
-               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
+               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]) {
@@@ -354,13 -358,6 +358,13 @@@ int mlx4_register_vlan(struct mlx4_dev 
        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;
                goto out;
        }
  
 -      if (table->total == table->max) {
 -              /* No free vlan entries */
 -              err = -ENOSPC;
 -              goto out;
 -      }
 -
        /* Register new MAC */
        table->refs[free] = 1;
        table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
@@@ -465,6 -468,48 +469,48 @@@ int mlx4_get_port_ib_caps(struct mlx4_d
        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;
@@@ -280,6 -280,9 +280,9 @@@ int mlx4_init_qp_table(struct mlx4_dev 
         * 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);
  struct mlx4_srq_context {
        __be32                  state_logsize_srqn;
        u8                      logstride;
-       u8                      reserved1[3];
-       u8                      pg_offset;
-       u8                      reserved2[3];
-       u32                     reserved3;
+       u8                      reserved1;
+       __be16                  xrcd;
+       __be32                  pg_offset_cqn;
+       u32                     reserved2;
        u8                      log_page_size;
-       u8                      reserved4[2];
+       u8                      reserved3[2];
        u8                      mtt_base_addr_h;
        __be32                  mtt_base_addr_l;
        __be32                  pd;
        __be16                  limit_watermark;
        __be16                  wqe_cnt;
-       u16                     reserved5;
+       u16                     reserved4;
        __be16                  wqe_counter;
-       u32                     reserved6;
+       u32                     reserved5;
        __be64                  db_rec_addr;
  };
  
@@@ -109,8 -109,8 +109,8 @@@ static int mlx4_QUERY_SRQ(struct mlx4_d
                            MLX4_CMD_TIME_CLASS_A);
  }
  
- int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
-                  u64 db_rec, struct mlx4_srq *srq)
+ 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;
        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);
@@@ -61,6 -61,7 +61,7 @@@ enum 
        MLX4_DEV_CAP_FLAG_RC            = 1LL <<  0,
        MLX4_DEV_CAP_FLAG_UC            = 1LL <<  1,
        MLX4_DEV_CAP_FLAG_UD            = 1LL <<  2,
+       MLX4_DEV_CAP_FLAG_XRC           = 1LL <<  3,
        MLX4_DEV_CAP_FLAG_SRQ           = 1LL <<  6,
        MLX4_DEV_CAP_FLAG_IPOIB_CSUM    = 1LL <<  7,
        MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL <<  8,
@@@ -75,7 -76,6 +76,7 @@@
        MLX4_DEV_CAP_FLAG_UD_MCAST      = 1LL << 21,
        MLX4_DEV_CAP_FLAG_IBOE          = 1LL << 30,
        MLX4_DEV_CAP_FLAG_UC_LOOPBACK   = 1LL << 32,
 +      MLX4_DEV_CAP_FLAG_FCS_KEEP      = 1LL << 34,
        MLX4_DEV_CAP_FLAG_WOL           = 1LL << 38,
        MLX4_DEV_CAP_FLAG_UDP_RSS       = 1LL << 40,
        MLX4_DEV_CAP_FLAG_VEP_UC_STEER  = 1LL << 41,
        MLX4_DEV_CAP_FLAG_COUNTERS      = 1LL << 48
  };
  
+ #define MLX4_ATTR_EXTENDED_PORT_INFO  cpu_to_be16(0xff90)
+ enum {
+       MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO        = 1 <<  0
+ };
  enum {
        MLX4_BMME_FLAG_LOCAL_INV        = 1 <<  6,
        MLX4_BMME_FLAG_REMOTE_INV       = 1 <<  7,
@@@ -257,6 -263,8 +264,8 @@@ struct mlx4_caps 
        int                     num_qp_per_mgm;
        int                     num_pds;
        int                     reserved_pds;
+       int                     max_xrcds;
+       int                     reserved_xrcds;
        int                     mtt_entry_sz;
        u32                     max_msg_sz;
        u32                     page_size_cap;
        u32                     port_mask;
        enum mlx4_port_type     possible_type[MLX4_MAX_PORTS + 1];
        u32                     max_counters;
+       u8                      ext_port_cap[MLX4_MAX_PORTS + 1];
  };
  
  struct mlx4_buf_list {
@@@ -500,6 -509,8 +510,8 @@@ static inline void *mlx4_buf_offset(str
  
  int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn);
  void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn);
+ int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn);
+ void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn);
  
  int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar);
  void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar);
@@@ -539,8 -550,8 +551,8 @@@ void mlx4_qp_release_range(struct mlx4_
  int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp);
  void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp);
  
- int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
-                  u64 db_rec, struct mlx4_srq *srq);
+ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcdn,
+                  struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq);
  void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq);
  int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark);
  int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark);