linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / infiniband / hw / mthca / mthca_av.c
index ee7f1dc..a19e0ed 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, 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
  */
 
 #include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
 
-#include <ib_verbs.h>
-#include <ib_cache.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_cache.h>
 
 #include "mthca_dev.h"
 
 struct mthca_av {
-       u32 port_pd;
-       u8  reserved1;
-       u8  g_slid;
-       u16 dlid;
-       u8  reserved2;
-       u8  gid_index;
-       u8  msg_sr;
-       u8  hop_limit;
-       u32 sl_tclass_flowlabel;
-       u32 dgid[4];
+       __be32 port_pd;
+       u8     reserved1;
+       u8     g_slid;
+       __be16 dlid;
+       u8     reserved2;
+       u8     gid_index;
+       u8     msg_sr;
+       u8     hop_limit;
+       __be32 sl_tclass_flowlabel;
+       __be32 dgid[4];
 };
 
 int mthca_create_ah(struct mthca_dev *dev,
@@ -60,29 +63,36 @@ int mthca_create_ah(struct mthca_dev *dev,
        u32 index = -1;
        struct mthca_av *av = NULL;
 
-       ah->on_hca = 0;
+       ah->type = MTHCA_AH_PCI_POOL;
 
-       if (!atomic_read(&pd->sqp_count) &&
-           !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
+       if (mthca_is_memfree(dev)) {
+               ah->av   = kmalloc(sizeof *ah->av, GFP_ATOMIC);
+               if (!ah->av)
+                       return -ENOMEM;
+
+               ah->type = MTHCA_AH_KMALLOC;
+               av       = ah->av;
+       } else if (!atomic_read(&pd->sqp_count) &&
+                !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
                index = mthca_alloc(&dev->av_table.alloc);
 
                /* fall back to allocate in host memory */
                if (index == -1)
-                       goto host_alloc;
+                       goto on_hca_fail;
 
-               av = kmalloc(sizeof *av, GFP_KERNEL);
+               av = kmalloc(sizeof *av, GFP_ATOMIC);
                if (!av)
-                       goto host_alloc;
+                       goto on_hca_fail;
 
-               ah->on_hca = 1;
+               ah->type = MTHCA_AH_ON_HCA;
                ah->avdma  = dev->av_table.ddr_av_base +
                        index * MTHCA_AV_SIZE;
        }
 
- host_alloc:
-       if (!ah->on_hca) {
+on_hca_fail:
+       if (ah->type == MTHCA_AH_PCI_POOL) {
                ah->av = pci_pool_alloc(dev->av_table.pool,
-                                       SLAB_KERNEL, &ah->avdma);
+                                       SLAB_ATOMIC, &ah->avdma);
                if (!ah->av)
                        return -ENOMEM;
 
@@ -120,10 +130,10 @@ int mthca_create_ah(struct mthca_dev *dev,
                          av, (unsigned long) ah->avdma);
                for (j = 0; j < 8; ++j)
                        printk(KERN_DEBUG "  [%2x] %08x\n",
-                              j * 4, be32_to_cpu(((u32 *) av)[j]));
+                              j * 4, be32_to_cpu(((__be32 *) av)[j]));
        }
 
-       if (ah->on_hca) {
+       if (ah->type == MTHCA_AH_ON_HCA) {
                memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE,
                            av, MTHCA_AV_SIZE);
                kfree(av);
@@ -134,39 +144,50 @@ int mthca_create_ah(struct mthca_dev *dev,
 
 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
 {
-       if (ah->on_hca)
+       switch (ah->type) {
+       case MTHCA_AH_ON_HCA:
                mthca_free(&dev->av_table.alloc,
                           (ah->avdma - dev->av_table.ddr_av_base) /
                           MTHCA_AV_SIZE);
-       else
+               break;
+
+       case MTHCA_AH_PCI_POOL:
                pci_pool_free(dev->av_table.pool, ah->av, ah->avdma);
+               break;
+
+       case MTHCA_AH_KMALLOC:
+               kfree(ah->av);
+               break;
+       }
 
        return 0;
 }
 
+int mthca_ah_grh_present(struct mthca_ah *ah)
+{
+       return !!(ah->av->g_slid & 0x80);
+}
+
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                  struct ib_ud_header *header)
 {
-       if (ah->on_hca)
+       if (ah->type == MTHCA_AH_ON_HCA)
                return -EINVAL;
 
        header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
        header->lrh.destination_lid = ah->av->dlid;
-       header->lrh.source_lid      = ah->av->g_slid & 0x7f;
-       if (ah->av->g_slid & 0x80) {
-               header->grh_present = 1;
+       header->lrh.source_lid      = cpu_to_be16(ah->av->g_slid & 0x7f);
+       if (mthca_ah_grh_present(ah)) {
                header->grh.traffic_class =
                        (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff;
                header->grh.flow_label    =
                        ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff);
                ib_get_cached_gid(&dev->ib_dev,
                                  be32_to_cpu(ah->av->port_pd) >> 24,
-                                 ah->av->gid_index,
+                                 ah->av->gid_index % dev->limits.gid_table_len,
                                  &header->grh.source_gid);
                memcpy(header->grh.destination_gid.raw,
                       ah->av->dgid, 16);
-       } else {
-               header->grh_present = 0;
        }
 
        return 0;
@@ -176,6 +197,9 @@ int __devinit mthca_init_av_table(struct mthca_dev *dev)
 {
        int err;
 
+       if (mthca_is_memfree(dev))
+               return 0;
+
        err = mthca_alloc_init(&dev->av_table.alloc,
                               dev->av_table.num_ddr_avs,
                               dev->av_table.num_ddr_avs - 1,
@@ -212,6 +236,9 @@ int __devinit mthca_init_av_table(struct mthca_dev *dev)
 
 void __devexit mthca_cleanup_av_table(struct mthca_dev *dev)
 {
+       if (mthca_is_memfree(dev))
+               return;
+
        if (dev->av_table.av_map)
                iounmap(dev->av_table.av_map);
        pci_pool_destroy(dev->av_table.pool);