2006-08-17 20:10:00

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 00/16] IB/ehca: introduction

Here's a series of patches (split up rather arbitrarily to avoid
too-big emails) which adds a driver for the IBM eHCA InfiniBand
adapter. The driver has been around for a while, and my feeling is
that it is good enough to merge, even though it could certainly use
some cleaning up. However, my feeling is that we don't need to wait
for this driver to be perfect before merging it, and that it would be
better for everyone if it gets into mainline (eg coordination with
Anton's hcall cleanup becomes simpler).

Please review and comment, and do let me know if you disagree with my
decision to merge this for 2.6.19. (BTW, just to be clear -- I'll
collapse this driver into a single git commit with full changelog and
Signed-off-by: lines before actually merging it -- the bare patches
are just for review)

The driver is also available in git for your reviewing pleasure at

git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git ehca

The developers of the driver are cc'ed on this thread and should
respond to any comments.

Thanks,
Roland


2006-08-17 20:09:34

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 01/16] IB/ehca: main

drivers/infiniband/hw/ehca/ehca_main.c | 958 ++++++++++++++++++++++++++++++++
1 files changed, 958 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
new file mode 100644
index 0000000..229ee9c
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -0,0 +1,958 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * module start stop, hca detection
+ *
+ * Authors: Heiko J Schick <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEB_PREFIX "shca"
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Christoph Raisch <[email protected]>");
+MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
+MODULE_VERSION("SVNEHCA_0012");
+
+int ehca_open_aqp1 = 0;
+int ehca_debug_level = -1;
+int ehca_hw_level = 0;
+int ehca_nr_ports = 2;
+int ehca_use_hp_mr = 0;
+int ehca_port_act_time = 30;
+int ehca_poll_all_eqs = 1;
+int ehca_static_rate = -1;
+
+module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
+module_param_named(debug_level, ehca_debug_level, int, 0);
+module_param_named(hw_level, ehca_hw_level, int, 0);
+module_param_named(nr_ports, ehca_nr_ports, int, 0);
+module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
+module_param_named(port_act_time, ehca_port_act_time, int, 0);
+module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
+module_param_named(static_rate, ehca_static_rate, int, 0);
+
+MODULE_PARM_DESC(open_aqp1,
+ "AQP1 on startup (0: no (default), 1: yes)");
+MODULE_PARM_DESC(debug_level,
+ "debug level"
+ " (0: node, 6: only errors (default), 9: all)");
+MODULE_PARM_DESC(hw_level,
+ "hardware level"
+ " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
+MODULE_PARM_DESC(nr_ports,
+ "number of connected ports (default: 2)");
+MODULE_PARM_DESC(use_hp_mr,
+ "high performance MRs (0: no (default), 1: yes)");
+MODULE_PARM_DESC(port_act_time,
+ "time to wait for port activation (default: 30 sec)");
+MODULE_PARM_DESC(poll_all_eqs,
+ "polls all event queues periodically"
+ " (0: no, 1: yes (default))");
+MODULE_PARM_DESC(static_rate,
+ "set permanent static rate (default: disabled)");
+
+/*
+ * This external trace mask controls what will end up in the
+ * kernel ring buffer. Number 6 means, that everything between
+ * 0 and 5 will be stored.
+ */
+u8 ehca_edeb_mask[EHCA_EDEB_TRACE_MASK_SIZE]={6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 0, 0};
+
+spinlock_t ehca_qp_idr_lock;
+spinlock_t ehca_cq_idr_lock;
+DEFINE_IDR(ehca_qp_idr);
+DEFINE_IDR(ehca_cq_idr);
+
+struct ehca_module ehca_module;
+
+void ehca_init_trace(void)
+{
+ EDEB_EN(7, "");
+
+ if (ehca_debug_level != -1) {
+ int i;
+ for (i = 0; i < EHCA_EDEB_TRACE_MASK_SIZE; i++)
+ ehca_edeb_mask[i] = ehca_debug_level;
+ }
+
+ EDEB_EX(7, "");
+}
+
+int ehca_create_slab_caches(struct ehca_module *ehca_module)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "");
+
+ ehca_module->cache_pd =
+ kmem_cache_create("ehca_cache_pd",
+ sizeof(struct ehca_pd),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!ehca_module->cache_pd) {
+ EDEB_ERR(4, "Cannot create PD SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches1;
+ }
+
+ ehca_module->cache_cq =
+ kmem_cache_create("ehca_cache_cq",
+ sizeof(struct ehca_cq),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!ehca_module->cache_cq) {
+ EDEB_ERR(4, "Cannot create CQ SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches2;
+ }
+
+ ehca_module->cache_qp =
+ kmem_cache_create("ehca_cache_qp",
+ sizeof(struct ehca_qp),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!ehca_module->cache_qp) {
+ EDEB_ERR(4, "Cannot create QP SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches3;
+ }
+
+ ehca_module->cache_av =
+ kmem_cache_create("ehca_cache_av",
+ sizeof(struct ehca_av),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!ehca_module->cache_av) {
+ EDEB_ERR(4, "Cannot create AV SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches4;
+ }
+
+ ehca_module->cache_mw =
+ kmem_cache_create("ehca_cache_mw",
+ sizeof(struct ehca_mw),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!ehca_module->cache_mw) {
+ EDEB_ERR(4, "Cannot create MW SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches5;
+ }
+
+ ehca_module->cache_mr =
+ kmem_cache_create("ehca_cache_mr",
+ sizeof(struct ehca_mr),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!ehca_module->cache_mr) {
+ EDEB_ERR(4, "Cannot create MR SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches6;
+ }
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+
+create_slab_caches6:
+ kmem_cache_destroy(ehca_module->cache_mw);
+
+create_slab_caches5:
+ kmem_cache_destroy(ehca_module->cache_av);
+
+create_slab_caches4:
+ kmem_cache_destroy(ehca_module->cache_qp);
+
+create_slab_caches3:
+ kmem_cache_destroy(ehca_module->cache_cq);
+
+create_slab_caches2:
+ kmem_cache_destroy(ehca_module->cache_pd);
+
+create_slab_caches1:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_destroy_slab_caches(struct ehca_module *ehca_module)
+{
+ int ret;
+
+ EDEB_EN(7, "");
+
+ ret = kmem_cache_destroy(ehca_module->cache_pd);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy PD SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_cq);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy CQ SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_qp);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy QP SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_av);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy AV SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_mw);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy MW SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_mr);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy MR SLAB cache. ret=%x", ret);
+
+ EDEB_EX(7, "");
+
+ return 0;
+}
+
+#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
+#define EHCA_REVID EHCA_BMASK_IBM(40,63)
+
+int ehca_sense_attributes(struct ehca_shca *shca)
+{
+ int ret = -EINVAL;
+ u64 h_ret = H_SUCCESS;
+ struct hipz_query_hca *rblock;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Cannot allocate rblock memory.");
+ ret = -ENOMEM;
+ goto num_ports0;
+ }
+
+ h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "Cannot query device properties. h_ret=%lx", h_ret);
+ ret = -EPERM;
+ goto num_ports1;
+ }
+
+ if (ehca_nr_ports == 1)
+ shca->num_ports = 1;
+ else
+ shca->num_ports = (u8)rblock->num_ports;
+
+ EDEB(6, " ... found %x ports", rblock->num_ports);
+
+ if (ehca_hw_level == 0) {
+ u32 hcaaver;
+ u32 revid;
+
+ hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver);
+ revid = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver);
+
+ EDEB(6, " ... hardware version=%x:%x",
+ hcaaver, revid);
+
+ if ((hcaaver == 1) && (revid == 0))
+ shca->hw_level = 0;
+ else if ((hcaaver == 1) && (revid == 1))
+ shca->hw_level = 1;
+ else if ((hcaaver == 1) && (revid == 2))
+ shca->hw_level = 2;
+ }
+ EDEB(6, " ... hardware level=%x", shca->hw_level);
+
+ shca->sport[0].rate = IB_RATE_30_GBPS;
+ shca->sport[1].rate = IB_RATE_30_GBPS;
+
+ ret = 0;
+
+num_ports1:
+ kfree(rblock);
+
+num_ports0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static int init_node_guid(struct ehca_shca* shca)
+{
+ int ret = 0;
+ struct hipz_query_hca *rblock;
+
+ EDEB_EN(7, "");
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto init_node_guid0;
+ }
+
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query device properties");
+ ret = -EINVAL;
+ goto init_node_guid1;
+ }
+
+ memcpy(&shca->ib_device.node_guid, &rblock->node_guid, (sizeof(u64)));
+
+init_node_guid1:
+ kfree(rblock);
+
+init_node_guid0:
+ EDEB_EX(7, "node_guid=%lx ret=%x", shca->ib_device.node_guid, ret);
+
+ return ret;
+}
+
+int ehca_register_device(struct ehca_shca *shca)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ ret = init_node_guid(shca);
+ if (ret)
+ return ret;
+
+ strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
+ shca->ib_device.owner = THIS_MODULE;
+
+ shca->ib_device.uverbs_abi_ver = 5;
+ shca->ib_device.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
+ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
+
+ shca->ib_device.node_type = IB_NODE_CA;
+ shca->ib_device.phys_port_cnt = shca->num_ports;
+ shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev;
+ shca->ib_device.query_device = ehca_query_device;
+ shca->ib_device.query_port = ehca_query_port;
+ shca->ib_device.query_gid = ehca_query_gid;
+ shca->ib_device.query_pkey = ehca_query_pkey;
+ /* shca->in_device.modify_device = ehca_modify_device */
+ shca->ib_device.modify_port = ehca_modify_port;
+ shca->ib_device.alloc_ucontext = ehca_alloc_ucontext;
+ shca->ib_device.dealloc_ucontext = ehca_dealloc_ucontext;
+ shca->ib_device.alloc_pd = ehca_alloc_pd;
+ shca->ib_device.dealloc_pd = ehca_dealloc_pd;
+ shca->ib_device.create_ah = ehca_create_ah;
+ /* shca->ib_device.modify_ah = ehca_modify_ah; */
+ shca->ib_device.query_ah = ehca_query_ah;
+ shca->ib_device.destroy_ah = ehca_destroy_ah;
+ shca->ib_device.create_qp = ehca_create_qp;
+ shca->ib_device.modify_qp = ehca_modify_qp;
+ shca->ib_device.query_qp = ehca_query_qp;
+ shca->ib_device.destroy_qp = ehca_destroy_qp;
+ shca->ib_device.post_send = ehca_post_send;
+ shca->ib_device.post_recv = ehca_post_recv;
+ shca->ib_device.create_cq = ehca_create_cq;
+ shca->ib_device.destroy_cq = ehca_destroy_cq;
+ shca->ib_device.resize_cq = ehca_resize_cq;
+ shca->ib_device.poll_cq = ehca_poll_cq;
+ /* shca->ib_device.peek_cq = ehca_peek_cq; */
+ shca->ib_device.req_notify_cq = ehca_req_notify_cq;
+ /* shca->ib_device.req_ncomp_notif = ehca_req_ncomp_notif; */
+ shca->ib_device.get_dma_mr = ehca_get_dma_mr;
+ shca->ib_device.reg_phys_mr = ehca_reg_phys_mr;
+ shca->ib_device.reg_user_mr = ehca_reg_user_mr;
+ shca->ib_device.query_mr = ehca_query_mr;
+ shca->ib_device.dereg_mr = ehca_dereg_mr;
+ shca->ib_device.rereg_phys_mr = ehca_rereg_phys_mr;
+ shca->ib_device.alloc_mw = ehca_alloc_mw;
+ shca->ib_device.bind_mw = ehca_bind_mw;
+ shca->ib_device.dealloc_mw = ehca_dealloc_mw;
+ shca->ib_device.alloc_fmr = ehca_alloc_fmr;
+ shca->ib_device.map_phys_fmr = ehca_map_phys_fmr;
+ shca->ib_device.unmap_fmr = ehca_unmap_fmr;
+ shca->ib_device.dealloc_fmr = ehca_dealloc_fmr;
+ shca->ib_device.attach_mcast = ehca_attach_mcast;
+ shca->ib_device.detach_mcast = ehca_detach_mcast;
+ /* shca->ib_device.process_mad = ehca_process_mad; */
+ shca->ib_device.mmap = ehca_mmap;
+
+ ret = ib_register_device(&shca->ib_device);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
+{
+ struct ehca_sport *sport;
+ struct ib_cq *ibcq;
+ struct ib_qp *ibqp;
+ struct ib_qp_init_attr qp_init_attr;
+ int ret = 0;
+
+ EDEB_EN(7, "shca=%p port=%x", shca, port);
+
+ sport = &shca->sport[port - 1];
+
+ if (sport->ibcq_aqp1) {
+ EDEB_ERR(4, "AQP1 CQ is already created.");
+ return -EPERM;
+ }
+
+ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+ if (IS_ERR(ibcq)) {
+ EDEB_ERR(4, "Cannot create AQP1 CQ.");
+ return PTR_ERR(ibcq);
+ }
+ sport->ibcq_aqp1 = ibcq;
+
+ if (sport->ibqp_aqp1) {
+ EDEB_ERR(4, "AQP1 QP is already created.");
+ ret = -EPERM;
+ goto create_aqp1;
+ }
+
+ memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr));
+ qp_init_attr.send_cq = ibcq;
+ qp_init_attr.recv_cq = ibcq;
+ qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
+ qp_init_attr.cap.max_send_wr = 100;
+ qp_init_attr.cap.max_recv_wr = 100;
+ qp_init_attr.cap.max_send_sge = 2;
+ qp_init_attr.cap.max_recv_sge = 1;
+ qp_init_attr.qp_type = IB_QPT_GSI;
+ qp_init_attr.port_num = port;
+ qp_init_attr.qp_context = NULL;
+ qp_init_attr.event_handler = NULL;
+ qp_init_attr.srq = NULL;
+
+ ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr);
+ if (IS_ERR(ibqp)) {
+ EDEB_ERR(4, "Cannot create AQP1 QP.");
+ ret = PTR_ERR(ibqp);
+ goto create_aqp1;
+ }
+ sport->ibqp_aqp1 = ibqp;
+
+ goto create_aqp0;
+
+create_aqp1:
+ ib_destroy_cq(sport->ibcq_aqp1);
+
+create_aqp0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static int ehca_destroy_aqp1(struct ehca_sport *sport)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "sport=%p", sport);
+
+ ret = ib_destroy_qp(sport->ibqp_aqp1);
+ if (ret) {
+ EDEB_ERR(4, "Cannot destroy AQP1 QP. ret=%x", ret);
+ goto destroy_aqp1;
+ }
+
+ ret = ib_destroy_cq(sport->ibcq_aqp1);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy AQP1 CQ. ret=%x", ret);
+
+destroy_aqp1:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static ssize_t ehca_show_debug_mask(struct device_driver *ddp, char *buf)
+{
+ int i;
+ int total = 0;
+ total += snprintf(buf + total, PAGE_SIZE - total, "%d",
+ ehca_edeb_mask[0]);
+ for (i = 1; i < EHCA_EDEB_TRACE_MASK_SIZE; i++) {
+ total += snprintf(buf + total, PAGE_SIZE - total, "%d",
+ ehca_edeb_mask[i]);
+ }
+
+ total += snprintf(buf + total, PAGE_SIZE - total, "\n");
+
+ return total;
+}
+
+static ssize_t ehca_store_debug_mask(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ int i;
+ for (i = 0; i < EHCA_EDEB_TRACE_MASK_SIZE; i++) {
+ char value = buf[i] - '0';
+ if ((value <= 9) && (count >= i)) {
+ ehca_edeb_mask[i] = value;
+ }
+ }
+ return count;
+}
+DRIVER_ATTR(debug_mask, S_IRUSR | S_IWUSR,
+ ehca_show_debug_mask, ehca_store_debug_mask);
+
+void ehca_create_driver_sysfs(struct ibmebus_driver *drv)
+{
+ driver_create_file(&drv->driver, &driver_attr_debug_mask);
+}
+
+void ehca_remove_driver_sysfs(struct ibmebus_driver *drv)
+{
+ driver_remove_file(&drv->driver, &driver_attr_debug_mask);
+}
+
+#define EHCA_RESOURCE_ATTR(name) \
+static ssize_t ehca_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ehca_shca *shca; \
+ struct hipz_query_hca *rblock; \
+ int data; \
+ \
+ shca = dev->driver_data; \
+ \
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); \
+ if (!rblock) { \
+ EDEB_ERR(4, "Can't allocate rblock memory."); \
+ return 0; \
+ } \
+ \
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \
+ EDEB_ERR(4, "Can't query device properties"); \
+ kfree(rblock); \
+ return 0; \
+ } \
+ \
+ data = rblock->name; \
+ kfree(rblock); \
+ \
+ if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \
+ return snprintf(buf, 256, "1\n"); \
+ else \
+ return snprintf(buf, 256, "%d\n", data); \
+ \
+} \
+static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL);
+
+EHCA_RESOURCE_ATTR(num_ports);
+EHCA_RESOURCE_ATTR(hw_ver);
+EHCA_RESOURCE_ATTR(max_eq);
+EHCA_RESOURCE_ATTR(cur_eq);
+EHCA_RESOURCE_ATTR(max_cq);
+EHCA_RESOURCE_ATTR(cur_cq);
+EHCA_RESOURCE_ATTR(max_qp);
+EHCA_RESOURCE_ATTR(cur_qp);
+EHCA_RESOURCE_ATTR(max_mr);
+EHCA_RESOURCE_ATTR(cur_mr);
+EHCA_RESOURCE_ATTR(max_mw);
+EHCA_RESOURCE_ATTR(cur_mw);
+EHCA_RESOURCE_ATTR(max_pd);
+EHCA_RESOURCE_ATTR(max_ah);
+
+static ssize_t ehca_show_adapter_handle(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ehca_shca *shca = dev->driver_data;
+
+ return sprintf(buf, "%lx\n", shca->ipz_hca_handle.handle);
+
+}
+static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
+
+
+void ehca_create_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_create_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
+ device_create_file(&dev->ofdev.dev, &dev_attr_num_ports);
+ device_create_file(&dev->ofdev.dev, &dev_attr_hw_ver);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_eq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_eq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_cq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_cq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_qp);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_qp);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_mr);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mr);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_mw);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mw);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_pd);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_ah);
+}
+
+void ehca_remove_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_remove_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_num_ports);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_hw_ver);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_eq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_eq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_cq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_cq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_qp);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_qp);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mr);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mr);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mw);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mw);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_pd);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_ah);
+}
+
+static int __devinit ehca_probe(struct ibmebus_dev *dev,
+ const struct of_device_id *id)
+{
+ struct ehca_shca *shca;
+ u64 *handle;
+ struct ib_pd *ibpd;
+ int ret = 0;
+
+ EDEB_EN(7, "");
+
+ handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+ if (!handle) {
+ EDEB_ERR(4, "Cannot get eHCA handle for adapter: %s.",
+ dev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ if (!(*handle)) {
+ EDEB_ERR(4, "Wrong eHCA handle for adapter: %s.",
+ dev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca));
+ if (shca == NULL) {
+ EDEB_ERR(4, "Cannot allocate shca memory.");
+ return -ENOMEM;
+ }
+
+ shca->ibmebus_dev = dev;
+ shca->ipz_hca_handle.handle = *handle;
+ dev->ofdev.dev.driver_data = shca;
+
+ ret = ehca_sense_attributes(shca);
+ if (ret < 0) {
+ EDEB_ERR(4, "Cannot sense eHCA attributes.");
+ goto probe1;
+ }
+
+ /* create event queues */
+ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
+ if (ret) {
+ EDEB_ERR(4, "Cannot create EQ.");
+ goto probe1;
+ }
+
+ ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);
+ if (ret) {
+ EDEB_ERR(4, "Cannot create NEQ.");
+ goto probe2;
+ }
+
+ /* create internal protection domain */
+ ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+ if (IS_ERR(ibpd)) {
+ EDEB_ERR(4, "Cannot create internal PD.");
+ ret = PTR_ERR(ibpd);
+ goto probe3;
+ }
+
+ shca->pd = container_of(ibpd, struct ehca_pd, ib_pd);
+ shca->pd->ib_pd.device = &shca->ib_device;
+
+ /* create internal max MR */
+ ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
+
+ if (ret) {
+ EDEB_ERR(4, "Cannot create internal MR. ret=%x", ret);
+ goto probe4;
+ }
+
+ ret = ehca_register_device(shca);
+ if (ret) {
+ EDEB_ERR(4, "Cannot register Infiniband device.");
+ goto probe5;
+ }
+
+ /* create AQP1 for port 1 */
+ if (ehca_open_aqp1 == 1) {
+ shca->sport[0].port_state = IB_PORT_DOWN;
+ ret = ehca_create_aqp1(shca, 1);
+ if (ret) {
+ EDEB_ERR(4, "Cannot create AQP1 for port 1.");
+ goto probe6;
+ }
+ }
+
+ /* create AQP1 for port 2 */
+ if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) {
+ shca->sport[1].port_state = IB_PORT_DOWN;
+ ret = ehca_create_aqp1(shca, 2);
+ if (ret) {
+ EDEB_ERR(4, "Cannot create AQP1 for port 2.");
+ goto probe7;
+ }
+ }
+
+ ehca_create_device_sysfs(dev);
+
+ spin_lock(&ehca_module.shca_lock);
+ list_add(&shca->shca_list, &ehca_module.shca_list);
+ spin_unlock(&ehca_module.shca_lock);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return 0;
+
+probe7:
+ ret = ehca_destroy_aqp1(&shca->sport[0]);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy AQP1 for port 1. ret=%x", ret);
+
+probe6:
+ ib_unregister_device(&shca->ib_device);
+
+probe5:
+ ret = ehca_dereg_internal_maxmr(shca);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy internal MR. ret=%x", ret);
+
+probe4:
+ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy internal PD. ret=%x", ret);
+
+probe3:
+ ret = ehca_destroy_eq(shca, &shca->neq);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy NEQ. ret=%x", ret);
+
+probe2:
+ ret = ehca_destroy_eq(shca, &shca->eq);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy EQ. ret=%x", ret);
+
+probe1:
+ ib_dealloc_device(&shca->ib_device);
+
+ EDEB_EX(4, "ret=%x", ret);
+
+ return -EINVAL;
+}
+
+static int __devexit ehca_remove(struct ibmebus_dev *dev)
+{
+ struct ehca_shca *shca = dev->ofdev.dev.driver_data;
+ int ret;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ ehca_remove_device_sysfs(dev);
+
+ if (ehca_open_aqp1 == 1) {
+ int i;
+
+ for (i = 0; i < shca->num_ports; i++) {
+ ret = ehca_destroy_aqp1(&shca->sport[i]);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy AQP1 for port %x."
+ " ret=%x", ret, i);
+ }
+ }
+
+ ib_unregister_device(&shca->ib_device);
+
+ ret = ehca_dereg_internal_maxmr(shca);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy internal MR. ret=%x", ret);
+
+ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy internal PD. ret=%x", ret);
+
+ ret = ehca_destroy_eq(shca, &shca->eq);
+ if (ret)
+ EDEB_ERR(4, "Cannot destroy EQ. ret=%x", ret);
+
+ ret = ehca_destroy_eq(shca, &shca->neq);
+ if (ret)
+ EDEB_ERR(4, "Canot destroy NEQ. ret=%x", ret);
+
+ ib_dealloc_device(&shca->ib_device);
+
+ spin_lock(&ehca_module.shca_lock);
+ list_del(&shca->shca_list);
+ spin_unlock(&ehca_module.shca_lock);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static struct of_device_id ehca_device_table[] =
+{
+ {
+ .name = "lhca",
+ .compatible = "IBM,lhca",
+ },
+ {},
+};
+
+static struct ibmebus_driver ehca_driver = {
+ .name = "ehca",
+ .id_table = ehca_device_table,
+ .probe = ehca_probe,
+ .remove = ehca_remove,
+};
+
+int __init ehca_module_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "eHCA Infiniband Device Driver "
+ "(Rel.: SVNEHCA_0012)\n");
+ EDEB_EN(7, "");
+
+ idr_init(&ehca_qp_idr);
+ idr_init(&ehca_cq_idr);
+ spin_lock_init(&ehca_qp_idr_lock);
+ spin_lock_init(&ehca_cq_idr_lock);
+
+ INIT_LIST_HEAD(&ehca_module.shca_list);
+ spin_lock_init(&ehca_module.shca_lock);
+
+ ehca_init_trace();
+
+ if ((ret = ehca_create_comp_pool())) {
+ EDEB_ERR(4, "Cannot create comp pool.");
+ goto module_init0;
+ }
+
+ if ((ret = ehca_create_slab_caches(&ehca_module))) {
+ EDEB_ERR(4, "Cannot create SLAB caches");
+ ret = -ENOMEM;
+ goto module_init1;
+ }
+
+ if ((ret = ibmebus_register_driver(&ehca_driver))) {
+ EDEB_ERR(4, "Cannot register eHCA device driver");
+ ret = -EINVAL;
+ goto module_init2;
+ }
+
+ ehca_create_driver_sysfs(&ehca_driver);
+
+ if (ehca_poll_all_eqs != 1) {
+ EDEB_ERR(4, "WARNING!!!");
+ EDEB_ERR(4, "It is possible to lose interrupts.");
+ } else {
+ init_timer(&ehca_module.timer);
+ ehca_module.timer.function = ehca_poll_eqs;
+ ehca_module.timer.data = (unsigned long)&ehca_module;
+ ehca_module.timer.expires = jiffies + HZ;
+ add_timer(&ehca_module.timer);
+ }
+
+ goto module_init0;
+
+module_init2:
+ ehca_destroy_slab_caches(&ehca_module);
+
+module_init1:
+ ehca_destroy_comp_pool();
+
+module_init0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+};
+
+void __exit ehca_module_exit(void)
+{
+ EDEB_EN(7, "");
+
+ if (ehca_poll_all_eqs == 1)
+ del_timer_sync(&ehca_module.timer);
+
+ ehca_remove_driver_sysfs(&ehca_driver);
+ ibmebus_unregister_driver(&ehca_driver);
+
+ if (ehca_destroy_slab_caches(&ehca_module) != 0)
+ EDEB_ERR(4, "Cannot destroy SLAB caches");
+
+ ehca_destroy_comp_pool();
+
+ idr_destroy(&ehca_cq_idr);
+ idr_destroy(&ehca_qp_idr);
+
+ EDEB_EX(7, "");
+};
+
+module_init(ehca_module_init);
+module_exit(ehca_module_exit);
--
1.4.1

