[mlx4] Added the latest revision of the mlx4 to the trunk.
authortzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Sun, 4 May 2008 09:09:48 +0000 (09:09 +0000)
committertzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Sun, 4 May 2008 09:09:48 +0000 (09:09 +0000)
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@1124 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

206 files changed:
hw/dirs
hw/mlx4/dirs [new file with mode: 0644]
hw/mlx4/inc/mx_abi.h [new file with mode: 0644]
hw/mlx4/inc/public.h [new file with mode: 0644]
hw/mlx4/inc/user.h [new file with mode: 0644]
hw/mlx4/kernel/bus/core/SOURCES [new file with mode: 0644]
hw/mlx4/kernel/bus/core/cache.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/core.def [new file with mode: 0644]
hw/mlx4/kernel/bus/core/core.h [new file with mode: 0644]
hw/mlx4/kernel/bus/core/core.rc [new file with mode: 0644]
hw/mlx4/kernel/bus/core/device.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/ev_log.mc [new file with mode: 0644]
hw/mlx4/kernel/bus/core/iobuf.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/l2w.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/l2w_debug.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/l2w_memory.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/l2w_radix.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/l2w_umem.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/makefile [new file with mode: 0644]
hw/mlx4/kernel/bus/core/pa_cash.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/pa_cash.h [new file with mode: 0644]
hw/mlx4/kernel/bus/core/packer.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/ud_header.c [new file with mode: 0644]
hw/mlx4/kernel/bus/core/verbs.c [new file with mode: 0644]
hw/mlx4/kernel/bus/dirs [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/bus.mof [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/bus.rc [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/drv.c [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/drv.h [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/makefile [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/makefile.inc [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/mlx4_bus.cdf [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/mlx4_bus.inf [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/pci.c [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/pdo.c [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/precomp.h [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/sources [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/wmi.c [new file with mode: 0644]
hw/mlx4/kernel/bus/drv/wpptrace.h [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/Kconfig [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/Makefile.lnx [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/SOURCES [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/ah.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/cq.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/doorbell.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/ib.def [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/ib.rc [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/mad.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/main.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/makefile [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/mlx4_ib.h [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/mr.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/qp.c [new file with mode: 0644]
hw/mlx4/kernel/bus/ib/srq.c [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/bus_intf.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/cmd.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/cq.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/device.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/doorbell.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/driver.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/ib_cache.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/ib_mad.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/ib_pack.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/ib_smi.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/ib_verbs.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/ib_verbs_ex.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/qp.h [new file with mode: 0644]
hw/mlx4/kernel/bus/inc/srq.h [new file with mode: 0644]
hw/mlx4/kernel/bus/net/Makefile.lnx [new file with mode: 0644]
hw/mlx4/kernel/bus/net/SOURCES [new file with mode: 0644]
hw/mlx4/kernel/bus/net/alloc.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/catas.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/cmd.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/cq.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/eq.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/fw.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/fw.h [new file with mode: 0644]
hw/mlx4/kernel/bus/net/icm.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/icm.h [new file with mode: 0644]
hw/mlx4/kernel/bus/net/intf.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/main.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/makefile [new file with mode: 0644]
hw/mlx4/kernel/bus/net/mcg.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/mlx4.h [new file with mode: 0644]
hw/mlx4/kernel/bus/net/mr.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/net.def [new file with mode: 0644]
hw/mlx4/kernel/bus/net/net.rc [new file with mode: 0644]
hw/mlx4/kernel/bus/net/pd.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/profile.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/qp.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/reset.c [new file with mode: 0644]
hw/mlx4/kernel/bus/net/srq.c [new file with mode: 0644]
hw/mlx4/kernel/dirs [new file with mode: 0644]
hw/mlx4/kernel/eth/GenDefs.h [new file with mode: 0644]
hw/mlx4/kernel/eth/GenUtils.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/GenUtils.h [new file with mode: 0644]
hw/mlx4/kernel/eth/connectx_child.cdf [new file with mode: 0644]
hw/mlx4/kernel/eth/connectx_child.inf [new file with mode: 0644]
hw/mlx4/kernel/eth/e100.mof [new file with mode: 0644]
hw/mlx4/kernel/eth/e100.rc [new file with mode: 0644]
hw/mlx4/kernel/eth/makefile [new file with mode: 0644]
hw/mlx4/kernel/eth/makefile.inc [new file with mode: 0644]
hw/mlx4/kernel/eth/mp.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_WorkerThread.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_WorkerThread.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_cmn.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_dbg.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_dbg.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_def.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_init.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_lbfo.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_lbfo.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_log.mc [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_lro.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_lro.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_main.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_nic.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_nic.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_req.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_rss.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mp_rss.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mtnic_cmd.cpp [new file with mode: 0644]
hw/mlx4/kernel/eth/mtnic_cmd.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mtnic_dev.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mtnic_if_defs.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mtnic_perf.h [new file with mode: 0644]
hw/mlx4/kernel/eth/mxe_bus.h [new file with mode: 0644]
hw/mlx4/kernel/eth/offload.h [new file with mode: 0644]
hw/mlx4/kernel/eth/precomp.h [new file with mode: 0644]
hw/mlx4/kernel/eth/sources [new file with mode: 0644]
hw/mlx4/kernel/eth/wineth.def [new file with mode: 0644]
hw/mlx4/kernel/eth/wpptrace.h [new file with mode: 0644]
hw/mlx4/kernel/hca/Makefile [new file with mode: 0644]
hw/mlx4/kernel/hca/SOURCES [new file with mode: 0644]
hw/mlx4/kernel/hca/av.c [new file with mode: 0644]
hw/mlx4/kernel/hca/ca.c [new file with mode: 0644]
hw/mlx4/kernel/hca/cq.c [new file with mode: 0644]
hw/mlx4/kernel/hca/data.c [new file with mode: 0644]
hw/mlx4/kernel/hca/data.h [new file with mode: 0644]
hw/mlx4/kernel/hca/debug.h [new file with mode: 0644]
hw/mlx4/kernel/hca/direct.c [new file with mode: 0644]
hw/mlx4/kernel/hca/drv.c [new file with mode: 0644]
hw/mlx4/kernel/hca/drv.h [new file with mode: 0644]
hw/mlx4/kernel/hca/fw.c [new file with mode: 0644]
hw/mlx4/kernel/hca/hca.mof [new file with mode: 0644]
hw/mlx4/kernel/hca/hca.rc [new file with mode: 0644]
hw/mlx4/kernel/hca/makefile.inc [new file with mode: 0644]
hw/mlx4/kernel/hca/mcast.c [new file with mode: 0644]
hw/mlx4/kernel/hca/mlx4_hca.cdf [new file with mode: 0644]
hw/mlx4/kernel/hca/mlx4_hca.inf [new file with mode: 0644]
hw/mlx4/kernel/hca/mlx4_hca32.cdf [new file with mode: 0644]
hw/mlx4/kernel/hca/mr.c [new file with mode: 0644]
hw/mlx4/kernel/hca/pd.c [new file with mode: 0644]
hw/mlx4/kernel/hca/precomp.h [new file with mode: 0644]
hw/mlx4/kernel/hca/qp.c [new file with mode: 0644]
hw/mlx4/kernel/hca/srq.c [new file with mode: 0644]
hw/mlx4/kernel/hca/verbs.c [new file with mode: 0644]
hw/mlx4/kernel/hca/verbs.h [new file with mode: 0644]
hw/mlx4/kernel/hca/vp.c [new file with mode: 0644]
hw/mlx4/kernel/hca/wmi.c [new file with mode: 0644]
hw/mlx4/kernel/inc/iobuf.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_atomic.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_bit.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_bitmap.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_debug.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_list.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_memory.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_pci.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_pcipool.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_radix.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_spinlock.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_sync.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_time.h [new file with mode: 0644]
hw/mlx4/kernel/inc/l2w_umem.h [new file with mode: 0644]
hw/mlx4/kernel/inc/mlx4_debug.h [new file with mode: 0644]
hw/mlx4/kernel/inc/shutter.h [new file with mode: 0644]
hw/mlx4/kernel/inc/vc.h [new file with mode: 0644]
hw/mlx4/kernel_patches/core_0020_csum.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/core_0030_lso.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/mlx4_0050_lso.patch [new file with mode: 0644]
hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch [new file with mode: 0644]
hw/mlx4/todo.txt [new file with mode: 0644]
hw/mlx4/user/dirs [new file with mode: 0644]
hw/mlx4/user/hca/Makefile [new file with mode: 0644]
hw/mlx4/user/hca/SOURCES [new file with mode: 0644]
hw/mlx4/user/hca/buf.c [new file with mode: 0644]
hw/mlx4/user/hca/cq.c [new file with mode: 0644]
hw/mlx4/user/hca/dbrec.c [new file with mode: 0644]
hw/mlx4/user/hca/doorbell.h [new file with mode: 0644]
hw/mlx4/user/hca/l2w.h [new file with mode: 0644]
hw/mlx4/user/hca/mlx4.c [new file with mode: 0644]
hw/mlx4/user/hca/mlx4.def [new file with mode: 0644]
hw/mlx4/user/hca/mlx4.h [new file with mode: 0644]
hw/mlx4/user/hca/mlx4_debug.c [new file with mode: 0644]
hw/mlx4/user/hca/mlx4_debug.h [new file with mode: 0644]
hw/mlx4/user/hca/qp.c [new file with mode: 0644]
hw/mlx4/user/hca/srq.c [new file with mode: 0644]
hw/mlx4/user/hca/verbs.c [new file with mode: 0644]
hw/mlx4/user/hca/verbs.h [new file with mode: 0644]
hw/mlx4/user/hca/wqe.h [new file with mode: 0644]

diff --git a/hw/dirs b/hw/dirs
index 5905f6c..5824275 100644 (file)
--- a/hw/dirs
+++ b/hw/dirs
@@ -1,2 +1,3 @@
 DIRS=\\r
-       mthca\r
+       mthca\\r
+        mlx4\r
diff --git a/hw/mlx4/dirs b/hw/mlx4/dirs
new file mode 100644 (file)
index 0000000..5927717
--- /dev/null
@@ -0,0 +1,3 @@
+DIRS= \\r
+       kernel \\r
+       user
\ No newline at end of file
diff --git a/hw/mlx4/inc/mx_abi.h b/hw/mlx4/inc/mx_abi.h
new file mode 100644 (file)
index 0000000..02ec7b6
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mx_abi.h 2002 2007-03-26 09:46:23Z sleybo $
+ */
+
+#ifndef MX_ABI_H
+#define MX_ABI_H
+
+#include <complib/cl_types_osd.h>
+#include "user.h"
+
+#pragma warning( disable : 4201)
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * Specifically:
+ *  - Do not use pointer types -- pass pointers in uint64_t instead.
+ *  - Make sure that any structure larger than 4 bytes is padded to a
+ *    multiple of 8 bytes.  Otherwise the structure size will be
+ *    different between 32-bit and 64-bit architectures.
+ */
+
+struct ibv_get_context_resp {
+
+       // mmap UAR
+       uint64_t uar_addr;
+       
+       // mmap Blue Flame
+       uint64_t bf_page;
+       int bf_buf_size;
+       int bf_offset;
+       
+       // mlx4_query_device result 
+       int max_qp_wr;
+       int max_sge;
+       int max_cqe;
+
+       // general parameters
+       uint32_t vend_id;
+       uint16_t dev_id;
+       uint16_t bf_reg_size;
+       uint16_t bf_regs_per_page;
+       uint16_t reserved1;
+
+       // ibv_cmd_get_context result 
+       uint32_t qp_tab_size;
+
+       uint32_t reserved2;
+};
+
+struct ibv_alloc_pd_resp {
+       uint64_t pd_handle;
+       uint32_t pdn;
+       uint32_t reserved;
+};
+
+struct ibv_reg_mr {
+       uint64_t start;
+       uint64_t length;
+       uint64_t hca_va;
+       uint32_t access_flags;
+       uint32_t pdn;
+       uint64_t pd_handle;
+};
+
+struct ibv_reg_mr_resp {
+       uint64_t mr_handle;
+       uint32_t lkey;
+       uint32_t rkey;
+};
+
+
+struct ibv_create_cq {
+       // struct ib_uverbs_create_cq
+       __declspec(align(8)) uint32_t cqe;
+       uint32_t reserved;
+       struct mlx4_ib_create_cq;
+};
+
+struct ibv_create_cq_resp {
+       // struct ib_uverbs_create_cq_resp
+       uint64_t cq_handle;
+       uint32_t cqe;
+       struct mlx4_ib_create_cq_resp;
+};
+
+struct ibv_create_srq {
+       // struct ib_uverbs_create_srq
+       uint64_t pd_handle;
+       uint32_t max_wr;
+       uint32_t max_sge;
+       uint32_t srq_limit;
+       uint32_t reserved;
+       struct mlx4_ib_create_srq;
+};
+
+struct ibv_create_srq_resp {
+       // struct ib_uverbs_create_srq_resp
+       uint64_t srq_handle;
+       uint32_t max_wr;
+       uint32_t max_sge;
+       struct mlx4_ib_create_srq_resp;
+};
+
+struct ibv_create_qp {
+       // struct ib_uverbs_create_qp
+       uint64_t pd_handle;
+       uint64_t send_cq_handle;
+       uint64_t recv_cq_handle;
+       uint64_t srq_handle;
+       uint32_t max_send_wr;
+       uint32_t max_recv_wr;
+       uint32_t max_send_sge;
+       uint32_t max_recv_sge;
+       uint32_t max_inline_data;
+       uint8_t  sq_sig_all;
+       uint8_t  qp_type;
+       uint8_t  is_srq;
+       uint8_t  reserved0;
+       struct mlx4_ib_create_qp;
+};
+
+struct ibv_create_qp_resp {
+       // struct ib_uverbs_create_qp_resp
+       uint64_t qp_handle;
+       uint32_t qpn;
+       uint32_t max_send_wr;
+       uint32_t max_recv_wr;
+       uint32_t max_send_sge;
+       uint32_t max_recv_sge;
+       uint32_t max_inline_data;
+};
+
+struct ibv_modify_qp_resp {
+       enum ibv_qp_attr_mask attr_mask;
+       uint8_t qp_state;
+       uint8_t reserved[3];
+};
+
+struct ibv_create_ah_resp {
+       uint64_t start;
+};
+
+#pragma warning( default  : 4201)
+
+#endif /* MX_ABI_H */
+
diff --git a/hw/mlx4/inc/public.h b/hw/mlx4/inc/public.h
new file mode 100644 (file)
index 0000000..e2ff2fe
--- /dev/null
@@ -0,0 +1,136 @@
+/*++\r
+Copyright (c) 1990-2000    Microsoft Corporation All Rights Reserved\r
+\r
+Module Name:\r
+\r
+    public.h\r
+\r
+Abstract:\r
+\r
+    This module contains the common declarations shared by driver\r
+    and user applications.\r
+\r
+Environment:\r
+\r
+    user and kernel\r
+\r
+--*/\r
+\r
+//\r
+// Define a WMI GUID to get MLX4_HCA info.\r
+// (used in hca\wmi.c)\r
+//\r
+\r
+// {2C4C8445-E4A6-45bc-889B-E5E93551DDAF}\r
+DEFINE_GUID(MLX4_HCA_WMI_STD_DATA_GUID, \r
+0x2c4c8445, 0xe4a6, 0x45bc, 0x88, 0x9b, 0xe5, 0xe9, 0x35, 0x51, 0xdd, 0xaf);\r
+\r
+\r
+\r
+//\r
+// Define a WMI GUID to get MLX4_BUS info.\r
+// (used in bus\wmi.c)\r
+//\r
+\r
+// {3337968C-F117-4289-84C2-04EF74CBAD77}\r
+DEFINE_GUID(MLX4_BUS_WMI_STD_DATA_GUID, \r
+0x3337968c, 0xf117, 0x4289, 0x84, 0xc2, 0x4, 0xef, 0x74, 0xcb, 0xad, 0x77);\r
+\r
+\r
+\r
+//\r
+// Define a GUID for MLX4_BUS upper (IB) interface.\r
+// (used in hca\drv.c)\r
+//\r
+\r
+// {48AC3404-269E-4ab0-B5F3-9EF15AA79D0C}\r
+DEFINE_GUID(MLX4_BUS_IB_INTERFACE_GUID, \r
+0x48ac3404, 0x269e, 0x4ab0, 0xb5, 0xf3, 0x9e, 0xf1, 0x5a, 0xa7, 0x9d, 0xc);\r
+\r
+\r
+\r
+//\r
+// Define the MLX4_BUS type GUID.\r
+// (used in bus\drv.c for responding to the IRP_MN_QUERY_BUS_INFORMATION)\r
+//\r
+\r
+// {CF9E3C49-48D1-45b5-ABD7-CBCA7D954DF4}\r
+DEFINE_GUID(MLX4_BUS_TYPE_GUID, \r
+0xcf9e3c49, 0x48d1, 0x45b5, 0xab, 0xd7, 0xcb, 0xca, 0x7d, 0x95, 0x4d, 0xf4);\r
+\r
+\r
+\r
+//\r
+// Installation Class for MLX4 BUS driver \r
+// (used in bus\mlx4_bus.inf)\r
+//\r
+\r
+// {714995B2-CD65-4a47-BCFE-95AC73A0D780}\r
+\r
+\r
+\r
+//\r
+// Installation Class for MLX4 HCA driver \r
+// (used in hca\mlx4_hca.inf)\r
+//\r
+\r
+// {31B0B28A-26FF-4dca-A6FA-E767C7DFBA20}\r
+\r
+\r
+#if 0\r
+\r
+//\r
+// Define an Interface Guid for mxe device class.\r
+// This GUID is used to register (IoRegisterDeviceInterface) \r
+// an instance of an interface so that user application \r
+// can control the mxe device.\r
+//\r
+\r
+DEFINE_GUID (GUID_DEVINTERFACE_MXE, \r
+        0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+//{781EF630-72B2-11d2-B852-00C04FAD5171}\r
+\r
+//\r
+// Define a Setup Class GUID for Mxe Class. This is same\r
+// as the TOASTSER CLASS guid in the INF files.\r
+//\r
+//leo\r
+DEFINE_GUID (GUID_DEVCLASS_MXEETHER, \r
+        0x4d36e972, 0xe325, 0x11ce, 0xBF, 0xC1, 0x08, 0x00, 0x2b, 0xE1, 0x03, 0x18);\r
+//{4d36e972-e325-11ce-bfc1-08002be10318}\r
+\r
+//\r
+// Define a WMI GUID to get mxe device info.\r
+//\r
+\r
+DEFINE_GUID (MXE_WMI_STD_DATA_GUID, \r
+        0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);\r
+\r
+//\r
+// Define a WMI GUID to represent device arrival notification WMIEvent class.\r
+//\r
+\r
+DEFINE_GUID (MXE_NOTIFY_DEVICE_ARRIVAL_EVENT, \r
+        0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c);\r
+// {01CDAFF1-C901-45b4-B359-B5542725E29C}\r
+\r
+\r
+//leo The Guid was taken from devguid.h\r
+//DEFINE_GUID( GUID_DEVCLASS_INFINIBAND,          0x30ef7132L, 0xd858, 0x4a0c, 0xac, 0x24, 0xb9, 0x02, 0x8a, 0x5c, 0xca, 0x3f );\r
+\r
+\r
+#endif\r
+\r
+//\r
+// GUID definition are required to be outside of header inclusion pragma to avoid\r
+// error during precompiled headers.\r
+//\r
+\r
+#ifndef __PUBLIC_H\r
+#define __PUBLIC_H\r
+\r
+#define BUS_HARDWARE_IDS L"MLX4\\ConnectX_Hca\0"\r
+#define BUSENUM_COMPATIBLE_IDS L"MLX4\\ConnectX_Hca\0"\r
+\r
+#endif\r
+\r
diff --git a/hw/mlx4/inc/user.h b/hw/mlx4/inc/user.h
new file mode 100644 (file)
index 0000000..a622099
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_IB_USER_H
+#define MLX4_IB_USER_H
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define MLX4_IB_UVERBS_ABI_VERSION     3
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mlx4_ib_alloc_ucontext_resp {
+       __u32   qp_tab_size;
+       __u16   bf_reg_size;
+       __u16   bf_regs_per_page;
+};
+
+struct mlx4_ib_alloc_pd_resp {
+       __u32   pdn;
+       __u32   reserved;
+};
+
+struct mlx4_ib_create_cq {
+       __u64   buf_addr;
+       __u64   db_addr;
+       __u64   arm_sn_addr;    // Windows specific
+};
+
+struct mlx4_ib_create_cq_resp {
+       __u32   cqn;
+};
+
+struct mlx4_ib_resize_cq {
+       __u64   buf_addr;
+};
+
+struct mlx4_ib_create_srq {
+       __u64   buf_addr;
+       __u64   db_addr;
+};
+
+struct mlx4_ib_create_srq_resp {
+       __u32   srqn;
+       __u32   reserved;
+};
+
+struct mlx4_ib_create_qp {
+       __u64   buf_addr;
+       __u64   db_addr;
+       __u8    log_sq_bb_count;
+       __u8    log_sq_stride;
+       __u8    sq_no_prefetch;
+       __u8    reserved[5];
+};
+
+#endif /* MLX4_IB_USER_H */
diff --git a/hw/mlx4/kernel/bus/core/SOURCES b/hw/mlx4/kernel/bus/core/SOURCES
new file mode 100644 (file)
index 0000000..b826032
--- /dev/null
@@ -0,0 +1,52 @@
+TARGETNAME=mlx4_core\r
+TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE=DRIVER_LIBRARY\r
+\r
+\r
+\r
+!if $(FREEBUILD)\r
+#ENABLE_EVENT_TRACING=1\r
+!else\r
+#ENABLE_EVENT_TRACING=1\r
+!endif\r
+\r
+\r
+DLLDEF=core.def\r
+PASS0_HEADERDIR=.\r
+\r
+SOURCES= \\r
+       ev_log.mc               \\r
+       core.rc                 \\r
+       cache.c                 \\r
+       device.c                \\r
+       iobuf.c                 \\r
+       l2w.c                   \\r
+       l2w_radix.c             \\r
+       l2w_debug.c             \\r
+       l2w_memory.c    \\r
+       l2w_umem.c              \\r
+       pa_cash.c               \\r
+       packer.c                \\r
+       ud_header.c             \\r
+       verbs.c                 \\r
+\r
+INCLUDES=..;..\inc;..\..\inc;..\net;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel;\r
+\r
+C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN -DUSE_WDM_INTERRUPTS \r
+\r
+TARGETLIBS= \\r
+    $(DDK_LIB_PATH)\ntstrsafe.lib \\r
+       $(TARGETPATH)\*\complib.lib\r
+       \r
+\r
+!IFDEF ENABLE_EVENT_TRACING\r
+\r
+C_DEFINES = $(C_DEFINES) -DEVENT_TRACING\r
+\r
+RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \\r
+       -scan:..\inc\mlx4_debug.h \\r
+       -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \\r
+       -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \r
+!ENDIF\r
+\r
+MSC_WARNING_LEVEL= /W4\r
diff --git a/hw/mlx4/kernel/bus/core/cache.c b/hw/mlx4/kernel/bus/core/cache.c
new file mode 100644 (file)
index 0000000..2e28107
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: cache.c 1349 2004-12-16 21:09:43Z roland $
+ */
+
+#include "ib\mlx4_ib.h"
+#include "ib_cache.h"
+
+#if defined(EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "cache.tmh"
+#endif
+
+#pragma warning( disable : 4200)
+struct ib_pkey_cache {
+       int             table_len;
+       u16             table[0];
+};
+
+struct ib_gid_cache {
+       int             table_len;
+       union ib_gid    table[0];
+};
+#pragma warning( default  : 4200)
+
+struct ib_update_work {
+       PIO_WORKITEM work_item;
+       struct ib_device  *device;
+       u8                 port_num;
+};
+
+static inline int start_port(struct ib_device *device)
+{
+       return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
+}
+
+static inline int end_port(struct ib_device *device)
+{
+       return (device->node_type == RDMA_NODE_IB_SWITCH) ?
+               0 : device->phys_port_cnt;
+}
+
+int ib_get_cached_gid(struct ib_device *device,
+                     u8                port_num,
+                     int               index,
+                     union ib_gid     *gid)
+{
+       struct ib_gid_cache *cache;
+       unsigned long flags;
+       int ret = 0;
+
+       if (port_num < start_port(device) || port_num > end_port(device))
+               return -EINVAL;
+
+       read_lock_irqsave(&device->cache.lock, &flags);
+
+       cache = device->cache.gid_cache[port_num - start_port(device)];
+
+       if (index < 0 || index >= cache->table_len)
+               ret = -EINVAL;
+       else
+               *gid = cache->table[index];
+
+       read_unlock_irqrestore(&device->cache.lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_get_cached_gid);
+
+int ib_find_cached_gid(struct ib_device *device,
+                      union ib_gid     *gid,
+                      u8               *port_num,
+                      u16              *index)
+{
+       struct ib_gid_cache *cache;
+       unsigned long flags;
+       int p, i;
+       int ret = -ENOENT;
+
+       *port_num = (u8)-1;
+       if (index)
+               *index = (u16)-1;
+
+       read_lock_irqsave(&device->cache.lock, &flags);
+
+       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+               cache = device->cache.gid_cache[p];
+               for (i = 0; i < cache->table_len; ++i) {
+                       if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
+                               *port_num = (u8)(p + start_port(device));
+                               if (index)
+                                       *index = (u16)i;
+                               ret = 0;
+                               goto found;
+                       }
+               }
+       }
+found:
+       read_unlock_irqrestore(&device->cache.lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_find_cached_gid);
+
+int ib_get_cached_pkey(struct ib_device *device,
+                      u8                port_num,
+                      int               index,
+                      u16              *pkey)
+{
+       struct ib_pkey_cache *cache;
+       unsigned long flags;
+       int ret = 0;
+
+       if (port_num < start_port(device) || port_num > end_port(device))
+               return -EINVAL;
+
+       read_lock_irqsave(&device->cache.lock, &flags);
+
+       cache = device->cache.pkey_cache[port_num - start_port(device)];
+
+       if (index < 0 || index >= cache->table_len)
+               ret = -EINVAL;
+       else
+               *pkey = cache->table[index];
+
+       read_unlock_irqrestore(&device->cache.lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_get_cached_pkey);
+
+int ib_find_cached_pkey(struct ib_device *device,
+                       u8                port_num,
+                       u16               pkey,
+                       u16              *index)
+{
+       struct ib_pkey_cache *cache;
+       unsigned long flags;
+       int i;
+       int ret = -ENOENT;
+
+       if (port_num < start_port(device) || port_num > end_port(device))
+               return -EINVAL;
+
+       read_lock_irqsave(&device->cache.lock, &flags);
+
+       cache = device->cache.pkey_cache[port_num - start_port(device)];
+
+       *index = (u16)-1;
+
+       for (i = 0; i < cache->table_len; ++i)
+               if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
+                       *index = (u16)i;
+                       ret = 0;
+                       break;
+               }
+
+       read_unlock_irqrestore(&device->cache.lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_find_cached_pkey);
+
+int ib_get_cached_lmc(struct ib_device *device,
+                     u8                port_num,
+                     u8                *lmc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (port_num < start_port(device) || port_num > end_port(device))
+               return -EINVAL;
+
+       read_lock_irqsave(&device->cache.lock, &flags);
+       *lmc = device->cache.lmc_cache[port_num - start_port(device)];
+       read_unlock_irqrestore(&device->cache.lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_get_cached_lmc);
+
+static void ib_cache_update(struct ib_device *device,
+                           u8                port)
+{
+       struct ib_port_attr       *tprops = NULL;
+       struct ib_pkey_cache      *pkey_cache = NULL, *old_pkey_cache;
+       struct ib_gid_cache       *gid_cache = NULL, *old_gid_cache;
+       int                        i;
+       int                        ret;
+
+       tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
+       if (!tprops)
+               return;
+
+       ret = ib_query_port(device, port, tprops);
+       if (ret) {
+               printk(KERN_WARNING "ib_query_port failed (%d) for %s\n",
+                      ret, device->name);
+               goto err;
+       }
+
+       pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len *
+                            sizeof *pkey_cache->table, GFP_KERNEL);
+       if (!pkey_cache)
+               goto err;
+
+       pkey_cache->table_len = tprops->pkey_tbl_len;
+
+       gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len *
+                           sizeof *gid_cache->table, GFP_KERNEL);
+       if (!gid_cache)
+               goto err;
+
+       gid_cache->table_len = tprops->gid_tbl_len;
+
+       for (i = 0; i < pkey_cache->table_len; ++i) {
+               ret = ib_query_pkey(device, port, (u16)i, pkey_cache->table + i);
+               if (ret) {
+                       printk(KERN_WARNING "ib_query_pkey failed (%d) for %s (index %d)\n",
+                              ret, device->name, i);
+                       goto err;
+               }
+       }
+
+       for (i = 0; i < gid_cache->table_len; ++i) {
+               ret = ib_query_gid(device, port, i, gid_cache->table + i);
+               if (ret) {
+                       printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n",
+                              ret, device->name, i);
+                       goto err;
+               }
+       }
+
+       write_lock_irq(&device->cache.lock);
+
+       old_pkey_cache = device->cache.pkey_cache[port - start_port(device)];
+       old_gid_cache  = device->cache.gid_cache [port - start_port(device)];
+
+       device->cache.pkey_cache[port - start_port(device)] = pkey_cache;
+       device->cache.gid_cache [port - start_port(device)] = gid_cache;
+
+       device->cache.lmc_cache[port - start_port(device)] = tprops->lmc;
+
+       write_unlock_irq(&device->cache.lock);
+
+       kfree(old_pkey_cache);
+       kfree(old_gid_cache);
+       kfree(tprops);
+       return;
+
+err:
+       kfree(pkey_cache);
+       kfree(gid_cache);
+       kfree(tprops);
+}
+
+static void ib_cache_task(void *work_ptr)
+{
+       struct ib_update_work *work = work_ptr;
+
+       ib_cache_update(work->device, work->port_num);
+}
+
+static void ib_work_item (
+       IN PDEVICE_OBJECT  DeviceObject,
+       IN PVOID  Context 
+       )
+{
+       struct ib_update_work *work = (struct ib_update_work *)Context;
+       UNREFERENCED_PARAMETER(DeviceObject);
+       ib_cache_task(Context);
+       shutter_loose( &work->device->cache.x.work_thread );
+       IoFreeWorkItem(work->work_item);
+       kfree(Context);
+}
+
+static void ib_cache_event(struct ib_event_handler *handler,
+                          struct ib_event *event)
+{
+       struct ib_update_work *work;
+
+       if (event->event == IB_EVENT_PORT_ERR    ||
+               event->event == IB_EVENT_PORT_ACTIVE ||
+               event->event == IB_EVENT_LID_CHANGE  ||
+               event->event == IB_EVENT_PKEY_CHANGE ||
+               event->event == IB_EVENT_SM_CHANGE   ||
+               event->event == IB_EVENT_CLIENT_REREGISTER) {
+
+               work = kmalloc(sizeof *work, GFP_ATOMIC);
+               if (work) {
+                       PDEVICE_OBJECT pdo = to_mdev(handler->device)->dev->pdev->p_self_do;
+
+                       // allocate work item
+                       work->work_item = IoAllocateWorkItem(pdo);
+                       if (work->work_item == NULL) {
+                               //TODO: at least - print error. Need to return code, but the function is void 
+                               kfree( work );
+                               return;
+                       }
+
+                       // check whether we are in shutdown
+                       if (shutter_use( &event->device->cache.x.work_thread ) <= 0) {
+                               kfree( work );
+                               return;
+                       }
+
+                       // schedule the work
+                       work->device   = event->device;
+                       work->port_num = event->element.port_num;
+                       IoQueueWorkItem( work->work_item, ib_work_item, DelayedWorkQueue, work );
+               }
+       }
+}
+
+static void ib_cache_setup_one(struct ib_device *device)
+{
+       int p;
+
+       rwlock_init(&device->cache.lock);
+
+       device->cache.pkey_cache =
+               kmalloc(sizeof *device->cache.pkey_cache *
+                       (end_port(device) - start_port(device) + 1), GFP_KERNEL);
+       device->cache.gid_cache =
+               kmalloc(sizeof *device->cache.gid_cache *
+                       (end_port(device) - start_port(device) + 1), GFP_KERNEL);
+
+       device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache *
+                                         (end_port(device) -
+                                          start_port(device) + 1),
+                                         GFP_KERNEL);
+
+       if (!device->cache.pkey_cache || !device->cache.gid_cache ||
+           !device->cache.lmc_cache) {
+               printk(KERN_WARNING "Couldn't allocate cache "
+                      "for %s\n", device->name);
+               goto err;
+       }
+
+       shutter_init( &device->cache.x.work_thread );
+
+       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+               device->cache.pkey_cache[p] = NULL;
+               device->cache.gid_cache [p] = NULL;
+               ib_cache_update(device, (u8)(p + start_port(device)));
+       }
+
+       INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
+                             device, ib_cache_event);
+       if (ib_register_event_handler(&device->cache.event_handler))
+               goto err_cache;
+
+       return;
+
+err_cache:
+       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+               kfree(device->cache.pkey_cache[p]);
+               kfree(device->cache.gid_cache[p]);
+       }
+
+err:
+       kfree(device->cache.pkey_cache);
+       kfree(device->cache.gid_cache);
+       kfree(device->cache.lmc_cache);
+}
+
+// calling sequence:
+// EvtReleaseHardware ==> mlx4_ib_cleanup ==> mlx4_unregister_interface ==>
+// ==> mlx4_remove_device ==> mlx4_ib_remove ==> ib_unregister_device ==>
+// ==> ib_cache_cleanup
+static void ib_cache_cleanup_one(struct ib_device *device)
+{
+       int p;
+
+       ib_unregister_event_handler(&device->cache.event_handler);
+       // instead of Linux flush_scheduled_work(): wait for them to quit
+       shutter_shut( &device->cache.x.work_thread );
+
+       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+               kfree(device->cache.pkey_cache[p]);
+               kfree(device->cache.gid_cache[p]);
+       }
+
+       kfree(device->cache.pkey_cache);
+       kfree(device->cache.gid_cache);
+       kfree(device->cache.lmc_cache);
+}
+
+static struct ib_client cache_client = { "cache", ib_cache_setup_one, ib_cache_cleanup_one };
+
+int __init ib_cache_setup(void)
+{
+       return ib_register_client(&cache_client);
+}
+
+void __exit ib_cache_cleanup(void)
+{
+       ib_unregister_client(&cache_client);
+}
diff --git a/hw/mlx4/kernel/bus/core/core.def b/hw/mlx4/kernel/bus/core/core.def
new file mode 100644 (file)
index 0000000..bfbb2f1
--- /dev/null
@@ -0,0 +1,64 @@
+LIBRARY        mlx4_core.lib\r
+\r
+EXPORTS\r
+; DllInitialize and DllUnload must be exported for the OS reference counting to\r
+; work, and must be private for the compiler to accept them.\r
+DllInitialize private\r
+DllUnload private\r
+\r
+; l2w.c\r
+pci_pool_create\r
+strlcpy\r
+__bitmap_full\r
+__bitmap_empty\r
+core_init\r
+core_cleanup\r
+\r
+; radix.c\r
+radix_tree_create\r
+radix_tree_insert\r
+radix_tree_lookup\r
+radix_tree_delete\r
+radix_tree_destroy\r
+\r
+; cache.c\r
+ib_get_cached_gid\r
+ib_find_cached_gid\r
+ib_get_cached_pkey\r
+ib_find_cached_pkey\r
+ib_get_cached_lmc\r
+\r
+; packer\r
+ib_pack\r
+ib_unpack\r
+\r
+; ud_header\r
+ib_ud_header_init\r
+ib_ud_header_pack\r
+ib_ud_header_unpack\r
+\r
+; device.c\r
+ib_alloc_device\r
+ib_dealloc_device\r
+ib_register_device\r
+ib_unregister_device\r
+ib_register_client\r
+ib_unregister_client\r
+ib_get_client_data\r
+ib_set_client_data\r
+ib_register_event_handler\r
+ib_unregister_event_handler\r
+ib_dispatch_event\r
+ib_query_device\r
+ib_query_port\r
+ib_query_gid\r
+ib_query_pkey\r
+ib_modify_device\r
+ib_modify_port\r
+ib_find_gid\r
+ib_find_pkey\r
+\r
+; verbs.c\r
+ib_modify_qp_is_ok\r
+ib_create_ah\r
+ib_destroy_ah
\ No newline at end of file
diff --git a/hw/mlx4/kernel/bus/core/core.h b/hw/mlx4/kernel/bus/core/core.h
new file mode 100644 (file)
index 0000000..ba5787b
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+int __init ib_cache_setup(void);
+
+void __exit ib_cache_cleanup(void);
+
+int __init ib_core_init(void);
+
+void __exit ib_core_cleanup(void);
+
+void init_qp_state_tbl();
+
diff --git a/hw/mlx4/kernel/bus/core/core.rc b/hw/mlx4/kernel/bus/core/core.rc
new file mode 100644 (file)
index 0000000..1d136d4
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id: ibal.rc 1611 2006-08-20 14:48:55Z sleybo $\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE                           VFT_DRV\r
+#define VER_FILESUBTYPE                                VFT2_UNKNOWN\r
+\r
+#ifdef _DEBUG_\r
+#define VER_FILEDESCRIPTION_STR                "MLX4 Upper Layer (Debug)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR                "MLX4 Upper Layer"\r
+#endif\r
+\r
+#define VER_INTERNALNAME_STR           "mlx4_core.lib"\r
+#define VER_ORIGINALFILENAME_STR       "mlx4_core.lib"\r
+\r
+#include <common.ver>\r
+\r
diff --git a/hw/mlx4/kernel/bus/core/device.c b/hw/mlx4/kernel/bus/core/device.c
new file mode 100644 (file)
index 0000000..63a9249
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: device.c 1349 2004-12-16 21:09:43Z roland $
+ */
+
+#if defined(EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "device.tmh"
+#endif
+
+#include "l2w.h"
+#include "ib_verbs.h"
+#include "core.h"
+
+struct ib_client_data {
+       struct list_head  list;
+       struct ib_client *client;
+       void *            data;
+};
+
+static LIST_HEAD(device_list);
+static LIST_HEAD(client_list);
+
+/*
+ * device_mutex protects access to both device_list and client_list.
+ * There's no real point to using multiple locks or something fancier
+ * like an rwsem: we always access both lists, and we're always
+ * modifying one list or the other list.  In any case this is not a
+ * hot path so there's no point in trying to optimize.
+ */
+static DEFINE_MUTEX(device_mutex);
+
+static int ib_device_check_mandatory(struct ib_device *device)
+{
+#define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device, x), #x }
+       static const struct {
+               size_t offset;
+               char  *name;
+       } mandatory_table[] = {
+               IB_MANDATORY_FUNC(query_device),
+               IB_MANDATORY_FUNC(query_port),
+               IB_MANDATORY_FUNC(query_pkey),
+               IB_MANDATORY_FUNC(query_gid),
+               IB_MANDATORY_FUNC(alloc_pd),
+               IB_MANDATORY_FUNC(dealloc_pd),
+               IB_MANDATORY_FUNC(create_ah),
+               IB_MANDATORY_FUNC(destroy_ah),
+               IB_MANDATORY_FUNC(create_qp),
+               IB_MANDATORY_FUNC(modify_qp),
+               IB_MANDATORY_FUNC(destroy_qp),
+               IB_MANDATORY_FUNC(post_send),
+               IB_MANDATORY_FUNC(post_recv),
+               IB_MANDATORY_FUNC(create_cq),
+               IB_MANDATORY_FUNC(destroy_cq),
+               IB_MANDATORY_FUNC(poll_cq),
+               IB_MANDATORY_FUNC(req_notify_cq),
+               IB_MANDATORY_FUNC(get_dma_mr),
+               IB_MANDATORY_FUNC(dereg_mr)
+       };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) {
+               if (!*(void **) ((u8 *) device + mandatory_table[i].offset)) {
+                       printk(KERN_WARNING "Device %s is missing mandatory function %s\n",
+                              device->name, mandatory_table[i].name);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static struct ib_device *__ib_device_get_by_name(const char *name)
+{
+       struct ib_device *device;
+
+       list_for_each_entry(device, &device_list, core_list, struct ib_device)
+               if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX))
+                       return device;
+
+       return NULL;
+}
+
+
+static int alloc_name(char *name)
+{
+       unsigned long *inuse;
+       char buf[IB_DEVICE_NAME_MAX];
+       struct ib_device *device;
+       int i;
+
+       inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL);
+       if (!inuse)
+               return -ENOMEM;
+
+       list_for_each_entry(device, &device_list, core_list, struct ib_device) {
+               if (!sscanf(device->name, name, &i))
+                       continue;
+               if (i < 0 || i >= PAGE_SIZE * 8)
+                       continue;
+               if (RtlStringCbPrintfA(buf, sizeof buf, name, i))
+                       return -EINVAL;
+               if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX))
+                       set_bit(i, inuse);
+       }
+
+       i = find_first_zero_bit(inuse, PAGE_SIZE * 8);
+       free_page(inuse);
+       if (RtlStringCbPrintfA(buf, sizeof buf, name, i))
+               return -EINVAL;
+
+       if (__ib_device_get_by_name(buf))
+               return -ENFILE;
+
+       strlcpy(name, buf, IB_DEVICE_NAME_MAX);
+       return 0;
+}
+
+static int start_port(struct ib_device *device)
+{
+       return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
+}
+
+
+static int end_port(struct ib_device *device)
+{
+       return (device->node_type == RDMA_NODE_IB_SWITCH) ?
+               0 : device->phys_port_cnt;
+}
+
+/**
+ * ib_alloc_device - allocate an IB device struct
+ * @size:size of structure to allocate
+ *
+ * Low-level drivers should use ib_alloc_device() to allocate &struct
+ * ib_device.  @size is the size of the structure to be allocated,
+ * including any private data used by the low-level driver.
+ * ib_dealloc_device() must be used to free structures allocated with
+ * ib_alloc_device().
+ */
+struct ib_device *ib_alloc_device(size_t size)
+{
+       BUG_ON(size < sizeof (struct ib_device));
+
+       return kzalloc(size, GFP_KERNEL);
+}
+EXPORT_SYMBOL(ib_alloc_device);
+
+/**
+ * ib_dealloc_device - free an IB device struct
+ * @device:structure to free
+ *
+ * Free a structure allocated with ib_alloc_device().
+ */
+void ib_dealloc_device(struct ib_device *device)
+{
+       if (device->reg_state == IB_DEV_UNINITIALIZED) {
+               kfree(device);
+               return;
+       }
+
+       BUG_ON(device->reg_state != IB_DEV_UNREGISTERED);
+
+}
+EXPORT_SYMBOL(ib_dealloc_device);
+
+static int add_client_context(struct ib_device *device, struct ib_client *client)
+{
+       struct ib_client_data *context;
+       unsigned long flags;
+
+       context = kmalloc(sizeof *context, GFP_KERNEL);
+       if (!context) {
+               printk(KERN_WARNING "Couldn't allocate client context for %s/%s\n",
+                      device->name, client->name);
+               return -ENOMEM;
+       }
+
+       context->client = client;
+       context->data   = NULL;
+
+       spin_lock_irqsave(&device->client_data_lock, &flags);
+       list_add(&context->list, &device->client_data_list);
+       spin_unlock_irqrestore(&device->client_data_lock, flags);
+
+       return 0;
+}
+
+static int read_port_table_lengths(struct ib_device *device)
+{
+       struct ib_port_attr *tprops = NULL;
+       int num_ports, ret = -ENOMEM;
+       u8 port_index;
+
+       tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
+       if (!tprops)
+               goto out;
+
+       num_ports = end_port(device) - start_port(device) + 1;
+
+       device->pkey_tbl_len = kmalloc(sizeof *device->pkey_tbl_len * num_ports,
+                                      GFP_KERNEL);
+       device->gid_tbl_len = kmalloc(sizeof *device->gid_tbl_len * num_ports,
+                                     GFP_KERNEL);
+       if (!device->pkey_tbl_len || !device->gid_tbl_len)
+               goto err;
+
+       for (port_index = 0; port_index < num_ports; ++port_index) {
+               ret = ib_query_port(device, (u8)(port_index + start_port(device)),
+                                       tprops);
+               if (ret)
+                       goto err;
+               device->pkey_tbl_len[port_index] = tprops->pkey_tbl_len;
+               device->gid_tbl_len[port_index]  = tprops->gid_tbl_len;
+       }
+
+       ret = 0;
+       goto out;
+
+err:
+       kfree(device->gid_tbl_len);
+       kfree(device->pkey_tbl_len);
+out:
+       kfree(tprops);
+       return ret;
+}
+
+/**
+ * ib_register_device - Register an IB device with IB core
+ * @device:Device to register
+ *
+ * Low-level drivers use ib_register_device() to register their
+ * devices with the IB core.  All registered clients will receive a
+ * callback for each device that is added. @device must be allocated
+ * with ib_alloc_device().
+ */
+int ib_register_device(struct ib_device *device)
+{
+       int ret;
+
+       mutex_lock(&device_mutex);
+
+       if (strchr(device->name, '%')) {
+               ret = alloc_name(device->name);
+               if (ret)
+                       goto out;
+       }
+
+       if (ib_device_check_mandatory(device)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&device->event_handler_list);
+       INIT_LIST_HEAD(&device->client_data_list);
+       spin_lock_init(&device->event_handler_lock);
+       spin_lock_init(&device->client_data_lock);
+
+       ret = read_port_table_lengths(device);
+       if (ret) {
+               printk(KERN_WARNING "Couldn't create table lengths cache for device %s\n",
+                      device->name);
+               goto out;
+       }
+
+       list_add_tail(&device->core_list, &device_list);
+
+       device->reg_state = IB_DEV_REGISTERED;
+
+       {
+               struct ib_client *client;
+
+               list_for_each_entry(client, &client_list, list, struct ib_client)
+                       if (client->add && !add_client_context(device, client))
+                               client->add(device);
+       }
+
+ out:
+       mutex_unlock(&device_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(ib_register_device);
+
+/**
+ * ib_unregister_device - Unregister an IB device
+ * @device:Device to unregister
+ *
+ * Unregister an IB device.  All clients will receive a remove callback.
+ */
+void ib_unregister_device(struct ib_device *device)
+{
+       struct ib_client *client;
+       struct ib_client_data *context, *tmp;
+       unsigned long flags;
+
+       mutex_lock(&device_mutex);
+
+       list_for_each_entry_reverse(client, &client_list, list, struct ib_client)
+               if (client->remove)
+                       client->remove(device);
+
+       list_del(&device->core_list);
+
+       kfree(device->gid_tbl_len);
+       kfree(device->pkey_tbl_len);
+
+       mutex_unlock(&device_mutex);
+
+       spin_lock_irqsave(&device->client_data_lock, &flags);
+       list_for_each_entry_safe(context, tmp, &device->client_data_list, list, struct ib_client_data, struct ib_client_data)
+               kfree(context);
+       spin_unlock_irqrestore(&device->client_data_lock, flags);
+
+       device->reg_state = IB_DEV_UNREGISTERED;
+}
+EXPORT_SYMBOL(ib_unregister_device);
+
+/**
+ * ib_register_client - Register an IB client
+ * @client:Client to register
+ *
+ * Upper level users of the IB drivers can use ib_register_client() to
+ * register callbacks for IB device addition and removal.  When an IB
+ * device is added, each registered client's add method will be called
+ * (in the order the clients were registered), and when a device is
+ * removed, each client's remove method will be called (in the reverse
+ * order that clients were registered).  In addition, when
+ * ib_register_client() is called, the client will receive an add
+ * callback for all devices already registered.
+ */
+int ib_register_client(struct ib_client *client)
+{
+       struct ib_device *device;
+
+       mutex_lock(&device_mutex);
+
+       list_add_tail(&client->list, &client_list);
+       list_for_each_entry(device, &device_list, core_list, struct ib_device)
+               if (client->add && !add_client_context(device, client))
+                       client->add(device);
+
+       mutex_unlock(&device_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(ib_register_client);
+
+/**
+ * ib_unregister_client - Unregister an IB client
+ * @client:Client to unregister
+ *
+ * Upper level users use ib_unregister_client() to remove their client
+ * registration.  When ib_unregister_client() is called, the client
+ * will receive a remove callback for each IB device still registered.
+ */
+void ib_unregister_client(struct ib_client *client)
+{
+       struct ib_client_data *context, *tmp;
+       struct ib_device *device;
+       unsigned long flags;
+
+       mutex_lock(&device_mutex);
+
+       list_for_each_entry(device, &device_list, core_list, struct ib_device) {
+               if (client->remove)
+                       client->remove(device);
+
+               spin_lock_irqsave(&device->client_data_lock, &flags);
+               list_for_each_entry_safe(context, tmp, &device->client_data_list, list, struct ib_client_data, struct ib_client_data)
+                       if (context->client == client) {
+                               list_del(&context->list);
+                               kfree(context);
+                       }
+               spin_unlock_irqrestore(&device->client_data_lock, flags);
+       }
+       list_del(&client->list);
+
+       mutex_unlock(&device_mutex);
+}
+EXPORT_SYMBOL(ib_unregister_client);
+
+/**
+ * ib_get_client_data - Get IB client context
+ * @device:Device to get context for
+ * @client:Client to get context for
+ *
+ * ib_get_client_data() returns client context set with
+ * ib_set_client_data().
+ */
+void *ib_get_client_data(struct ib_device *device, struct ib_client *client)
+{
+       struct ib_client_data *context;
+       void *ret = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&device->client_data_lock, &flags);
+       list_for_each_entry(context, &device->client_data_list, list, struct ib_client_data)
+               if (context->client == client) {
+                       ret = context->data;
+                       break;
+               }
+       spin_unlock_irqrestore(&device->client_data_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_get_client_data);
+
+/**
+ * ib_set_client_data - Set IB client context
+ * @device:Device to set context for
+ * @client:Client to set context for
+ * @data:Context to set
+ *
+ * ib_set_client_data() sets client context that can be retrieved with
+ * ib_get_client_data().
+ */
+void ib_set_client_data(struct ib_device *device, struct ib_client *client,
+                       void *data)
+{
+       struct ib_client_data *context;
+       unsigned long flags;
+
+       spin_lock_irqsave(&device->client_data_lock, &flags);
+       list_for_each_entry(context, &device->client_data_list, list, struct ib_client_data)
+               if (context->client == client) {
+                       context->data = data;
+                       goto out;
+               }
+
+       printk(KERN_WARNING "No client context found for %s/%s\n",
+              device->name, client->name);
+
+out:
+       spin_unlock_irqrestore(&device->client_data_lock, flags);
+}
+EXPORT_SYMBOL(ib_set_client_data);
+
+/**
+ * ib_register_event_handler - Register an IB event handler
+ * @event_handler:Handler to register
+ *
+ * ib_register_event_handler() registers an event handler that will be
+ * called back when asynchronous IB events occur (as defined in
+ * chapter 11 of the InfiniBand Architecture Specification).  This
+ * callback may occur in interrupt context.
+ */
+int ib_register_event_handler  (struct ib_event_handler *event_handler)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&event_handler->device->event_handler_lock, &flags);
+       list_add_tail(&event_handler->list,
+                     &event_handler->device->event_handler_list);
+       spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(ib_register_event_handler);
+
+/**
+ * ib_unregister_event_handler - Unregister an event handler
+ * @event_handler:Handler to unregister
+ *
+ * Unregister an event handler registered with
+ * ib_register_event_handler().
+ */
+int ib_unregister_event_handler(struct ib_event_handler *event_handler)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&event_handler->device->event_handler_lock, &flags);
+       list_del(&event_handler->list);
+       spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(ib_unregister_event_handler);
+
+/**
+ * ib_dispatch_event - Dispatch an asynchronous event
+ * @event:Event to dispatch
+ *
+ * Low-level drivers must call ib_dispatch_event() to dispatch the
+ * event to all registered event handlers when an asynchronous event
+ * occurs.
+ */
+void ib_dispatch_event(struct ib_event *event)
+{
+       unsigned long flags;
+       struct ib_event_handler *handler;
+
+       spin_lock_irqsave(&event->device->event_handler_lock, &flags);
+
+       list_for_each_entry(handler, &event->device->event_handler_list, list, struct ib_event_handler)
+               handler->handler(handler, event);
+
+       spin_unlock_irqrestore(&event->device->event_handler_lock, flags);
+}
+EXPORT_SYMBOL(ib_dispatch_event);
+
+/**
+ * ib_query_device - Query IB device attributes
+ * @device:Device to query
+ * @device_attr:Device attributes
+ *
+ * ib_query_device() returns the attributes of a device through the
+ * @device_attr pointer.
+ */
+int ib_query_device(struct ib_device *device,
+                   struct ib_device_attr *device_attr)
+{
+       return device->query_device(device, device_attr);
+}
+EXPORT_SYMBOL(ib_query_device);
+
+/**
+ * ib_query_port - Query IB port attributes
+ * @device:Device to query
+ * @port_num:Port number to query
+ * @port_attr:Port attributes
+ *
+ * ib_query_port() returns the attributes of a port through the
+ * @port_attr pointer.
+ */
+int ib_query_port(struct ib_device *device,
+                 u8 port_num,
+                 struct ib_port_attr *port_attr)
+{
+       if (port_num < start_port(device) || port_num > end_port(device))
+               return -EINVAL;
+
+       return device->query_port(device, port_num, port_attr);
+}
+EXPORT_SYMBOL(ib_query_port);
+
+/**
+ * ib_query_gid - Get GID table entry
+ * @device:Device to query
+ * @port_num:Port number to query
+ * @index:GID table index to query
+ * @gid:Returned GID
+ *
+ * ib_query_gid() fetches the specified GID table entry.
+ */
+int ib_query_gid(struct ib_device *device,
+                u8 port_num, int index, union ib_gid *gid)
+{
+       return device->query_gid(device, port_num, index, gid);
+}
+EXPORT_SYMBOL(ib_query_gid);
+
+/**
+ * ib_query_pkey - Get P_Key table entry
+ * @device:Device to query
+ * @port_num:Port number to query
+ * @index:P_Key table index to query
+ * @pkey:Returned P_Key
+ *
+ * ib_query_pkey() fetches the specified P_Key table entry.
+ */
+int ib_query_pkey(struct ib_device *device,
+                 u8 port_num, u16 index, u16 *pkey)
+{
+       return device->query_pkey(device, port_num, index, pkey);
+}
+EXPORT_SYMBOL(ib_query_pkey);
+
+/**
+ * ib_modify_device - Change IB device attributes
+ * @device:Device to modify
+ * @device_modify_mask:Mask of attributes to change
+ * @device_modify:New attribute values
+ *
+ * ib_modify_device() changes a device's attributes as specified by
+ * the @device_modify_mask and @device_modify structure.
+ */
+int ib_modify_device(struct ib_device *device,
+                    int device_modify_mask,
+                    struct ib_device_modify *device_modify)
+{
+       return device->modify_device(device, device_modify_mask,
+                                    device_modify);
+}
+EXPORT_SYMBOL(ib_modify_device);
+
+/**
+ * ib_modify_port - Modifies the attributes for the specified port.
+ * @device: The device to modify.
+ * @port_num: The number of the port to modify.
+ * @port_modify_mask: Mask used to specify which attributes of the port
+ *   to change.
+ * @port_modify: New attribute values for the port.
+ *
+ * ib_modify_port() changes a port's attributes as specified by the
+ * @port_modify_mask and @port_modify structure.
+ */
+int ib_modify_port(struct ib_device *device,
+                  u8 port_num, int port_modify_mask,
+                  struct ib_port_modify *port_modify)
+{
+       if (port_num < start_port(device) || port_num > end_port(device))
+               return -EINVAL;
+
+       return device->modify_port(device, port_num, port_modify_mask,
+                                  port_modify);
+}
+EXPORT_SYMBOL(ib_modify_port);
+
+/**
+ * ib_find_gid - Returns the port number and GID table index where
+ *   a specified GID value occurs.
+ * @device: The device to query.
+ * @gid: The GID value to search for.
+ * @port_num: The port number of the device where the GID value was found.
+ * @index: The index into the GID table where the GID was found.  This
+ *   parameter may be NULL.
+ */
+int ib_find_gid(struct ib_device *device, union ib_gid *gid,
+               u8 *port_num, u16 *index)
+{
+       union ib_gid tmp_gid;
+       int ret, port, i;
+
+       for (port = start_port(device); port <= end_port(device); ++port) {
+               for (i = 0; i < device->gid_tbl_len[port - start_port(device)]; ++i) {
+                       ret = ib_query_gid(device, (u8)port, i, &tmp_gid);
+                       if (ret)
+                               return ret;
+                       if (!memcmp(&tmp_gid, gid, sizeof *gid)) {
+                               *port_num = (u8)port;
+                               if (index)
+                                       *index = (u16)i;
+                               return 0;
+                       }
+               }
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(ib_find_gid);
+
+/**
+ * ib_find_pkey - Returns the PKey table index where a specified
+ *   PKey value occurs.
+ * @device: The device to query.
+ * @port_num: The port number of the device to search for the PKey.
+ * @pkey: The PKey value to search for.
+ * @index: The index into the PKey table where the PKey was found.
+ */
+int ib_find_pkey(struct ib_device *device,
+                u8 port_num, u16 pkey, u16 *index)
+{
+       int ret, i;
+       u16 tmp_pkey;
+
+       for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) {
+               ret = ib_query_pkey(device, port_num, (u16)i, &tmp_pkey);
+               if (ret)
+                       return ret;
+
+               if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) {
+                       *index = (u16)i;
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(ib_find_pkey);
+
+int __init ib_core_init(void)
+{
+       int ret;
+
+       mutex_init(&device_mutex);
+       ret = ib_cache_setup();
+       if (ret) {
+               printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n");
+       }
+
+       return ret;
+}
+
+void __exit ib_core_cleanup(void)
+{
+       ib_cache_cleanup();
+       /* Make sure that any pending umem accounting work is done. */
+       // TODO: how to do that ?
+       // LINUX: flush_scheduled_work();
+}
+
diff --git a/hw/mlx4/kernel/bus/core/ev_log.mc b/hw/mlx4/kernel/bus/core/ev_log.mc
new file mode 100644 (file)
index 0000000..7eb7f3a
--- /dev/null
@@ -0,0 +1,56 @@
+;/*++\r
+;=============================================================================\r
+;Copyright (c) 2007 Mellanox Technologies\r
+;\r
+;Module Name:\r
+;\r
+;    ev_log.mc\r
+;\r
+;Abstract:\r
+;\r
+;    MLX4 Driver event log messages\r
+;\r
+;Authors:\r
+;\r
+;    Leonid Keller\r
+;\r
+;Environment:\r
+;\r
+;   Kernel Mode .\r
+;\r
+;=============================================================================\r
+;--*/\r
+;\r
+MessageIdTypedef = NTSTATUS\r
+\r
+SeverityNames = (\r
+       Success                 = 0x0:STATUS_SEVERITY_SUCCESS\r
+       Informational   = 0x1:STATUS_SEVERITY_INFORMATIONAL\r
+       Warning                 = 0x2:STATUS_SEVERITY_WARNING\r
+       Error                   = 0x3:STATUS_SEVERITY_ERROR\r
+       )\r
+\r
+FacilityNames = (\r
+       System                  = 0x0\r
+       RpcRuntime              = 0x2:FACILITY_RPC_RUNTIME\r
+       RpcStubs                = 0x3:FACILITY_RPC_STUBS\r
+       Io                              = 0x4:FACILITY_IO_ERROR_CODE\r
+       MLX4                    = 0x8:FACILITY_MLX4_ERROR_CODE\r
+       )\r
+\r
+\r
+MessageId=0x0001 Facility=MLX4 Severity=Informational SymbolicName=EVENT_MLX4_ANY_INFO\r
+Language=English\r
+%2\r
+.\r
+\r
+MessageId=0x0002 Facility=MLX4 Severity=Warning SymbolicName=EVENT_MLX4_ANY_WARN\r
+Language=English\r
+%2\r
+.\r
+\r
+MessageId=0x0003 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ANY_ERROR\r
+Language=English\r
+%2\r
+.\r
+\r
diff --git a/hw/mlx4/kernel/bus/core/iobuf.c b/hw/mlx4/kernel/bus/core/iobuf.c
new file mode 100644 (file)
index 0000000..bc39763
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mt_memory.c 2020 2007-05-01 09:29:10Z leonid $
+ */
+#include "l2w.h"
+#include "pa_cash.h"
+#include "ib_verbs.h"
+
+#if defined (EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "iobuf.tmh"
+#endif 
+
+
+
+
+/*
+*      Function: map user buffer to kernel and lock it
+*
+*      Return: 
+*/
+int get_user_pages(
+       IN              struct mlx4_dev *dev,   /* device */
+       IN              u64 start,                                                      /* address in user space */
+       IN              int npages,                                             /* size in pages */
+       IN              int write_access,                               /* access rights */
+       OUT     struct scatterlist *sg                  /* s/g list */
+       )
+{
+       PMDL mdl_p;
+       int size = npages << PAGE_SHIFT;
+       int access = (write_access) ? IoWriteAccess : IoReadAccess;
+       int err;
+       void * kva;     /* kernel virtual address */
+
+       UNREFERENCED_PARAMETER(dev);
+       
+       MLX4_ENTER(MLX4_DBG_MEMORY);
+       ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+       
+       /* allocate MDL */
+       mdl_p = IoAllocateMdl( (PVOID)(ULONG_PTR)start, (ULONG)size, 
+               FALSE,
+               FALSE,          /* not charge quota */
+               NULL);
+       if (mdl_p == NULL) {
+               err = -ENOMEM;  
+               goto err0;
+       }
+
+       /* lock memory */
+       __try   {       
+               MmProbeAndLockPages( mdl_p, UserMode,   access ); 
+       } 
+       __except (EXCEPTION_EXECUTE_HANDLER)
+       {
+               NTSTATUS Status = GetExceptionCode();
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,("Exception 0x%x on MmProbeAndLockPages(), addr 0x%I64x, size %d\n", Status, start, size));
+               switch(Status){
+                       case STATUS_WORKING_SET_QUOTA:
+                               err = -ENOMEM;break;
+                       case STATUS_ACCESS_VIOLATION:
+                               err = -EACCES;break;
+                       default :
+                               err = -EINVAL;
+                       }
+
+               goto err1;
+       }
+
+       /* map it to kernel */
+       kva = MmMapLockedPagesSpecifyCache( mdl_p, 
+               KernelMode, MmNonCached, 
+               NULL, FALSE, NormalPagePriority );
+       if (kva == NULL) {
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,("MmMapLockedPagesSpecifyCache failed\n"));
+               err = -EFAULT;
+               goto err2;
+       }
+
+       sg->dma_addr.va = kva;
+       sg->dma_addr.sz = size;
+       sg->offset = (unsigned int)(start & ~PAGE_MASK);
+       sg->p_mdl = mdl_p;      
+       // TODO: has to be dma address, not physical one
+       sg->dma_addr.da = MmGetPhysicalAddress(kva).QuadPart;
+       return 0;       
+       
+err2:  
+       MmUnlockPages(mdl_p);
+err1:          
+       IoFreeMdl(mdl_p);
+err0:
+       MLX4_EXIT(MLX4_DBG_MEMORY);
+       return err;
+               
+ }
+
+void put_page(struct scatterlist *sg)
+{
+       if (sg->p_mdl) {
+               MmUnmapLockedPages( sg->dma_addr.va, sg->p_mdl );
+               MmUnlockPages(sg->p_mdl);
+               IoFreeMdl(sg->p_mdl);
+       }
+}
+
+
+typedef struct _iobuf_seg {
+       LIST_ENTRY      link;
+       PMDL   mdl_p;
+       u64 va;  /* virtual address of the buffer */
+       u64 size;     /* size in bytes of the buffer */
+       u32 nr_pages;
+       int     is_user;
+} iobuf_seg_t;
+
+// Returns: 0 on success, -ENOMEM or -EACCESS on error
+static int register_segment(
+       IN              u64 va,
+       IN              u64 size,
+       IN              int is_user,
+       IN              ib_access_t acc,
+       OUT iobuf_seg_t **iobuf_seg)
+{
+       PMDL mdl_p;
+       int rc;
+       KPROCESSOR_MODE mode;  
+       iobuf_seg_t * new_iobuf;
+       static ULONG cnt=0;
+       LOCK_OPERATION Operation;
+
+       // set Operation
+       if (acc & IB_AC_LOCAL_WRITE)
+               Operation = IoModifyAccess;
+       else
+               Operation = IoReadAccess;
+       
+       // allocate IOBUF segment object
+       new_iobuf = (iobuf_seg_t *)kmalloc(sizeof(iobuf_seg_t), GFP_KERNEL );
+       if (new_iobuf == NULL) {
+               rc = -ENOMEM;
+               goto err_nomem;
+       }
+
+       // allocate MDL 
+       mdl_p = IoAllocateMdl( (PVOID)(ULONG_PTR)va, (ULONG)size, FALSE,FALSE,NULL);
+       if (mdl_p == NULL) {
+               rc = -ENOMEM;
+               goto err_alloc_mdl;
+       }
+
+       // make context-dependent things
+       if (is_user) {
+               ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+               mode = UserMode;
+       }
+       else {  /* Mapping to kernel virtual address */
+               //    MmBuildMdlForNonPagedPool(mdl_p);   // fill MDL ??? - should we do that really ?
+               mode = KernelMode;
+       }
+
+       __try { /* try */
+               MmProbeAndLockPages( mdl_p, mode, Operation );   /* lock memory */
+       } /* try */
+               
+       __except (EXCEPTION_EXECUTE_HANDLER)    {
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_MEMORY, 
+                       ("MOSAL_iobuf_register: Exception 0x%x on MmProbeAndLockPages(), va %I64d, sz %I64d\n", 
+                       GetExceptionCode(), va, size));
+               rc = -EACCES;
+               goto err_probe;
+       }
+       
+       // fill IOBUF object
+       new_iobuf->va = va;
+       new_iobuf->size= size;
+       new_iobuf->nr_pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( va, size );
+       new_iobuf->mdl_p = mdl_p;
+       new_iobuf->is_user = is_user;
+       *iobuf_seg = new_iobuf;
+       return 0;
+
+err_probe:
+       IoFreeMdl(mdl_p);
+err_alloc_mdl:  
+       ExFreePool((PVOID)new_iobuf);
+err_nomem:  
+       return rc;
+}
+
+void iobuf_init(
+       IN              u64 va,
+       IN              u64 size,
+       IN              int is_user,
+       IN OUT  iobuf_t *iobuf_p)
+{
+       iobuf_p->va = va;
+       iobuf_p->size= size;
+       iobuf_p->is_user = is_user;
+       InitializeListHead( &iobuf_p->seg_que );
+       iobuf_p->seg_num = 0;
+       iobuf_p->nr_pages = 0;
+       iobuf_p->is_cashed = 0;
+}
+
+int iobuf_register(
+       IN              u64 va,
+       IN              u64 size,
+       IN              int is_user,
+       IN              enum ib_access_flags acc,
+       IN OUT  iobuf_t *iobuf_p)
+{
+       int rc=0;
+       u64 seg_va;     // current segment start
+       u64 seg_size;   // current segment size
+       u64 rdc;                        // remain data counter - what is rest to lock
+       u64 delta;                              // he size of the last not full page of the first segment
+       iobuf_seg_t * new_iobuf;
+       unsigned page_size = PAGE_SIZE;
+
+// 32 - for any case  
+#define PFNS_IN_PAGE_SIZE_MDL          ((PAGE_SIZE - sizeof(struct _MDL) - 32) / sizeof(long))
+#define MIN_IOBUF_SEGMENT_SIZE (PAGE_SIZE * PFNS_IN_PAGE_SIZE_MDL)     // 4MB  
+
+       ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+
+       // we'll try to register all at once.
+       seg_va = va;
+       seg_size = rdc = size;
+               
+       // allocate segments
+       while (rdc > 0) {
+               // map a segment
+               rc = register_segment(seg_va, seg_size, is_user, acc, &new_iobuf );
+
+               // success - move to another segment
+               if (!rc) {
+                       rdc -= seg_size;
+                       seg_va += seg_size;
+                       InsertTailList( &iobuf_p->seg_que, &new_iobuf->link );
+                       iobuf_p->seg_num++;
+                       // round the segment size to the next page boundary 
+                       delta = (seg_va + seg_size) & (page_size - 1);
+                       if (delta) {
+                               seg_size -= delta;
+                               seg_size += page_size;
+                       }
+                       if (seg_size > rdc)
+                               seg_size = rdc;
+                       continue;
+               }
+
+               // failure - too large a buffer: lessen it and try once more
+               if (rc == -ENOMEM) {
+                       // no where to lessen - too low memory
+                       if (seg_size <= MIN_IOBUF_SEGMENT_SIZE)
+                               break;
+                       // lessen the size
+                       seg_size >>= 1;
+                       // round the segment size to the next page boundary 
+                       delta = (seg_va + seg_size) & (page_size - 1);
+                       if (delta) {
+                               seg_size -= delta;
+                               seg_size += page_size;
+                       }
+                       if (seg_size > rdc)
+                               seg_size = rdc;
+                       continue;
+               }
+
+               // got unrecoverable error
+               break;
+       }
+
+       // SUCCESS
+       if (rc) 
+               iobuf_deregister( iobuf_p );
+       else     
+               iobuf_p->nr_pages += ADDRESS_AND_SIZE_TO_SPAN_PAGES( va, size );
+
+       return rc;
+}
+
+
+static void __iobuf_copy(
+       IN OUT  iobuf_t *dst_iobuf_p,
+       IN              iobuf_t *src_iobuf_p
+       )
+{
+       int i;
+       iobuf_seg_t *iobuf_seg_p;
+       
+       *dst_iobuf_p = *src_iobuf_p;
+       InitializeListHead( &dst_iobuf_p->seg_que );
+       for (i=0; i<src_iobuf_p->seg_num; ++i) {
+               iobuf_seg_p = (iobuf_seg_t *)(PVOID)RemoveHeadList( &src_iobuf_p->seg_que );
+               InsertTailList( &dst_iobuf_p->seg_que, &iobuf_seg_p->link );
+       }
+}
+
+/* if the buffer to be registered overlaps a buffer, already registered, 
+       a race can happen between HCA, writing to the previously registered
+       buffer and the probing functions (MmProbeAndLockPages, MmSecureVirtualMemory),
+       used in the algorithm of memory registration.
+       To prevent the race we maintain reference counters for the physical pages, being registered, 
+       and register every physical page FOR THE WRITE ACCESS only once.*/
+
+int iobuf_register_with_cash(
+       IN              u64 vaddr,
+       IN              u64 size,
+       IN              int is_user,
+       IN OUT  enum ib_access_flags *acc_p,
+       IN OUT  iobuf_t *iobuf_p)
+{
+       int rc, pa_in;
+       iobuf_t sec_iobuf;
+       int i, page_in , page_out, page_in_total;
+       int nr_pages;
+       char *subregion_start, *va;
+       u64 subregion_size;
+       u64 rdc;                                        // remain data counter - what is rest to lock
+       u64 delta;                              // he size of the last not full page of the first segment
+       enum ib_access_flags acc;
+
+       mutex_lock(&g_pa_mutex);
+
+       // register memory for read access to bring pages into the memory
+       rc = iobuf_register( vaddr, size, is_user, 0, iobuf_p);
+
+       // on error or read access - exit
+       if (rc || !(*acc_p & IB_ACCESS_LOCAL_WRITE))
+               goto exit;
+
+       // re-register buffer with the correct access rights
+       iobuf_init( (u64)vaddr, size, is_user, &sec_iobuf );
+       nr_pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( vaddr, size );
+       subregion_start = va = (char*)(ULONG_PTR)vaddr;
+       rdc = size;
+       pa_in = page_in = page_in_total = page_out = 0;
+
+       for (i=0; i<nr_pages; ++i, va+=PAGE_SIZE) {
+               // check whether a phys page is to be registered
+               PHYSICAL_ADDRESS pa = MmGetPhysicalAddress(va);
+               pa_in = pa_is_registered(pa.QuadPart);
+               if (pa_in) {
+                       ++page_in;
+                       ++page_in_total;
+               }
+               else
+                       ++page_out;
+
+               // check whether we get at the end of a subregion with the same rights wrt cash
+               if (page_in && page_out) {
+                       // prepare to registration of the subregion
+                       if (pa_in) {            // SUBREGION WITH WRITE ACCESS
+                               acc = IB_ACCESS_LOCAL_WRITE;
+                               subregion_size = (u64)page_out * PAGE_SIZE;
+                               page_out = 0;
+                       }
+                       else {          // SUBREGION WITH READ ACCESS
+                               acc = 0;
+                               subregion_size = (u64)page_in * PAGE_SIZE;
+                               page_in = 0;
+                       }
+                       
+                       // round the subregion size to the page boundary 
+                       delta = (u64)(subregion_start + subregion_size) & (PAGE_SIZE - 1);
+                       subregion_size -= delta;
+                       if (subregion_size > rdc)
+                               subregion_size = rdc;
+
+                       // register the subregion
+                       rc = iobuf_register( (u64)subregion_start, subregion_size, is_user, acc, &sec_iobuf);
+                       if (rc)
+                               goto cleanup;
+
+                       // prepare to the next loop
+                       rdc -= subregion_size;
+                       subregion_start +=subregion_size;
+               }
+       }
+
+       // prepare to registration of the subregion
+       if (pa_in) {            // SUBREGION WITH READ ACCESS
+               acc = 0;
+               subregion_size = (u64)page_in * PAGE_SIZE;
+       }
+       else {          // SUBREGION WITH WRITE ACCESS
+               acc = IB_ACCESS_LOCAL_WRITE;
+               subregion_size = (u64)page_out * PAGE_SIZE;
+       }
+       
+       // round the subregion size to the page boundary 
+       delta = (u64)(subregion_start + subregion_size) & (PAGE_SIZE - 1);
+       subregion_size -= delta;
+       if (subregion_size > rdc)
+               subregion_size = rdc;
+       
+       // register the subregion
+       rc = iobuf_register( (u64)subregion_start, subregion_size, is_user, acc, &sec_iobuf);
+       if (rc)
+               goto cleanup;
+
+       // cash phys pages
+       rc = pa_register(iobuf_p);
+       if (rc)
+               goto err_pa_reg;
+
+       // replace the iobuf
+       iobuf_deregister( iobuf_p );
+       sec_iobuf.is_cashed = TRUE;
+       __iobuf_copy( iobuf_p, &sec_iobuf );
+       
+       // buffer is a part of also registered buffer - change the rights 
+       if (page_in_total)
+               *acc_p &= ~IB_ACCESS_LOCAL_WRITE;
+
+       goto exit;
+       
+err_pa_reg:    
+       iobuf_deregister( &sec_iobuf );
+cleanup:
+       iobuf_deregister( iobuf_p );
+exit:  
+       mutex_unlock(&g_pa_mutex);
+       return rc;
+}
+
+static void deregister_segment(iobuf_seg_t * iobuf_seg_p)
+{
+       MmUnlockPages( iobuf_seg_p->mdl_p );    // unlock the buffer 
+       IoFreeMdl( iobuf_seg_p->mdl_p );        // free MDL
+       ExFreePool(iobuf_seg_p);
+}
+
+void iobuf_deregister(iobuf_t *iobuf_p)
+{
+       iobuf_seg_t *iobuf_seg_p;       // pointer to current segment object
+
+       ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+
+       // release segments
+       while (!IsListEmpty( &iobuf_p->seg_que )) {
+               iobuf_seg_p = (iobuf_seg_t *)(PVOID)RemoveTailList( &iobuf_p->seg_que );
+               deregister_segment(iobuf_seg_p);
+               iobuf_p->seg_num--;
+       }
+       ASSERT(iobuf_p->seg_num == 0);
+}
+
+void iobuf_deregister_with_cash(iobuf_t *iobuf_p)
+{
+       ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+       mutex_lock(&g_pa_mutex);
+       if (iobuf_p->is_cashed)
+               pa_deregister(iobuf_p);
+       iobuf_deregister(iobuf_p);
+       mutex_unlock(&g_pa_mutex);
+}
+
+void iobuf_iter_init(
+       IN              iobuf_t *iobuf_p, 
+       IN OUT  iobuf_iter_t *iterator_p)
+{
+       iterator_p->seg_p = iobuf_p->seg_que.Flink;
+       iterator_p->pfn_ix = 0;
+}
+
+// the function returns phys addresses of the pages, also for the first page
+// if one wants to get the phys address of the buffer, one has to 
+// add the offset from the start of the page to the first phys address
+// Returns: the number of entries, filled in page_tbl_p
+// Returns 0  while at the end of list.
+uint32_t iobuf_get_tpt_seg(
+       IN              iobuf_t *iobuf_p, 
+       IN OUT  iobuf_iter_t *iterator_p,
+       IN              uint32_t n_pages_in, 
+       IN OUT  uint64_t *page_tbl_p )
+{
+       uint32_t i=0;   // has to be initialized here for a premature exit
+       iobuf_seg_t *seg_p;     // pointer to current segment object 
+       PPFN_NUMBER     pfn_p; 
+       uint32_t        pfn_ix; // index of PFN in PFN array of the current segment
+       uint64_t *pa_buf_p = page_tbl_p;
+
+       // prepare to the loop
+       seg_p = iterator_p->seg_p;      // first segment of the first iobuf
+       pfn_ix= iterator_p->pfn_ix;
+
+       // check, whether we at the end of the list
+       if ((PVOID)seg_p == (PVOID)&iobuf_p->seg_que)
+               goto exit;
+       pfn_p = MmGetMdlPfnArray( seg_p->mdl_p ) + pfn_ix;
+
+       // pass along all the PFN arrays
+       for (; i < n_pages_in; i++, pa_buf_p++) {
+               // convert PFN to the physical address
+               *pa_buf_p = (uint64_t)*pfn_p++ << PAGE_SHIFT;
+       
+               // get to the next PFN 
+               if (++pfn_ix >= seg_p->nr_pages) {
+                       seg_p = (iobuf_seg_t*)seg_p->link.Flink;
+                       pfn_ix = 0;
+                       if ((PVOID)seg_p == (PVOID)&iobuf_p->seg_que) {
+                               i++;
+                               break;
+                       }
+                       pfn_p = MmGetMdlPfnArray( seg_p->mdl_p );
+               }
+       }
+
+exit:
+       iterator_p->seg_p = seg_p;
+       iterator_p->pfn_ix = pfn_ix;
+       return i;
+}
+
+
diff --git a/hw/mlx4/kernel/bus/core/l2w.c b/hw/mlx4/kernel/bus/core/l2w.c
new file mode 100644 (file)
index 0000000..f794495
--- /dev/null
@@ -0,0 +1,326 @@
+#include "l2w.h"
+#include "core.h"
+#include "pa_cash.h"
+#include "mlx4.h"
+
+/* Nth element of the table contains the index of the first set bit of N; 8 - for N=0 */
+char g_set_bit_tbl[256];
+
+/* Nth element of the table contains the index of the first 0 bit of N; 8 - for N=255 */
+char g_clr_bit_tbl[256];
+
+/* interval for a cmd go-bit waiting */
+// TODO: not clear what is to be this value:
+// 1. it has to be enough great, so as the tread will go waiting;
+// 2. it has to be enough small, so as there is no too large waiting after first command try;
+// 3. it has to be enough great, so as not to cause to intensive rescheduling;
+#define CMD_WAIT_USECS                 2
+#define CMD_WAIT_INTERVAL              ((-10) * CMD_WAIT_USECS)
+LARGE_INTEGER g_cmd_interval = { (ULONG)CMD_WAIT_INTERVAL, 0 };
+
+////////////////////////////////////////////////////////
+//
+// PCI POOL 
+//
+////////////////////////////////////////////////////////
+
+pci_pool_t *
+pci_pool_create (const char *name, struct pci_dev *pdev,
+       size_t size, size_t align, size_t allocation)
+{
+       pci_pool_t *pool;
+       UNREFERENCED_PARAMETER(align);
+       UNREFERENCED_PARAMETER(allocation);
+
+       ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+       
+       // allocation parameter is not handled yet
+       ASSERT(allocation == 0);
+
+       //TODO: not absolutely correct: Linux's pci_pool_alloc provides contiguous physical memory,
+       // while default alloc function  - ExAllocatePoolWithTag -doesn't.
+       // But for now it is used for elements of size <= PAGE_SIZE
+       // Anyway - a sanity check:
+       ASSERT(size <= PAGE_SIZE);
+       if (size > PAGE_SIZE)
+               return NULL;
+
+       // allocate object
+       pool = (pci_pool_t *)ExAllocatePoolWithTag( NonPagedPool, sizeof(pci_pool_t), MT_TAG_PCIPOOL );
+       if (pool == NULL) 
+               return NULL;
+
+       //TODO: not too effective: one can read its own alloc/free functions
+       ExInitializeNPagedLookasideList( &pool->pool_hdr, NULL, NULL, 0, size, MT_TAG_PCIPOOL, 0 );
+       
+       // fill the object
+       pool->mdev = pdev->dev;
+       pool->size = size;
+       strncpy( pool->name, name, sizeof pool->name );
+
+       return pool;            
+}
+
+
+////////////////////////////////////////////////////////
+//
+// BIT TECHNIQUES 
+//
+////////////////////////////////////////////////////////
+
+void fill_bit_tbls()
+{      
+       unsigned long i;
+       for (i=0; i<256; ++i) {
+               g_set_bit_tbl[i] = (char)(_ffs_raw(&i,0) - 1);
+               g_clr_bit_tbl[i] = (char)(_ffz_raw(&i,0) - 1);
+       }
+       g_set_bit_tbl[0] = g_clr_bit_tbl[255] = 8;
+}
+
+
+////////////////////////////////////////////////////////
+//
+// BIT MAPS
+//
+////////////////////////////////////////////////////////
+
+int __bitmap_full(const unsigned long *bitmap, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (~bitmap[k])
+               return 0;
+
+       if (bits % BITS_PER_LONG)
+               if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
+               return 0;
+
+       return 1;
+}
+
+int __bitmap_empty(const unsigned long *bitmap, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (bitmap[k])
+                       return 0;
+
+       if (bits % BITS_PER_LONG)
+               if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
+                       return 0;
+
+       return 1;
+}
+
+
+////////////////////////////////////////////////////////
+//
+// DEBUG PRINT
+//
+////////////////////////////////////////////////////////
+
+VOID
+WriteEventLogEntry(
+       PVOID   pi_pIoObject,
+       ULONG   pi_ErrorCode,
+       ULONG   pi_UniqueErrorCode,
+       ULONG   pi_FinalStatus,
+       ULONG   pi_nDataItems,
+       ...
+       )
+/*++
+
+Routine Description:
+    Writes an event log entry to the event log.
+
+Arguments:
+
+       pi_pIoObject......... The IO object ( driver object or device object ).
+       pi_ErrorCode......... The error code.
+       pi_UniqueErrorCode... A specific error code.
+       pi_FinalStatus....... The final status.
+       pi_nDataItems........ Number of data items.
+       .
+       . data items values
+       .
+
+Return Value:
+
+       None .
+
+--*/
+{ /* WriteEventLogEntry */
+
+       /* Variable argument list */    
+       va_list                                 l_Argptr;
+       /* Pointer to an error log entry */
+       PIO_ERROR_LOG_PACKET    l_pErrorLogEntry; 
+
+       /* Init the variable argument list */   
+       va_start(l_Argptr, pi_nDataItems);
+
+       /* Allocate an error log entry */ 
+       l_pErrorLogEntry = 
+       (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+                                                               pi_pIoObject,
+                                                               (UCHAR)(sizeof(IO_ERROR_LOG_PACKET)+pi_nDataItems*sizeof(ULONG))
+                                                               ); 
+       /* Check allocation */
+       if ( l_pErrorLogEntry != NULL) 
+       { /* OK */
+
+               /* Data item index */
+               USHORT l_nDataItem ;
+
+               /* Set the error log entry header */
+               l_pErrorLogEntry->ErrorCode                     = pi_ErrorCode; 
+               l_pErrorLogEntry->DumpDataSize          = (USHORT) (pi_nDataItems*sizeof(ULONG)); 
+               l_pErrorLogEntry->SequenceNumber        = 0; 
+               l_pErrorLogEntry->MajorFunctionCode = 0; 
+               l_pErrorLogEntry->IoControlCode         = 0; 
+               l_pErrorLogEntry->RetryCount            = 0; 
+               l_pErrorLogEntry->UniqueErrorValue      = pi_UniqueErrorCode; 
+               l_pErrorLogEntry->FinalStatus           = pi_FinalStatus; 
+
+               /* Insert the data items */
+               for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) 
+               { /* Inset a data item */
+
+                       /* Current data item */
+                       int l_CurDataItem ;
+                               
+                       /* Get next data item */
+                       l_CurDataItem = va_arg( l_Argptr, int);
+
+                       /* Put it into the data array */
+                       l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ;
+
+               } /* Inset a data item */
+
+               /* Write the packet */
+               IoWriteErrorLogEntry(l_pErrorLogEntry);
+
+       } /* OK */
+
+       /* Term the variable argument list */   
+       va_end(l_Argptr);
+
+} /* WriteEventLogEntry */
+
+
+////////////////////////////////////////////////////////
+//
+// GENERAL 
+//
+////////////////////////////////////////////////////////
+
+// from lib/string.c
+/**
+* strlcpy - Copy a %NUL terminated string into a sized buffer
+* @dest: Where to copy the string to
+* @src: Where to copy the string from
+* @size: size of destination buffer
+*
+* Compatible with *BSD: the result is always a valid
+* NUL-terminated string that fits in the buffer (unless,
+* of course, the buffer size is zero). It does not pad
+* out the result like strncpy() does.
+*/
+SIZE_T strlcpy(char *dest, const void *src, SIZE_T size)
+{
+       SIZE_T ret = strlen(src);
+
+       if (size) {
+               SIZE_T len = (ret >= size) ? size-1 : ret;
+               memcpy(dest, src, len);
+               dest[len] = '\0';
+       }
+       return ret;
+}
+
+int core_init()
+{
+       int err;
+       
+       fill_bit_tbls();
+       init_qp_state_tbl();
+       err =  ib_core_init();
+       if (err)
+               return err;
+       return pa_cash_init();
+}
+
+void core_cleanup()
+{
+       ib_core_cleanup();
+       pa_cash_release();
+}
+
+#ifdef USE_WDM_INTERRUPTS
+
+// TODO: put into Globals
+uint32_t g_processor_affinity = 0;
+
+int request_irq(
+       IN              struct mlx4_dev *       dev,            
+       IN              ULONG                           vector,         /* interrupt or MSI-X vector */
+       IN              PKSERVICE_ROUTINE       isr,            /* ISR */
+       IN              PVOID                           isr_ctx,        /* ISR context */
+       IN              dpc_t                           dpc,
+       IN              PVOID                           dpc_ctx,        /* ISR context */
+       OUT             PKINTERRUPT             *       int_obj         /* interrupt object */
+       )
+{
+       int i;
+       NTSTATUS status;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct pci_dev *pdev = dev->pdev;               /* interrupt resources */
+
+#ifdef CONFIG_PCI_MSI
+       // TODO: for MSI interrupts one needs to use new API
+#if (NTDDI_VERSION >= NTDDI_LONGHORN)
+       NTKERNELAPI
+       NTSTATUS
+       IoConnectInterruptEx (
+               __inout PIO_CONNECT_INTERRUPT_PARAMETERS Parameters
+               );
+#endif // NTDDI_VERSION >= NTDDI_LONGHORN
+
+#else
+       UNUSED_PARAM(dpc_ctx);
+#endif
+
+       KeInitializeSpinLock( &pdev->isr_lock );
+       
+       status = IoConnectInterrupt(
+               int_obj,                                                                                /* InterruptObject */
+               isr,                                                                                    /* ISR */ 
+               isr_ctx,                                                                                /* ISR context */
+               &pdev->isr_lock,                                                                /* spinlock */
+               vector,                                                                                 /* interrupt vector */
+               (KIRQL)pdev->int_info.u.Interrupt.Level,                /* IRQL */
+               (KIRQL)pdev->int_info.u.Interrupt.Level,                /* Synchronize IRQL */
+               (BOOLEAN)((pdev->int_info.Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? 
+                       Latched : LevelSensitive),                                      /* interrupt type: LATCHED or LEVEL */
+               (BOOLEAN)(pdev->int_info.ShareDisposition == CmResourceShareShared),    /* vector shared or not */
+               g_processor_affinity ? g_processor_affinity : (KAFFINITY)pdev->int_info.u.Interrupt.Affinity,   /* interrupt affinity */
+               FALSE                                                                                                                   /* whether to save Float registers */
+               );
+
+       if (!NT_SUCCESS(status)) {
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT ,("IoConnectInterrupt  failed status %d (did you change the processor_affinity ? )\n",status));
+               return -EFAULT;         /* failed to connect interrupt */
+       } 
+
+       /* init DPC stuff */
+       pdev->dpc_lock = 0;
+       for (i = 0; i < MLX4_NUM_EQ; ++i) {
+               spin_lock_init( &priv->eq_table.eq[i].lock );   
+               KeInitializeDpc( &priv->eq_table.eq[i].dpc, dpc, &priv->eq_table.eq[i]);
+               priv->eq_table.eq[i].eq_ix = i;
+       }
+
+       return 0;
+}
+#endif
diff --git a/hw/mlx4/kernel/bus/core/l2w_debug.c b/hw/mlx4/kernel/bus/core/l2w_debug.c
new file mode 100644 (file)
index 0000000..551261d
--- /dev/null
@@ -0,0 +1,205 @@
+#include "l2w.h"
+#include "ev_log.h"
+
+#define MAX_BUFFER_SIZE                256
+
+VOID
+WriteEventLogEntryStr(
+       PVOID   pi_pIoObject,
+       ULONG   pi_ErrorCode,
+       ULONG   pi_UniqueErrorCode,
+       ULONG   pi_FinalStatus,
+       PWCHAR  pi_InsertionStr,
+       ULONG   pi_nDataItems,
+       ...
+       )
+/*++
+
+Routine Description:
+    Writes an event log entry to the event log.
+
+Arguments:
+
+       pi_pIoObject......... The IO object ( driver object or device object ).
+       pi_ErrorCode......... The error code.
+       pi_UniqueErrorCode... A specific error code.
+       pi_FinalStatus....... The final status.
+       pi_nDataItems........ Number of data items.
+       .
+       . data items values
+       .
+
+Return Value:
+
+       None .
+
+--*/
+{ /* WriteEventLogEntryStr */
+
+       /* Variable argument list */    
+       va_list                                 l_Argptr;
+       /* Pointer to an error log entry */
+       PIO_ERROR_LOG_PACKET    l_pErrorLogEntry; 
+       /* sizeof insertion string */
+       int     l_Size = (int)((pi_InsertionStr) ? ((wcslen(pi_InsertionStr) + 1) * sizeof( WCHAR )) : 0);
+       int l_PktSize =sizeof(IO_ERROR_LOG_PACKET)+pi_nDataItems*sizeof(ULONG);
+       int l_TotalSize =l_PktSize +l_Size;
+
+       /* Init the variable argument list */   
+       va_start(l_Argptr, pi_nDataItems);
+
+       /* Allocate an error log entry */ 
+       if (l_TotalSize >= ERROR_LOG_MAXIMUM_SIZE - 2) 
+               l_TotalSize = ERROR_LOG_MAXIMUM_SIZE - 2;
+       l_pErrorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+               pi_pIoObject,  (UCHAR)l_TotalSize );
+
+       /* Check allocation */
+       if ( l_pErrorLogEntry != NULL) 
+       { /* OK */
+
+               /* Data item index */
+               USHORT l_nDataItem ;
+
+               /* Set the error log entry header */
+               l_pErrorLogEntry->ErrorCode                     = pi_ErrorCode; 
+               l_pErrorLogEntry->DumpDataSize          = (USHORT) (pi_nDataItems*sizeof(ULONG)); 
+               l_pErrorLogEntry->SequenceNumber        = 0; 
+               l_pErrorLogEntry->MajorFunctionCode = 0; 
+               l_pErrorLogEntry->IoControlCode         = 0; 
+               l_pErrorLogEntry->RetryCount            = 0; 
+               l_pErrorLogEntry->UniqueErrorValue      = pi_UniqueErrorCode; 
+               l_pErrorLogEntry->FinalStatus           = pi_FinalStatus; 
+
+               /* Insert the data items */
+               for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) 
+               { /* Inset a data item */
+
+                       /* Current data item */
+                       int l_CurDataItem ;
+                               
+                       /* Get next data item */
+                       l_CurDataItem = va_arg( l_Argptr, int);
+
+                       /* Put it into the data array */
+                       l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ;
+
+               } /* Inset a data item */
+
+               /* add insertion string */
+               if (pi_InsertionStr) {
+                       char *ptr; 
+                       int sz = min( l_TotalSize - l_PktSize, l_Size );
+                       l_pErrorLogEntry->NumberOfStrings = 1;
+                       l_pErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + l_pErrorLogEntry->DumpDataSize;
+                       ptr = (char*)l_pErrorLogEntry + l_pErrorLogEntry->StringOffset;
+                       memcpy( ptr, pi_InsertionStr, sz );
+                       *(WCHAR*)&ptr[sz - 2] = (WCHAR)0;
+               }
+               
+               /* Write the packet */
+               IoWriteErrorLogEntry(l_pErrorLogEntry);
+
+       } /* OK */
+
+       /* Term the variable argument list */   
+       va_end(l_Argptr);
+
+} /* WriteEventLogEntry */
+
+
+VOID
+mlx4_err(
+       IN struct mlx4_dev *    mdev,
+       IN char*                                format,
+       ...
+       )
+{
+       va_list         list;
+       UCHAR           buf[MAX_BUFFER_SIZE];
+       WCHAR           wbuf[MAX_BUFFER_SIZE];
+
+       // print to Debugger
+       va_start(list, format);
+       buf[MAX_BUFFER_SIZE - 1] = '\0';
+       RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list);
+       DbgPrint( (char*)buf );
+       va_end(list);
+
+       // print to Event Log
+       if (!RtlStringCchPrintfW(wbuf, sizeof(wbuf), L"%S", buf))
+               WriteEventLogEntryStr( mdev->pdev->p_self_do, (ULONG)EVENT_MLX4_ANY_ERROR, 0, 0, wbuf, 0, 0 ); 
+}
+
+VOID
+mlx4_dbg(
+       IN struct mlx4_dev *    mdev,
+       IN char*                                format,
+       ...
+       )
+{
+#if DBG
+       va_list         list;
+       UCHAR           buf[MAX_BUFFER_SIZE];
+       UNUSED_PARAM(mdev);
+
+       // print to Debugger
+       va_start(list, format);
+       buf[MAX_BUFFER_SIZE - 1] = '\0';
+       RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list);
+       DbgPrint( (char*)buf );
+       va_end(list);
+#else  
+       UNUSED_PARAM(mdev);
+       UNUSED_PARAM(format);
+#endif //DBG
+}
+
+VOID
+dev_err(
+       IN struct mlx4_dev **   mdev,
+       IN char*                                format,
+       ...
+       )
+{
+       va_list         list;
+       UCHAR           buf[MAX_BUFFER_SIZE];
+       WCHAR           wbuf[MAX_BUFFER_SIZE];
+
+       // print to Debugger
+       va_start(list, format);
+       buf[MAX_BUFFER_SIZE - 1] = '\0';
+       RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list);
+       DbgPrint( (char*)buf );
+       va_end(list);
+
+       // print to Event Log
+       RtlStringCchPrintfW(wbuf, sizeof(wbuf), L"%S", buf);
+       WriteEventLogEntryStr( (*mdev)->pdev->p_self_do, (ULONG)EVENT_MLX4_ANY_ERROR, 0, 0, wbuf, 0, 0 ); 
+}
+
+VOID
+dev_info(
+       IN struct mlx4_dev **   p_mdev,
+       IN char*                                format,
+       ...
+       )
+{
+#if DBG
+       va_list         list;
+       UCHAR           buf[MAX_BUFFER_SIZE];
+       UNUSED_PARAM(p_mdev);
+
+       // print to Debugger
+       va_start(list, format);
+       buf[MAX_BUFFER_SIZE - 1] = '\0';
+       RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list);
+       DbgPrint( (char*)buf );
+       va_end(list);
+#else  
+       UNUSED_PARAM(p_mdev);
+       UNUSED_PARAM(format);
+#endif
+}
+
+
diff --git a/hw/mlx4/kernel/bus/core/l2w_memory.c b/hw/mlx4/kernel/bus/core/l2w_memory.c
new file mode 100644 (file)
index 0000000..bb0f885
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mt_memory.c 2020 2007-05-01 09:29:10Z leonid $
+ */
+#include "l2w.h"
+
+#if defined (EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "l2w_memory.tmh"
+#endif 
+
+
+
+void *alloc_cont_mem(
+       IN              struct pci_dev *pdev, 
+       IN              unsigned long size,
+       OUT             dma_addr_t*p_dma_addr)
+{
+       void *va;
+       DMA_ADAPTER *p_adapter = pdev->p_dma_adapter;
+       PHYSICAL_ADDRESS  pa = {0};
+
+       ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+       memset( p_dma_addr, 0, sizeof(dma_addr_t) );
+
+       if (!size)
+               return NULL;
+
+       va      = p_adapter->DmaOperations->AllocateCommonBuffer(
+               p_adapter, (ULONG)size, &pa, FALSE );
+       if (va) {
+               p_dma_addr->da = pa.QuadPart;
+               p_dma_addr->va = va;
+               p_dma_addr->sz  = (ULONG)size;
+       }
+
+       return va;
+}
+
+void free_cont_mem(
+       IN              struct pci_dev *pdev, 
+       IN              dma_addr_t*p_dma_addr)
+{
+       PHYSICAL_ADDRESS  pa;
+       DMA_ADAPTER *p_adapter = pdev->p_dma_adapter;
+
+       ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+       pa.QuadPart = p_dma_addr->da;
+       p_adapter->DmaOperations->FreeCommonBuffer( 
+               p_adapter, (ULONG)p_dma_addr->sz, pa, p_dma_addr->va, FALSE );
+}
+
+void *
+dma_alloc_coherent( struct mlx4_dev **dev, size_t size, 
+       dma_addr_t *p_dma_addr, gfp_t gfp )
+{
+       UNUSED_PARAM(gfp);
+
+       if (!size)
+               return NULL;
+       return alloc_cont_mem( (*dev)->pdev, (unsigned long)size, p_dma_addr );
+}
+
+void 
+dma_free_coherent( struct mlx4_dev **dev, size_t size, 
+       void *vaddr, dma_addr_t dma_addr)
+{
+       UNUSED_PARAM(size);
+       UNUSED_PARAM(vaddr);
+       ASSERT(size == dma_addr.sz);
+       ASSERT(vaddr == dma_addr.va);
+       free_cont_mem( (*dev)->pdev, &dma_addr );
+}
+
+void 
+pci_free_consistent( struct pci_dev *pdev, size_t size, 
+       void *vaddr, dma_addr_t dma_addr)
+{
+       dma_free_coherent( &pdev->dev, size, vaddr, dma_addr );
+}
+
+
+
diff --git a/hw/mlx4/kernel/bus/core/l2w_radix.c b/hw/mlx4/kernel/bus/core/l2w_radix.c
new file mode 100644 (file)
index 0000000..abea412
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: radix.c 1611 2006-08-20 14:48:55Z sleybo $
+ */
+
+#include "l2w.h"
+#include "errno.h"
+
+int radix_tree_insert(struct radix_tree_root *root,
+       unsigned long index, void *item)
+{
+       if ( NULL == cl_map_insert( &root->map, (const uint64_t)index, item ) )
+               return -EFAULT;
+       return 0;
+}
+
+void *radix_tree_lookup(struct radix_tree_root *root, 
+       unsigned long index)
+{
+       void* item = cl_map_get( &root->map, (const uint64_t)index );
+       return item;
+}
+
+void *radix_tree_delete(struct radix_tree_root *root, 
+       unsigned long index)
+{
+       void* item = cl_map_remove( &root->map, (const uint64_t)index );
+       return item;
+}
+
+cl_status_t radix_tree_create(struct radix_tree_root *root,
+       gfp_t gfp_mask)
+{
+#define MIN_ITEMS              32
+       cl_status_t cl_status;
+       UNUSED_PARAM(gfp_mask);
+
+       cl_map_construct( &root->map );
+       cl_status = cl_map_init( &root->map, MIN_ITEMS );
+       return cl_status;
+}
+
+void radix_tree_destroy(struct radix_tree_root *root )
+{
+       cl_map_destroy( &root->map );
+}
+
diff --git a/hw/mlx4/kernel/bus/core/l2w_umem.c b/hw/mlx4/kernel/bus/core/l2w_umem.c
new file mode 100644 (file)
index 0000000..fe449c4
--- /dev/null
@@ -0,0 +1,164 @@
+
+#include "l2w.h"
+#include "ib_verbs.h"
+
+/**
+ * ib_umem_release - release memory pinned with ib_umem_get
+ * @umem: umem struct to release
+ */
+void ib_umem_release(struct ib_umem *p_ib_umem)
+{
+       MLX4_ENTER(MLX4_DBG_MEMORY);
+       if (p_ib_umem->secure_handle)
+               MmUnsecureVirtualMemory( p_ib_umem->secure_handle );
+       if (p_ib_umem->iobuf_used)
+               iobuf_deregister_with_cash(&p_ib_umem->iobuf);
+       kfree(p_ib_umem);
+       MLX4_EXIT(MLX4_DBG_MEMORY);
+}
+
+
+/**
+ * ib_umem_get - Pin and DMA map userspace memory.
+ * @context: userspace context to pin memory for
+ * @addr: userspace virtual address to start at
+ * @size: length of region to pin
+ * @access: IB_ACCESS_xxx flags for memory being pinned
+ */
+struct ib_umem *ib_umem_get(struct ib_ucontext *context, u64 addr,
+                           size_t size, enum ib_access_flags access)
+{
+       int err;
+       struct ib_umem *p_ib_umem;
+
+       MLX4_ENTER(MLX4_DBG_MEMORY);
+
+       // create the object
+       p_ib_umem = kzalloc(sizeof *p_ib_umem, GFP_KERNEL);
+       if (!p_ib_umem)
+               goto done;
+
+       p_ib_umem->p_uctx = context;
+       p_ib_umem->page_size = PAGE_SIZE;
+       
+       // register the memory 
+       iobuf_init( addr, (u64)size, !!context, &p_ib_umem->iobuf);
+       err =  iobuf_register_with_cash( addr, (u64)size, !!context, 
+               &access, &p_ib_umem->iobuf );
+       if (err)
+               goto err_reg_mem;
+       p_ib_umem->iobuf_used = TRUE;
+
+       // TODO: map the memory for DMA
+       
+       // secure memory
+       if (!context)
+               goto done;
+       __try {
+               p_ib_umem->secure_handle = MmSecureVirtualMemory ( 
+                       (PVOID)(ULONG_PTR)addr, size,
+                       (access & IB_ACCESS_LOCAL_WRITE) ? PAGE_READWRITE : PAGE_READONLY );
+               if (p_ib_umem->secure_handle == NULL) 
+                       goto err_secure;
+       }
+       __except (EXCEPTION_EXECUTE_HANDLER) {
+               NTSTATUS Status = GetExceptionCode();
+               UNUSED_PARAM_WOWPP(Status);
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,
+                       ("Exception 0x%x on MmSecureVirtualMemory(), addr %I64x, size %I64x, access %#x\n", 
+                       Status, addr, (u64)size, access ));
+               goto err_secure;
+       }
+       goto done;
+
+err_secure:
+       iobuf_deregister(&p_ib_umem->iobuf);
+
+err_reg_mem:   
+       kfree(p_ib_umem);
+       p_ib_umem = NULL;
+
+done:  
+       MLX4_EXIT(MLX4_DBG_MEMORY);
+       return p_ib_umem;
+}
+
+int ib_umem_page_count(struct ib_umem *p_ib_umem)
+{
+       return (int)p_ib_umem->iobuf.nr_pages;
+}
+
+dma_addr_t ib_umem_get_dma(struct ib_umem *p_ib_umem)
+{
+       u64 pages[1] = { 0 };
+       iobuf_iter_t iobuf_iter;
+       dma_addr_t dma_addr = { 0, 0 , 0 };
+
+       iobuf_iter_init( &p_ib_umem->iobuf, &iobuf_iter );
+       iobuf_get_tpt_seg( &p_ib_umem->iobuf, &iobuf_iter, 1, pages );
+       // TODO: convert phys address to DMA one
+       dma_addr.da = pages[0];
+
+       return dma_addr;
+}
+
+
+// Returns: 0 on success, -ENOMEM or -EACCESS or -EFAULT on error
+int ib_umem_map(
+       IN              u64 va,
+       IN              u64 size,
+       IN              ib_access_t acc,
+       OUT             PMDL *mdl,
+       OUT             void **kva)
+{
+       PMDL p_mdl;
+       int rc = 0;
+       LOCK_OPERATION lock_op = (acc & IB_AC_LOCAL_WRITE) ? IoModifyAccess : IoReadAccess;
+
+       p_mdl = IoAllocateMdl( (PVOID)(ULONG_PTR)va, (ULONG)size, FALSE,FALSE,NULL);
+       if (p_mdl == NULL) {
+               rc = -ENOMEM;
+               goto err_alloc_mdl;
+       }
+
+       __try { 
+               MmProbeAndLockPages( p_mdl, UserMode, lock_op );   /* lock memory */
+       } 
+       __except (EXCEPTION_EXECUTE_HANDLER)    {
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_MEMORY, 
+                       ("MOSAL_iobuf_register: Exception 0x%x on MmProbeAndLockPages(), va %I64d, sz %I64d\n", 
+                       GetExceptionCode(), va, size));
+               rc = -EACCES;
+               goto err_probe;
+       }
+
+       *kva = MmMapLockedPagesSpecifyCache( p_mdl, 
+               KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority );
+       if (*kva == NULL) {
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,("MmMapLockedPagesSpecifyCache failed\n"));
+               rc = -EFAULT;
+               goto err_map;
+       }
+       
+       *mdl = p_mdl;
+       return 0;
+
+err_map:
+       MmUnlockPages(p_mdl);
+err_probe:
+       IoFreeMdl(p_mdl);
+err_alloc_mdl:  
+       return rc;
+}
+
+void ib_umem_unmap(
+       IN PMDL p_mdl,
+       IN void *kva)
+{
+       if (kva) {
+               MmUnmapLockedPages( kva, p_mdl );
+               MmUnlockPages(p_mdl);
+               IoFreeMdl(p_mdl);
+       }
+}
+
diff --git a/hw/mlx4/kernel/bus/core/makefile b/hw/mlx4/kernel/bus/core/makefile
new file mode 100644 (file)
index 0000000..d493855
--- /dev/null
@@ -0,0 +1,7 @@
+#\r
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source\r
+# file to this component.  This file merely indirects to the real make file\r
+# that is shared by all the driver components of the OpenIB Windows project.\r
+#\r
+\r
+!INCLUDE ..\..\..\..\..\inc\openib.def\r
diff --git a/hw/mlx4/kernel/bus/core/pa_cash.c b/hw/mlx4/kernel/bus/core/pa_cash.c
new file mode 100644 (file)
index 0000000..b682645
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mlnx_uvp_cq.c 1611 2006-08-20 14:48:55Z sleybo $
+ */
+
+#include "l2w.h"
+#include "pa_cash.h"
+
+#if defined(EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "pa_cash.tmh"
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+//
+// RESTRICTIONS
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN64
+#define MAX_PAGES_SUPPORTED    (64 * 1024 * 1024)              // 256 GB
+#else
+#define MAX_PAGES_SUPPORTED    (16 * 1024 * 1024)              // 64 GB
+#endif
+
+#define FREE_LIST_TRESHOLD             256             // max number of pages in free list
+
+///////////////////////////////////////////////////////////////////////////
+//
+// CONSTANTS
+//
+///////////////////////////////////////////////////////////////////////////
+
+#define PA_TABLE_ENTRY_SIZE    sizeof(pa_table_entry_t)
+#define PA_TABLE_ENTRY_NUM     (PAGE_SIZE / PA_TABLE_ENTRY_SIZE)
+#define PA_TABLE_SIZE                  (PA_TABLE_ENTRY_SIZE * PA_TABLE_ENTRY_NUM)
+
+#define PA_DIR_ENTRY_SIZE              sizeof(pa_dir_entry_t)
+#define PA_DIR_ENTRY_NUM               (MAX_PAGES_SUPPORTED /PA_TABLE_ENTRY_NUM)
+#define PA_DIR_SIZE                            (PA_DIR_ENTRY_SIZE * PA_DIR_ENTRY_NUM)
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// STRUCTURES
+//
+///////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+       int     ref_cnt;
+} pa_table_entry_t;
+
+typedef struct {
+       pa_table_entry_t *pa_te;                /* pointer to one page of pa_table_entry_t elements */
+       int used;                                               /* number of pa_table_entry_t elements, used now. When 0 - the page may be freed */
+} pa_dir_entry_t;
+
+typedef struct pa_cash_s {
+       pa_dir_entry_t *pa_dir;
+       SINGLE_LIST_ENTRY  free_list_hdr;
+       uint32_t free_nr_pages;
+       uint32_t free_list_threshold;
+       uint32_t max_nr_pages;
+       uint32_t cur_nr_pages;
+} pa_cash_t;
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// GLOBALS
+//
+///////////////////////////////////////////////////////////////////////////
+
+DEFINE_MUTEX(g_pa_mutex);
+u64 g_pa[1024];
+pa_cash_t g_cash;
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// STATIC FUNCTIONS
+//
+///////////////////////////////////////////////////////////////////////////
+
+static uint32_t pa_calc_threshold()
+{
+       // threshold expresses the max length of free pages list, which gets released only at driver unload time
+       // so it can be calculated to be proportional to the system memory size
+       return FREE_LIST_TRESHOLD;
+}
+
+static pa_table_entry_t *pa_alloc_page()
+{
+       pa_table_entry_t *pa_te;
+
+       /* take from the list of reserved if it is not empty */
+       if (g_cash.free_nr_pages) {
+               pa_te = (pa_table_entry_t *)PopEntryList( &g_cash.free_list_hdr );
+               ((SINGLE_LIST_ENTRY*)pa_te)->Next = NULL;
+               g_cash.free_nr_pages--;
+       }
+       else  /* allocate new page */
+               pa_te = (pa_table_entry_t *)kzalloc( PA_TABLE_SIZE, GFP_KERNEL );
+
+       return pa_te;
+}
+
+static void pa_free_page(pa_table_entry_t *pa_te)
+{
+       if (g_cash.free_nr_pages < g_cash.free_list_threshold) {
+               PushEntryList( &g_cash.free_list_hdr, (SINGLE_LIST_ENTRY*)pa_te );
+               g_cash.free_nr_pages++;
+       }
+       else
+               kfree(pa_te);
+}
+
+static pa_table_entry_t * pa_get_page(uint32_t ix)
+{
+       pa_table_entry_t *pa_te =  g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te;
+
+       /* no this page_table - add a new one */
+       if (!pa_te) {
+               pa_te = pa_alloc_page();
+               if (!pa_te) 
+                       return NULL;
+               g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te = pa_te;
+               g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used = 0;
+               g_cash.cur_nr_pages++;
+       }
+
+       return pa_te;
+}
+
+static void pa_put_page(uint32_t ix)
+{
+       pa_free_page(g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te);
+       g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te = NULL;
+       g_cash.cur_nr_pages--;
+}
+
+static int pa_add_pa(uint64_t pa)
+{
+       uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT);
+       pa_table_entry_t *pa_te;
+
+       /* or pa is incorrect or memory that big is not supported */
+       if (ix > g_cash.max_nr_pages) {
+               ASSERT(FALSE);
+               return -EFAULT;
+       }
+
+       /* get page address */
+       pa_te = pa_get_page(ix);
+       if (!pa_te)
+               return -ENOMEM;
+       
+       /* register page address */
+       if (!pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt)
+               ++g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used;
+       ++pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt;
+
+       return 0;
+}
+
+
+static int pa_rmv_pa(uint64_t pa)
+{
+       uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT);
+       pa_table_entry_t *pa_te;
+
+       /* or pa is incorrect or memory that big is not supported */
+       if (ix > g_cash.max_nr_pages) {
+               ASSERT(FALSE);
+               return -EFAULT;
+       }
+               
+       pa_te =  g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te;
+
+       /* no this page_table - error*/
+       if (!pa_te)  {
+               ASSERT(FALSE);
+               return -EFAULT;
+       }
+
+       /* deregister page address */
+       --pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt;
+       ASSERT(pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt >= 0);
+
+       /* release the page on need */
+       if (!pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt)
+               --g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used;
+       if (!g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used) 
+               pa_put_page(ix);
+               
+       return 0;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// PUBLIC FUNCTIONS
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+int pa_register(iobuf_t *iobuf_p)
+{
+       int i,j,n;
+       iobuf_iter_t iobuf_iter;
+
+       iobuf_iter_init( iobuf_p, &iobuf_iter );
+       n = 0;
+       for (;;) {
+               i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, 
+                       sizeof(g_pa) / sizeof (u64), g_pa );
+               if (!i)
+                       break;
+               for (j=0; j<i; ++j, ++n)
+                       if (pa_add_pa(g_pa[j]))
+                               goto cleanup;
+       }
+       return 0;
+
+cleanup:       
+       iobuf_iter_init( iobuf_p, &iobuf_iter );
+       for (;;) {
+               i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, 
+                       sizeof(g_pa) / sizeof (u64), g_pa );
+               if (!i)
+                       break;
+               for (j=0; j<i; ++j, --n) {
+                       pa_rmv_pa(g_pa[j]);
+                       if (n<=0)
+                               goto done;
+               }
+       }
+done:  
+       return -ENOMEM;
+}
+
+void pa_deregister(iobuf_t *iobuf_p)
+{
+       int i,j;
+       iobuf_iter_t iobuf_iter;
+
+       iobuf_iter_init( iobuf_p, &iobuf_iter );
+       for (;;) {
+               i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, 
+                       sizeof(g_pa) / sizeof (u64), g_pa );
+               if (!i)
+                       break;
+               for (j=0; j<i; ++j)
+                       pa_rmv_pa(g_pa[j]);
+       }
+}
+
+void pa_cash_print()
+{
+       MLX4_PRINT(TRACE_LEVEL_WARNING  ,MLX4_DBG_LOW,
+               ("pa_cash_print: max_nr_pages %d (%#x), cur_nr_pages  %d (%#x), free_list_hdr %d, free_threshold %d\n",
+               g_cash.max_nr_pages, g_cash.max_nr_pages, 
+               g_cash.cur_nr_pages, g_cash.cur_nr_pages,
+               g_cash.free_nr_pages, g_cash.free_list_threshold ));
+}
+
+
+void pa_cash_release()
+{
+       int i;
+
+       pa_cash_print();
+
+       if (!g_cash.pa_dir)
+               return;
+
+       /* free cash tables */
+       for (i=0; i<PA_DIR_ENTRY_NUM; ++i)
+               if (g_cash.pa_dir[i].pa_te) {
+                       kfree(g_cash.pa_dir[i].pa_te);
+                       g_cash.cur_nr_pages--;
+               }
+                       
+       kfree(g_cash.pa_dir);
+       g_cash.pa_dir = NULL;
+
+       while (g_cash.free_nr_pages) {
+               void *page = PopEntryList( &g_cash.free_list_hdr );
+               g_cash.free_nr_pages--;
+               kfree(page);
+       }
+       ASSERT(g_cash.free_list_hdr.Next == NULL);
+       ASSERT(g_cash.cur_nr_pages == 0);
+}
+
+int pa_is_registered(uint64_t pa)
+{
+       uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT);
+       pa_table_entry_t *pa_te;
+
+       /* or pa is incorrect or memory that big is not supported */
+       if (ix > g_cash.max_nr_pages) {
+               ASSERT(FALSE);
+               return -EFAULT;
+       }
+               
+       pa_te =  g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te;
+
+       /* no this page_table */
+       if (!pa_te)
+               return 0;
+
+       return pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt;
+}
+
+int pa_cash_init()
+{
+       void *pa_dir;
+       pa_dir = kzalloc(PA_DIR_SIZE, GFP_KERNEL);
+
+       if (!pa_dir)
+               return -ENOMEM;
+       g_cash.pa_dir = pa_dir;
+       g_cash.max_nr_pages = PA_TABLE_ENTRY_NUM * PA_DIR_ENTRY_NUM;
+       g_cash.free_list_hdr.Next = NULL;
+       g_cash.cur_nr_pages = 0;
+       g_cash.free_nr_pages = 0;
+       g_cash.free_list_threshold = pa_calc_threshold();
+       mutex_init(&g_pa_mutex);
+       return 0;
+}
+
diff --git a/hw/mlx4/kernel/bus/core/pa_cash.h b/hw/mlx4/kernel/bus/core/pa_cash.h
new file mode 100644 (file)
index 0000000..a231c89
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: mlnx_uvp_cq.c 1611 2006-08-20 14:48:55Z sleybo $
+ */
+
+#include "iobuf.h"
+
+extern struct mutex g_pa_mutex;
+
+int pa_cash_init();
+
+void pa_cash_release();
+
+int pa_is_registered(uint64_t pa);
+
+int pa_register(iobuf_t *iobuf_p);
+
+void pa_deregister(iobuf_t *iobuf_p);
+
+void pa_cash_print();
+
diff --git a/hw/mlx4/kernel/bus/core/packer.c b/hw/mlx4/kernel/bus/core/packer.c
new file mode 100644 (file)
index 0000000..5b0da95
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: packer.c 1349 2004-12-16 21:09:43Z roland $
+ */
+
+#include "l2w.h"
+#include "ib_pack.h"
+
+static u64 value_read(int offset, int size, u8 *structure)
+{
+       switch (size) {
+       case 1: return                *(u8  *) (structure + offset);
+       case 2: return be16_to_cpup((__be16 *) (structure + offset));
+       case 4: return be32_to_cpup((__be32 *) (structure + offset));
+       case 8: return be64_to_cpup((__be64 *) (structure + offset));
+       default:
+               printk(KERN_WARNING "Field size %d bits not handled\n", size * 8);
+               return 0;
+       }
+}
+
+/**
+ * ib_pack - Pack a structure into a buffer
+ * @desc:Array of structure field descriptions
+ * @desc_len:Number of entries in @desc
+ * @structure:Structure to pack from
+ * @buf:Buffer to pack into
+ *
+ * ib_pack() packs a list of structure fields into a buffer,
+ * controlled by the array of fields in @desc.
+ */
+void ib_pack(const struct ib_field        *desc,
+            int                           desc_len,
+            void                         *structure,
+            u8                         *buf)
+{
+       int i;
+
+       for (i = 0; i < desc_len; ++i) {
+               if (desc[i].size_bits <= 32) {
+                       int shift;
+                       u32 val;
+                       __be32 mask;
+                       __be32 *addr;
+
+                       shift = 32 - desc[i].offset_bits - desc[i].size_bits;
+                       if (desc[i].struct_size_bytes)
+                               val = (u32)(value_read((int)desc[i].struct_offset_bytes,
+                                                (int)desc[i].struct_size_bytes,
+                                                structure) << shift);
+                       else
+                               val = 0;
+
+                       mask = cpu_to_be32(((1ull << desc[i].size_bits) - 1) << shift);
+                       addr = (__be32 *) buf + desc[i].offset_words;
+                       *addr = (*addr & ~mask) | (cpu_to_be32(val) & mask);
+               } else if (desc[i].size_bits <= 64) {
+                       int shift;
+                       u64 val;
+                       __be64 mask;
+                       __be64 *addr;
+
+                       shift = 64 - desc[i].offset_bits - desc[i].size_bits;
+                       if (desc[i].struct_size_bytes)
+                               val = value_read((int)desc[i].struct_offset_bytes,
+                                                (int)desc[i].struct_size_bytes,
+                                                structure) << shift;
+                       else
+                               val = 0;
+
+                       mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
+                       addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
+                       *addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
+               } else {
+                       if (desc[i].offset_bits % 8 ||
+                           desc[i].size_bits   % 8) {
+                               printk(KERN_WARNING "Structure field %s of size %d "
+                                      "bits is not byte-aligned\n",
+                                      desc[i].field_name, desc[i].size_bits);
+                       }
+
+                       if (desc[i].struct_size_bytes)
+                               memcpy(buf + desc[i].offset_words * 4 +
+                                      desc[i].offset_bits / 8,
+                                      (u8*)structure + desc[i].struct_offset_bytes,
+                                      desc[i].size_bits / 8);
+                       else
+                               memset(buf + desc[i].offset_words * 4 +
+                                      desc[i].offset_bits / 8,
+                                      0,
+                                      desc[i].size_bits / 8);
+               }
+       }
+}
+EXPORT_SYMBOL(ib_pack);
+
+static void value_write(int offset, int size, u64 val, u8 *structure)
+{
+       switch (size * 8) {
+       case 8:  *(    u8 *) (structure + offset) = (u8)val; break;
+       case 16: *(__be16 *) (structure + offset) = cpu_to_be16(val); break;
+       case 32: *(__be32 *) (structure + offset) = cpu_to_be32(val); break;
+       case 64: *(__be64 *) (structure + offset) = cpu_to_be64(val); break;
+       default:
+               printk(KERN_WARNING "Field size %d bits not handled\n", size * 8);
+       }
+}
+
+/**
+ * ib_unpack - Unpack a buffer into a structure
+ * @desc:Array of structure field descriptions
+ * @desc_len:Number of entries in @desc
+ * @buf:Buffer to unpack from
+ * @structure:Structure to unpack into
+ *
+ * ib_pack() unpacks a list of structure fields from a buffer,
+ * controlled by the array of fields in @desc.
+ */
+void ib_unpack(const struct ib_field        *desc,
+              int                           desc_len,
+              void                         *buf,
+              void                         *structure)
+{
+       int i;
+
+       for (i = 0; i < desc_len; ++i) {
+               if (!desc[i].struct_size_bytes)
+                       continue;
+
+               if (desc[i].size_bits <= 32) {
+                       int shift;
+                       u32  val;
+                       u32  mask;
+                       __be32 *addr;
+
+                       shift = 32 - desc[i].offset_bits - desc[i].size_bits;
+                       mask = ((1ull << desc[i].size_bits) - 1) << shift;
+                       addr = (__be32 *) buf + desc[i].offset_words;
+                       val = (be32_to_cpup(addr) & mask) >> shift;
+                       value_write((int)desc[i].struct_offset_bytes,
+                                   (int)desc[i].struct_size_bytes,
+                                   val,
+                                   structure);
+               } else if (desc[i].size_bits <= 64) {
+                       int shift;
+                       u64  val;
+                       u64  mask;
+                       __be64 *addr;
+
+                       shift = 64 - desc[i].offset_bits - desc[i].size_bits;
+                       mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
+                       addr = (__be64 *) buf + desc[i].offset_words;
+                       val = (be64_to_cpup(addr) & mask) >> shift;
+                       value_write((int)desc[i].struct_offset_bytes,
+                                   (int)desc[i].struct_size_bytes,
+                                   val,
+                                   structure);
+               } else {
+                       if (desc[i].offset_bits % 8 ||
+                           desc[i].size_bits   % 8) {
+                               printk(KERN_WARNING "Structure field %s of size %d "
+                                      "bits is not byte-aligned\n",
+                                      desc[i].field_name, desc[i].size_bits);
+                       }
+
+                       memcpy((u8*)structure + desc[i].struct_offset_bytes,
+                              (u8*)buf + desc[i].offset_words * 4 +
+                              desc[i].offset_bits / 8,
+                              desc[i].size_bits / 8);
+               }
+       }
+}
+EXPORT_SYMBOL(ib_unpack);
diff --git a/hw/mlx4/kernel/bus/core/ud_header.c b/hw/mlx4/kernel/bus/core/ud_header.c
new file mode 100644 (file)
index 0000000..4be128e
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: ud_header.c 1349 2004-12-16 21:09:43Z roland $
+ */
+
+#include "l2w.h"
+#include "ib_pack.h"
+
+#define STRUCT_FIELD(header, field) \
+       .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
+       .struct_size_bytes   = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \
+       .field_name          = #header ":" #field
+
+#define STRUCT_FIELD_INIT(header, field,ow,ob,sb) \
+       offsetof(struct ib_unpacked_ ## header, field),      \
+       sizeof ((struct ib_unpacked_ ## header *) 0)->field, \
+       ow,ob,sb, \
+       #header ":" #field
+
+#define STRUCT_FIELD_INITR(ow,ob,sb) \
+               0, 0, ow, ob, sb, "reserved"
+
+static const struct ib_field lrh_table[]  = {
+       { STRUCT_FIELD_INIT(lrh, virtual_lane, 0, 0, 4) },
+       { STRUCT_FIELD_INIT(lrh, link_version, 0, 4, 4) },
+       { STRUCT_FIELD_INIT(lrh, service_level, 0, 8, 4) },
+       { STRUCT_FIELD_INITR(0,12,2) },
+       { STRUCT_FIELD_INIT(lrh, link_next_header, 0, 14, 2) },
+       { STRUCT_FIELD_INIT(lrh, destination_lid, 0, 16, 16) },
+       { STRUCT_FIELD_INITR(1,0,5) },
+       { STRUCT_FIELD_INIT(lrh, packet_length, 1, 5, 11) },
+       { STRUCT_FIELD_INIT(lrh, source_lid, 1, 16, 16) }
+};
+
+static const struct ib_field grh_table[]  = {
+       { STRUCT_FIELD_INIT(grh, ip_version, 0, 0, 4) },
+       { STRUCT_FIELD_INIT(grh, traffic_class, 0, 4, 8) },
+       { STRUCT_FIELD_INIT(grh, flow_label, 0, 12, 20) },
+       { STRUCT_FIELD_INIT(grh, payload_length, 1, 0, 16) },
+       { STRUCT_FIELD_INIT(grh, next_header, 1, 16, 8) },
+       { STRUCT_FIELD_INIT(grh, hop_limit, 1, 24, 8) },
+       { STRUCT_FIELD_INIT(grh, source_gid, 2, 0, 128) },
+       { STRUCT_FIELD_INIT(grh, destination_gid, 6, 0, 128) }
+};
+
+static const struct ib_field bth_table[]  = {
+       { STRUCT_FIELD_INIT(bth, opcode, 0, 0, 8) },
+       { STRUCT_FIELD_INIT(bth, solicited_event, 0, 8, 1) },
+       { STRUCT_FIELD_INIT(bth, mig_req, 0, 9, 1) },
+       { STRUCT_FIELD_INIT(bth, pad_count, 0, 10, 2) },
+       { STRUCT_FIELD_INIT(bth, transport_header_version, 0, 12, 4) },
+       { STRUCT_FIELD_INIT(bth, pkey, 0, 16, 16) },
+       { STRUCT_FIELD_INITR(1,0,8) },
+       { STRUCT_FIELD_INIT(bth, destination_qpn, 1, 8, 24) },
+       { STRUCT_FIELD_INIT(bth, ack_req, 2, 0, 1) },
+       { STRUCT_FIELD_INITR(2,1,7) },
+       { STRUCT_FIELD_INIT(bth, psn, 2, 8, 24) }
+};
+
+static const struct ib_field deth_table[] = {
+       { STRUCT_FIELD_INIT(deth, qkey, 0, 0, 32) },
+       { STRUCT_FIELD_INITR(1,0,8) },
+       { STRUCT_FIELD_INIT(deth, source_qpn, 1, 8, 24) }
+};
+
+/**
+ * ib_ud_header_init - Initialize UD header structure
+ * @payload_bytes:Length of packet payload
+ * @grh_present:GRH flag (if non-zero, GRH will be included)
+ * @header:Structure to initialize
+ *
+ * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
+ * lrh.packet_length, grh.ip_version, grh.payload_length,
+ * grh.next_header, bth.opcode, bth.pad_count and
+ * bth.transport_header_version fields of a &struct ib_ud_header given
+ * the payload length and whether a GRH will be included.
+ */
+void ib_ud_header_init(int                         payload_bytes,
+                      int                  grh_present,
+                      struct ib_ud_header *header)
+{
+       int header_len;
+       u16 packet_length;
+
+       memset(header, 0, sizeof *header);
+
+       header_len =
+               IB_LRH_BYTES  +
+               IB_BTH_BYTES  +
+               IB_DETH_BYTES;
+       if (grh_present) {
+               header_len += IB_GRH_BYTES;
+       }
+
+       header->lrh.link_version     = 0;
+       header->lrh.link_next_header =
+               grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
+       packet_length                = (u16)((IB_LRH_BYTES     +
+                                       IB_BTH_BYTES     +
+                                       IB_DETH_BYTES    +
+                                       payload_bytes    +
+                                       4                + /* ICRC     */
+                                       3) / 4);            /* round up */
+
+       header->grh_present          = grh_present;
+       if (grh_present) {
+               packet_length              += IB_GRH_BYTES / 4;
+               header->grh.ip_version      = 6;
+               header->grh.payload_length  =
+                       cpu_to_be16((IB_BTH_BYTES     +
+                                    IB_DETH_BYTES    +
+                                    payload_bytes    +
+                                    4                + /* ICRC     */
+                                    3) & ~3);          /* round up */
+               header->grh.next_header     = 0x1b;
+       }
+
+       header->lrh.packet_length = cpu_to_be16(packet_length);
+
+       if (header->immediate_present)
+               header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
+       else
+               header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
+       header->bth.pad_count                = (u8)((4 - payload_bytes) & 3);
+       header->bth.transport_header_version = 0;
+}
+EXPORT_SYMBOL(ib_ud_header_init);
+
+/**
+ * ib_ud_header_pack - Pack UD header struct into wire format
+ * @header:UD header struct
+ * @buf:Buffer to pack into
+ *
+ * ib_ud_header_pack() packs the UD header structure @header into wire
+ * format in the buffer @buf.
+ */
+int ib_ud_header_pack(struct ib_ud_header *header,
+                     u8                *buf)
+{
+       int len = 0;
+
+       ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
+               &header->lrh, buf);
+       len += IB_LRH_BYTES;
+
+       if (header->grh_present) {
+               ib_pack(grh_table, ARRAY_SIZE(grh_table),
+                       &header->grh, buf + len);
+               len += IB_GRH_BYTES;
+       }
+
+       ib_pack(bth_table, ARRAY_SIZE(bth_table),
+               &header->bth, buf + len);
+       len += IB_BTH_BYTES;
+
+       ib_pack(deth_table, ARRAY_SIZE(deth_table),
+               &header->deth, buf + len);
+       len += IB_DETH_BYTES;
+
+       if (header->immediate_present) {
+               memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
+               len += sizeof header->immediate_data;
+       }
+
+       return len;
+}
+EXPORT_SYMBOL(ib_ud_header_pack);
+
+/**
+ * ib_ud_header_unpack - Unpack UD header struct from wire format
+ * @header:UD header struct
+ * @buf:Buffer to pack into
+ *
+ * ib_ud_header_pack() unpacks the UD header structure @header from wire
+ * format in the buffer @buf.
+ */
+int ib_ud_header_unpack(u8                *buf,
+                       struct ib_ud_header *header)
+{
+       ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
+                 buf, &header->lrh);
+       buf += IB_LRH_BYTES;
+
+       if (header->lrh.link_version != 0) {
+               printk(KERN_WARNING "Invalid LRH.link_version %d\n",
+                      header->lrh.link_version);
+               return -EINVAL;
+       }
+
+       switch (header->lrh.link_next_header) {
+       case IB_LNH_IBA_LOCAL:
+               header->grh_present = 0;
+               break;
+
+       case IB_LNH_IBA_GLOBAL:
+               header->grh_present = 1;
+               ib_unpack(grh_table, ARRAY_SIZE(grh_table),
+                         buf, &header->grh);
+               buf += IB_GRH_BYTES;
+
+               if (header->grh.ip_version != 6) {
+                       printk(KERN_WARNING "Invalid GRH.ip_version %d\n",
+                              header->grh.ip_version);
+                       return -EINVAL;
+               }
+               if (header->grh.next_header != 0x1b) {
+                       printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n",
+                              header->grh.next_header);
+                       return -EINVAL;
+               }
+               break;
+
+       default:
+               printk(KERN_WARNING "Invalid LRH.link_next_header %d\n",
+                      header->lrh.link_next_header);
+               return -EINVAL;
+       }
+
+       ib_unpack(bth_table, ARRAY_SIZE(bth_table),
+                 buf, &header->bth);
+       buf += IB_BTH_BYTES;
+
+       switch (header->bth.opcode) {
+       case IB_OPCODE_UD_SEND_ONLY:
+               header->immediate_present = 0;
+               break;
+       case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
+               header->immediate_present = 1;
+               break;
+       default:
+               printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n",
+                      header->bth.opcode);
+               return -EINVAL;
+       }
+
+       if (header->bth.transport_header_version != 0) {
+               printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n",
+                      header->bth.transport_header_version);
+               return -EINVAL;
+       }
+
+       ib_unpack(deth_table, ARRAY_SIZE(deth_table),
+                 buf, &header->deth);
+       buf += IB_DETH_BYTES;
+
+       if (header->immediate_present)
+               memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
+
+       return 0;
+}
+EXPORT_SYMBOL(ib_ud_header_unpack);
diff --git a/hw/mlx4/kernel/bus/core/verbs.c b/hw/mlx4/kernel/bus/core/verbs.c
new file mode 100644 (file)
index 0000000..fd9daa7
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
+ * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
+ * Copyright (c) 2004 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+ * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: verbs.c 1349 2004-12-16 21:09:43Z roland $
+ */
+
+#if defined(EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "device.tmh"
+#endif
+
+#include "l2w.h"
+#include "ib_verbs.h"
+
+// qp_state_table
+static struct {
+       int                     valid;
+       enum ib_qp_attr_mask    req_param[IB_QPT_RAW_ETY + 1];
+       enum ib_qp_attr_mask    opt_param[IB_QPT_RAW_ETY + 1];
+} qst[XIB_QPS_ERR + 1][XIB_QPS_ERR + 1];
+
+
+void init_qp_state_tbl()
+{
+       memset( qst, 0, sizeof(qst) );
+
+       //
+       // XIB_QPS_RESET
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_RESET][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_RESET][XIB_QPS_ERR].valid = 1;
+
+               // XIB_QPS_INIT
+
+               qst[XIB_QPS_RESET][XIB_QPS_INIT].valid = 1;
+               qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_UD]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_QKEY);
+               qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_UC]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS);
+               qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_RC]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS);
+               qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_SMI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+               qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_GSI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+
+       //
+       // XIB_QPS_INIT
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_INIT][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_INIT][XIB_QPS_ERR].valid = 1;
+
+               // XIB_QPS_INIT
+               qst[XIB_QPS_INIT][XIB_QPS_INIT].valid = 1;
+
+               qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_QKEY);
+               qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS);
+               qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_RC]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS);
+               qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+               qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+
+               // XIB_QPS_RTR
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].valid = 1;
+
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].req_param[IB_QPT_UC]  = 
+                       (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | IB_QP_RQ_PSN);
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].req_param[IB_QPT_RC]  = 
+                       (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN |
+                       IB_QP_RQ_PSN | IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER);
+               
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX);
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_RC]  = 
+                       (IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX);
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+               qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+
+       //
+       // XIB_QPS_RTR
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_RTR][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_RTR][XIB_QPS_ERR].valid = 1;
+
+               // XIB_QPS_RTS
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].valid = 1;
+
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_UD]  = IB_QP_SQ_PSN;
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_UC]  = IB_QP_SQ_PSN;
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_RC]  = (IB_QP_TIMEOUT | 
+                       IB_QP_RETRY_CNT | IB_QP_RNR_RETRY | IB_QP_SQ_PSN | IB_QP_MAX_QP_RD_ATOMIC);
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_SMI] = IB_QP_SQ_PSN;
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_GSI] = IB_QP_SQ_PSN;
+
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
+                       IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_RC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | 
+                       IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+
+       //
+       // XIB_QPS_RTS
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_RTS][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_RTS][XIB_QPS_ERR].valid = 1;
+
+               // XIB_QPS_RTS
+               qst[XIB_QPS_RTS][XIB_QPS_RTS].valid = 1;
+
+               qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS | IB_QP_ALT_PATH |
+                       IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_RC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS | IB_QP_ALT_PATH |
+                       IB_QP_PATH_MIG_STATE | IB_QP_MIN_RNR_TIMER);
+               qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+
+               // XIB_QPS_SQD
+               qst[XIB_QPS_RTS][XIB_QPS_SQD].valid = 1;
+               qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY;
+               qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY;
+               qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY;
+               qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY;
+               qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY;
+
+       //
+       // XIB_QPS_SQD
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_SQD][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_SQD][XIB_QPS_ERR].valid = 1;
+
+               // XIB_QPS_RTS
+               qst[XIB_QPS_SQD][XIB_QPS_RTS].valid = 1;
+
+               qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
+                       IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_RC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
+                       IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+
+               // XIB_QPS_SQD
+               qst[XIB_QPS_SQD][XIB_QPS_SQD].valid = 1;
+
+               qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+               qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_AV | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
+                       IB_QP_PKEY_INDEX | IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_RC]  = 
+                       (IB_QP_PORT | IB_QP_AV | IB_QP_TIMEOUT | IB_QP_RETRY_CNT |
+                       IB_QP_RNR_RETRY | IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC |
+                       IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX |
+                       IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE);
+               qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+               qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_PKEY_INDEX | IB_QP_QKEY);
+
+       //
+       // XIB_QPS_SQE
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_SQE][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_SQE][XIB_QPS_ERR].valid = 1;
+
+               // XIB_QPS_RTS
+               qst[XIB_QPS_SQE][XIB_QPS_RTS].valid = 1;
+
+               qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_UD]  = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_UC]  = 
+                       (IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS);
+               qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+               qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = 
+                       (IB_QP_CUR_STATE | IB_QP_QKEY);
+
+
+       //
+       // XIB_QPS_ERR
+       //
+
+               // XIB_QPS_RESET
+               qst[XIB_QPS_ERR][XIB_QPS_RESET].valid = 1;
+
+               // XIB_QPS_ERR
+               qst[XIB_QPS_ERR][XIB_QPS_ERR].valid = 1;
+
+}
+
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+                      enum ib_qp_type type, enum ib_qp_attr_mask mask)
+{
+       enum ib_qp_attr_mask req_param, opt_param;
+               
+       if (cur_state  < 0 || cur_state  > XIB_QPS_ERR ||
+           next_state < 0 || next_state > XIB_QPS_ERR)
+               return 0;
+
+       if (mask & IB_QP_CUR_STATE  &&
+           cur_state != XIB_QPS_RTR && cur_state != XIB_QPS_RTS &&
+           cur_state != XIB_QPS_SQD && cur_state != XIB_QPS_SQE)
+               return 0;
+
+       if (!qst[cur_state][next_state].valid)
+               return 0;
+
+       req_param = qst[cur_state][next_state].req_param[type];
+       opt_param = qst[cur_state][next_state].opt_param[type];
+
+       if ((mask & req_param) != req_param)
+               return 0;
+
+       if (mask & ~(req_param | opt_param | IB_QP_STATE))
+               return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(ib_modify_qp_is_ok);
+
+struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+       struct ib_ah *ah;
+
+       ah = pd->device->create_ah(pd, ah_attr);
+
+       if (!IS_ERR(ah)) {
+               ah->device  = pd->device;
+               ah->pd      = pd;
+               ah->p_uctx = NULL;
+               atomic_inc(&pd->usecnt);
+       }
+
+       return ah;
+}
+EXPORT_SYMBOL(ib_create_ah);
+
+int ib_destroy_ah(struct ib_ah *ah)
+{
+       int ret;
+       struct ib_pd *pd = ah->pd;
+
+       ret = ah->device->destroy_ah(ah);
+       if (!ret)
+               atomic_dec(&pd->usecnt);
+
+       return ret;
+}
+EXPORT_SYMBOL(ib_destroy_ah);
+
diff --git a/hw/mlx4/kernel/bus/dirs b/hw/mlx4/kernel/bus/dirs
new file mode 100644 (file)
index 0000000..b70ba29
--- /dev/null
@@ -0,0 +1,5 @@
+DIRS=\\r
+       core \\r
+       net \\r
+       ib \\r
+       drv \r
diff --git a/hw/mlx4/kernel/bus/drv/bus.mof b/hw/mlx4/kernel/bus/drv/bus.mof
new file mode 100644 (file)
index 0000000..f5b1f1a
--- /dev/null
@@ -0,0 +1,27 @@
+#PRAGMA AUTORECOVER\r
+\r
+[Dynamic, Provider("WMIProv"),\r
+ WMI,\r
+ Description("Mlx4 Bus driver information"),\r
+ guid("{3337968C-F117-4289-84C2-04EF74CBAD77}"),\r
+ locale("MS\\0x409")]\r
+class Mlx4BusInformation\r
+{\r
+    [key, read]\r
+     string InstanceName;\r
+    [read] boolean Active;\r
+\r
+    [WmiDataId(1),\r
+     read,\r
+     Description("The DebugPrintLevel property indicates the debug output level of MLX4_BUS device.")]\r
+     uint32   DebugPrintLevel;\r
+\r
+    [WmiDataId(2),\r
+     read,\r
+     write,\r
+     Description("The DebugPrintLevel property indicates the debug output flags of MLX4_BUS device.")]\r
+        uint32 DebugPrintFlags;\r
+\r
+};\r
+\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/bus.rc b/hw/mlx4/kernel/bus/drv/bus.rc
new file mode 100644 (file)
index 0000000..58cac5b
--- /dev/null
@@ -0,0 +1,16 @@
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE                           VFT_DRV\r
+#define VER_FILESUBTYPE                                VFT2_UNKNOWN\r
+#ifdef DBG\r
+#define VER_FILEDESCRIPTION_STR     "MLX4 Bus Driver (checked)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR     "MLX4 Bus Driver"\r
+#endif\r
+#define VER_INTERNALNAME_STR        "mlx4_bus.sys"\r
+#define VER_ORIGINALFILENAME_STR    "mlx4_bus.sys"\r
+#include <common.ver>\r
+\r
+#include "ev_log.rc"\r
+\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/drv.c b/hw/mlx4/kernel/bus/drv/drv.c
new file mode 100644 (file)
index 0000000..51e2335
--- /dev/null
@@ -0,0 +1,994 @@
+/*++\r
+\r
+Copyright (c) 2003  Microsoft Corporation All Rights Reserved\r
+\r
+Module Name:\r
+\r
+    BUSENUM.C\r
+\r
+Abstract:\r
+\r
+    This module contains routines to handle the function driver\r
+    aspect of the bus driver. This sample is functionally\r
+    equivalent to the WDM mxe bus driver.\r
+\r
+Environment:\r
+\r
+    kernel mode only\r
+\r
+--*/\r
+\r
+#include "precomp.h"\r
+#include <initguid.h>\r
+#include <wdmguid.h>\r
+\r
+#if defined(EVENT_TRACING)\r
+#include "drv.tmh"\r
+#endif \r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (INIT, DriverEntry)\r
+#pragma alloc_text (PAGE, EvtDeviceAdd)\r
+#pragma alloc_text (PAGE, EvtDriverUnload)\r
+#pragma alloc_text (PAGE, EvtDeviceD0Entry)\r
+#pragma alloc_text (PAGE, EvtDeviceD0Exit)\r
+#pragma alloc_text (PAGE, EvtPrepareHardware)\r
+#pragma alloc_text (PAGE, EvtReleaseHardware)\r
+#endif\r
+\r
+#define DRV_VERSION    "1.0"\r
+#define DRV_RELDATE    "02/01/2008"\r
+\r
+GLOBALS g = {0};\r
+uint32_t g_mlx4_dbg_flags = 0xffff;\r
+uint32_t g_mlx4_dbg_level = TRACE_LEVEL_INFORMATION;\r
+WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ];\r
+UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ];\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+\r
+typedef struct {\r
+       int                                     int_num;\r
+       PFDO_DEVICE_DATA        p_fdo;\r
+       struct mlx4_eq *        eq;\r
+} INTERRUPT_DATA, *PINTERRUPT_DATA;\r
+\r
+WDF_DECLARE_CONTEXT_TYPE(INTERRUPT_DATA);\r
+\r
+NTSTATUS    \r
+EvtEnableInterrupt(    \r
+       IN WDFINTERRUPT  Interrupt,\r
+       IN WDFDEVICE  AssociatedDevice\r
+       )\r
+{\r
+       UNUSED_PARAM(Interrupt);\r
+       UNUSED_PARAM(AssociatedDevice);\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+NTSTATUS\r
+EvtDisableInterrupt (\r
+       IN WDFINTERRUPT  Interrupt,\r
+       IN WDFDEVICE  AssociatedDevice\r
+       )\r
+{\r
+       UNUSED_PARAM(Interrupt);\r
+       UNUSED_PARAM(AssociatedDevice);\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+EvtInterruptIsr(\r
+       IN WDFINTERRUPT  Interrupt,\r
+       IN ULONG  MessageID\r
+       )\r
+{\r
+       BOOLEAN isr_handled = FALSE;\r
+       PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( Interrupt, INTERRUPT_DATA );\r
+\r
+       UNUSED_PARAM(MessageID);\r
+\r
+//     MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("Fdo %p\n", p_isr_ctx->p_fdo));\r
+       if (p_isr_ctx->eq && p_isr_ctx->eq->isr)\r
+               isr_handled = p_isr_ctx->eq->isr( p_isr_ctx->eq->eq_ix, p_isr_ctx->eq->ctx );\r
+       \r
+       return isr_handled;\r
+}\r
+\r
+#endif\r
+\r
+NTSTATUS\r
+__create_child(\r
+       __in WDFDEVICE  Device,\r
+       __in PWCHAR     HardwareIds,\r
+       __in ULONG      SerialNo\r
+       )\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+       The user application has told us that a new device on the bus has arrived.\r
+\r
+       We therefore need to create a new PDO, initialize it, add it to the list\r
+       of PDOs for this FDO bus, and then tell Plug and Play that all of this\r
+       happened so that it will start sending prodding IRPs.\r
+\r
+--*/\r
+\r
+{\r
+       NTSTATUS                        status = STATUS_SUCCESS;\r
+       BOOLEAN                         unique = TRUE;\r
+       WDFDEVICE                       hChild;\r
+       PPDO_DEVICE_DATA        p_pdo;\r
+       PFDO_DEVICE_DATA        p_fdo;\r
+\r
+       PAGED_CODE ();\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       //\r
+       // First make sure that we don't already have another device with the\r
+       // same serial number.\r
+       // Framework creates a collection of all the child devices we have\r
+       // created so far. So acquire the handle to the collection and lock\r
+       // it before walking the item.\r
+       //\r
+       p_fdo = FdoGetData(Device);\r
+       hChild = NULL;\r
+\r
+       //\r
+       // We need an additional lock to synchronize addition because\r
+       // WdfFdoLockStaticChildListForIteration locks against anyone immediately\r
+       // updating the static child list (the changes are put on a queue until the\r
+       // list has been unlocked).  This type of lock does not enforce our concept\r
+       // of unique IDs on the bus (ie SerialNo).\r
+       //\r
+       // Without our additional lock, 2 threads could execute this function, both\r
+       // find that the requested SerialNo is not in the list and attempt to add\r
+       // it.  If that were to occur, 2 PDOs would have the same unique SerialNo,\r
+       // which is incorrect.\r
+       //\r
+       // We must use a passive level lock because you can only call WdfDeviceCreate\r
+       // at PASSIVE_LEVEL.\r
+       //\r
+       WdfWaitLockAcquire(p_fdo->ChildLock, NULL);\r
+       WdfFdoLockStaticChildListForIteration(Device);\r
+\r
+       while ((hChild = WdfFdoRetrieveNextStaticChild(Device,\r
+               hChild, WdfRetrieveAddedChildren)) != NULL) {\r
+               //\r
+               // WdfFdoRetrieveNextStaticChild returns reported and to be reported\r
+               // children (ie children who have been added but not yet reported to PNP).\r
+               //\r
+               // A surprise removed child will not be returned in this list.\r
+               //\r
+               p_pdo = PdoGetData(hChild);\r
+               p_pdo->PdoDevice = hChild;\r
+               p_pdo->p_fdo = p_fdo;\r
+\r
+               //\r
+               // It's okay to plug in another device with the same serial number\r
+               // as long as the previous one is in a surprise-removed state. The\r
+               // previous one would be in that state after the device has been\r
+               // physically removed, if somebody has an handle open to it.\r
+               //\r
+               if (SerialNo == p_pdo->SerialNo) {\r
+               unique = FALSE;\r
+               status = STATUS_INVALID_PARAMETER;\r
+               break;\r
+               }\r
+       }\r
+\r
+       if (unique) {\r
+               //\r
+               // Create a new child device.  It is OK to create and add a child while\r
+               // the list locked for enumeration.  The enumeration lock applies only\r
+               // to enumeration, not addition or removal.\r
+               //\r
+               status = create_pdo(Device, HardwareIds, SerialNo);\r
+       }\r
+\r
+       WdfFdoUnlockStaticChildListFromIteration(Device);\r
+       WdfWaitLockRelease(p_fdo->ChildLock);\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+\r
+NTSTATUS\r
+__do_static_enumeration(\r
+       IN WDFDEVICE Device\r
+       )\r
+/*++\r
+Routine Description:\r
+\r
+       The routine enables you to statically enumerate child devices\r
+       during start instead of running the enum.exe/notify.exe to\r
+       enumerate mxe devices.\r
+\r
+       In order to statically enumerate, user must specify the number\r
+       of mxes in the Mxe Bus driver's device registry. The\r
+       default value is 2.\r
+\r
+       You can also configure this value in the Mxe Bus Inf file.\r
+\r
+--*/\r
+\r
+{\r
+       NTSTATUS status;\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       // eventually we'll have all information about children in Registry\r
+       // DriverEntry will read it into a Global storage and\r
+       // this routine will create all the children on base on this info\r
+\r
+       status = __create_child(Device, BUS_HARDWARE_IDS, 0 );\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+NTSTATUS\r
+EvtDeviceD0Entry(\r
+       IN WDFDEVICE  Device,\r
+       IN WDF_POWER_DEVICE_STATE  PreviousState\r
+       )\r
+{\r
+       NTSTATUS status = STATUS_SUCCESS;\r
+       \r
+       UNUSED_PARAM(Device);\r
+       UNUSED_PARAM(PreviousState);\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));\r
+\r
+       status = __do_static_enumeration(Device);\r
+       if (!NT_SUCCESS(status)) {\r
+                MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("DoStaticEnumeration failed with 0x%x\n", status));\r
+       }\r
+\r
+       {\r
+               PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+               struct pci_dev *pdev    = &p_fdo->pci_dev;\r
+               struct mlx4_dev *mdev   = pdev->dev;\r
+\r
+               MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,\r
+                       ("Ven %x Dev %d Fw %d.%d.%d Drv %s (%s), BD %s\n", \r
+                       (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,\r
+                       (int) (mdev->caps.fw_ver >> 32),\r
+                       (int) (mdev->caps.fw_ver >> 16) & 0xffff, \r
+                       (int) (mdev->caps.fw_ver & 0xffff),\r
+                       DRV_VERSION, DRV_RELDATE, \r
+                       mlx4_is_livefish(mdev) ? "Y" : "N"\r
+                       ));\r
+       }\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+NTSTATUS\r
+EvtDeviceD0Exit(\r
+       IN WDFDEVICE  Device,\r
+       IN WDF_POWER_DEVICE_STATE  TargetState\r
+       )\r
+{\r
+       UNUSED_PARAM(Device);\r
+       UNUSED_PARAM(TargetState);\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState));\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/* Forwards the request to the HCA's PDO. */\r
+static \r
+void\r
+__put_bus_ifc(\r
+               IN      BUS_INTERFACE_STANDARD          *pBusIfc )\r
+{\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("pBusIfc=0x%p\n", pBusIfc));\r
+       pBusIfc->InterfaceDereference( pBusIfc->Context );\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+}\r
+\r
+static \r
+NTSTATUS\r
+__get_bus_ifc(\r
+       IN                              PFDO_DEVICE_DATA const  p_fdo,\r
+       IN              const   GUID* const                             pGuid,\r
+       OUT                     BUS_INTERFACE_STANDARD  *pBusIfc )\r
+{\r
+       NTSTATUS status;\r
+       WDFDEVICE  FdoDevice = p_fdo->FdoDevice;\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       \r
+       status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc,\r
+               sizeof(BUS_INTERFACE_STANDARD), 1, NULL );\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+static\r
+void\r
+__put_dma_adapter(\r
+       IN PFDO_DEVICE_DATA p_fdo,\r
+       IN PDMA_ADAPTER         p_dma )\r
+{\r
+       UNUSED_PARAM(p_fdo);\r
+       UNUSED_PARAM(p_dma);\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+}\r
+\r
+\r
+// this routine releases the resources, taken in __get_resources\r
+static\r
+void \r
+__put_resources(\r
+       IN PFDO_DEVICE_DATA p_fdo\r
+       )\r
+{\r
+       struct pci_dev *pdev = &p_fdo->pci_dev;\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       if (p_fdo->dma_adapter_taken) {\r
+               p_fdo->dma_adapter_taken = FALSE;\r
+               __put_dma_adapter( p_fdo, pdev->p_dma_adapter );\r
+       }\r
+\r
+       if (p_fdo->pci_bus_ifc_taken) {\r
+               p_fdo->pci_bus_ifc_taken = FALSE;\r
+               __put_bus_ifc(&pdev->bus_pci_ifc);\r
+       }\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+}\r
+\r
+static\r
+NTSTATUS \r
+__get_dma_adapter(\r
+       IN PFDO_DEVICE_DATA p_fdo,\r
+       OUT PDMA_ADAPTER *      pp_dma )\r
+{\r
+       NTSTATUS status;\r
+       WDF_DMA_ENABLER_CONFIG  dmaConfig;\r
+       \r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,\r
+               WdfDmaProfileScatterGather64, 0x80000000 - 1 );\r
+\r
+       status = WdfDmaEnablerCreate( p_fdo->FdoDevice,\r
+               &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &p_fdo->dma_enabler );\r
+       if (!NT_SUCCESS (status)) {\r
+               return status;\r
+       }\r
+       \r
+       *pp_dma = WdfDmaEnablerWdmGetDmaAdapter( \r
+               p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice );\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+// this routine fills pci_dev structure, containing all HW \r
+// and some other necessary common resources\r
+static\r
+NTSTATUS \r
+__get_resources(\r
+       IN PFDO_DEVICE_DATA p_fdo,\r
+       IN WDFCMRESLIST  ResourcesRaw,\r
+       IN WDFCMRESLIST  ResourcesTranslated\r
+       )\r
+{\r
+       NTSTATUS status;\r
+       ULONG i, k=0;\r
+       PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc;\r
+       PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc_raw;\r
+       BUS_INTERFACE_STANDARD  bus_pci_ifc;\r
+       struct pci_dev *pdev = &p_fdo->pci_dev;\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       //\r
+       // Get PCI BUS interface\r
+       // \r
+       status = __get_bus_ifc( p_fdo, &GUID_BUS_INTERFACE_STANDARD, &bus_pci_ifc );\r
+       if( !NT_SUCCESS( status ) ) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
+                       ("failed: status=0x%x\n", status));\r
+               return status;\r
+       }\r
+       RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );\r
+       p_fdo->pci_bus_ifc_taken = TRUE;\r
+\r
+       // \r
+       // get HW resources\r
+       //\r
+       for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {\r
+\r
+               desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );\r
+               desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i );\r
+\r
+               switch (desc->Type) {\r
+\r
+                       case CmResourceTypeMemory:\r
+                               MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
+                                       ("EvtPrepareHardware(Raw): Desc %d: Memory: Start %#I64x, Length %#x\n", \r
+                                       i, desc_raw->u.Memory.Start.QuadPart, desc_raw->u.Memory.Length ));\r
+                               MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
+                                       ("EvtPrepareHardware: Desc %d: Memory: Start %#I64x, Length %#x\n", \r
+                                       i, desc->u.Memory.Start.QuadPart, desc->u.Memory.Length ));\r
+\r
+                               if (k < N_BARS) {\r
+                                       pdev->bar[k].phys = desc->u.Memory.Start.QuadPart;\r
+                                       pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length;\r
+                               }\r
+                               k++;\r
+                               break;\r
+\r
+#ifdef USE_WDM_INTERRUPTS\r
+                       case CmResourceTypeInterrupt:\r
+                               pdev->int_info = *desc;\r
+                               break;\r
+#endif\r
+\r
+                       default:\r
+                               //\r
+                               // Ignore all other descriptors.\r
+                               //\r
+                               break;\r
+               }\r
+       }\r
+       if (i ==0) {\r
+               // This means that no resources are found\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("WdfCmResourceListGetCount: returned 0, quiting\n"));\r
+               return STATUS_INSUFFICIENT_RESOURCES;\r
+       }\r
+\r
+       //\r
+       // get uplink info. \r
+       //\r
+       status = pci_save_config( &pdev->bus_pci_ifc, &pdev->pci_cfg_space);\r
+       if( !NT_SUCCESS( status ) )\r
+       {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
+                       ("Failed to save HCA config: status=0x%x\n", status));\r
+               goto err;\r
+       }\r
+       pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info );\r
+\r
+       //\r
+       // allocate DMA adapter\r
+       //\r
+       status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter );\r
+       if( !NT_SUCCESS( status ) )\r
+       {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
+                       ("Failed to get DMA adapter: status=0x%x\n", status));\r
+               goto err;\r
+       }\r
+       p_fdo->dma_adapter_taken = TRUE;\r
+       \r
+       //\r
+       // fill more fields in pci_dev\r
+       //\r
+       pdev->ven_id = pdev->pci_cfg_space.VendorID;\r
+       pdev->dev_id = pdev->pci_cfg_space.DeviceID;\r
+       pdev->p_self_do = WdfDeviceWdmGetDeviceObject(p_fdo->FdoDevice);\r
+       \r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+err:\r
+       __put_resources(p_fdo);\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+\r
+NTSTATUS\r
+EvtPrepareHardware(\r
+       IN WDFDEVICE  Device,\r
+       IN WDFCMRESLIST  ResourcesRaw,\r
+       IN WDFCMRESLIST  ResourcesTranslated\r
+       )\r
+{\r
+#ifndef USE_WDM_INTERRUPTS\r
+       int i;\r
+#endif\r
+       int err;\r
+       NTSTATUS status;\r
+       PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+       struct pci_dev *pdev = &p_fdo->pci_dev;\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       // get resources\r
+       status = __get_resources( p_fdo, ResourcesRaw, ResourcesTranslated );\r
+       if( !NT_SUCCESS( status ) ) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__get_bus_ifc failed: status=0x%x\n", status));\r
+               goto err;\r
+       }\r
+\r
+       // enable the card\r
+       status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );\r
+       if( !NT_SUCCESS( status ) ) \r
+               goto err;\r
+\r
+       //\r
+       // init the card\r
+       //\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+       // enable interrupts for start up\r
+       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) \r
+               WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);\r
+#endif \r
+\r
+       // NET library\r
+       err = mlx4_init_one( &p_fdo->pci_dev );\r
+       if (err) {\r
+               status = errno_to_ntstatus(err);\r
+               goto err;\r
+       }\r
+\r
+       // IB library\r
+       err = mlx4_ib_init();\r
+       if (err) {\r
+               status = errno_to_ntstatus(err);\r
+               goto err;\r
+       }\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+       //\r
+       // complete filling interrupt context (for more efficiency)\r
+       //\r
+       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
+               struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );\r
+               PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( \r
+                       p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );\r
+\r
+               p_isr_ctx->eq = &priv->eq_table.eq[i];\r
+       }\r
+#endif\r
+\r
+       //\r
+       // prepare MLX4 IB interface\r
+       //\r
+\r
+       // fill the header\r
+       p_fdo->bus_ib_ifc.Size = sizeof(MLX4_BUS_IB_INTERFACE);\r
+       p_fdo->bus_ib_ifc.Version = MLX4_BUS_IB_INTERFACE_VERSION;\r
+       // Let the framework handle reference counting.\r
+       p_fdo->bus_ib_ifc.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
+       p_fdo->bus_ib_ifc.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
+\r
+       p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;\r
+       p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
+       p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
+\r
+       status = STATUS_SUCCESS;\r
+       \r
+err:\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+NTSTATUS\r
+EvtReleaseHardware(\r
+       IN WDFDEVICE  Device,\r
+       IN WDFCMRESLIST  ResourcesTranslated\r
+       )\r
+{\r
+       PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+\r
+       UNUSED_PARAM(ResourcesTranslated);\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       mlx4_ib_cleanup();\r
+       mlx4_remove_one( &p_fdo->pci_dev );\r
+       __put_resources( p_fdo );\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+\r
+static\r
+NTSTATUS \r
+__create_interrupt(\r
+       IN WDFDEVICE                            device,\r
+       IN int                                          int_num,\r
+       IN PFN_WDF_INTERRUPT_ISR        isr,\r
+       IN PFN_WDF_INTERRUPT_DPC        dpc,\r
+       IN PFDO_DEVICE_DATA                     p_fdo,\r
+       OUT WDFINTERRUPT                *       p_int_obj\r
+       )\r
+{\r
+       NTSTATUS Status;\r
+\r
+       WDF_INTERRUPT_CONFIG  interruptConfig;\r
+       WDF_OBJECT_ATTRIBUTES  interruptAttributes;\r
+       PINTERRUPT_DATA p_isr_ctx;\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );\r
+       \r
+       interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;\r
+       interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;\r
+       \r
+       \r
+       WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( \r
+               &interruptAttributes, INTERRUPT_DATA );\r
+\r
+       Status = WdfInterruptCreate( device,\r
+               &interruptConfig, &interruptAttributes, p_int_obj );\r
+\r
+       p_isr_ctx = WdfObjectGetTypedContext( *p_int_obj, INTERRUPT_DATA );\r
+       p_isr_ctx->int_num = int_num;\r
+       p_isr_ctx->p_fdo = p_fdo;\r
+       p_isr_ctx->eq = NULL;\r
+\r
+       // one can call WdfInterruptSetPolicy() to set the policy, affinity etc\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return Status;\r
+}\r
+\r
+#endif\r
+\r
+NTSTATUS\r
+EvtDeviceAdd(\r
+       IN WDFDRIVER        Driver,\r
+       IN PWDFDEVICE_INIT  DeviceInit\r
+       )\r
+/*++\r
+Routine Description:\r
+\r
+       EvtDeviceAdd is called by the framework in response to AddDevice\r
+       call from the PnP manager. We create and initialize a device object to\r
+       represent a new instance of mxe bus.\r
+\r
+Arguments:\r
+\r
+       Driver - Handle to a framework driver object created in DriverEntry\r
+\r
+       DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
+\r
+Return Value:\r
+\r
+       NTSTATUS\r
+\r
+--*/\r
+{\r
+#ifndef USE_WDM_INTERRUPTS\r
+       int i;\r
+#endif\r
+       WDF_OBJECT_ATTRIBUTES                   attributes;\r
+       NTSTATUS                                                status;\r
+       WDFDEVICE                                               device;\r
+       PFDO_DEVICE_DATA                                p_fdo;\r
+       PNP_BUS_INFORMATION                             busInfo;\r
+       WDF_PNPPOWER_EVENT_CALLBACKS    Callbacks;\r
+\r
+       UNREFERENCED_PARAMETER(Driver);\r
+\r
+       PAGED_CODE ();\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       //\r
+       // register PnP & Power stuff\r
+       //\r
+       WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);\r
+       Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware;\r
+       Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;\r
+       Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;\r
+       Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;\r
+\r
+       WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );\r
+       \r
+       //\r
+       // Initialize all the properties specific to the device.\r
+       // Framework has default values for the one that are not\r
+       // set explicitly here. So please read the doc and make sure\r
+       // you are okay with the defaults.\r
+       //\r
+       WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
+       WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r
+\r
+       //\r
+       // Initialize attributes structure to specify size and accessor function\r
+       // for storing device context.\r
+       //\r
+       WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);\r
+\r
+       //\r
+       // Create a framework device object. In response to this call, framework\r
+       // creates a WDM deviceobject.\r
+       //\r
+       status = WdfDeviceCreate(&DeviceInit, &attributes, &device);\r
+       if (!NT_SUCCESS(status)) {\r
+               MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
+                       ("WdfDeviceCreate failed with 0x%x\n", status));\r
+               goto end;\r
+       }\r
+\r
+       //\r
+       // Get the device context.\r
+       //\r
+       p_fdo = FdoGetData(device);\r
+       RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
+       p_fdo->FdoDevice = device;\r
+\r
+       //\r
+       // Purpose of this lock is documented in PlugInDevice routine below.\r
+       //\r
+       WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r
+       attributes.ParentObject = device;\r
+       status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock);\r
+       if (!NT_SUCCESS(status)) {\r
+               MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
+                       ("WdfWaitLockCreate failed with 0x%x\n", status));\r
+               goto end;\r
+       }\r
+\r
+       //\r
+       // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION\r
+       // for the child devices. This is an optional information provided to\r
+       // uniquely identify the bus the device is connected.\r
+       //\r
+       busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;\r
+       busInfo.LegacyBusType = PNPBus;\r
+       busInfo.BusNumber = 0;\r
+\r
+       WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
+\r
+       //\r
+       // WMI\r
+       //\r
+       status = WmiRegistration(device);\r
+       if (!NT_SUCCESS(status)) {\r
+               MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
+                       ("WmiRegistration failed with 0x%x\n", status));\r
+               goto end;\r
+       }\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+\r
+       //\r
+       // create interrupt objects\r
+       //\r
+       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
+               status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr,\r
+                       NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt );\r
+               if (NT_SUCCESS(status)) \r
+                       p_fdo->interrupt[i].valid = TRUE;\r
+               else {\r
+                       MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,\r
+                               ("WdfInterruptCreate failed %#x\n", status ));\r
+                       goto end;\r
+               }\r
+       }\r
+\r
+#endif\r
+\r
+       status = STATUS_SUCCESS;\r
+\r
+end:   \r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+\r
+\r
+void\r
+EvtDriverUnload(\r
+       IN              WDFDRIVER  Driver\r
+       )\r
+{\r
+       MLX4_ENTER( MLX4_DBG_DRV );\r
+\r
+       UNUSED_PARAM( Driver );\r
+\r
+       core_cleanup();\r
+\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+#if defined(EVENT_TRACING)\r
+       WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));\r
+#endif\r
+\r
+}\r
+\r
+static\r
+NTSTATUS\r
+__read_registry(WDFDRIVER *hDriver)\r
+{\r
+       DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");\r
+       DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");\r
+\r
+       // "log maximum number of QPs per HCA"\r
+       DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");\r
+\r
+       // "log number of RDMARC buffers per QP"\r
+       DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");\r
+\r
+       // "log maximum number of SRQs per HCA"\r
+       DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");\r
+\r
+       // "log maximum number of CQs per HCA"\r
+       DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");\r
+\r
+       // "log maximum number of multicast groups per HCA"\r
+       DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");\r
+\r
+       // "log maximum number of memory protection table entries per HCA"\r
+       DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");\r
+\r
+       // "log maximum number of memory translation table segments per HCA"\r
+       DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");     \r
+\r
+       // "Enable Quality of Service support in the HCA if > 0, (default 1)"\r
+       DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");  \r
+\r
+       ULONG value;\r
+       WDFKEY hKey = NULL;\r
+       NTSTATUS status = STATUS_SUCCESS;\r
+       \r
+       status = WdfDriverOpenParametersRegistryKey( *hDriver,\r
+               STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );\r
+\r
+       if (NT_SUCCESS (status)) {\r
+\r
+               //\r
+               // Read general values\r
+               //\r
+               status = WdfRegistryQueryULong(hKey, &debugLevel, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g_mlx4_dbg_level = g.DebugPrintLevel = value;\r
+               \r
+               status = WdfRegistryQueryULong(hKey, &debugFlags, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g_mlx4_dbg_flags = g.DebugPrintFlags = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &numQp, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_num_qp = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_rdmarc_per_qp = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &numSrq, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_num_srq = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &numCq, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_num_cq = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &numMcg, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_num_mcg = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &numMpt, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_num_mpt = value;\r
+               \r
+               status = WdfRegistryQueryULong(hKey, &numMtt, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_num_mtt = value;\r
+\r
+               status = WdfRegistryQueryULong(hKey, &enableQoS, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.enable_qos = value;\r
+               else\r
+                       g.enable_qos = 1;\r
+\r
+               WdfRegistryClose(hKey);\r
+               status = STATUS_SUCCESS;\r
+       }\r
+\r
+       return status;\r
+}\r
+\r
+NTSTATUS\r
+DriverEntry(\r
+       IN PDRIVER_OBJECT DriverObject,\r
+       IN PUNICODE_STRING RegistryPath\r
+       )\r
+/*++\r
+Routine Description:\r
+\r
+       Initialize the call backs structure of Driver Framework.\r
+\r
+Arguments:\r
+\r
+       DriverObject - pointer to the driver object\r
+\r
+       RegistryPath - pointer to a unicode string representing the path,\r
+                               to driver-specific key in the registry.\r
+\r
+Return Value:\r
+\r
+  NT Status Code\r
+\r
+--*/\r
+{\r
+       int err;\r
+       WDF_DRIVER_CONFIG   config;\r
+       NTSTATUS            status;\r
+       WDFDRIVER hDriver;\r
+\r
+#if defined(EVENT_TRACING)\r
+       WPP_INIT_TRACING(DriverObject, RegistryPath);\r
+#endif\r
+\r
+\r
+       // global initializations\r
+       g_mlx4_dbg_level = g.DebugPrintLevel = TRACE_LEVEL_VERBOSE;\r
+       g_mlx4_dbg_flags = g.DebugPrintFlags = 0xffff;\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+       MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, \r
+               ("Built %s %s, Version %s, RelDate %s\n", \r
+               __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE));\r
+\r
+       mlx4_net_init();\r
+       err = core_init();\r
+       if (err) {\r
+               status = errno_to_ntstatus(err);\r
+               goto end;\r
+       }\r
+\r
+       //\r
+       // Initiialize driver config to control the attributes that\r
+       // are global to the driver. Note that framework by default\r
+       // provides a driver unload routine. If you create any resources\r
+       // in the DriverEntry and want to be cleaned in driver unload,\r
+       // you can override that by specifing one in the Config structure.\r
+       //\r
+\r
+       WDF_DRIVER_CONFIG_INIT(\r
+               &config, EvtDeviceAdd );\r
+       config.EvtDriverUnload = EvtDriverUnload;\r
+\r
+       //\r
+       // Create a framework driver object to represent our driver.\r
+       //\r
+       status = WdfDriverCreate(DriverObject,\r
+               RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
+               &config, &hDriver);\r
+\r
+       if (!NT_SUCCESS(status)) {\r
+               MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status));\r
+               goto end;\r
+       }\r
+\r
+       //\r
+       // read registry parameters\r
+       //\r
+       status = __read_registry(&hDriver);\r
+\r
+       // we don't matter the failure in the work with Registry\r
+       status = STATUS_SUCCESS;\r
+       \r
+end:\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+\r
+}\r
+\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/drv.h b/hw/mlx4/kernel/bus/drv/drv.h
new file mode 100644 (file)
index 0000000..64d7dbd
--- /dev/null
@@ -0,0 +1,221 @@
+/*++\r
+\r
+Copyright (c) 2003 Microsoft Corporation All Rights Reserved\r
+\r
+Module Name:\r
+\r
+    mxe_drv.h\r
+\r
+Abstract:\r
+\r
+    This module contains the common private declarations\r
+    for the Mxe Bus enumerator.\r
+\r
+Environment:\r
+\r
+    kernel mode only\r
+\r
+--*/\r
+\r
+#pragma once\r
+\r
+#define BUSENUM_POOL_TAG (ULONG) 'suBT'\r
+#define N_BARS         3\r
+\r
+#include "net\mlx4.h"\r
+#include "bus_intf.h"\r
+\r
+#if DBG\r
+#define BUS_DEFAULT_DEBUG_OUTPUT_LEVEL 0x000FFFFF\r
+\r
+#else\r
+\r
+#define BUS_DEFAULT_DEBUG_OUTPUT_LEVEL 0x0\r
+\r
+#endif\r
+\r
+#define BUSRESOURCENAME L"MofResourceName"\r
+\r
+#ifndef min\r
+#define min(_a, _b)     (((_a) < (_b)) ? (_a) : (_b))\r
+#endif\r
+\r
+#ifndef max\r
+#define max(_a, _b)     (((_a) > (_b)) ? (_a) : (_b))\r
+#endif\r
+\r
+\r
+#define MLX4_MAX_INTERRUPTS            MLX4_NUM_EQ\r
+\r
+typedef struct {\r
+       WDFINTERRUPT                            WdfInterrupt;\r
+       BOOLEAN                                         valid;\r
+} res_interrupt_t;\r
+\r
+//\r
+// The device extension of the bus itself.  From whence the PDO's are born.\r
+//\r
+\r
+typedef struct _FDO_DEVICE_DATA\r
+{\r
+       BUS_WMI_STD_DATA                        WmiData;\r
+       WDFWAITLOCK                                     ChildLock;\r
+       WDFDEVICE                                       FdoDevice;\r
+       struct pci_dev                          pci_dev;\r
+       int                                                     pci_bus_ifc_taken;\r
+       WDFDMAENABLER                           dma_enabler;\r
+       int                                                     dma_adapter_taken;\r
+       res_interrupt_t                         interrupt[MLX4_MAX_INTERRUPTS];\r
+       MLX4_BUS_IB_INTERFACE           bus_ib_ifc;\r
+\r
+} FDO_DEVICE_DATA, *PFDO_DEVICE_DATA;\r
+\r
+\r
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData)\r
+\r
+//\r
+// The device extension for the PDOs.\r
+// That's of the mxe device which this bus driver enumerates.\r
+//\r
+\r
+typedef struct _PDO_DEVICE_DATA\r
+{\r
+       // Unique serial number of the device on the bus\r
+       ULONG                                                   SerialNo;\r
+       // WDF PDO object\r
+       WDFDEVICE                                               PdoDevice;\r
+       // FDO context\r
+       PFDO_DEVICE_DATA                                p_fdo;\r
+       // MLX4 BUS IB interface\r
+       WDF_QUERY_INTERFACE_CONFIG              qiMlx4Bus;\r
+       WDF_QUERY_INTERFACE_CONFIG              qiPciBus;\r
\r
+} PDO_DEVICE_DATA, *PPDO_DEVICE_DATA;\r
+\r
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_DEVICE_DATA, PdoGetData)\r
+\r
+\r
+typedef struct _QUEUE_DATA\r
+{\r
+       PFDO_DEVICE_DATA FdoData;\r
+\r
+} QUEUE_DATA, *PQUEUE_DATA;\r
+\r
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_DATA, QueueGetData)\r
+\r
+ //\r
+// wmi.c\r
+//\r
+\r
+NTSTATUS\r
+WmiRegistration(\r
+       WDFDEVICE      Device\r
+);\r
+\r
+NTSTATUS\r
+EvtStdDataSetItem(\r
+       IN  WDFWMIINSTANCE WmiInstance,\r
+       IN  ULONG DataItemId,\r
+       IN  ULONG InBufferSize,\r
+       IN  PVOID InBuffer\r
+       );\r
+\r
+NTSTATUS\r
+EvtStdDataSetInstance(\r
+       IN  WDFWMIINSTANCE WmiInstance,\r
+       IN  ULONG InBufferSize,\r
+       IN  PVOID InBuffer\r
+       );\r
+\r
+NTSTATUS\r
+EvtStdDataQueryInstance(\r
+       IN  WDFWMIINSTANCE WmiInstance,\r
+       IN  ULONG OutBufferSize,\r
+       IN  PVOID OutBuffer,\r
+       OUT PULONG BufferUsed\r
+       );\r
+\r
+\r
+//\r
+// drv.c\r
+//\r
+\r
+NTSTATUS\r
+DriverEntry(\r
+       IN PDRIVER_OBJECT DriverObject,\r
+       IN PUNICODE_STRING RegistryPath\r
+       );\r
+\r
+void\r
+EvtDriverUnload(\r
+       IN              WDFDRIVER  Driver\r
+       );\r
+       \r
+NTSTATUS\r
+EvtDeviceAdd(\r
+       IN WDFDRIVER        Driver,\r
+       IN PWDFDEVICE_INIT  DeviceInit\r
+       );\r
+\r
+NTSTATUS\r
+EvtPrepareHardware(\r
+       IN WDFDEVICE  Device,\r
+       IN WDFCMRESLIST  ResourcesRaw,\r
+       IN WDFCMRESLIST  ResourcesTranslated\r
+       );\r
+\r
+NTSTATUS\r
+EvtReleaseHardware(\r
+       IN WDFDEVICE  Device,\r
+       IN WDFCMRESLIST  ResourcesTranslated\r
+       );\r
+\r
+NTSTATUS\r
+EvtDeviceD0Exit(\r
+       IN WDFDEVICE  Device,\r
+       IN WDF_POWER_DEVICE_STATE  TargetState\r
+       );\r
+\r
+NTSTATUS\r
+EvtDeviceD0Entry(\r
+       IN WDFDEVICE  Device,\r
+       IN WDF_POWER_DEVICE_STATE  PreviousState\r
+       );\r
+\r
+\r
+//\r
+// pci.c\r
+//\r
+\r
+NTSTATUS\r
+pci_save_config(\r
+       IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
+               OUT                     PCI_COMMON_CONFIG* const        pConfig );\r
+\r
+NTSTATUS\r
+pci_hca_reset( \r
+       IN              struct pci_dev *pdev\r
+);\r
+\r
+void\r
+pci_get_uplink_info(\r
+       IN                              PCI_COMMON_CONFIG *     p_cfg,\r
+       OUT                     uplink_info_t *                 p_uplink_info );\r
+\r
+NTSTATUS\r
+pci_hca_enable(\r
+       IN              PBUS_INTERFACE_STANDARD         p_ifc,\r
+       IN              PCI_COMMON_CONFIG*                      p_cfg\r
+       );\r
+\r
+//\r
+// pdo.c\r
+//\r
+\r
+NTSTATUS\r
+create_pdo(\r
+       __in WDFDEVICE  Device,\r
+       __in PWCHAR     HardwareIds,\r
+       __in ULONG      SerialNo\r
+);\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/makefile b/hw/mlx4/kernel/bus/drv/makefile
new file mode 100644 (file)
index 0000000..a0343a1
--- /dev/null
@@ -0,0 +1,8 @@
+#\r
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source\r
+# file to this component.  This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+!INCLUDE ..\..\..\..\..\inc\openib.def\r
+\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/makefile.inc b/hw/mlx4/kernel/bus/drv/makefile.inc
new file mode 100644 (file)
index 0000000..6f8b1a6
--- /dev/null
@@ -0,0 +1,10 @@
+mofcomp: mlx4_bus.bmf\r
+\r
+mlx4_bus.bmf: bus.mof\r
+        mofcomp -B:$(OBJ_PATH)\$O\mlx4_bus.bmf bus.mof\r
+        wmimofck $(OBJ_PATH)\$O\mlx4_bus.bmf\r
+\r
+\r
+\r
+\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf b/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf
new file mode 100644 (file)
index 0000000..032c5d7
--- /dev/null
@@ -0,0 +1,9 @@
+[CatalogHeader]\r
+Name=mlx4_bus.cat\r
+PublicVersion=0x0000001\r
+EncodingType=0x00010001\r
+CATATTR1=0x10010001:OSAttr:2:6.0\r
+[CatalogFiles]\r
+<hash>mlx4_bus.inf=mlx4_bus.inf\r
+<hash>mlx4_bus.sys=mlx4_bus.sys\r
+<hash>WdfCoInstaller01005.dll=WdfCoInstaller01005.dll\r
diff --git a/hw/mlx4/kernel/bus/drv/mlx4_bus.inf b/hw/mlx4/kernel/bus/drv/mlx4_bus.inf
new file mode 100644 (file)
index 0000000..16eddf5
--- /dev/null
@@ -0,0 +1,209 @@
+; Mellanox Technologies InfiniBand HCAs.\r
+; Copyright 2008 Mellanox Technologies all Rights Reserved.\r
+\r
+[Version]\r
+Signature="$WINDOWS NT$"\r
+Class=Mlx4Bus\r
+ClassGUID={714995B2-CD65-4a47-BCFE-95AC73A0D780}\r
+Provider=%MTL%\r
+; must be synchronized with bus\drv.c\r
+DriverVer=02/01/2008,1.0.0.0\r
+CatalogFile=mlx4_bus.cat\r
+\r
+\r
+;*****************************************\r
+; Destination directory section\r
+;*****************************************\r
+\r
+[DestinationDirs]\r
+DefaultDestDir = 12\r
+Wdf_CoInstaller_CopyFiles = 11\r
+\r
+\r
+;*****************************************\r
+; Class Install section\r
+;*****************************************\r
+\r
+[ClassInstall32]\r
+AddReg=ClassAddReg\r
+\r
+[ClassAddReg]\r
+HKR,,,,"Mellanox ConnectX Adapters"\r
+HKR,,Icon,,-5\r
+HKR,,SilentInstall,,1\r
+\r
+\r
+;*****************************************\r
+; Device Install section\r
+;*****************************************\r
+\r
+[SourceDisksNames.x86]\r
+1=%DiskId%,,,""\r
+\r
+[SourceDisksNames.amd64]\r
+1=%DiskId%,,,""\r
+\r
+[SourceDisksNames.ia64]\r
+1=%DiskId%,,,""\r
+\r
+[SourceDisksFiles.x86]\r
+mlx4_bus.sys = 1,,\r
+wdfcoinstaller01005.dll = 1,,\r
+\r
+[SourceDisksFiles.amd64]\r
+mlx4_bus.sys = 1,,\r
+wdfcoinstaller01005.dll = 1,,\r
+\r
+[SourceDisksFiles.ia64]\r
+mlx4_bus.sys = 1,,\r
+wdfcoinstaller01005.dll = 1,,\r
+\r
+;*****************************************\r
+; Mlx4Bus  Install Section\r
+;*****************************************\r
+\r
+[Manufacturer]\r
+%MTL% = MLX4BUS.DeviceSection,ntx86,ntamd64,ntia64\r
+\r
+[MLX4BUS.DeviceSection]\r
+; empty since we don't support W9x/Me\r
+\r
+[MLX4BUS.DeviceSection.ntx86]\r
+%MT25408.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6340\r
+%MT25418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_634A\r
+%MT25428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6354\r
+%MT26418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6732\r
+%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c\r
+%MT00401.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_0191\r
+\r
+[MLX4BUS.DeviceSection.ntamd64]\r
+%MT25408.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6340\r
+%MT25418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_634A\r
+%MT25428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6354\r
+%MT26418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6732\r
+%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c\r
+%MT00401.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_0191\r
+\r
+[MLX4BUS.DeviceSection.ntia64]\r
+%MT25408.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6340\r
+%MT25418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_634A\r
+%MT25428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6354\r
+%MT26418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6732\r
+%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c\r
+%MT00401.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_0191\r
+\r
+[MLX4BUS.DDInstall.ntx86]\r
+CopyFiles = MLX4BUS.CopyFiles\r
+\r
+[MLX4BUS.DDInstall.ntamd64]\r
+CopyFiles = MLX4BUS.CopyFiles\r
+\r
+[MLX4BUS.DDInstall.ntia64]\r
+CopyFiles = MLX4BUS.CopyFiles\r
+\r
+[MLX4BUS.DDInstall.ntx86.Services]\r
+AddService = mlx4_bus,%SPSVCINST_ASSOCSERVICE%,MLX4BUS.ServiceInstall,MLX4BUS.EventLog\r
+\r
+[MLX4BUS.DDInstall.ntamd64.Services]\r
+AddService = mlx4_bus,%SPSVCINST_ASSOCSERVICE%,MLX4BUS.ServiceInstall,MLX4BUS.EventLog\r
+\r
+[MLX4BUS.DDInstall.ntia64.Services]\r
+AddService = mlx4_bus,%SPSVCINST_ASSOCSERVICE%,MLX4BUS.ServiceInstall,MLX4BUS.EventLog\r
+\r
+[MLX4BUS.CopyFiles]\r
+mlx4_bus.sys\r
+\r
+\r
+;*****************************************\r
+; Service Install section\r
+;*****************************************\r
+\r
+[MLX4BUS.ServiceInstall]\r
+DisplayName     = %MLX4BUS.ServiceDesc%\r
+ServiceType     = %SERVICE_KERNEL_DRIVER%\r
+StartType       = %SERVICE_DEMAND_START%\r
+ErrorControl    = %SERVICE_ERROR_NORMAL%\r
+ServiceBinary   = %12%\mlx4_bus.sys\r
+LoadOrderGroup  = extended base\r
+AddReg          = MLX4BUS.ParamsReg\r
+\r
+[MLX4BUS.EventLog]\r
+AddReg = MLX4BUS.AddEventLogReg\r
+\r
+[MLX4BUS.AddEventLogReg]\r
+HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\mlx4_bus.sys"\r
+HKR, , TypesSupported,   0x00010001, 7\r
+\r
+[MLX4BUS.ParamsReg]\r
+HKR,,DeviceCharacteristics,0x10001,0x0100         ; Use same security checks on relative opens\r
+HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)"      ; Allow generic-all access to Built-in administrators and Local system \r
+HKR,"Parameters","DebugLevel",%REG_DWORD%,0x00000003\r
+HKR,"Parameters","DebugFlags",%REG_DWORD%,0x0000ffff\r
+HKR,"Parameters","LogNumQp",%REG_DWORD%,0x00000011\r
+HKR,"Parameters","LogNumRdmaRc",%REG_DWORD%,0x00000004\r
+HKR,"Parameters","LogNumSrq",%REG_DWORD%,0x00000010\r
+HKR,"Parameters","LogNumCq",%REG_DWORD%,0x00000010\r
+HKR,"Parameters","LogNumMcg",%REG_DWORD%,0x0000000D\r
+HKR,"Parameters","LogNumMpt",%REG_DWORD%,0x00000011\r
+HKR,"Parameters","LogNumMtt",%REG_DWORD%,0x00000014\r
+HKR,"Parameters","EnableQoS",%REG_DWORD%,0x00000001\r
+\r
+HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\E51BB6E2-914A-4e21-93C0-192F4801BBFF","Flags",%REG_DWORD%,0xffff\r
+HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\E51BB6E2-914A-4e21-93C0-192F4801BBFF","Level",%REG_DWORD%,0x3\r
+\r
+;*****************************************\r
+; WDF Coinstaller installation section\r
+;*****************************************\r
+\r
+[MLX4BUS.DDInstall.ntx86.CoInstallers]\r
+AddReg=Wdf_CoInstaller_AddReg\r
+CopyFiles=Wdf_CoInstaller_CopyFiles\r
+\r
+[MLX4BUS.DDInstall.ntamd64.CoInstallers]\r
+AddReg=Wdf_CoInstaller_AddReg\r
+CopyFiles=Wdf_CoInstaller_CopyFiles\r
+\r
+[MLX4BUS.DDInstall.ntia64.CoInstallers]\r
+AddReg=Wdf_CoInstaller_AddReg\r
+CopyFiles=Wdf_CoInstaller_CopyFiles\r
+\r
+[Wdf_CoInstaller_AddReg]\r
+HKR,,CoInstallers32,0x00010000, "wdfcoinstaller01005.dll,WdfCoInstaller"\r
+\r
+[Wdf_CoInstaller_CopyFiles]\r
+wdfcoinstaller01005.dll\r
+\r
+[MLX4BUS.DDInstall.ntx86.Wdf]\r
+KmdfService = mlx4_bus, mlx4_bus_wdfsect\r
+\r
+[MLX4BUS.DDInstall.ntamd64.Wdf]\r
+KmdfService = mlx4_bus, mlx4_bus_wdfsect\r
+\r
+[MLX4BUS.DDInstall.ntia64.Wdf]\r
+KmdfService = mlx4_bus, mlx4_bus_wdfsect\r
+\r
+[mlx4_bus_wdfsect]\r
+KmdfLibraryVersion = 1.5\r
+\r
+\r
+;*****************************************\r
+; Strings\r
+;*****************************************\r
+\r
+[Strings]\r
+MTL="Mellanox Technologies Ltd."\r
+MLX4BUS.ServiceDesc = "Mellanox ConnectX Bus Enumerator"\r
+MT25408.DeviceDesc="ConnectX (MT25408) - Mellanox ConnectX SDR Channel Adapter"\r
+MT25418.DeviceDesc="ConnectX (MT25418) - Mellanox ConnectX DDR Channel Adapter"\r
+MT25428.DeviceDesc="ConnectX (MT25428) - Mellanox ConnectX QDR Channel Adapter"\r
+MT26418.DeviceDesc="ConnectX (MT26418) - Mellanox ConnectX DDR_G2 Channel Adapter"\r
+MT26428.DeviceDesc="ConnectX (MT26428) - Mellanox ConnectX QDR_G2 Channel Adapter"\r
+MT00401.DeviceDesc="ConnectX (MT00401) - Mellanox ConnectX Channel Adapter in Burning Mode"\r
+DiskId = "Mellanox Mlx4 Bus installation disk"\r
+SPSVCINST_NULL = 0x0\r
+SPSVCINST_ASSOCSERVICE = 0x00000002\r
+SERVICE_KERNEL_DRIVER  = 1\r
+SERVICE_DEMAND_START   = 3\r
+SERVICE_ERROR_NORMAL   = 1\r
+REG_DWORD              = 0x00010001\r
+REG_MULTI_SZ_APPEND    = 0x00010008\r
diff --git a/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf b/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf
new file mode 100644 (file)
index 0000000..032c5d7
--- /dev/null
@@ -0,0 +1,9 @@
+[CatalogHeader]\r
+Name=mlx4_bus.cat\r
+PublicVersion=0x0000001\r
+EncodingType=0x00010001\r
+CATATTR1=0x10010001:OSAttr:2:6.0\r
+[CatalogFiles]\r
+<hash>mlx4_bus.inf=mlx4_bus.inf\r
+<hash>mlx4_bus.sys=mlx4_bus.sys\r
+<hash>WdfCoInstaller01005.dll=WdfCoInstaller01005.dll\r
diff --git a/hw/mlx4/kernel/bus/drv/pci.c b/hw/mlx4/kernel/bus/drv/pci.c
new file mode 100644 (file)
index 0000000..c561b4d
--- /dev/null
@@ -0,0 +1,468 @@
+\r
+#include "precomp.h"\r
+\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "pci.tmh"\r
+#endif\r
+\r
+#include <complib/cl_thread.h>\r
+#include <initguid.h>\r
+#include <wdmguid.h>\r
+\r
+#define MLX4_RESET_BASE                0xf0000\r
+#define MLX4_RESET_SIZE                  0x400\r
+#define MLX4_SEM_OFFSET                  0x3fc\r
+#define MLX4_RESET_OFFSET         0x10\r
+#define MLX4_RESET_VALUE       swab32(1)\r
+\r
+#define MLX4_SEM_TIMEOUT_JIFFIES       (10 * HZ)\r
+#define MLX4_RESET_TIMEOUT_JIFFIES     (2 * HZ)\r
+\r
+#define PCI_CAPABILITY_ID_VPD                          0x03\r
+#define PCI_CAPABILITY_ID_PCIX                         0x07\r
+#define PCI_CAPABILITY_ID_PCIEXP                       0x10\r
+\r
+\r
+/*\r
+ * Vital Product Data Capability\r
+ */\r
+typedef struct _PCI_VPD_CAPABILITY {\r
+\r
+       PCI_CAPABILITIES_HEADER Header;\r
+\r
+       USHORT          Flags;\r
+       ULONG                   Data;\r
+\r
+} PCI_VPD_CAPABILITY, *PPCI_VPD_CAPABILITY;\r
+\r
+\r
+/*\r
+ * PCI-X Capability\r
+ */\r
+typedef struct _PCI_PCIX_CAPABILITY {\r
+\r
+       PCI_CAPABILITIES_HEADER Header;\r
+\r
+       USHORT          Command;\r
+       ULONG                   Status;\r
+\r
+/* for Command: */\r
+} PCI_PCIX_CAPABILITY, *PPCI_PCIX_CAPABILITY;\r
+\r
+#define  PCI_X_CMD_MAX_READ     0x000c  /* Max Memory Read Byte Count */\r
+\r
+/*\r
+ * PCI-Express Capability\r
+ */\r
+typedef struct _PCI_PCIEXP_CAPABILITY {\r
+\r
+       PCI_CAPABILITIES_HEADER Header;\r
+\r
+       USHORT          Flags;\r
+       ULONG                   DevCapabilities;\r
+       USHORT          DevControl;\r
+       USHORT          DevStatus;\r
+       ULONG                   LinkCapabilities;\r
+       USHORT          LinkControl;\r
+       USHORT          LinkStatus;\r
+       ULONG                   SlotCapabilities;\r
+       USHORT          SlotControl;\r
+       USHORT          SlotStatus;\r
+       USHORT          RootControl;\r
+       USHORT          RootCapabilities;\r
+       USHORT          RootStatus;\r
+} PCI_PCIEXP_CAPABILITY, *PPCI_PCIEXP_CAPABILITY;\r
+\r
+/* for DevControl: */\r
+#define  PCI_EXP_DEVCTL_READRQ  0x7000  /* Max_Read_Request_Size */\r
+\r
+static NTSTATUS\r
+__get_bus_ifc(\r
+       IN                              DEVICE_OBJECT* const            pDevObj,\r
+       IN              const   GUID* const                                     pGuid,\r
+               OUT                     BUS_INTERFACE_STANDARD          *pBusIfc );\r
+\r
+static NTSTATUS\r
+__restore_pci_config(\r
+       IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
+       IN                              PCI_COMMON_CONFIG* const        pConfig );\r
+\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (PAGE, __get_bus_ifc)\r
+#pragma alloc_text (PAGE, __restore_pci_config)\r
+#endif\r
+\r
+/*\r
+ * Returns the offset in configuration space of the PCI-X capabilites.\r
+ */\r
+static ULONG\r
+__find_capability(\r
+       IN                              PCI_COMMON_CONFIG* const        pConfig,  \r
+       IN                              char cap_id\r
+       )\r
+{\r
+       ULONG                                           offset = 0;\r
+       PCI_CAPABILITIES_HEADER         *pHdr = NULL;\r
+       UCHAR                                           *pBuf = (UCHAR*)pConfig;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+\r
+       if  ( pConfig->HeaderType == PCI_DEVICE_TYPE ) {\r
+               if( pConfig->u.type0.CapabilitiesPtr )\r
+               {\r
+                       pHdr = (PCI_CAPABILITIES_HEADER*)\r
+                               (pBuf + pConfig->u.type0.CapabilitiesPtr);\r
+               }\r
+       }\r
+\r
+       if  ( pConfig->HeaderType == PCI_BRIDGE_TYPE ) {\r
+               if( pConfig->u.type1.CapabilitiesPtr )\r
+               {\r
+                       pHdr = (PCI_CAPABILITIES_HEADER*)\r
+                               (pBuf + pConfig->u.type1.CapabilitiesPtr);\r
+               }\r
+       }\r
+\r
+       /*\r
+        * Fix up any fields that might cause changes to the\r
+        * device - like writing VPD data.\r
+        */\r
+       while( pHdr )\r
+       {\r
+               if( pHdr->CapabilityID == cap_id )\r
+               {\r
+                       offset = (UCHAR)(((ULONG_PTR)pHdr) - ((ULONG_PTR)pConfig));\r
+                       break;\r
+               }\r
+\r
+               if( pHdr->Next )\r
+                       pHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next);\r
+               else\r
+                       pHdr = NULL;\r
+       }\r
+\r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+       return offset;\r
+}\r
+\r
+/*\r
+ * Restore saved PCI configuration, skipping registers 22 and 23, as well\r
+ * as any registers where writing will have side effects such as the flags\r
+ * field of the VPD and vendor specific capabilities.  The function also delays\r
+ * writing the command register, bridge control register (if applicable), and\r
+ * PCIX command register (if present).\r
+ */\r
+static NTSTATUS\r
+__restore_pci_config(\r
+       IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
+       IN                              PCI_COMMON_CONFIG* const        pConfig )\r
+{\r
+       NTSTATUS status = STATUS_SUCCESS;\r
+       int             i, *pci_hdr = (int*)pConfig;\r
+       int hca_pcix_cap = 0;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+\r
+       /* get capabilities */\r
+       hca_pcix_cap = __find_capability( pConfig, PCI_CAPABILITY_ID_PCIX );\r
+\r
+       /* restore capabilities*/\r
+       {\r
+               int hca_pcie_cap = __find_capability( pConfig, PCI_CAPABILITY_ID_PCIEXP );\r
+               PCI_PCIEXP_CAPABILITY   *pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)pConfig) + hca_pcie_cap);\r
+\r
+               if (hca_pcix_cap) {\r
+                       if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
+                               &pci_hdr[hca_pcix_cap/4], hca_pcix_cap, 4) ) {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                                       ("Couldn't restore HCA PCI-X command register, aborting.\n"));\r
+                               status = STATUS_UNSUCCESSFUL;\r
+                               goto out;\r
+                       }\r
+               }\r
+\r
+               if (hca_pcie_cap) {\r
+                       /* restore HCA PCI Express Device Control register */\r
+                       if ( sizeof( pPciExpCap->DevControl ) != pBusIfc->SetBusData( \r
+                               pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
+                               &pPciExpCap->DevControl,        hca_pcie_cap + \r
+                               offsetof( PCI_PCIEXP_CAPABILITY, DevControl),\r
+                               sizeof( pPciExpCap->DevControl ) )) {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                                       ("Couldn't restore HCA PCI Express Device Control register, aborting.\n"));\r
+                               status = STATUS_UNSUCCESSFUL;\r
+                               goto out;\r
+                       }\r
+                       /* restore HCA PCI Express Link Control register */\r
+                       if ( sizeof( pPciExpCap->LinkControl ) != pBusIfc->SetBusData( \r
+                               pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
+                               &pPciExpCap->LinkControl,       hca_pcie_cap + \r
+                               offsetof( PCI_PCIEXP_CAPABILITY, LinkControl),\r
+                               sizeof( pPciExpCap->LinkControl ) )) {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                                       ("Couldn't restore HCA PCI Express Link Control register, aborting.\n"));\r
+                               status = STATUS_UNSUCCESSFUL;\r
+                               goto out;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* write basic part */\r
+       for (i = 0; i < 16; ++i) {\r
+               if (i == 1)\r
+                       continue;\r
+       \r
+               if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
+                       PCI_WHICHSPACE_CONFIG, &pci_hdr[i], i * 4, 4 )) {\r
+                       MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,\r
+                               ("Couldn't restore PCI cfg reg %x,   aborting.\n", i));\r
+                       status =  STATUS_DEVICE_NOT_READY;\r
+                       goto out;\r
+               }\r
+       }\r
+\r
+       /* Write the command register. */\r
+       if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
+               PCI_WHICHSPACE_CONFIG, &pci_hdr[1], 4, 4 )) {\r
+               MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Couldn't restore COMMAND.\n"));\r
+               status =  STATUS_DEVICE_NOT_READY;\r
+       }\r
+\r
+out:   \r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+       return status;\r
+}\r
+\r
+/*\r
+ * Reads and saves the PCI configuration of the device accessible\r
+ * through the provided bus interface.  Does not read registers 22 or 23\r
+ * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset.\r
+ */\r
+NTSTATUS\r
+pci_save_config(\r
+       IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
+               OUT                     PCI_COMMON_CONFIG* const        pConfig )\r
+{\r
+       ULONG                                   len;\r
+       UINT32                                  *pBuf;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+       \r
+       pBuf = (UINT32*)pConfig;\r
+\r
+       /*\r
+        * Read the lower portion of the configuration, up to but excluding\r
+        * register 22.\r
+        */\r
+       len = pBusIfc->GetBusData(\r
+               pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 );\r
+       if( len != 88 )\r
+       {\r
+               MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,("Failed to read HCA config.\n"));\r
+               return STATUS_DEVICE_NOT_READY;\r
+       }\r
+\r
+       /* Read the upper portion of the configuration, from register 24. */\r
+       len = pBusIfc->GetBusData(\r
+               pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 );\r
+       if( len != 160 )\r
+       {\r
+               MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to read HCA config.\n"));\r
+               return STATUS_DEVICE_NOT_READY;\r
+       }\r
+\r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS\r
+pci_hca_reset( \r
+       IN              struct pci_dev *pdev\r
+)\r
+{\r
+       u32 sem;\r
+       NTSTATUS                                        status = STATUS_SUCCESS;\r
+       PBUS_INTERFACE_STANDARD         p_ifc = &pdev->bus_pci_ifc;\r
+       PCI_COMMON_CONFIG*                      p_cfg = &pdev->pci_cfg_space;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+\r
+       {\r
+               u64 end;\r
+               PUCHAR  p_reset;\r
+               PHYSICAL_ADDRESS  pa;\r
+               int cnt = 0;\r
+\r
+               /* map reset register */\r
+               pa.QuadPart = pdev->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)MLX4_RESET_BASE;\r
+               p_reset = MmMapIoSpace( pa, MLX4_RESET_SIZE, MmNonCached );\r
+               MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
+                       ("Reset area ia mapped from pa 0x%I64x to va %p, size %#x\n", \r
+                       pa.QuadPart, p_reset, MLX4_RESET_SIZE));\r
+               if( !p_reset ) {\r
+                       MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart));\r
+                       status = STATUS_UNSUCCESSFUL;\r
+                       goto err;\r
+               }\r
+\r
+               /* grab HW semaphore to lock out flash updates  f0014 - dev_id 00a00190 */\r
+               end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;\r
+               MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
+                       ("Obtaining HW semaphore at %p till %I64d\n", p_reset + MLX4_SEM_OFFSET, end));\r
+               do {\r
+                       sem = READ_REGISTER_ULONG((void*)(p_reset + MLX4_SEM_OFFSET));\r
+                       if (!sem)\r
+                               break;\r
+               \r
+                       cl_thread_suspend(1);\r
+               } while (time_before(jiffies, end) || ++cnt < 100);\r
+               \r
+               if (sem) {\r
+                       MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
+                               ("Failed to obtain HW semaphore in %d attemps till %I64d, aborting\n",\r
+                               cnt, jiffies));\r
+                       status = STATUS_UNSUCCESSFUL;\r
+                       MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE );\r
+                       goto err;\r
+               }\r
+               \r
+               \r
+               /* Issue the reset. */\r
+               MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
+                       ("Resetting  the chip at %p with %#x...\n", p_reset + MLX4_RESET_OFFSET, MLX4_RESET_VALUE));\r
+               WRITE_REGISTER_ULONG( (void*)(p_reset + MLX4_RESET_OFFSET), MLX4_RESET_VALUE );\r
+\r
+               /* unmap the reset register */\r
+               MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,("Unmapping reset register \n"));\r
+               MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE );\r
+\r
+               /* Wait a second. */\r
+               cl_thread_suspend( 1000 );\r
+       }\r
+\r
+       /* Read the configuration register until it doesn't return 0xFFFFFFFF */\r
+       {\r
+               ULONG                                   data, i, reset_failed = 1;\r
+               MLX4_PRINT( TRACE_LEVEL_INFORMATION     ,MLX4_DBG_PNP  ,("Read the configuration register \n"));\r
+               for( i = 0; i < 100; i++ ) {\r
+                       if (4 != p_ifc->GetBusData( p_ifc->Context,\r
+                               PCI_WHICHSPACE_CONFIG, &data, 0, 4)) {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                                       ("Failed to read device configuration data. Card reset failed !\n"));\r
+                               status = STATUS_UNSUCCESSFUL;\r
+                               break;\r
+                       }\r
+                       /* See if we got valid data. */\r
+                       if( data != 0xFFFFFFFF ) {\r
+                               reset_failed = 0;\r
+                               break;\r
+                       }\r
+               \r
+                       cl_thread_suspend( 100 );\r
+               }       \r
+\r
+               if (reset_failed) {\r
+                       MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                               ("Doh! PCI device did not come back after reset!\n"));\r
+                       status = STATUS_UNSUCCESSFUL;\r
+                       goto err;\r
+               }\r
+       }\r
+\r
+       /* restore the HCA's PCI configuration headers */\r
+       {\r
+               /* Restore the HCA's configuration. */\r
+               MLX4_PRINT( TRACE_LEVEL_INFORMATION  ,MLX4_DBG_PNP  ,("Restoring HCA PCI configuration \n"));\r
+               status = __restore_pci_config( p_ifc, p_cfg );\r
+               if( !NT_SUCCESS( status ) ) {\r
+                       MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                               ("Failed to restore HCA config. Card reset failed !\n"));\r
+                       goto err;\r
+               }\r
+       }\r
+\r
+       MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP , ("HCA is reset ! \n"));\r
+\r
+       status = STATUS_SUCCESS;\r
+\r
+err:\r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+       return status;\r
+}\r
+\r
+\r
+/*\r
+ * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM.\r
+ */\r
+void\r
+pci_get_uplink_info(\r
+       IN                              PCI_COMMON_CONFIG *             p_cfg,\r
+       OUT                             uplink_info_t *                 p_uplink_info )\r
+{\r
+       ULONG                                   capOffset;\r
+       PCI_PCIX_CAPABILITY             *pPciXCap;\r
+       PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+\r
+       // PCIX Capability\r
+       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX );\r
+       if( capOffset ) {\r
+               pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
+\r
+               p_uplink_info->bus_type = UPLINK_BUS_PCIX;\r
+               if (pPciXCap->Status & (1 << 17))\r
+                       p_uplink_info->u.pci_x.capabilities = UPLINK_BUS_PCIX_133;\r
+               \r
+       }\r
+\r
+       // PCI Express Capability\r
+       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIEXP );\r
+       if( capOffset ) {\r
+               pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
+\r
+               p_uplink_info->bus_type = UPLINK_BUS_PCIE;\r
+               if ((pPciExpCap->LinkStatus & 15) == 1)\r
+                       p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_SDR;\r
+               if ((pPciExpCap->LinkStatus & 15) == 2)\r
+                       p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_DDR;\r
+               p_uplink_info->u.pci_e.link_width = (uint8_t)((pPciExpCap->LinkStatus >> 4) & 0x03f);\r
+               p_uplink_info->u.pci_e.capabilities = (uint8_t)((pPciExpCap->LinkCapabilities >> 2) & 0xfc);\r
+               p_uplink_info->u.pci_e.capabilities |= pPciExpCap->LinkCapabilities & 3;\r
+       }\r
+\r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+}\r
+\r
+NTSTATUS\r
+pci_hca_enable(\r
+       IN              PBUS_INTERFACE_STANDARD         p_ifc,\r
+       IN              PCI_COMMON_CONFIG*                      p_cfg\r
+       )\r
+{\r
+               NTSTATUS                        status = STATUS_SUCCESS;\r
+               ULONG                           len;\r
+       \r
+               MLX4_ENTER( MLX4_DBG_PNP );\r
+       \r
+               /* fix command register (set PCI Master bit) */\r
+               // NOTE: we change here the saved value of the command register\r
+               if ( (p_cfg->Command & 7) != 7 ) {\r
+                       p_cfg->Command |= 7;\r
+                       len = p_ifc->SetBusData( p_ifc->Context, PCI_WHICHSPACE_CONFIG,\r
+                               (PVOID)&p_cfg->Command , 4, sizeof(ULONG) );\r
+                       if( len != sizeof(ULONG) ) {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to write command register.\n"));\r
+                               status = STATUS_DEVICE_NOT_READY;\r
+                       }\r
+               }\r
+\r
+               MLX4_EXIT( MLX4_DBG_PNP );\r
+               return status;\r
+}\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/pdo.c b/hw/mlx4/kernel/bus/drv/pdo.c
new file mode 100644 (file)
index 0000000..4fb02c5
--- /dev/null
@@ -0,0 +1,240 @@
+#include "precomp.h"\r
+#include <initguid.h>\r
+#include <wdmguid.h>\r
+\r
+#if defined(EVENT_TRACING)\r
+#include "pdo.tmh"\r
+#endif\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text(PAGE, create_pdo)\r
+#endif\r
+\r
+#define MAX_ID_LEN 80\r
+\r
+NTSTATUS\r
+create_pdo(\r
+       __in WDFDEVICE  Device,\r
+       __in PWCHAR     HardwareIds,\r
+       __in ULONG      SerialNo\r
+)\r
+/*++\r
+\r
+Routine Description:\r
+\r
+    This routine creates and initialize a PDO.\r
+\r
+Arguments:\r
+\r
+Return Value:\r
+\r
+    NT Status code.\r
+\r
+--*/\r
+{\r
+       NTSTATUS                    status;\r
+       PWDFDEVICE_INIT             pDeviceInit = NULL;\r
+       PPDO_DEVICE_DATA            p_pdo = NULL;\r
+       PFDO_DEVICE_DATA            p_fdo;\r
+       WDFDEVICE                   hChild = NULL;\r
+       WDF_OBJECT_ATTRIBUTES       pdoAttributes;\r
+       WDF_DEVICE_PNP_CAPABILITIES pnpCaps;\r
+       WDF_DEVICE_POWER_CAPABILITIES powerCaps;\r
+       DECLARE_CONST_UNICODE_STRING(compatId, BUSENUM_COMPATIBLE_IDS);\r
+       DECLARE_CONST_UNICODE_STRING(deviceLocation, L"MLX4 Bus 0");\r
+       UNICODE_STRING deviceId;\r
+       DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN);\r
+\r
+       MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("Entered CreatePdo\n"));\r
+\r
+       PAGED_CODE();\r
+\r
+       //\r
+       // Allocate a WDFDEVICE_INIT structure and set the properties\r
+       // so that we can create a device object for the child.\r
+       //\r
+       pDeviceInit = WdfPdoInitAllocate(Device);\r
+\r
+       if (pDeviceInit == NULL) {\r
+               status = STATUS_INSUFFICIENT_RESOURCES;\r
+               goto Cleanup;\r
+       }\r
+\r
+       //\r
+       // Set DeviceType\r
+       //\r
+       WdfDeviceInitSetDeviceType(pDeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
+\r
+       //\r
+       // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId\r
+       //\r
+       RtlInitUnicodeString(&deviceId,HardwareIds);\r
+\r
+       status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       //\r
+       // Note same string  is used to initialize hardware id too\r
+       //\r
+       status = WdfPdoInitAddHardwareID(pDeviceInit, &deviceId);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       status = WdfPdoInitAddCompatibleID(pDeviceInit, &compatId);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       status =  RtlUnicodeStringPrintf(&buffer, L"%02d", SerialNo);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       //\r
+       // Provide a description about the device. This text is usually read from\r
+       // the device. In the case of USB device, this text comes from the string\r
+       // descriptor. This text is displayed momentarily by the PnP manager while\r
+       // it's looking for a matching INF. If it finds one, it uses the Device\r
+       // Description from the INF file or the friendly name created by\r
+       // coinstallers to display in the device manager. FriendlyName takes\r
+       // precedence over the DeviceDesc from the INF file.\r
+       //\r
+       status = RtlUnicodeStringPrintf(&buffer,L"Mellanox ConnectX Virtual Infiniband Adapter (#%02d)", SerialNo );\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       //\r
+       // You can call WdfPdoInitAddDeviceText multiple times, adding device\r
+       // text for multiple locales. When the system displays the text, it\r
+       // chooses the text that matches the current locale, if available.\r
+       // Otherwise it will use the string for the default locale.\r
+       // The driver can specify the driver's default locale by calling\r
+       // WdfPdoInitSetDefaultLocale.\r
+       //\r
+       status = WdfPdoInitAddDeviceText(pDeviceInit,\r
+               &buffer, &deviceLocation, 0x409);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409);\r
+\r
+       //\r
+       // Initialize the attributes to specify the size of PDO device extension.\r
+       // All the state information private to the PDO will be tracked here.\r
+       //\r
+       WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_DATA);\r
+\r
+       status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       //\r
+       // Once the device is created successfully, framework frees the\r
+       // DeviceInit memory and sets the pDeviceInit to NULL. So don't\r
+       // call any WdfDeviceInit functions after that.\r
+       //\r
+       // Get the device context.\r
+       //\r
+       p_pdo = PdoGetData(hChild);\r
+       p_fdo = FdoGetData(Device);\r
+\r
+       p_pdo->p_fdo = p_fdo;\r
+       p_pdo->SerialNo = SerialNo;\r
+       p_pdo->PdoDevice = hChild;\r
+\r
+       //\r
+       // Set some properties for the child device.\r
+       //\r
+       WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);\r
+       pnpCaps.Removable         = WdfTrue;\r
+       pnpCaps.EjectSupported    = WdfTrue;\r
+       pnpCaps.SurpriseRemovalOK = WdfTrue;\r
+\r
+       pnpCaps.Address  = SerialNo;\r
+       pnpCaps.UINumber = SerialNo;\r
+\r
+       WdfDeviceSetPnpCapabilities(hChild, &pnpCaps);\r
+\r
+       WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);\r
+\r
+       powerCaps.DeviceD1 = WdfTrue;\r
+       powerCaps.WakeFromD1 = WdfTrue;\r
+       powerCaps.DeviceWake = PowerDeviceD1;\r
+\r
+       powerCaps.DeviceState[PowerSystemWorking]   = PowerDeviceD0;\r
+       powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;\r
+       powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
+       powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
+       powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
+       powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
+\r
+       WdfDeviceSetPowerCapabilities(hChild, &powerCaps);\r
+\r
+       //\r
+       // Create a custom interface so that other drivers can\r
+       // query (IRP_MN_QUERY_INTERFACE) and use our callbacks directly.\r
+       //\r
+       p_fdo->bus_ib_ifc.Context = p_pdo;\r
+\r
+       WDF_QUERY_INTERFACE_CONFIG_INIT( &p_pdo->qiMlx4Bus,\r
+               (PINTERFACE) &p_fdo->bus_ib_ifc,\r
+               &MLX4_BUS_IB_INTERFACE_GUID, NULL);\r
+\r
+       status = WdfDeviceAddQueryInterface( hChild, &p_pdo->qiMlx4Bus );\r
+       if (!NT_SUCCESS(status))\r
+               goto Cleanup;\r
+\r
+       //\r
+       // Expose also PCI.SYS interface for MLX4_HCA\r
+       //\r
+       WDF_QUERY_INTERFACE_CONFIG_INIT( &p_pdo->qiPciBus,\r
+               (PINTERFACE) &p_fdo->pci_dev.bus_pci_ifc,\r
+               &GUID_BUS_INTERFACE_STANDARD, NULL);\r
+\r
+       status = WdfDeviceAddQueryInterface( hChild, &p_pdo->qiPciBus );\r
+       if (!NT_SUCCESS(status))\r
+               goto Cleanup;\r
+\r
+       //\r
+       // Add this device to the FDO's collection of children.\r
+       // After the child device is added to the static collection successfully,\r
+       // driver must call WdfPdoMarkMissing to get the device deleted. It\r
+       // shouldn't delete the child device directly by calling WdfObjectDelete.\r
+       //\r
+       status = WdfFdoAddStaticChild(Device, hChild);\r
+       if (!NT_SUCCESS(status)) {\r
+               goto Cleanup;\r
+       }\r
+\r
+       return status;\r
+\r
+Cleanup:\r
+       KdPrint(("BusEnum: Bus_CreatePdo failed %x\n", status));\r
+\r
+       //\r
+       // Call WdfDeviceInitFree if you encounter an error before the\r
+       // device is created. Once the device is created, framework\r
+       // NULLs the pDeviceInit value.\r
+       //\r
+       if (pDeviceInit != NULL) {\r
+               WdfDeviceInitFree(pDeviceInit);\r
+       }\r
+\r
+       if(hChild) {\r
+               WdfObjectDelete(hChild);\r
+       }\r
+\r
+       return status;\r
+}\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/precomp.h b/hw/mlx4/kernel/bus/drv/precomp.h
new file mode 100644 (file)
index 0000000..bcfbcdb
--- /dev/null
@@ -0,0 +1,18 @@
+#include <ntddk.h>\r
+#include <wdf.h>\r
+#define NTSTRSAFE_LIB\r
+#include <ntstrsafe.h>\r
+#include <initguid.h> // required for GUID definitions\r
+#include "public.h"\r
+#include "l2w.h"\r
+#include "ib\mlx4_ib.h"\r
+#include "drv.h"\r
+#if 0\r
+#include "mxe_hca.h"\r
+#include "mtnic_if_defs.h"\r
+#include "mxe_utils.h"\r
+#include "mxe_wpptrace.h"\r
+#include "mtnic_dev.h"\r
+#include "mxe_drv.h"\r
+#endif\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/sources b/hw/mlx4/kernel/bus/drv/sources
new file mode 100644 (file)
index 0000000..bf237d7
--- /dev/null
@@ -0,0 +1,54 @@
+TARGETNAME=mlx4_bus\r
+TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE=DRIVER\r
+\r
+!if $(FREEBUILD)\r
+#ENABLE_EVENT_TRACING=1\r
+!else\r
+#ENABLE_EVENT_TRACING=1\r
+!endif\r
+\r
+SOURCES= \\r
+       bus.rc \\r
+       drv.c \\r
+       pci.c \\r
+       pdo.c \\r
+       wmi.c \\r
+\r
+PRECOMPILED_INCLUDE=precomp.h\r
+\r
+NTTARGETFILE0=mofcomp\r
+\r
+KMDF_VERSION=1\r
+\r
+C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN -DUSE_WDM_INTERRUPTS\r
+\r
+INCLUDES=..;..\inc;..\..\inc;..\core;..\..\..\inc;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel;..\core;..\core\$O\r
+\r
+\r
+TARGETLIBS= $(TARGETLIBS) \\r
+       $(DDK_LIB_PATH)\ntstrsafe.lib \\r
+       $(TARGETPATH)\*\complib.lib \\r
+       $(TARGETPATH)\*\mlx4_core.lib \\r
+       $(TARGETPATH)\*\mlx4_ib.lib \\r
+       $(TARGETPATH)\*\mlx4_net.lib \r
+       \r
+       \r
+\r
+#LINKER_FLAGS=/MAP \r
+\r
+\r
+!IFDEF ENABLE_EVENT_TRACING\r
+\r
+C_DEFINES = $(C_DEFINES) -DEVENT_TRACING\r
+\r
+RUN_WPP= $(SOURCES) -km -dll -ext: .c .cpp .h .C .CPP .H\\r
+#      -preserveext:.cpp .h\\r
+       -scan:..\inc\mlx4_debug.h \\r
+       -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \\r
+       -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \r
+!ENDIF\r
+\r
+MSC_OPTIMIZATION=/Oi\r
+MSC_WARNING_LEVEL= /W4\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/wmi.c b/hw/mlx4/kernel/bus/drv/wmi.c
new file mode 100644 (file)
index 0000000..e3faf50
--- /dev/null
@@ -0,0 +1,244 @@
+/*++\r
+\r
+Copyright (c) Microsoft Corporation.  All rights reserved.\r
+\r
+    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY\r
+    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r
+    PURPOSE.\r
+\r
+Module Name:\r
+\r
+    WMI.C\r
+\r
+Abstract:\r
+\r
+    This module handles all the WMI Irps.\r
+\r
+Environment:\r
+\r
+    Kernel mode\r
+\r
+--*/\r
+\r
+#include "precomp.h"\r
+\r
+#if defined(EVENT_TRACING)\r
+#include "wmi.tmh"\r
+#endif\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text(PAGE,WmiRegistration)\r
+#pragma alloc_text(PAGE,EvtStdDataSetItem)\r
+#pragma alloc_text(PAGE,EvtStdDataSetInstance)\r
+#pragma alloc_text(PAGE,EvtStdDataQueryInstance)\r
+#endif\r
+\r
+NTSTATUS\r
+WmiRegistration(\r
+       WDFDEVICE      Device\r
+       )\r
+/*++\r
+Routine Description\r
+\r
+    Registers with WMI as a data provider for this\r
+    instance of the device\r
+\r
+--*/\r
+{\r
+       WDF_WMI_PROVIDER_CONFIG providerConfig;\r
+       WDF_WMI_INSTANCE_CONFIG instanceConfig;\r
+       PFDO_DEVICE_DATA deviceData;\r
+       NTSTATUS status;\r
+       DECLARE_CONST_UNICODE_STRING(busRsrcName, BUSRESOURCENAME);\r
+\r
+       PAGED_CODE();\r
+\r
+       deviceData = FdoGetData(Device);\r
+\r
+       //\r
+       // Register WMI classes.\r
+       // First specify the resource name which contain the binary mof resource.\r
+       //\r
+       status = WdfDeviceAssignMofResourceName(Device, &busRsrcName);\r
+       if (!NT_SUCCESS(status)) {\r
+               return status;\r
+       }\r
+\r
+       WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &MLX4_BUS_WMI_STD_DATA_GUID);\r
+       providerConfig.MinInstanceBufferSize = sizeof(BUS_WMI_STD_DATA);\r
+\r
+       //\r
+       // You would want to create a WDFWMIPROVIDER handle separately if you are\r
+       // going to dynamically create instances on the provider.  Since we are\r
+       // statically creating one instance, there is no need to create the provider\r
+       // handle.\r
+       //\r
+       WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig);\r
+\r
+       //\r
+       // By setting Register to TRUE, we tell the framework to create a provider\r
+       // as part of the Instance creation call. This eliminates the need to\r
+       // call WdfWmiProviderRegister.\r
+       //\r
+       instanceConfig.Register = TRUE;\r
+       instanceConfig.EvtWmiInstanceQueryInstance = EvtStdDataQueryInstance;\r
+       instanceConfig.EvtWmiInstanceSetInstance = EvtStdDataSetInstance;\r
+       instanceConfig.EvtWmiInstanceSetItem = EvtStdDataSetItem;\r
+\r
+       status = WdfWmiInstanceCreate(  Device,\r
+               &instanceConfig, WDF_NO_OBJECT_ATTRIBUTES,WDF_NO_HANDLE );\r
+\r
+       return status;\r
+}\r
+\r
+//\r
+// WMI System Call back functions\r
+//\r
+NTSTATUS\r
+EvtStdDataSetItem(\r
+       IN  WDFWMIINSTANCE WmiInstance,\r
+       IN  ULONG DataItemId,\r
+       IN  ULONG InBufferSize,\r
+       IN  PVOID InBuffer\r
+       )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+       This routine is a callback into the driver to set for the contents of\r
+       an instance.\r
+\r
+Arguments:\r
+\r
+       WmiInstance is the instance being set\r
+\r
+       DataItemId has the id of the data item being set\r
+\r
+       InBufferSize has the size of the data item passed\r
+\r
+       InBuffer has the new values for the data item\r
+\r
+Return Value:\r
+\r
+       status\r
+\r
+--*/\r
+{\r
+       PFDO_DEVICE_DATA fdoData;\r
+\r
+       PAGED_CODE();\r
+\r
+       fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));\r
+\r
+       switch(DataItemId)\r
+       {\r
+       case 1:\r
+               if (InBufferSize < sizeof(ULONG)) {\r
+                       return STATUS_BUFFER_TOO_SMALL;\r
+               }\r
+               g_mlx4_dbg_level = fdoData->WmiData.DebugPrintLevel = *((PULONG)InBuffer);\r
+               return STATUS_SUCCESS;\r
+\r
+       case 2:\r
+               if (InBufferSize < sizeof(ULONG)) {\r
+                       return STATUS_BUFFER_TOO_SMALL;\r
+               }\r
+               g_mlx4_dbg_flags = fdoData->WmiData.DebugPrintFlags = *((PULONG)InBuffer);\r
+               return STATUS_SUCCESS;\r
+\r
+       default:\r
+               return STATUS_WMI_READ_ONLY;\r
+       }\r
+}\r
+\r
+NTSTATUS\r
+EvtStdDataSetInstance(\r
+       IN  WDFWMIINSTANCE WmiInstance,\r
+       IN  ULONG InBufferSize,\r
+       IN  PVOID InBuffer\r
+       )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+       This routine is a callback into the driver to set for the contents of\r
+       an instance.\r
+\r
+Arguments:\r
+\r
+       WmiInstance is the instance being set\r
+\r
+       BufferSize has the size of the data block passed\r
+\r
+       Buffer has the new values for the data block\r
+\r
+Return Value:\r
+\r
+       status\r
+\r
+--*/\r
+{\r
+       PFDO_DEVICE_DATA   fdoData;\r
+\r
+       UNREFERENCED_PARAMETER(InBufferSize);\r
+\r
+       PAGED_CODE();\r
+\r
+       fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));\r
+\r
+       //\r
+       // We will update only writable elements.\r
+       //\r
+       g_mlx4_dbg_level = fdoData->WmiData.DebugPrintLevel = ((PBUS_WMI_STD_DATA)InBuffer)->DebugPrintLevel;\r
+       g_mlx4_dbg_flags = fdoData->WmiData.DebugPrintFlags = ((PBUS_WMI_STD_DATA)InBuffer)->DebugPrintFlags;\r
+\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+NTSTATUS\r
+EvtStdDataQueryInstance(\r
+       IN  WDFWMIINSTANCE WmiInstance,\r
+       IN  ULONG OutBufferSize,\r
+       IN  PVOID OutBuffer,\r
+       OUT PULONG BufferUsed\r
+       )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+       This routine is a callback into the driver to set for the contents of\r
+       a wmi instance\r
+\r
+Arguments:\r
+\r
+       WmiInstance is the instance being set\r
+\r
+       OutBufferSize on has the maximum size available to write the data\r
+               block.\r
+\r
+       OutBuffer on return is filled with the returned data block\r
+\r
+       BufferUsed pointer containing how many bytes are required (upon failure) or\r
+               how many bytes were used (upon success)\r
+\r
+Return Value:\r
+\r
+       status\r
+\r
+--*/\r
+{\r
+       PFDO_DEVICE_DATA fdoData;\r
+\r
+       UNREFERENCED_PARAMETER(OutBufferSize);\r
+\r
+       PAGED_CODE();\r
+\r
+       fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));\r
+\r
+       *BufferUsed = sizeof (BUS_WMI_STD_DATA);\r
+       * (PBUS_WMI_STD_DATA) OutBuffer = fdoData->WmiData;\r
+\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
diff --git a/hw/mlx4/kernel/bus/drv/wpptrace.h b/hw/mlx4/kernel/bus/drv/wpptrace.h
new file mode 100644 (file)
index 0000000..81ab335
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+ * Copyright (c) 2005 Mellanox Technologies LTD.  All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * This source code may incorporate intellectual property owned by\r
+ * Microsoft Corporation. Our provision of this source code does not\r
+ * include any licenses or any other rights to you under any Microsoft\r
+ * intellectual property. If you would like a license from Microsoft\r
+ * (e.g., to rebrand, redistribute), you need to contact Microsoft\r
+ * directly.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ */\r
+\r
+// Author: Uri Habusha  \r
+\r
+#pragma once\r
+\r
+#if defined(EVENT_TRACING)\r
+\r
+#define WPP_CONTROL_GUIDS \\r
+        WPP_DEFINE_CONTROL_GUID(EthrnetGuid,(d7221994, d451, 4272, af18, 55df9ca9bfa7),  \\r
+        WPP_DEFINE_BIT(BUS_DRIVER)  \\r
+        WPP_DEFINE_BIT(BUS_SS)     \\r
+        WPP_DEFINE_BIT(BUS_PNP)     \\r
+        WPP_DEFINE_BIT(BUS_IOCTL)     \\r
+        WPP_DEFINE_BIT(BUS_POWER)     \\r
+        WPP_DEFINE_BIT(BUS_WMI))\r
+\r
+\r
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level  >= lvl)\r
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)\r
+#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level  >= TRACE_LEVEL_VERBOSE)\r
+#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags)\r
+\r
+// begin_wpp config\r
+// TRACE_FUNC_ENTER(FLAG);\r
+// TRACE_FUNC_EXIT(FLAG);\r
+// TRACE_PRINT(LEVEL,FLAGS,MSG,...)\r
+// USESUFFIX(TRACE_FUNC_ENTER, "====>>> %!FUNC! ");\r
+// USESUFFIX(TRACE_FUNC_EXIT, "<<<====== %!FUNC!]");\r
+// end_wpp\r
+\r
+#else //defined(EVENT_TRACING)\r
+\r
+#include <evntrace.h>\r
+\r
+// Debug toppics\r
+#define BUS_DRIVER            0x000001\r
+#define BUS_SS                0x000002\r
+#define BUS_PNP               0x000004\r
+#define BUS_IOCTL             0x000008\r
+#define BUS_POWER             0x000010\r
+#define BUS_WMI               0x000020\r
+\r
+#if DBG\r
+\r
+extern const unsigned int g_SdpDbgLevel;\r
+extern const unsigned int g_SdpDbgFlags;\r
+\r
+//                                                                      \r
+//BUGBUG: need to protect against context switch otherwise there can    \r
+//  be mismatched of trace messages. We can't use a simple spinlock     \r
+//  since some of the printing occours in IRQ level and the spinlock    \r
+//  can be alreardy use.                                                \r
+//                                                                      \r
+#define TRACE_PRINT(_level_,_flag_,_msg_)                                       \\r
+    if (g_SdpDbgLevel >= (_level_) && (g_SdpDbgFlags & (_flag_)))               \\r
+    {                                                                           \\r
+        if(_level_ == TRACE_LEVEL_ERROR)                                        \\r
+            DbgPrint ("***ERROR***  ");                                         \\r
+        DbgPrint ("%s(): ",__FUNCTION__);                                       \\r
+        DbgPrint _msg_;                                                         \\r
+    }\r
+\r
+#else\r
+\r
+#define TRACE_PRINT(lvl ,flags, msg) \r
+\r
+#endif\r
+\r
+\r
+\r
+#define TRACE_FUNC_ENTER(flags)\\r
+       ETH_PRINT(TRACE_LEVEL_VERBOSE, flags,("===>\n"));\r
+\r
+#define TRACE_FUNC_EXIT(flags)\\r
+       ETH_PRINT(TRACE_LEVEL_VERBOSE, flags, ("<===\n" ));\r
+\r
+\r
+\r
+#endif //defined(EVENT_TRACING)\r
+\r
diff --git a/hw/mlx4/kernel/bus/ib/Kconfig b/hw/mlx4/kernel/bus/ib/Kconfig
new file mode 100644 (file)
index 0000000..4175a4b
--- /dev/null
@@ -0,0 +1,8 @@
+config MLX4_INFINIBAND
+       tristate "Mellanox ConnectX HCA support"
+       select MLX4_CORE
+       ---help---
+         This driver provides low-level InfiniBand support for
+         Mellanox ConnectX PCI Express host channel adapters (HCAs).
+         This is required to use InfiniBand protocols such as
+         IP-over-IB or SRP with these devices.
diff --git a/hw/mlx4/kernel/bus/ib/Makefile.lnx b/hw/mlx4/kernel/bus/ib/Makefile.lnx
new file mode 100644 (file)
index 0000000..70f09c7
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MLX4_INFINIBAND)  += mlx4_ib.o
+
+mlx4_ib-y :=   ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o
diff --git a/hw/mlx4/kernel/bus/ib/SOURCES b/hw/mlx4/kernel/bus/ib/SOURCES
new file mode 100644 (file)
index 0000000..7468622
--- /dev/null
@@ -0,0 +1,45 @@
+TARGETNAME=mlx4_ib\r
+TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE=DRIVER_LIBRARY\r
+\r
+\r
+\r
+!if $(FREEBUILD)\r
+#ENABLE_EVENT_TRACING=1\r
+!else\r
+#ENABLE_EVENT_TRACING=1\r
+!endif\r
+\r
+\r
+DLLDEF=ib.def\r
+\r
+SOURCES= ib.rc         \\r
+       ah.c                    \\r
+       cq.c                    \\r
+       doorbell.c              \\r
+       mad.c                   \\r
+       main.c                  \\r
+       mr.c                    \\r
+       qp.c                    \\r
+       srq.c                   \\r
+\r
+INCLUDES=..;..\inc;..\..\inc;..\core;..\..\..\inc;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel;\r
+\r
+C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN\r
+\r
+TARGETLIBS= \\r
+    $(DDK_LIB_PATH)\ntstrsafe.lib \\r
+       $(TARGETPATH)\*\complib.lib \\r
+       $(TARGETPATH)\*\mlx4_core.lib \\r
+       \r
+!IFDEF ENABLE_EVENT_TRACING\r
+\r
+C_DEFINES = $(C_DEFINES) -DEVENT_TRACING\r
+\r
+RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \\r
+       -scan:..\inc\mlx4_debug.h \\r
+       -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \\r
+       -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \r
+!ENDIF\r
+\r
+MSC_WARNING_LEVEL= /W4\r
diff --git a/hw/mlx4/kernel/bus/ib/ah.c b/hw/mlx4/kernel/bus/ib/ah.c
new file mode 100644 (file)
index 0000000..d281e62
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "mlx4_ib.h"
+
+struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+       struct mlx4_dev *dev = to_mdev(pd->device)->dev;
+       struct mlx4_ib_ah *ah;
+
+       ah = kmalloc(sizeof *ah, GFP_ATOMIC);
+       if (!ah)
+               return ERR_PTR(-ENOMEM);
+
+       memset(&ah->av, 0, sizeof ah->av);
+
+       ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+       ah->av.g_slid  = ah_attr->src_path_bits;
+       ah->av.dlid    = cpu_to_be16(ah_attr->dlid);
+       if (ah_attr->static_rate) {
+               ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+               while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+                      !(1 << ah->av.stat_rate & dev->caps.stat_rate_support))
+                       --ah->av.stat_rate;
+       }
+       ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+       if (ah_attr->ah_flags & IB_AH_GRH) {
+               ah->av.g_slid   |= 0x80;
+               ah->av.gid_index = ah_attr->grh.sgid_index;
+               ah->av.hop_limit = ah_attr->grh.hop_limit;
+               ah->av.sl_tclass_flowlabel |=
+                       cpu_to_be32((ah_attr->grh.traffic_class << 20) |
+                                   ah_attr->grh.flow_label);
+               memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16);
+       }
+
+       return &ah->ibah;
+}
+
+int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+       struct mlx4_ib_ah *ah = to_mah(ibah);
+
+       memset(ah_attr, 0, sizeof *ah_attr);
+       ah_attr->dlid          = be16_to_cpu(ah->av.dlid);
+       ah_attr->sl            = (u8)(be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28);
+       ah_attr->port_num      = (u8)(be32_to_cpu(ah->av.port_pd) >> 24);
+       if (ah->av.stat_rate)
+               ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET;
+       ah_attr->src_path_bits = ah->av.g_slid & 0x7F;
+
+       if (mlx4_ib_ah_grh_present(ah)) {
+               ah_attr->ah_flags = IB_AH_GRH;
+
+               ah_attr->grh.traffic_class =
+                       (u8)(be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20);
+               ah_attr->grh.flow_label =
+                       be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff;
+               ah_attr->grh.hop_limit  = ah->av.hop_limit;
+               ah_attr->grh.sgid_index = ah->av.gid_index;
+               memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16);
+       }
+
+       return 0;
+}
+
+int mlx4_ib_destroy_ah(struct ib_ah *ah)
+{
+       kfree(to_mah(ah));
+       return 0;
+}
+
+// Leo: temporary 
+int mlx4_ib_modify_ah( struct ib_ah *ibah, struct ib_ah_attr *ah_attr )
+{
+       struct mlx4_av *av       = &to_mah(ibah)->av;
+       struct mlx4_dev *dev = to_mdev(ibah->pd->device)->dev;
+
+       // taken from mthca_create_av
+       av->port_pd = cpu_to_be32(to_mpd(ibah->pd)->pdn | (ah_attr->port_num << 24));
+       av->g_slid      = ah_attr->src_path_bits;
+       av->dlid             &