DIRS=\\r
- mthca\r
+ mthca\\r
+ mlx4\r
--- /dev/null
+DIRS= \\r
+ kernel \\r
+ user
\ No newline at end of file
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+/*++\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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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
--- /dev/null
+#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();
+
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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();
+}
+
--- /dev/null
+;/*++\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
--- /dev/null
+/*
+ * 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;
+}
+
+
--- /dev/null
+#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
--- /dev/null
+#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
+}
+
+
--- /dev/null
+/*
+ * 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 );
+}
+
+
+
--- /dev/null
+/*
+ * 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 );
+}
+
--- /dev/null
+
+#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);
+ }
+}
+
--- /dev/null
+#\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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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();
+
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+
--- /dev/null
+DIRS=\\r
+ core \\r
+ net \\r
+ ib \\r
+ drv \r
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*++\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
--- /dev/null
+/*++\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
--- /dev/null
+#\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
--- /dev/null
+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
--- /dev/null
+[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
--- /dev/null
+; 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
--- /dev/null
+[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
--- /dev/null
+\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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+/*++\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
--- /dev/null
+/*\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
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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 &