2006-08-17 20:09:35

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 03/16] IB/ehca: uverbs

drivers/infiniband/hw/ehca/ehca_uverbs.c | 400 ++++++++++++++++++++++++++++++
1 files changed, 400 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
new file mode 100644
index 0000000..c148c23
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -0,0 +1,400 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * userspace support verbs
+ *
+ * Authors: Christoph Raisch <[email protected]>
+ * Hoang-Nam Nguyen <[email protected]>
+ * Heiko J Schick <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "uver"
+
+#include <asm/current.h>
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata)
+{
+ struct ehca_ucontext *my_context = NULL;
+
+ EHCA_CHECK_ADR_P(device);
+ EDEB_EN(7, "device=%p name=%s", device, device->name);
+
+ my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
+ if (!my_context) {
+ EDEB_ERR(4, "Out of memory device=%p", device);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ EDEB_EX(7, "device=%p ucontext=%p", device, my_context);
+
+ return &my_context->ib_ucontext;
+}
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct ehca_ucontext *my_context = NULL;
+ EHCA_CHECK_ADR(context);
+ EDEB_EN(7, "ucontext=%p", context);
+ my_context = container_of(context, struct ehca_ucontext, ib_ucontext);
+ kfree(my_context);
+ EDEB_EN(7, "ucontext=%p", context);
+ return 0;
+}
+
+struct page *ehca_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct page *mypage = NULL;
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EDEB_EN(7, "vm_start=%lx vm_end=%lx vm_page_prot=%lx vm_fileoff=%lx "
+ "address=%lx",
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, fileoffset,
+ address);
+
+ if (q_type == 1) { /* CQ */
+ struct ehca_cq *cq = NULL;
+ u64 offset;
+ void *vaddr = NULL;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!cq) {
+ EDEB_ERR(4, "cq is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ if (rsrc_type == 2) {
+ EDEB(6, "cq=%p cq queuearea", cq);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ } else if (q_type == 2) { /* QP */
+ struct ehca_qp *qp = NULL;
+ struct ehca_pd *pd = NULL;
+ u64 offset;
+ void *vaddr = NULL;
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!qp) {
+ EDEB_ERR(4, "qp is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ if (rsrc_type == 2) { /* rqueue */
+ EDEB(6, "qp=%p qp rqueuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ } else if (rsrc_type == 3) { /* squeue */
+ EDEB(6, "qp=%p qp squeuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ }
+
+ if (!mypage) {
+ EDEB_ERR(4, "Invalid page adr==NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ get_page(mypage);
+ EDEB_EX(7, "page adr=%p", mypage);
+ return mypage;
+}
+
+static struct vm_operations_struct ehcau_vm_ops = {
+ .nopage = ehca_nopage,
+};
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 ret = -EFAULT; /* assume the worst */
+ u64 vsize = 0; /* must be calculated/set below */
+ u64 physical = 0; /* must be calculated/set below */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EDEB_EN(7, "vm_start=%lx vm_end=%lx vm_page_prot=%lx vm_fileoff=%lx",
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, fileoffset);
+
+ if (q_type == 1) { /* CQ */
+ struct ehca_cq *cq;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return -ENOMEM;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!cq)
+ return -EINVAL;
+ if (!cq->ib_cq.uobject)
+ return -EINVAL;
+ if (cq->ib_cq.uobject->context != context)
+ return -EINVAL;
+ if (rsrc_type == 1) { /* galpa fw handle */
+ EDEB(6, "cq=%p cq triggerarea", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+ physical = cq->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret) {
+ EDEB_ERR(4, "remap_pfn_range() failed ret=%x",
+ ret);
+ ret = -ENOMEM;
+ }
+ goto mmap_exit0;
+ } else if (rsrc_type == 2) { /* cq queue_addr */
+ EDEB(6, "cq=%p cq q_addr", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else {
+ EDEB_ERR(6, "bad resource type %x", rsrc_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ } else if (q_type == 2) { /* QP */
+ struct ehca_qp *qp = NULL;
+ struct ehca_pd *pd = NULL;
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return -ENOMEM;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!qp || !qp->ib_qp.uobject ||
+ qp->ib_qp.uobject->context != context) {
+ EDEB(6, "qp=%p, uobject=%p, context=%p",
+ qp, qp->ib_qp.uobject, qp->ib_qp.uobject->context);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ if (rsrc_type == 1) { /* galpa fw handle */
+ EDEB(6, "qp=%p qp triggerarea", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+ physical = qp->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret) {
+ EDEB_ERR(4, "remap_pfn_range() failed ret=%x",
+ ret);
+ ret = -ENOMEM;
+ }
+ goto mmap_exit0;
+ } else if (rsrc_type == 2) { /* qp rqueue_addr */
+ EDEB(6, "qp=%p qp rqueue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else if (rsrc_type == 3) { /* qp squeue_addr */
+ EDEB(6, "qp=%p qp squeue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else {
+ EDEB_ERR(4, "bad resource type %x", rsrc_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ } else {
+ EDEB_ERR(4, "bad queue type %x", q_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+mmap_exit0:
+ EDEB_EX(7, "ret=%x", ret);
+ return ret;
+}
+
+int ehca_mmap_nopage(u64 foffset, u64 length, void ** mapped,
+ struct vm_area_struct ** vma)
+{
+ EDEB_EN(7, "foffset=%lx length=%lx", foffset, length);
+ down_write(&current->mm->mmap_sem);
+ *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS,
+ foffset);
+ up_write(&current->mm->mmap_sem);
+ if (!(*mapped)) {
+ EDEB_ERR(4, "couldn't mmap foffset=%lx length=%lx",
+ foffset, length);
+ return -EINVAL;
+ }
+
+ *vma = find_vma(current->mm, (u64)*mapped);
+ if (!(*vma)) {
+ down_write(&current->mm->mmap_sem);
+ do_munmap(current->mm, 0, length);
+ up_write(&current->mm->mmap_sem);
+ EDEB_ERR(4, "couldn't find vma queue=%p", *mapped);
+ return -EINVAL;
+ }
+ (*vma)->vm_flags |= VM_RESERVED;
+ (*vma)->vm_ops = &ehcau_vm_ops;
+
+ EDEB_EX(7, "mapped=%p", *mapped);
+ return 0;
+}
+
+int ehca_mmap_register(u64 physical, void ** mapped,
+ struct vm_area_struct ** vma)
+{
+ int ret = 0;
+ unsigned long vsize;
+ /* ehca hw supports only 4k page */
+ ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
+ if (ret) {
+ EDEB(4, "could'nt mmap physical=%lx", physical);
+ return ret;
+ }
+
+ (*vma)->vm_flags |= VM_RESERVED;
+ vsize = (*vma)->vm_end - (*vma)->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ (*vma)->vm_end - (*vma)->vm_start);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
+ (*vma)->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range((*vma), (*vma)->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ (*vma)->vm_page_prot);
+ if (ret) {
+ EDEB_ERR(4, "remap_pfn_range() failed ret=%x", ret);
+ ret = -ENOMEM;
+ }
+ return ret;
+
+}
+
+int ehca_munmap(unsigned long addr, size_t len) {
+ int ret = 0;
+ struct mm_struct *mm = current->mm;
+ if (mm) {
+ down_write(&mm->mmap_sem);
+ ret = do_munmap(mm, addr, len);
+ up_write(&mm->mmap_sem);
+ }
+ return ret;
+}
--
1.4.1

2006-08-17 20:10:00

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 02/16] IB/ehca: classes

drivers/infiniband/hw/ehca/ehca_classes.h | 343 +++++++++++++++++++++
drivers/infiniband/hw/ehca/ehca_classes_pSeries.h | 236 ++++++++++++++
2 files changed, 579 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
new file mode 100644
index 0000000..1a87bee
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -0,0 +1,343 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Struct definition for eHCA internal structures
+ *
+ * Authors: Heiko J Schick <[email protected]>
+ * Christoph Raisch <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_CLASSES_H__
+#define __EHCA_CLASSES_H__
+
+#include "ehca_classes.h"
+#include "ipz_pt_fn.h"
+
+struct ehca_module;
+struct ehca_qp;
+struct ehca_cq;
+struct ehca_eq;
+struct ehca_mr;
+struct ehca_mw;
+struct ehca_pd;
+struct ehca_av;
+
+#ifdef CONFIG_PPC64
+#include "ehca_classes_pSeries.h"
+#endif
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "ehca_irq.h"
+
+struct ehca_module {
+ struct list_head shca_list;
+ spinlock_t shca_lock;
+ struct timer_list timer;
+ kmem_cache_t *cache_pd;
+ kmem_cache_t *cache_cq;
+ kmem_cache_t *cache_qp;
+ kmem_cache_t *cache_av;
+ kmem_cache_t *cache_mr;
+ kmem_cache_t *cache_mw;
+};
+
+struct ehca_eq {
+ u32 length;
+ struct ipz_queue ipz_queue;
+ struct ipz_eq_handle ipz_eq_handle;
+ struct work_struct work;
+ struct h_galpas galpas;
+ int is_initialized;
+ struct ehca_pfeq pf;
+ spinlock_t spinlock;
+ struct tasklet_struct interrupt_task;
+ u32 ist;
+};
+
+struct ehca_sport {
+ struct ib_cq *ibcq_aqp1;
+ struct ib_qp *ibqp_aqp1;
+ enum ib_rate rate;
+ enum ib_port_state port_state;
+};
+
+struct ehca_shca {
+ struct ib_device ib_device;
+ struct ibmebus_dev *ibmebus_dev;
+ u8 num_ports;
+ int hw_level;
+ struct list_head shca_list;
+ struct ipz_adapter_handle ipz_hca_handle;
+ struct ehca_sport sport[2];
+ struct ehca_eq eq;
+ struct ehca_eq neq;
+ struct ehca_mr *maxmr;
+ struct ehca_pd *pd;
+ struct h_galpas galpas;
+};
+
+struct ehca_pd {
+ struct ib_pd ib_pd;
+ struct ipz_pd fw_pd;
+ u32 ownpid;
+};
+
+struct ehca_qp {
+ struct ib_qp ib_qp;
+ u32 qp_type;
+ struct ipz_queue ipz_squeue;
+ struct ipz_queue ipz_rqueue;
+ struct h_galpas galpas;
+ u32 qkey;
+ u32 real_qp_num;
+ u32 token;
+ spinlock_t spinlock_s;
+ spinlock_t spinlock_r;
+ u32 sq_max_inline_data_size;
+ struct ipz_qp_handle ipz_qp_handle;
+ struct ehca_pfqp pf;
+ struct ib_qp_init_attr init_attr;
+ u64 uspace_squeue;
+ u64 uspace_rqueue;
+ u64 uspace_fwh;
+ struct ehca_cq *send_cq;
+ struct ehca_cq *recv_cq;
+ unsigned int sqerr_purgeflag;
+ struct hlist_node list_entries;
+};
+
+/* must be power of 2 */
+#define QP_HASHTAB_LEN 8
+
+struct ehca_cq {
+ struct ib_cq ib_cq;
+ struct ipz_queue ipz_queue;
+ struct h_galpas galpas;
+ spinlock_t spinlock;
+ u32 cq_number;
+ u32 token;
+ u32 nr_of_entries;
+ struct ipz_cq_handle ipz_cq_handle;
+ struct ehca_pfcq pf;
+ spinlock_t cb_lock;
+ u64 uspace_queue;
+ u64 uspace_fwh;
+ struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
+ struct list_head entry;
+ u32 nr_callbacks;
+ spinlock_t task_lock;
+ u32 ownpid;
+};
+
+enum ehca_mr_flag {
+ EHCA_MR_FLAG_FMR = 0x80000000, /* FMR, created with ehca_alloc_fmr */
+ EHCA_MR_FLAG_MAXMR = 0x40000000, /* max-MR */
+};
+
+struct ehca_mr {
+ union {
+ struct ib_mr ib_mr; /* must always be first in ehca_mr */
+ struct ib_fmr ib_fmr; /* must always be first in ehca_mr */
+ } ib;
+ spinlock_t mrlock;
+
+ enum ehca_mr_flag flags;
+ u32 num_pages; /* number of MR pages */
+ u32 num_4k; /* number of 4k "page" portions to form MR */
+ int acl; /* ACL (stored here for usage in reregister) */
+ u64 *start; /* virtual start address (stored here for */
+ /* usage in reregister) */
+ u64 size; /* size (stored here for usage in reregister) */
+ u32 fmr_page_size; /* page size for FMR */
+ u32 fmr_max_pages; /* max pages for FMR */
+ u32 fmr_max_maps; /* max outstanding maps for FMR */
+ u32 fmr_map_cnt; /* map counter for FMR */
+ /* fw specific data */
+ struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */
+ struct h_galpas galpas;
+ /* data for userspace bridge */
+ u32 nr_of_pages;
+ void *pagearray;
+};
+
+struct ehca_mw {
+ struct ib_mw ib_mw; /* gen2 mw, must always be first in ehca_mw */
+ spinlock_t mwlock;
+
+ u8 never_bound; /* indication MW was never bound */
+ struct ipz_mrmw_handle ipz_mw_handle; /* MW handle for h-calls */
+ struct h_galpas galpas;
+};
+
+enum ehca_mr_pgi_type {
+ EHCA_MR_PGI_PHYS = 1, /* type of ehca_reg_phys_mr,
+ * ehca_rereg_phys_mr,
+ * ehca_reg_internal_maxmr */
+ EHCA_MR_PGI_USER = 2, /* type of ehca_reg_user_mr */
+ EHCA_MR_PGI_FMR = 3 /* type of ehca_map_phys_fmr */
+};
+
+struct ehca_mr_pginfo {
+ enum ehca_mr_pgi_type type;
+ u64 num_pages;
+ u64 page_cnt;
+ u64 num_4k; /* number of 4k "page" portions */
+ u64 page_4k_cnt; /* counter for 4k "page" portions */
+ u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */
+
+ /* type EHCA_MR_PGI_PHYS section */
+ int num_phys_buf;
+ struct ib_phys_buf *phys_buf_array;
+ u64 next_buf;
+
+ /* type EHCA_MR_PGI_USER section */
+ struct ib_umem *region;
+ struct ib_umem_chunk *next_chunk;
+ u64 next_nmap;
+
+ /* type EHCA_MR_PGI_FMR section */
+ u64 *page_list;
+ u64 next_listelem;
+ /* next_4k also used within EHCA_MR_PGI_FMR */
+};
+
+/* output parameters for MR/FMR hipz calls */
+struct ehca_mr_hipzout_parms {
+ struct ipz_mrmw_handle handle;
+ u32 lkey;
+ u32 rkey;
+ u64 len;
+ u64 vaddr;
+ u32 acl;
+};
+
+/* output parameters for MW hipz calls */
+struct ehca_mw_hipzout_parms {
+ struct ipz_mrmw_handle handle;
+ u32 rkey;
+};
+
+struct ehca_av {
+ struct ib_ah ib_ah;
+ struct ehca_ud_av av;
+};
+
+struct ehca_ucontext {
+ struct ib_ucontext ib_ucontext;
+};
+
+struct ehca_module *ehca_module_new(void);
+
+int ehca_module_delete(struct ehca_module *me);
+
+int ehca_eq_ctor(struct ehca_eq *eq);
+
+int ehca_eq_dtor(struct ehca_eq *eq);
+
+struct ehca_shca *ehca_shca_new(void);
+
+int ehca_shca_delete(struct ehca_shca *me);
+
+struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
+
+extern spinlock_t ehca_qp_idr_lock;
+extern spinlock_t ehca_cq_idr_lock;
+extern struct idr ehca_qp_idr;
+extern struct idr ehca_cq_idr;
+
+struct ipzu_queue_resp {
+ u64 queue; /* points to first queue entry */
+ u32 qe_size; /* queue entry size */
+ u32 act_nr_of_sg;
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state;
+ u32 dummy; /* padding for 8 byte alignment */
+};
+
+struct ehca_create_cq_resp {
+ u32 cq_number;
+ u32 token;
+ struct ipzu_queue_resp ipz_queue;
+ struct h_galpas galpas;
+};
+
+struct ehca_create_qp_resp {
+ u32 qp_num;
+ u32 token;
+ u32 qp_type;
+ u32 qkey;
+ /* qp_num assigned by ehca: sqp0/1 may have got different numbers */
+ u32 real_qp_num;
+ u32 dummy; /* padding for 8 byte alignment */
+ struct ipzu_queue_resp ipz_squeue;
+ struct ipzu_queue_resp ipz_rqueue;
+ struct h_galpas galpas;
+};
+
+struct ehca_alloc_cq_parms {
+ u32 nr_cqe;
+ u32 act_nr_of_entries;
+ u32 act_pages;
+ struct ipz_eq_handle eq_handle;
+};
+
+struct ehca_alloc_qp_parms {
+ int servicetype;
+ int sigtype;
+ int daqp_ctrl;
+ int max_send_sge;
+ int max_recv_sge;
+ int ud_av_l_key_ctl;
+
+ u16 act_nr_send_wqes;
+ u16 act_nr_recv_wqes;
+ u8 act_nr_recv_sges;
+ u8 act_nr_send_sges;
+
+ u32 nr_rq_pages;
+ u32 nr_sq_pages;
+
+ struct ipz_eq_handle ipz_eq_handle;
+ struct ipz_pd pd;
+};
+
+int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
+int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
+struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
new file mode 100644
index 0000000..5665f21
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
@@ -0,0 +1,236 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * pSeries interface definitions
+ *
+ * Authors: Waleri Fomin <[email protected]>
+ * Christoph Raisch <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_CLASSES_PSERIES_H__
+#define __EHCA_CLASSES_PSERIES_H__
+
+#include "hcp_phyp.h"
+#include "ipz_pt_fn.h"
+
+
+struct ehca_pfqp {
+ struct ipz_qpt sqpt;
+ struct ipz_qpt rqpt;
+};
+
+struct ehca_pfcq {
+ struct ipz_qpt qpt;
+ u32 cqnr;
+};
+
+struct ehca_pfeq {
+ struct ipz_qpt qpt;
+ struct h_galpa galpa;
+ u32 eqnr;
+};
+
+struct ipz_adapter_handle {
+ u64 handle;
+};
+
+struct ipz_cq_handle {
+ u64 handle;
+};
+
+struct ipz_eq_handle {
+ u64 handle;
+};
+
+struct ipz_qp_handle {
+ u64 handle;
+};
+struct ipz_mrmw_handle {
+ u64 handle;
+};
+
+struct ipz_pd {
+ u32 value;
+};
+
+struct hcp_modify_qp_control_block {
+ u32 qkey; /* 00 */
+ u32 rdd; /* reliable datagram domain */
+ u32 send_psn; /* 02 */
+ u32 receive_psn; /* 03 */
+ u32 prim_phys_port; /* 04 */
+ u32 alt_phys_port; /* 05 */
+ u32 prim_p_key_idx; /* 06 */
+ u32 alt_p_key_idx; /* 07 */
+ u32 rdma_atomic_ctrl; /* 08 */
+ u32 qp_state; /* 09 */
+ u32 reserved_10; /* 10 */
+ u32 rdma_nr_atomic_resp_res; /* 11 */
+ u32 path_migration_state; /* 12 */
+ u32 rdma_atomic_outst_dest_qp; /* 13 */
+ u32 dest_qp_nr; /* 14 */
+ u32 min_rnr_nak_timer_field; /* 15 */
+ u32 service_level; /* 16 */
+ u32 send_grh_flag; /* 17 */
+ u32 retry_count; /* 18 */
+ u32 timeout; /* 19 */
+ u32 path_mtu; /* 20 */
+ u32 max_static_rate; /* 21 */
+ u32 dlid; /* 22 */
+ u32 rnr_retry_count; /* 23 */
+ u32 source_path_bits; /* 24 */
+ u32 traffic_class; /* 25 */
+ u32 hop_limit; /* 26 */
+ u32 source_gid_idx; /* 27 */
+ u32 flow_label; /* 28 */
+ u32 reserved_29; /* 29 */
+ union { /* 30 */
+ u64 dw[2];
+ u8 byte[16];
+ } dest_gid;
+ u32 service_level_al; /* 34 */
+ u32 send_grh_flag_al; /* 35 */
+ u32 retry_count_al; /* 36 */
+ u32 timeout_al; /* 37 */
+ u32 max_static_rate_al; /* 38 */
+ u32 dlid_al; /* 39 */
+ u32 rnr_retry_count_al; /* 40 */
+ u32 source_path_bits_al; /* 41 */
+ u32 traffic_class_al; /* 42 */
+ u32 hop_limit_al; /* 43 */
+ u32 source_gid_idx_al; /* 44 */
+ u32 flow_label_al; /* 45 */
+ u32 reserved_46; /* 46 */
+ u32 reserved_47; /* 47 */
+ union { /* 48 */
+ u64 dw[2];
+ u8 byte[16];
+ } dest_gid_al;
+ u32 max_nr_outst_send_wr; /* 52 */
+ u32 max_nr_outst_recv_wr; /* 53 */
+ u32 disable_ete_credit_check; /* 54 */
+ u32 qp_number; /* 55 */
+ u64 send_queue_handle; /* 56 */
+ u64 recv_queue_handle; /* 58 */
+ u32 actual_nr_sges_in_sq_wqe; /* 60 */
+ u32 actual_nr_sges_in_rq_wqe; /* 61 */
+ u32 qp_enable; /* 62 */
+ u32 curr_srq_limit; /* 63 */
+ u64 qp_aff_asyn_ev_log_reg; /* 64 */
+ u64 shared_rq_hndl; /* 66 */
+ u64 trigg_doorbell_qp_hndl; /* 68 */
+ u32 reserved_70_127[58]; /* 70 */
+};
+
+#define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0)
+#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2)
+#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3)
+#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4)
+#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6)
+#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8)
+#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9)
+#define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13)
+#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15)
+#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16)
+#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17)
+#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18)
+#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19)
+#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20)
+#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21)
+#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22)
+#define MQPCB_DLID EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23)
+#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24)
+#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31)
+#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25)
+#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26)
+#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27)
+#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28)
+#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31)
+#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31)
+#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32)
+#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31)
+#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33)
+#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34)
+#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35)
+#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36)
+#define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37)
+#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38)
+#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39)
+#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40)
+#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41)
+#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42)
+#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31)
+#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31)
+#define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48)
+#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31)
+#define MQPCB_MASK_CURR_SQR_LIMIT EHCA_BMASK_IBM(49,49)
+#define MQPCB_CURR_SQR_LIMIT EHCA_BMASK_IBM(15,31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50)
+#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51)
+
+#endif /* __EHCA_CLASSES_PSERIES_H__ */
--
1.4.1

2006-08-17 20:11:52

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 01/13] IB/ehca: hca

drivers/infiniband/hw/ehca/ehca_hca.c | 282 +++++++++++++++++++++++++++++++
drivers/infiniband/hw/ehca/ehca_mcast.c | 200 ++++++++++++++++++++++
2 files changed, 482 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
new file mode 100644
index 0000000..7a871b2
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -0,0 +1,282 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HCA query functions
+ *
+ * Authors: Heiko J Schick <[email protected]>
+ * Christoph Raisch <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "shca"
+
+#include "ehca_tools.h"
+
+#include "hcp_if.h"
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_hca *rblock;
+
+ EDEB_EN(7, "");
+
+ memset(props, 0, sizeof(struct ib_device_attr));
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_device0;
+ }
+
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query device properties");
+ ret = -EINVAL;
+ goto query_device1;
+ }
+ props->fw_ver = rblock->hw_ver;
+ props->max_mr_size = rblock->max_mr_size;
+ props->vendor_id = rblock->vendor_id >> 8;
+ props->vendor_part_id = rblock->vendor_part_id >> 16;
+ props->hw_ver = rblock->hw_ver;
+ props->max_qp = min_t(int, rblock->max_qp, INT_MAX);
+ props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX);
+ props->max_sge = min_t(int, rblock->max_sge, INT_MAX);
+ props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX);
+ props->max_cq = min_t(int, rblock->max_cq, INT_MAX);
+ props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX);
+ props->max_mr = min_t(int, rblock->max_mr, INT_MAX);
+ props->max_mw = min_t(int, rblock->max_mw, INT_MAX);
+ props->max_pd = min_t(int, rblock->max_pd, INT_MAX);
+ props->max_ah = min_t(int, rblock->max_ah, INT_MAX);
+ props->max_fmr = min_t(int, rblock->max_mr, INT_MAX);
+ props->max_srq = 0;
+ props->max_srq_wr = 0;
+ props->max_srq_sge = 0;
+ props->max_pkeys = 16;
+ props->local_ca_ack_delay
+ = rblock->local_ca_ack_delay;
+ props->max_raw_ipv6_qp
+ = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
+ props->max_raw_ethy_qp
+ = min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
+ props->max_mcast_grp
+ = min_t(int, rblock->max_mcast_grp, INT_MAX);
+ props->max_mcast_qp_attach
+ = min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
+ props->max_total_mcast_qp_attach
+ = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+
+query_device1:
+ kfree(rblock);
+
+query_device0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_port *rblock;
+
+ EDEB_EN(7, "port=%x", port);
+
+ memset(props, 0, sizeof(struct ib_port_attr));
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_port0;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_port1;
+ }
+
+ props->state = rblock->state;
+
+ switch (rblock->max_mtu) {
+ case 0x1:
+ props->active_mtu = props->max_mtu = IB_MTU_256;
+ break;
+ case 0x2:
+ props->active_mtu = props->max_mtu = IB_MTU_512;
+ break;
+ case 0x3:
+ props->active_mtu = props->max_mtu = IB_MTU_1024;
+ break;
+ case 0x4:
+ props->active_mtu = props->max_mtu = IB_MTU_2048;
+ break;
+ case 0x5:
+ props->active_mtu = props->max_mtu = IB_MTU_4096;
+ break;
+ default:
+ EDEB_ERR(4, "Unknown MTU size: %x.", rblock->max_mtu);
+ }
+
+ props->gid_tbl_len = rblock->gid_tbl_len;
+ props->max_msg_sz = rblock->max_msg_sz;
+ props->bad_pkey_cntr = rblock->bad_pkey_cntr;
+ props->qkey_viol_cntr = rblock->qkey_viol_cntr;
+ props->pkey_tbl_len = rblock->pkey_tbl_len;
+ props->lid = rblock->lid;
+ props->sm_lid = rblock->sm_lid;
+ props->lmc = rblock->lmc;
+ props->sm_sl = rblock->sm_sl;
+ props->subnet_timeout = rblock->subnet_timeout;
+ props->init_type_reply = rblock->init_type_reply;
+
+ props->active_width = IB_WIDTH_12X;
+ props->active_speed = 0x1;
+
+query_port1:
+ kfree(rblock);
+
+query_port0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_port *rblock;
+
+ EDEB_EN(7, "port=%x index=%x", port, index);
+
+ if (index > 16) {
+ EDEB_ERR(4, "Invalid index: %x.", index);
+ ret = -EINVAL;
+ goto query_pkey0;
+ }
+
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_pkey0;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_pkey1;
+ }
+
+ memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16));
+
+query_pkey1:
+ kfree(rblock);
+
+query_pkey0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_port *rblock;
+
+ EDEB_EN(7, "port=%x index=%x", port, index);
+
+ if (index > 255) {
+ EDEB_ERR(4, "Invalid index: %x.", index);
+ ret = -EINVAL;
+ goto query_gid0;
+ }
+
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_gid0;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_gid1;
+ }
+
+ memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64));
+ memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64));
+
+query_gid1:
+ kfree(rblock);
+
+query_gid0:
+ EDEB_EX(7, "ret=%x GID=%lx%lx", ret,
+ *(u64 *) & gid->raw[0],
+ *(u64 *) & gid->raw[8]);
+
+ return ret;
+}
+
+int ehca_modify_port(struct ib_device *ibdev,
+ u8 port, int port_modify_mask,
+ struct ib_port_modify *props)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "port=%x", port);
+
+ /* Not implemented yet. */
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
new file mode 100644
index 0000000..5c5b024
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
@@ -0,0 +1,200 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * mcast functions
+ *
+ * Authors: Khadija Souissi <[email protected]>
+ * Waleri Fomin <[email protected]>
+ * Reinhard Ernst <[email protected]>
+ * Hoang-Nam Nguyen <[email protected]>
+ * Heiko J Schick <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEB_PREFIX "mcas"
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+
+#include "hcp_if.h"
+
+#define MAX_MC_LID 0xFFFE
+#define MIN_MC_LID 0xC000 /* Multicast limits */
+#define EHCA_VALID_MULTICAST_GID(gid) ((gid)[0] == 0xFF)
+#define EHCA_VALID_MULTICAST_LID(lid) (((lid) >= MIN_MC_LID) && ((lid) <= MAX_MC_LID))
+
+int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ union ib_gid my_gid;
+ u64 subnet_prefix;
+ u64 interface_id;
+ u64 h_ret = H_SUCCESS;
+ int ret = 0;
+
+ EHCA_CHECK_ADR(ibqp);
+ EHCA_CHECK_ADR(gid);
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+
+ EHCA_CHECK_QP(my_qp);
+ if (ibqp->qp_type != IB_QPT_UD) {
+ EDEB_ERR(4, "invalid qp_type %x gid, ret=%x",
+ ibqp->qp_type, EINVAL);
+ return -EINVAL;
+ }
+
+ shca = container_of(ibqp->pd->device, struct ehca_shca, ib_device);
+ EHCA_CHECK_ADR(shca);
+
+ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
+ EDEB_ERR(4, "gid is not valid mulitcast gid ret=%x",
+ EINVAL);
+ return -EINVAL;
+ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
+ EDEB_ERR(4, "lid=%x is not valid mulitcast lid ret=%x",
+ lid, EINVAL);
+ return -EINVAL;
+ }
+
+ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+
+ subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
+ interface_id = be64_to_cpu(my_gid.global.interface_id);
+ h_ret = hipz_h_attach_mcqp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ my_qp->galpas.kernel,
+ lid, subnet_prefix, interface_id);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4,
+ "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
+ "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+ }
+ ret = ehca2ib_return_code(h_ret);
+
+ EDEB_EX(7, "mcast attach ret=%x\n"
+ "ehca_qp=%p qp_num=%x lid=%x\n"
+ "my_gid= %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n",
+ ret, my_qp, ibqp->qp_num, lid,
+ my_gid.raw[0], my_gid.raw[1],
+ my_gid.raw[2], my_gid.raw[3],
+ my_gid.raw[4], my_gid.raw[5],
+ my_gid.raw[6], my_gid.raw[7],
+ my_gid.raw[8], my_gid.raw[9],
+ my_gid.raw[10], my_gid.raw[11],
+ my_gid.raw[12], my_gid.raw[13],
+ my_gid.raw[14], my_gid.raw[15]);
+
+ return ret;
+}
+
+int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ union ib_gid my_gid;
+ u64 subnet_prefix;
+ u64 interface_id;
+ u64 h_ret = H_SUCCESS;
+ int ret = 0;
+
+ EHCA_CHECK_ADR(ibqp);
+ EHCA_CHECK_ADR(gid);
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+
+ EHCA_CHECK_QP(my_qp);
+ if (ibqp->qp_type != IB_QPT_UD) {
+ EDEB_ERR(4, "invalid qp_type %x gid, ret=%x",
+ ibqp->qp_type, EINVAL);
+ return -EINVAL;
+ }
+
+ shca = container_of(ibqp->pd->device, struct ehca_shca, ib_device);
+ EHCA_CHECK_ADR(shca);
+
+ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
+ EDEB_ERR(4, "gid is not valid mulitcast gid ret=%x",
+ EINVAL);
+ return -EINVAL;
+ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
+ EDEB_ERR(4, "lid=%x is not valid mulitcast lid ret=%x",
+ lid, EINVAL);
+ return -EINVAL;
+ }
+
+ EDEB_EN(7, "dgid=%p qp_numl=%x lid=%x",
+ gid, ibqp->qp_num, lid);
+
+ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+
+ subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
+ interface_id = be64_to_cpu(my_gid.global.interface_id);
+ h_ret = hipz_h_detach_mcqp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ my_qp->galpas.kernel,
+ lid, subnet_prefix, interface_id);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4,
+ "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
+ "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+ }
+ ret = ehca2ib_return_code(h_ret);
+
+ EDEB_EX(7, "mcast detach ret=%x\n"
+ "ehca_qp=%p qp_num=%x lid=%x\n"
+ "my_gid= %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n",
+ ret, my_qp, ibqp->qp_num, lid,
+ my_gid.raw[0], my_gid.raw[1],
+ my_gid.raw[2], my_gid.raw[3],
+ my_gid.raw[4], my_gid.raw[5],
+ my_gid.raw[6], my_gid.raw[7],
+ my_gid.raw[8], my_gid.raw[9],
+ my_gid.raw[10], my_gid.raw[11],
+ my_gid.raw[12], my_gid.raw[13],
+ my_gid.raw[14], my_gid.raw[15]);
+
+ return ret;
+}
--
1.4.1

2006-08-17 20:15:28

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 02/13] IB/ehca: includes

drivers/infiniband/hw/ehca/ehca_iverbs.h | 181 +++++++++++++
drivers/infiniband/hw/ehca/ehca_tools.h | 417 ++++++++++++++++++++++++++++++
2 files changed, 598 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
new file mode 100644
index 0000000..bbdc437
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -0,0 +1,181 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Function definitions for internal functions
+ *
+ * Authors: Heiko J Schick <[email protected]>
+ * Dietmar Decker <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_IVERBS_H__
+#define __EHCA_IVERBS_H__
+
+#include "ehca_classes.h"
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
+
+int ehca_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props);
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid);
+
+int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask,
+ struct ib_port_modify *props);
+
+struct ib_pd *ehca_alloc_pd(struct ib_device *device,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int ehca_dealloc_pd(struct ib_pd *pd);
+
+struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+
+int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
+
+int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
+
+int ehca_destroy_ah(struct ib_ah *ah);
+
+struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
+
+struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags, u64 *iova_start);
+
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags, struct ib_udata *udata);
+
+int ehca_rereg_phys_mr(struct ib_mr *mr,
+ int mr_rereg_mask,
+ struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf, int mr_access_flags, u64 *iova_start);
+
+int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr);
+
+int ehca_dereg_mr(struct ib_mr *mr);
+
+struct ib_mw *ehca_alloc_mw(struct ib_pd *pd);
+
+int ehca_bind_mw(struct ib_qp *qp, struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind);
+
+int ehca_dealloc_mw(struct ib_mw *mw);
+
+struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
+ int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr);
+
+int ehca_map_phys_fmr(struct ib_fmr *fmr,
+ u64 *page_list, int list_len, u64 iova);
+
+int ehca_unmap_fmr(struct list_head *fmr_list);
+
+int ehca_dealloc_fmr(struct ib_fmr *fmr);
+
+enum ehca_eq_type {
+ EHCA_EQ = 0, /* Event Queue */
+ EHCA_NEQ /* Notification Event Queue */
+};
+
+int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq,
+ enum ehca_eq_type type, const u32 length);
+
+int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
+
+void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
+
+
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int ehca_destroy_cq(struct ib_cq *cq);
+
+int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata);
+
+int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
+
+int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
+
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify);
+
+struct ib_qp *ehca_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int ehca_destroy_qp(struct ib_qp *qp);
+
+int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
+
+int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
+
+int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
+ struct ib_send_wr **bad_send_wr);
+
+int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr);
+
+u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp,
+ struct ib_qp_init_attr *qp_init_attr);
+
+int ehca_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
+
+int ehca_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata);
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context);
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
+void ehca_poll_eqs(unsigned long data);
+
+int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
+ struct vm_area_struct **vma);
+
+int ehca_mmap_register(u64 physical,void **mapped,
+ struct vm_area_struct **vma);
+
+int ehca_munmap(unsigned long addr, size_t len);
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
new file mode 100644
index 0000000..783fbb3
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -0,0 +1,417 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * auxiliary functions
+ *
+ * Authors: Christoph Raisch <[email protected]>
+ * Hoang-Nam Nguyen <[email protected]>
+ * Khadija Souissi <[email protected]>
+ * Waleri Fomin <[email protected]>
+ * Heiko J Schick <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef EHCA_TOOLS_H
+#define EHCA_TOOLS_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/version.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+
+#include <asm/abs_addr.h>
+#include <asm/ibmebus.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+#define EHCA_EDEB_TRACE_MASK_SIZE 32
+extern u8 ehca_edeb_mask[EHCA_EDEB_TRACE_MASK_SIZE];
+#define EDEB_ID_TO_U32(str4) (str4[3] | (str4[2] << 8) | (str4[1] << 16) | \
+ (str4[0] << 24))
+
+static inline u64 ehca_edeb_filter(const u32 level,
+ const u32 id, const u32 line)
+{
+ u64 ret = 0;
+ u32 filenr = 0;
+ u32 filter_level = 9;
+ u32 dynamic_level = 0;
+
+ /*
+ * This is code written for the gcc -O2 optimizer
+ * which should collapse to two single ints.
+ * Filter_level is the first level kicked out by
+ * compiler and means trace everything below 6.
+ */
+
+ if (id == EDEB_ID_TO_U32("ehav")) {
+ filenr = 0x01;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("clas")) {
+ filenr = 0x02;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("cqeq")) {
+ filenr = 0x03;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("shca")) {
+ filenr = 0x05;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("eirq")) {
+ filenr = 0x06;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("lMad")) {
+ filenr = 0x07;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("mcas")) {
+ filenr = 0x08;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("mrmw")) {
+ filenr = 0x09;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("vpd ")) {
+ filenr = 0x0a;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("e_qp")) {
+ filenr = 0x0b;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("uqes")) {
+ filenr = 0x0c;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("PHYP")) {
+ filenr = 0x0d;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("hcpi")) {
+ filenr = 0x0e;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("iptz")) {
+ filenr = 0x0f;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("spta")) {
+ filenr = 0x10;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("simp")) {
+ filenr = 0x11;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("reqs")) {
+ filenr = 0x12;
+ filter_level = 8;
+ }
+
+ if ((filenr - 1) > sizeof(ehca_edeb_mask)) {
+ filenr = 0;
+ }
+
+ if (filenr == 0) {
+ filter_level = 9;
+ } /* default */
+ ret = filenr * 0x10000 + line;
+ if (filter_level <= level) {
+ return ret | 0x100000000L; /* this is the flag to not trace */
+ }
+ dynamic_level = ehca_edeb_mask[filenr];
+ if (likely(dynamic_level <= level)) {
+ ret = ret | 0x100000000L;
+ };
+ return ret;
+}
+
+#ifdef EHCA_USE_HCALL_KERNEL
+#ifdef CONFIG_PPC_PSERIES
+
+#include <asm/paca.h>
+
+/*
+ * IS_EDEB_ON - Checks if debug is on for the given level.
+ */
+#define IS_EDEB_ON(level) \
+((ehca_edeb_filter(level, EDEB_ID_TO_U32(DEB_PREFIX), __LINE__) & \
+ 0x100000000L) == 0)
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+do { \
+ u64 ehca_edeb_filterresult = \
+ ehca_edeb_filter(level, EDEB_ID_TO_U32(DEB_PREFIX), __LINE__);\
+ if ((ehca_edeb_filterresult & 0x100000000L) == 0) \
+ printk("PU%04x %08x:%s " idstring " "format "\n", \
+ get_paca()->paca_index, (u32)(ehca_edeb_filterresult), \
+ __func__, ##args); \
+} while (1 == 0)
+
+#elif REAL_HCALL
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+do { \
+ u64 ehca_edeb_filterresult = \
+ ehca_edeb_filter(level, EDEB_ID_TO_U32(DEB_PREFIX), __LINE__); \
+ if ((ehca_edeb_filterresult & 0x100000000L) == 0) \
+ printk("%08x:%s " idstring " "format "\n", \
+ (u32)(ehca_edeb_filterresult), \
+ __func__, ##args); \
+} while (1 == 0)
+
+#endif
+#else
+
+#define IS_EDEB_ON(level) (1)
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+do { \
+ printk("%s " idstring " "format "\n", \
+ __func__, ##args); \
+} while (1 == 0)
+
+#endif
+
+/**
+ * EDEB - Trace output macro.
+ * @level: tracelevel
+ * @format: optional format string, use "" if not desired
+ * @args: printf like arguments for trace
+ */
+#define EDEB(level,format,args...) \
+ EDEB_P_GENERIC(level,"",format,##args)
+#define EDEB_ERR(level,format,args...) \
+ EDEB_P_GENERIC(level,"HCAD_ERROR ",format,##args)
+#define EDEB_EN(level,format,args...) \
+ EDEB_P_GENERIC(level,">>>",format,##args)
+#define EDEB_EX(level,format,args...) \
+ EDEB_P_GENERIC(level,"<<<",format,##args)
+
+/**
+ * EDEB_DMP - macro to dump a memory block, whose length is n*8 bytes.
+ * Each line has the following layout:
+ * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
+ */
+#define EDEB_DMP(level,adr,len,format,args...) \
+ do { \
+ unsigned int x; \
+ unsigned int l = (unsigned int)(len); \
+ unsigned char *deb = (unsigned char*)(adr); \
+ for (x = 0; x < l; x += 16) { \
+ EDEB(level, format " adr=%p ofs=%04x %016lx %016lx", \
+ ##args, deb, x, \
+ *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
+ deb += 16; \
+ } \
+ } while (0)
+
+/* define a bitmask, little endian version */
+#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+
+/* define a bitmask, the ibm way... */
+#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+
+/* internal function, don't use */
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+
+/* internal function, don't use */
+#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+
+/**
+ * EHCA_BMASK_SET - return value shifted and masked by mask
+ * variable|=EHCA_BMASK_SET(MY_MASK,0x4711) ORs the bits in variable
+ * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
+ * in variable
+ */
+#define EHCA_BMASK_SET(mask,value) \
+ ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+
+/**
+ * EHCA_BMASK_GET - extract a parameter from value by mask
+ */
+#define EHCA_BMASK_GET(mask,value) \
+ ( EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
+
+#define PARANOIA_MODE
+#ifdef PARANOIA_MODE
+
+#define EHCA_CHECK_ADR_P(adr) \
+ if (unlikely(adr == 0)) { \
+ EDEB_ERR(4, "adr=%p check failed line %i", adr, \
+ __LINE__); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_ADR(adr) \
+ if (unlikely(adr == 0)) { \
+ EDEB_ERR(4, "adr=%p check failed line %i", adr, \
+ __LINE__); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_DEVICE_P(device) \
+ if (unlikely(device == 0)) { \
+ EDEB_ERR(4, "device=%p check failed", device); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_DEVICE(device) \
+ if (unlikely(device == 0)) { \
+ EDEB_ERR(4, "device=%p check failed", device); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_PD(pd) \
+ if (unlikely(pd == 0)) { \
+ EDEB_ERR(4, "pd=%p check failed", pd); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_PD_P(pd) \
+ if (unlikely(pd == 0)) { \
+ EDEB_ERR(4, "pd=%p check failed", pd); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_AV(av) \
+ if (unlikely(av == 0)) { \
+ EDEB_ERR(4, "av=%p check failed", av); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_AV_P(av) \
+ if (unlikely(av == 0)) { \
+ EDEB_ERR(4, "av=%p check failed", av); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_CQ(cq) \
+ if (unlikely(cq == 0)) { \
+ EDEB_ERR(4, "cq=%p check failed", cq); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_CQ_P(cq) \
+ if (unlikely(cq == 0)) { \
+ EDEB_ERR(4, "cq=%p check failed", cq); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_EQ(eq) \
+ if (unlikely(eq == 0)) { \
+ EDEB_ERR(4, "eq=%p check failed", eq); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_EQ_P(eq) \
+ if (unlikely(eq == 0)) { \
+ EDEB_ERR(4, "eq=%p check failed", eq); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_QP(qp) \
+ if (unlikely(qp == 0)) { \
+ EDEB_ERR(4, "qp=%p check failed", qp); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_QP_P(qp) \
+ if (unlikely(qp == 0)) { \
+ EDEB_ERR(4, "qp=%p check failed", qp); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_MR(mr) \
+ if (unlikely(mr == 0)) { \
+ EDEB_ERR(4, "mr=%p check failed", mr); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_MR_P(mr) \
+ if (unlikely(mr == 0)) { \
+ EDEB_ERR(4, "mr=%p check failed", mr); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_MW(mw) \
+ if (unlikely(mw == 0)) { \
+ EDEB_ERR(4, "mw=%p check failed", mw); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_MW_P(mw) \
+ if (unlikely(mw == 0)) { \
+ EDEB_ERR(4, "mw=%p check failed", mw); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_FMR(fmr) \
+ if (unlikely(fmr == 0)) { \
+ EDEB_ERR(4, "fmr=%p check failed", fmr); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_FMR_P(fmr) \
+ if (unlikely(fmr == 0)) { \
+ EDEB_ERR(4, "fmr=%p check failed", fmr); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_REGISTER_PD(device,pd)
+#define EHCA_REGISTER_AV(pd,av)
+#define EHCA_DEREGISTER_PD(PD)
+#define EHCA_DEREGISTER_AV(av)
+#else
+#define EHCA_CHECK_DEVICE_P(device)
+
+#define EHCA_CHECK_PD(pd)
+#define EHCA_REGISTER_PD(device,pd)
+#define EHCA_DEREGISTER_PD(PD)
+#endif
+
+static inline int ehca_adr_bad(void *adr)
+{
+ return !adr;
+}
+
+/* Converts ehca to ib return code */
+static inline int ehca2ib_return_code(u64 ehca_rc)
+{
+ switch (ehca_rc) {
+ case H_SUCCESS:
+ return 0;
+ case H_BUSY:
+ return -EBUSY;
+ case H_NO_MEM:
+ return -ENOMEM;
+ default:
+ return -EINVAL;
+ }
+}
+
+#endif /* EHCA_TOOLS_H */
--
1.4.1

2006-08-17 20:15:27

by Roland Dreier

[permalink] [raw]
Subject: [PATCH 00/13] IB/ehca: uverbs

drivers/infiniband/hw/ehca/ehca_uverbs.c | 400 ++++++++++++++++++++++++++++++
1 files changed, 400 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
new file mode 100644
index 0000000..c148c23
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -0,0 +1,400 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * userspace support verbs
+ *
+ * Authors: Christoph Raisch <[email protected]>
+ * Hoang-Nam Nguyen <[email protected]>
+ * Heiko J Schick <[email protected]>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "uver"
+
+#include <asm/current.h>
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata)
+{
+ struct ehca_ucontext *my_context = NULL;
+
+ EHCA_CHECK_ADR_P(device);
+ EDEB_EN(7, "device=%p name=%s", device, device->name);
+
+ my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
+ if (!my_context) {
+ EDEB_ERR(4, "Out of memory device=%p", device);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ EDEB_EX(7, "device=%p ucontext=%p", device, my_context);
+
+ return &my_context->ib_ucontext;
+}
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct ehca_ucontext *my_context = NULL;
+ EHCA_CHECK_ADR(context);
+ EDEB_EN(7, "ucontext=%p", context);
+ my_context = container_of(context, struct ehca_ucontext, ib_ucontext);
+ kfree(my_context);
+ EDEB_EN(7, "ucontext=%p", context);
+ return 0;
+}
+
+struct page *ehca_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct page *mypage = NULL;
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EDEB_EN(7, "vm_start=%lx vm_end=%lx vm_page_prot=%lx vm_fileoff=%lx "
+ "address=%lx",
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, fileoffset,
+ address);
+
+ if (q_type == 1) { /* CQ */
+ struct ehca_cq *cq = NULL;
+ u64 offset;
+ void *vaddr = NULL;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!cq) {
+ EDEB_ERR(4, "cq is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ if (rsrc_type == 2) {
+ EDEB(6, "cq=%p cq queuearea", cq);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ } else if (q_type == 2) { /* QP */
+ struct ehca_qp *qp = NULL;
+ struct ehca_pd *pd = NULL;
+ u64 offset;
+ void *vaddr = NULL;
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!qp) {
+ EDEB_ERR(4, "qp is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ if (rsrc_type == 2) { /* rqueue */
+ EDEB(6, "qp=%p qp rqueuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ } else if (rsrc_type == 3) { /* squeue */
+ EDEB(6, "qp=%p qp squeuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ }
+
+ if (!mypage) {
+ EDEB_ERR(4, "Invalid page adr==NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ get_page(mypage);
+ EDEB_EX(7, "page adr=%p", mypage);
+ return mypage;
+}
+
+static struct vm_operations_struct ehcau_vm_ops = {
+ .nopage = ehca_nopage,
+};
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 ret = -EFAULT; /* assume the worst */
+ u64 vsize = 0; /* must be calculated/set below */
+ u64 physical = 0; /* must be calculated/set below */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EDEB_EN(7, "vm_start=%lx vm_end=%lx vm_page_prot=%lx vm_fileoff=%lx",
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, fileoffset);
+
+ if (q_type == 1) { /* CQ */
+ struct ehca_cq *cq;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return -ENOMEM;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!cq)
+ return -EINVAL;
+ if (!cq->ib_cq.uobject)
+ return -EINVAL;
+ if (cq->ib_cq.uobject->context != context)
+ return -EINVAL;
+ if (rsrc_type == 1) { /* galpa fw handle */
+ EDEB(6, "cq=%p cq triggerarea", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+ physical = cq->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret) {
+ EDEB_ERR(4, "remap_pfn_range() failed ret=%x",
+ ret);
+ ret = -ENOMEM;
+ }
+ goto mmap_exit0;
+ } else if (rsrc_type == 2) { /* cq queue_addr */
+ EDEB(6, "cq=%p cq q_addr", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else {
+ EDEB_ERR(6, "bad resource type %x", rsrc_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ } else if (q_type == 2) { /* QP */
+ struct ehca_qp *qp = NULL;
+ struct ehca_pd *pd = NULL;
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return -ENOMEM;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!qp || !qp->ib_qp.uobject ||
+ qp->ib_qp.uobject->context != context) {
+ EDEB(6, "qp=%p, uobject=%p, context=%p",
+ qp, qp->ib_qp.uobject, qp->ib_qp.uobject->context);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ if (rsrc_type == 1) { /* galpa fw handle */
+ EDEB(6, "qp=%p qp triggerarea", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+ physical = qp->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret) {
+ EDEB_ERR(4, "remap_pfn_range() failed ret=%x",
+ ret);
+ ret = -ENOMEM;
+ }
+ goto mmap_exit0;
+ } else if (rsrc_type == 2) { /* qp rqueue_addr */
+ EDEB(6, "qp=%p qp rqueue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else if (rsrc_type == 3) { /* qp squeue_addr */
+ EDEB(6, "qp=%p qp squeue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else {
+ EDEB_ERR(4, "bad resource type %x", rsrc_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ } else {
+ EDEB_ERR(4, "bad queue type %x", q_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+mmap_exit0:
+ EDEB_EX(7, "ret=%x", ret);
+ return ret;
+}
+
+int ehca_mmap_nopage(u64 foffset, u64 length, void ** mapped,
+ struct vm_area_struct ** vma)
+{
+ EDEB_EN(7, "foffset=%lx length=%lx", foffset, length);
+ down_write(&current->mm->mmap_sem);
+ *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS,
+ foffset);
+ up_write(&current->mm->mmap_sem);
+ if (!(*mapped)) {
+ EDEB_ERR(4, "couldn't mmap foffset=%lx length=%lx",
+ foffset, length);
+ return -EINVAL;
+ }
+
+ *vma = find_vma(current->mm, (u64)*mapped);
+ if (!(*vma)) {
+ down_write(&current->mm->mmap_sem);
+ do_munmap(current->mm, 0, length);
+ up_write(&current->mm->mmap_sem);
+ EDEB_ERR(4, "couldn't find vma queue=%p", *mapped);
+ return -EINVAL;
+ }
+ (*vma)->vm_flags |= VM_RESERVED;
+ (*vma)->vm_ops = &ehcau_vm_ops;
+
+ EDEB_EX(7, "mapped=%p", *mapped);
+ return 0;
+}
+
+int ehca_mmap_register(u64 physical, void ** mapped,
+ struct vm_area_struct ** vma)
+{
+ int ret = 0;
+ unsigned long vsize;
+ /* ehca hw supports only 4k page */
+ ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
+ if (ret) {
+ EDEB(4, "could'nt mmap physical=%lx", physical);
+ return ret;
+ }
+
+ (*vma)->vm_flags |= VM_RESERVED;
+ vsize = (*vma)->vm_end - (*vma)->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ (*vma)->vm_end - (*vma)->vm_start);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
+ (*vma)->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range((*vma), (*vma)->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ (*vma)->vm_page_prot);
+ if (ret) {
+ EDEB_ERR(4, "remap_pfn_range() failed ret=%x", ret);
+ ret = -ENOMEM;
+ }
+ return ret;
+
+}
+
+int ehca_munmap(unsigned long addr, size_t len) {
+ int ret = 0;
+ struct mm_struct *mm = current->mm;
+ if (mm) {
+ down_write(&mm->mmap_sem);
+ ret = do_munmap(mm, addr, len);
+ up_write(&mm->mmap_sem);
+ }
+ return ret;
+}
--
1.4.1

2006-08-17 20:31:42

by Roland Dreier

[permalink] [raw]
Subject: Re: [openib-general] [PATCH 00/16] IB/ehca: introduction

Sorry-- my patchbombing script blew up in the middle, and I didn't
restart quite correctly. But I'm pretty sure all 16 patches did make
it out, although the numbering is screwy. The correct series is:

01/16, 02/16, 00/13, 01/13, ..., 13/13

I'm not going to spam everybody and resend to all the lists, but I'm
happy to resend privately to anyone who asks, or you can clone the
git tree to get the series

git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git ehca

Thanks,
Roland

2006-08-18 15:32:04

by Christoph Raisch

[permalink] [raw]
Subject: Re: [PATCH 02/13] IB/ehca: includes


abergman

> > +#define EDEB_P_GENERIC(level,idstring,format,args...) \
>
> These macros are responsible for 61% of the object code size of your
module.
> ...Please get rid of that crap entirely and replace
> it with dev_info/dev_dbg/dev_warn calls where appropriate!
>
> Arnd <><

we'll change these EDEBs to a wrapper around dev_err, dev_dbg and dev_warn
as it's done in the mthca driver.
All EDEB_EN and EDEB_EX will be removed, that type of tracing can be done
if needed by kprobes.
There are a few cases where we won't get to a dev, for these few places
we'll use a simple wrapper around printk, as done in ipoib.

Hope that's the "official" way how to implement it in ib drivers.


Gruss / Regards . . . Christoph R

2006-08-18 16:21:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 02/13] IB/ehca: includes

On Friday 18 August 2006 17:35, Christoph Raisch wrote:
> we'll change these EDEBs to a wrapper around dev_err, dev_dbg and dev_warn
> as it's done in the mthca driver.
>
> ...
>
> Hope that's the "official" way how to implement it in ib drivers.

I guess it would be even better to just use the dev_* macros directly
instead of having your own wrapper. You can do that in both ehca and ehea.

Arnd <><

2006-08-30 09:09:18

by Hoang-Nam Nguyen

[permalink] [raw]
Subject: Re: [PATCH 02/13] IB/ehca: includes

> Christoph Raisch wrote on 18.08.2006 17:35:54:
> we'll change these EDEBs to a wrapper around dev_err, dev_dbg and
> dev_warn as it's done in the mthca driver.
> All EDEB_EN and EDEB_EX will be removed, that type of tracing can be
> done if needed by kprobes.
> There are a few cases where we won't get to a dev, for these few
> places we'll use a simple wrapper around printk, as done in ipoib.
We incorporated those changes throughout ehca code, which is accessible
from
Roland's git tree:
git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git
for-2.6.19
Further comments/suggestions are appreciated!
Regards
Hoang-Nam Nguyen

2006-08-30 09:43:39

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 02/13] IB/ehca: includes

On Wednesday 30 August 2006 11:13, Hoang-Nam Nguyen wrote:
> Further comments/suggestions are appreciated!

There are a few places in the driver where you declare
external variables (mostly ehca_module and ehca_debug_level)
from C files instead of a header. This sometimes leads
to bugs when a type changes and is therefore considered
bad style.

ehca_debug_level is already declared in a header so you
should not need any other declaration.

For ehca_module, the usage pattern is very uncommon.
Declaring the structure in a header helps a bit, but I
don't really see the need for this structure at all.

Each member of the struct seems to be used mostly in a
single file, so I would declare it statically in there.
E.g. in drivers/infiniband/hw/ehca/ehca_pd.c, you can do

static struct kmem_cache *ehca_pd_cache;

int ehca_init_pd_cache(void)
{
ehca_pd_cache = kmem_cache_init("ehca_cache_pd",
sizeof(struct ehca_pd), 0, SLAB_HWCACHE_ALIGN,
NULL, NULL);

if (!ehca_pd_cache)
return -ENOMEM;
return 0;
}

void ehca_cleanup_pd_cache(void)
{
if (ehca_pd_cache)
kmem_cache_destroy(ehca_pd_cache);
}

Moreover, for some of your more heavily used caches, you may
want to look into using constructor/destructor calls to
speed up allocation.

Arnd <><

2006-08-30 18:23:43

by Hoang-Nam Nguyen

[permalink] [raw]
Subject: Re: [openib-general] [PATCH 02/13] IB/ehca: includes

Hi,
> There are a few places in the driver where you declare
> external variables (mostly ehca_module and ehca_debug_level)
> from C files instead of a header. This sometimes leads
> to bugs when a type changes and is therefore considered
> bad style.
Good point. See patch attached below.

> Moreover, for some of your more heavily used caches, you may
> want to look into using constructor/destructor calls to
> speed up allocation.
That makes sense. Will look into this for a later patch.

Thanks!
Nam


Makefile | 1
ehca_av.c | 29 +++++++---
ehca_classes.h | 27 +++++----
ehca_cq.c | 27 +++++++--
ehca_eq.c | 14 ----
ehca_irq.c | 1
ehca_main.c | 164
++++++++++++++++++++-------------------------------------
ehca_mrmw.c | 45 +++++++++++----
ehca_pd.c | 25 +++++++-
ehca_qp.c | 32 +++++++----
ehca_reqs.c | 2
ehca_sqp.c | 2
hcp_if.c | 1
hcp_phyp.h | 4 -
ipz_pt_fn.c | 2
15 files changed, 198 insertions(+), 178 deletions(-)


diff -Nurp infiniband/drivers/infiniband/hw/ehca/Makefile
infiniband_work/drivers/infiniband/hw/ehca/Makefile
--- infiniband/drivers/infiniband/hw/ehca/Makefile 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/Makefile 2006-08-30
20:00:17.000000000 +0200
@@ -10,6 +10,7 @@

obj-$(CONFIG_INFINIBAND_EHCA) += ib_ehca.o

+
ib_ehca-objs = ehca_main.o ehca_hca.o ehca_mcast.o ehca_pd.o ehca_av.o
ehca_eq.o \
ehca_cq.o ehca_qp.o ehca_sqp.o ehca_mrmw.o ehca_reqs.o
ehca_irq.o \
ehca_uverbs.o ipz_pt_fn.o hcp_if.o hcp_phyp.o
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_av.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_av.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_av.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_av.c 2006-08-30
20:00:16.000000000 +0200
@@ -48,16 +48,16 @@
#include "ehca_iverbs.h"
#include "hcp_if.h"

+static struct kmem_cache *av_cache;
+
struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
{
- extern struct ehca_module ehca_module;
- extern int ehca_static_rate;
int ret;
struct ehca_av *av;
struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
ib_device);

- av = kmem_cache_alloc(ehca_module.cache_av, SLAB_KERNEL);
+ av = kmem_cache_alloc(av_cache, SLAB_KERNEL);
if (!av) {
ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p",
pd, ah_attr);
@@ -128,7 +128,7 @@ struct ib_ah *ehca_create_ah(struct ib_p
return &av->ib_ah;

create_ah_exit1:
- kmem_cache_free(ehca_module.cache_av, av);
+ kmem_cache_free(av_cache, av);

return ERR_PTR(ret);
}
@@ -238,7 +238,6 @@ int ehca_query_ah(struct ib_ah *ah, stru

int ehca_destroy_ah(struct ib_ah *ah)
{
- extern struct ehca_module ehca_module;
struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
u32 cur_pid = current->tgid;

@@ -249,8 +248,24 @@ int ehca_destroy_ah(struct ib_ah *ah)
return -EINVAL;
}

- kmem_cache_free(ehca_module.cache_av,
- container_of(ah, struct ehca_av, ib_ah));
+ kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah));
+
+ return 0;
+}

+int ehca_init_av_cache(void)
+{
+ av_cache = kmem_cache_create("ehca_cache_av",
+ sizeof(struct ehca_av), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!av_cache)
+ return -ENOMEM;
return 0;
}
+
+void ehca_cleanup_av_cache(void)
+{
+ if (av_cache)
+ kmem_cache_destroy(av_cache);
+}
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_classes.h
infiniband_work/drivers/infiniband/hw/ehca/ehca_classes.h
--- infiniband/drivers/infiniband/hw/ehca/ehca_classes.h 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_classes.h
2006-08-30 20:00:16.000000000 +0200
@@ -63,18 +63,6 @@ struct ehca_av;

#include "ehca_irq.h"

-struct ehca_module {
- struct list_head shca_list;
- spinlock_t shca_lock;
- struct timer_list timer;
- kmem_cache_t *cache_pd;
- kmem_cache_t *cache_cq;
- kmem_cache_t *cache_qp;
- kmem_cache_t *cache_av;
- kmem_cache_t *cache_mr;
- kmem_cache_t *cache_mw;
-};
-
struct ehca_eq {
u32 length;
struct ipz_queue ipz_queue;
@@ -274,11 +262,26 @@ int ehca_shca_delete(struct ehca_shca *m

struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);

+int ehca_init_pd_cache(void);
+void ehca_cleanup_pd_cache(void);
+int ehca_init_cq_cache(void);
+void ehca_cleanup_cq_cache(void);
+int ehca_init_qp_cache(void);
+void ehca_cleanup_qp_cache(void);
+int ehca_init_av_cache(void);
+void ehca_cleanup_av_cache(void);
+int ehca_init_mrmw_cache(void);
+void ehca_cleanup_mrmw_cache(void);
+
extern spinlock_t ehca_qp_idr_lock;
extern spinlock_t ehca_cq_idr_lock;
extern struct idr ehca_qp_idr;
extern struct idr ehca_cq_idr;

+extern int ehca_static_rate;
+extern int ehca_port_act_time;
+extern int ehca_use_hp_mr;
+
struct ipzu_queue_resp {
u64 queue; /* points to first queue entry */
u32 qe_size; /* queue entry size */
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_cq.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_cq.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_cq.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_cq.c 2006-08-30
20:00:17.000000000 +0200
@@ -50,6 +50,8 @@
#include "ehca_irq.h"
#include "hcp_if.h"

+static struct kmem_cache *cq_cache;
+
int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp)
{
unsigned int qp_num = qp->real_qp_num;
@@ -115,7 +117,6 @@ struct ib_cq *ehca_create_cq(struct ib_d
struct ib_ucontext *context,
struct ib_udata *udata)
{
- extern struct ehca_module ehca_module;
static const u32 additional_cqe = 20;
struct ib_cq *cq;
struct ehca_cq *my_cq;
@@ -133,7 +134,7 @@ struct ib_cq *ehca_create_cq(struct ib_d
if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
return ERR_PTR(-EINVAL);

- my_cq = kmem_cache_alloc(ehca_module.cache_cq, SLAB_KERNEL);
+ my_cq = kmem_cache_alloc(cq_cache, SLAB_KERNEL);
if (!my_cq) {
ehca_err(device, "Out of memory for ehca_cq struct device=%p",
device);
@@ -324,14 +325,13 @@ create_cq_exit2:
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);

create_cq_exit1:
- kmem_cache_free(ehca_module.cache_cq, my_cq);
+ kmem_cache_free(cq_cache, my_cq);

return cq;
}

int ehca_destroy_cq(struct ib_cq *cq)
{
- extern struct ehca_module ehca_module;
u64 h_ret;
int ret;
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
@@ -387,7 +387,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
return ehca2ib_return_code(h_ret);
}
ipz_queue_dtor(&my_cq->ipz_queue);
- kmem_cache_free(ehca_module.cache_cq, my_cq);
+ kmem_cache_free(cq_cache, my_cq);

return 0;
}
@@ -408,3 +408,20 @@ int ehca_resize_cq(struct ib_cq *cq, int

return -EFAULT;
}
+
+int ehca_init_cq_cache(void)
+{
+ cq_cache = kmem_cache_create("ehca_cache_cq",
+ sizeof(struct ehca_cq), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!cq_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_cq_cache(void)
+{
+ if (cq_cache)
+ kmem_cache_destroy(cq_cache);
+}
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_eq.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_eq.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_eq.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_eq.c 2006-08-30
20:00:16.000000000 +0200
@@ -163,20 +163,6 @@ void *ehca_poll_eq(struct ehca_shca *shc
return eqe;
}

-void ehca_poll_eqs(unsigned long data)
-{
- struct ehca_shca *shca;
- struct ehca_module *module = (struct ehca_module*)data;
-
- spin_lock(&module->shca_lock);
- list_for_each_entry(shca, &module->shca_list, shca_list) {
- if (shca->eq.is_initialized)
- ehca_tasklet_eq((unsigned long)(void*)shca);
- }
- mod_timer(&module->timer, jiffies + HZ);
- spin_unlock(&module->shca_lock);
-}
-
int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
{
unsigned long flags;
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_irq.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_irq.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_irq.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_irq.c 2006-08-30
20:00:16.000000000 +0200
@@ -427,7 +427,6 @@ void ehca_tasklet_eq(unsigned long data)
/* TODO: better structure */
if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT,
eqe_value)) {
- extern struct idr ehca_cq_idr;
unsigned long flags;
u32 token;
struct ehca_cq *cq;
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_main.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_main.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_main.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_main.c 2006-08-30
20:01:34.000000000 +0200
@@ -4,6 +4,7 @@
* module start stop, hca detection
*
* Authors: Heiko J Schick <[email protected]>
+ * Hoang-Nam Nguyen <[email protected]>
*
* Copyright (c) 2005 IBM Corporation
*
@@ -47,7 +48,7 @@
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <[email protected]>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0014");
+MODULE_VERSION("SVNEHCA_0015");

int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -92,129 +93,69 @@ spinlock_t ehca_cq_idr_lock;
DEFINE_IDR(ehca_qp_idr);
DEFINE_IDR(ehca_cq_idr);

-struct ehca_module ehca_module;
+static struct list_head shca_list; /* list of all registered ehcas */
+static spinlock_t shca_list_lock;

-int ehca_create_slab_caches(struct ehca_module *ehca_module)
+static struct timer_list poll_eqs_timer;
+
+static int ehca_create_slab_caches(void)
{
int ret;

- ehca_module->cache_pd =
- kmem_cache_create("ehca_cache_pd",
- sizeof(struct ehca_pd),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (!ehca_module->cache_pd) {
+ ret = ehca_init_pd_cache();
+ if (ret) {
ehca_gen_err("Cannot create PD SLAB cache.");
- ret = -ENOMEM;
- goto create_slab_caches1;
+ return ret;
}

- ehca_module->cache_cq =
- kmem_cache_create("ehca_cache_cq",
- sizeof(struct ehca_cq),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (!ehca_module->cache_cq) {
+ ret = ehca_init_cq_cache();
+ if (ret) {
ehca_gen_err("Cannot create CQ SLAB cache.");
- ret = -ENOMEM;
goto create_slab_caches2;
}

- ehca_module->cache_qp =
- kmem_cache_create("ehca_cache_qp",
- sizeof(struct ehca_qp),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (!ehca_module->cache_qp) {
+ ret = ehca_init_qp_cache();
+ if (ret) {
ehca_gen_err("Cannot create QP SLAB cache.");
- ret = -ENOMEM;
goto create_slab_caches3;
}

- ehca_module->cache_av =
- kmem_cache_create("ehca_cache_av",
- sizeof(struct ehca_av),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (!ehca_module->cache_av) {
+ ret = ehca_init_av_cache();
+ if (ret) {
ehca_gen_err("Cannot create AV SLAB cache.");
- ret = -ENOMEM;
goto create_slab_caches4;
}

- ehca_module->cache_mw =
- kmem_cache_create("ehca_cache_mw",
- sizeof(struct ehca_mw),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (!ehca_module->cache_mw) {
- ehca_gen_err("Cannot create MW SLAB cache.");
- ret = -ENOMEM;
+ ret = ehca_init_mrmw_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create MR&MW SLAB cache.");
goto create_slab_caches5;
}

- ehca_module->cache_mr =
- kmem_cache_create("ehca_cache_mr",
- sizeof(struct ehca_mr),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (!ehca_module->cache_mr) {
- ehca_gen_err("Cannot create MR SLAB cache.");
- ret = -ENOMEM;
- goto create_slab_caches6;
- }
-
return 0;

-create_slab_caches6:
- kmem_cache_destroy(ehca_module->cache_mw);
-
create_slab_caches5:
- kmem_cache_destroy(ehca_module->cache_av);
+ ehca_cleanup_av_cache();

create_slab_caches4:
- kmem_cache_destroy(ehca_module->cache_qp);
+ ehca_cleanup_qp_cache();

create_slab_caches3:
- kmem_cache_destroy(ehca_module->cache_cq);
+ ehca_cleanup_cq_cache();

create_slab_caches2:
- kmem_cache_destroy(ehca_module->cache_pd);
-
-create_slab_caches1:
+ ehca_cleanup_pd_cache();

return ret;
}

-int ehca_destroy_slab_caches(struct ehca_module *ehca_module)
+static void ehca_destroy_slab_caches(void)
{
- int ret;
-
- ret = kmem_cache_destroy(ehca_module->cache_pd);
- if (ret)
- ehca_gen_err("Cannot destroy PD SLAB cache. ret=%x", ret);
-
- ret = kmem_cache_destroy(ehca_module->cache_cq);
- if (ret)
- ehca_gen_err("Cannot destroy CQ SLAB cache. ret=%x", ret);
-
- ret = kmem_cache_destroy(ehca_module->cache_qp);
- if (ret)
- ehca_gen_err("Cannot destroy QP SLAB cache. ret=%x", ret);
-
- ret = kmem_cache_destroy(ehca_module->cache_av);
- if (ret)
- ehca_gen_err("Cannot destroy AV SLAB cache. ret=%x", ret);
-
- ret = kmem_cache_destroy(ehca_module->cache_mw);
- if (ret)
- ehca_gen_err("Cannot destroy MW SLAB cache. ret=%x", ret);
-
- ret = kmem_cache_destroy(ehca_module->cache_mr);
- if (ret)
- ehca_gen_err("Cannot destroy MR SLAB cache. ret=%x", ret);
-
- return 0;
+ ehca_cleanup_mrmw_cache();
+ ehca_cleanup_av_cache();
+ ehca_cleanup_qp_cache();
+ ehca_cleanup_cq_cache();
+ ehca_cleanup_pd_cache();
}

#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
@@ -682,9 +623,9 @@ static int __devinit ehca_probe(struct i

ehca_create_device_sysfs(dev);

- spin_lock(&ehca_module.shca_lock);
- list_add(&shca->shca_list, &ehca_module.shca_list);
- spin_unlock(&ehca_module.shca_lock);
+ spin_lock(&shca_list_lock);
+ list_add(&shca->shca_list, &shca_list);
+ spin_unlock(&shca_list_lock);

return 0;

@@ -767,9 +708,9 @@ static int __devexit ehca_remove(struct

ib_dealloc_device(&shca->ib_device);

- spin_lock(&ehca_module.shca_lock);
+ spin_lock(&shca_list_lock);
list_del(&shca->shca_list);
- spin_unlock(&ehca_module.shca_lock);
+ spin_unlock(&shca_list_lock);

return ret;
}
@@ -790,26 +731,39 @@ static struct ibmebus_driver ehca_driver
.remove = ehca_remove,
};

+void ehca_poll_eqs(unsigned long data)
+{
+ struct ehca_shca *shca;
+
+ spin_lock(&shca_list_lock);
+ list_for_each_entry(shca, &shca_list, shca_list) {
+ if (shca->eq.is_initialized)
+ ehca_tasklet_eq((unsigned long)(void*)shca);
+ }
+ mod_timer(&poll_eqs_timer, jiffies + HZ);
+ spin_unlock(&shca_list_lock);
+}
+
int __init ehca_module_init(void)
{
int ret;

printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0014)\n");
+ "(Rel.: SVNEHCA_0015)\n");
idr_init(&ehca_qp_idr);
idr_init(&ehca_cq_idr);
spin_lock_init(&ehca_qp_idr_lock);
spin_lock_init(&ehca_cq_idr_lock);

- INIT_LIST_HEAD(&ehca_module.shca_list);
- spin_lock_init(&ehca_module.shca_lock);
+ INIT_LIST_HEAD(&shca_list);
+ spin_lock_init(&shca_list_lock);

if ((ret = ehca_create_comp_pool())) {
ehca_gen_err("Cannot create comp pool.");
return ret;
}

- if ((ret = ehca_create_slab_caches(&ehca_module))) {
+ if ((ret = ehca_create_slab_caches())) {
ehca_gen_err("Cannot create SLAB caches");
ret = -ENOMEM;
goto module_init1;
@@ -827,17 +781,16 @@ int __init ehca_module_init(void)
ehca_gen_err("WARNING!!!");
ehca_gen_err("It is possible to lose interrupts.");
} else {
- init_timer(&ehca_module.timer);
- ehca_module.timer.function = ehca_poll_eqs;
- ehca_module.timer.data = (unsigned long)&ehca_module;
- ehca_module.timer.expires = jiffies + HZ;
- add_timer(&ehca_module.timer);
+ init_timer(&poll_eqs_timer);
+ poll_eqs_timer.function = ehca_poll_eqs;
+ poll_eqs_timer.expires = jiffies + HZ;
+ add_timer(&poll_eqs_timer);
}

return 0;

module_init2:
- ehca_destroy_slab_caches(&ehca_module);
+ ehca_destroy_slab_caches();

module_init1:
ehca_destroy_comp_pool();
@@ -847,13 +800,12 @@ module_init1:
void __exit ehca_module_exit(void)
{
if (ehca_poll_all_eqs == 1)
- del_timer_sync(&ehca_module.timer);
+ del_timer_sync(&poll_eqs_timer);

ehca_remove_driver_sysfs(&ehca_driver);
ibmebus_unregister_driver(&ehca_driver);

- if (ehca_destroy_slab_caches(&ehca_module) != 0)
- ehca_gen_err("Cannot destroy SLAB caches");
+ ehca_destroy_slab_caches();

ehca_destroy_comp_pool();

diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_mrmw.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_mrmw.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_mrmw.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_mrmw.c 2006-08-30
20:00:16.000000000 +0200
@@ -46,14 +46,14 @@
#include "hcp_if.h"
#include "hipz_hw.h"

-extern int ehca_use_hp_mr;
+static struct kmem_cache *mr_cache;
+static struct kmem_cache *mw_cache;

static struct ehca_mr *ehca_mr_new(void)
{
- extern struct ehca_module ehca_module;
struct ehca_mr *me;

- me = kmem_cache_alloc(ehca_module.cache_mr, SLAB_KERNEL);
+ me = kmem_cache_alloc(mr_cache, SLAB_KERNEL);
if (me) {
memset(me, 0, sizeof(struct ehca_mr));
spin_lock_init(&me->mrlock);
@@ -65,17 +65,14 @@ static struct ehca_mr *ehca_mr_new(void)

static void ehca_mr_delete(struct ehca_mr *me)
{
- extern struct ehca_module ehca_module;
-
- kmem_cache_free(ehca_module.cache_mr, me);
+ kmem_cache_free(mr_cache, me);
}

static struct ehca_mw *ehca_mw_new(void)
{
- extern struct ehca_module ehca_module;
struct ehca_mw *me;

- me = kmem_cache_alloc(ehca_module.cache_mw, SLAB_KERNEL);
+ me = kmem_cache_alloc(mw_cache, SLAB_KERNEL);
if (me) {
memset(me, 0, sizeof(struct ehca_mw));
spin_lock_init(&me->mwlock);
@@ -87,9 +84,7 @@ static struct ehca_mw *ehca_mw_new(void)

static void ehca_mw_delete(struct ehca_mw *me)
{
- extern struct ehca_module ehca_module;
-
- kmem_cache_free(ehca_module.cache_mw, me);
+ kmem_cache_free(mw_cache, me);
}

/*----------------------------------------------------------------------*/
@@ -2236,3 +2231,31 @@ void ehca_mr_deletenew(struct ehca_mr *m
mr->nr_of_pages = 0;
mr->pagearray = NULL;
} /* end ehca_mr_deletenew() */
+
+int ehca_init_mrmw_cache(void)
+{
+ mr_cache = kmem_cache_create("ehca_cache_mr",
+ sizeof(struct ehca_mr), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!mr_cache)
+ return -ENOMEM;
+ mw_cache = kmem_cache_create("ehca_cache_mw",
+ sizeof(struct ehca_mw), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!mw_cache) {
+ kmem_cache_destroy(mr_cache);
+ mr_cache = NULL;
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void ehca_cleanup_mrmw_cache(void)
+{
+ if (mr_cache)
+ kmem_cache_destroy(mr_cache);
+ if (mw_cache)
+ kmem_cache_destroy(mw_cache);
+}
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_pd.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_pd.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_pd.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_pd.c 2006-08-30
20:00:16.000000000 +0200
@@ -43,13 +43,14 @@
#include "ehca_tools.h"
#include "ehca_iverbs.h"

+static struct kmem_cache *pd_cache;
+
struct ib_pd *ehca_alloc_pd(struct ib_device *device,
struct ib_ucontext *context, struct ib_udata *udata)
{
- extern struct ehca_module ehca_module;
struct ehca_pd *pd;

- pd = kmem_cache_alloc(ehca_module.cache_pd, SLAB_KERNEL);
+ pd = kmem_cache_alloc(pd_cache, SLAB_KERNEL);
if (!pd) {
ehca_err(device, "device=%p context=%p out of memory",
device, context);
@@ -79,7 +80,6 @@ struct ib_pd *ehca_alloc_pd(struct ib_de

int ehca_dealloc_pd(struct ib_pd *pd)
{
- extern struct ehca_module ehca_module;
u32 cur_pid = current->tgid;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);

@@ -90,8 +90,25 @@ int ehca_dealloc_pd(struct ib_pd *pd)
return -EINVAL;
}

- kmem_cache_free(ehca_module.cache_pd,
+ kmem_cache_free(pd_cache,
container_of(pd, struct ehca_pd, ib_pd));

return 0;
}
+
+int ehca_init_pd_cache(void)
+{
+ pd_cache = kmem_cache_create("ehca_cache_pd",
+ sizeof(struct ehca_pd), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!pd_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_pd_cache(void)
+{
+ if (pd_cache)
+ kmem_cache_destroy(pd_cache);
+}
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_qp.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_qp.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_qp.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_qp.c 2006-08-30
20:00:16.000000000 +0200
@@ -51,6 +51,8 @@
#include "hcp_if.h"
#include "hipz_fns.h"

+static struct kmem_cache *qp_cache;
+
/*
* attributes not supported by query qp
*/
@@ -387,7 +389,6 @@ struct ib_qp *ehca_create_qp(struct ib_p
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata)
{
- extern struct ehca_module ehca_module;
static int da_rc_msg_size[]={ 128, 256, 512, 1024, 2048, 4096 };
static int da_ud_sq_msg_size[]={ 128, 384, 896, 1920, 3968 };
struct ehca_qp *my_qp;
@@ -449,7 +450,7 @@ struct ib_qp *ehca_create_qp(struct ib_p
if (pd->uobject && udata)
context = pd->uobject->context;

- my_qp = kmem_cache_alloc(ehca_module.cache_qp, SLAB_KERNEL);
+ my_qp = kmem_cache_alloc(qp_cache, SLAB_KERNEL);
if (!my_qp) {
ehca_err(pd->device, "pd=%p not enough memory to alloc qp",
pd);
return ERR_PTR(-ENOMEM);
@@ -716,7 +717,7 @@ create_qp_exit1:
spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);

create_qp_exit0:
- kmem_cache_free(ehca_module.cache_qp, my_qp);
+ kmem_cache_free(qp_cache, my_qp);
return ERR_PTR(ret);
}

@@ -728,7 +729,6 @@ create_qp_exit0:
static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
int *bad_wqe_cnt)
{
- extern int ehca_debug_level;
u64 h_ret;
struct ipz_queue *squeue;
void *bad_send_wqe_p, *bad_send_wqe_v;
@@ -797,7 +797,6 @@ static int internal_modify_qp(struct ib_
struct ib_qp_attr *attr,
int attr_mask, int smi_reset2init)
{
- extern int ehca_debug_level;
enum ib_qp_state qp_cur_state, qp_new_state;
int cnt, qp_attr_idx, ret = 0;
enum ib_qp_statetrans statetrans;
@@ -807,7 +806,7 @@ static int internal_modify_qp(struct ib_
container_of(ibqp->pd->device, struct ehca_shca, ib_device);
u64 update_mask;
u64 h_ret;
- int bad_wqe_cnt;
+ int bad_wqe_cnt = 0;
int squeue_locked = 0;
unsigned long spl_flags = 0;

@@ -1253,7 +1251,6 @@ int ehca_query_qp(struct ib_qp *qp,
struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
{
- extern int ehca_debug_level;
struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
ib_pd);
@@ -1410,7 +1407,6 @@ query_qp_exit1:

int ehca_destroy_qp(struct ib_qp *ibqp)
{
- extern struct ehca_module ehca_module;
struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
ib_device);
@@ -1488,6 +1484,23 @@ int ehca_destroy_qp(struct ib_qp *ibqp)

ipz_queue_dtor(&my_qp->ipz_rqueue);
ipz_queue_dtor(&my_qp->ipz_squeue);
- kmem_cache_free(ehca_module.cache_qp, my_qp);
+ kmem_cache_free(qp_cache, my_qp);
return 0;
}
+
+int ehca_init_qp_cache(void)
+{
+ qp_cache = kmem_cache_create("ehca_cache_qp",
+ sizeof(struct ehca_qp), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!qp_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_qp_cache(void)
+{
+ if (qp_cache)
+ kmem_cache_destroy(qp_cache);
+}
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_reqs.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_reqs.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_reqs.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_reqs.c 2006-08-30
20:00:16.000000000 +0200
@@ -49,8 +49,6 @@
#include "hcp_if.h"
#include "hipz_fns.h"

-extern int ehca_debug_level;
-
static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
struct ehca_wqe *wqe_p,
struct ib_recv_wr *recv_wr)
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ehca_sqp.c
infiniband_work/drivers/infiniband/hw/ehca/ehca_sqp.c
--- infiniband/drivers/infiniband/hw/ehca/ehca_sqp.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ehca_sqp.c 2006-08-30
20:00:16.000000000 +0200
@@ -49,8 +49,6 @@
#include "hcp_if.h"


-extern int ehca_port_act_time;
-
/**
* ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special
queue
* pair is created successfully, the corresponding port gets active.
diff -Nurp infiniband/drivers/infiniband/hw/ehca/hcp_if.c
infiniband_work/drivers/infiniband/hw/ehca/hcp_if.c
--- infiniband/drivers/infiniband/hw/ehca/hcp_if.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/hcp_if.c 2006-08-30
20:00:17.000000000 +0200
@@ -410,7 +410,6 @@ u64 hipz_h_query_port(const struct ipz_a
const u8 port_id,
struct hipz_query_port *query_port_response_block)
{
- extern int ehca_debug_level;
u64 ret;
u64 dummy;
u64 r_cb = virt_to_abs(query_port_response_block);
diff -Nurp infiniband/drivers/infiniband/hw/ehca/hcp_phyp.h
infiniband_work/drivers/infiniband/hw/ehca/hcp_phyp.h
--- infiniband/drivers/infiniband/hw/ehca/hcp_phyp.h 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/hcp_phyp.h 2006-08-30
20:00:16.000000000 +0200
@@ -69,13 +69,13 @@ struct h_galpas {
static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset)
{
u64 addr = galpa.fw_handle + offset;
- return *(u64 *)addr;
+ return *(volatile u64 __force *)addr;
}

static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64
value)
{
u64 addr = galpa.fw_handle + offset;
- *(u64 *)addr = value;
+ *(volatile u64 __force *)addr = value;
}

int hcp_galpas_ctor(struct h_galpas *galpas,
diff -Nurp infiniband/drivers/infiniband/hw/ehca/ipz_pt_fn.c
infiniband_work/drivers/infiniband/hw/ehca/ipz_pt_fn.c
--- infiniband/drivers/infiniband/hw/ehca/ipz_pt_fn.c 2006-08-30
18:02:01.000000000 +0200
+++ infiniband_work/drivers/infiniband/hw/ehca/ipz_pt_fn.c 2006-08-30
20:00:16.000000000 +0200
@@ -41,8 +41,6 @@
#include "ehca_tools.h"
#include "ipz_pt_fn.h"

-extern int ehca_hwlevel;
-
void *ipz_qpageit_get_inc(struct ipz_queue *queue)
{
void *ret = ipz_qeit_get(queue);