]> git.openfabrics.org - ~shefty/rdma-win.git/commitdiff
[MLX4] g_stat: added more prints and flags
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Tue, 17 Nov 2009 15:03:51 +0000 (15:03 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Tue, 17 Nov 2009 15:03:51 +0000 (15:03 +0000)
added support for g_stat structure for MLX4_BUS driver + MAD tracing mechanism.

MAD tracing mechanism works under the control of flags, set in new Registry mlx4_bus parameter StatFlags.
The mechanism prints to debugger the IB headers of packets sent over MLX transport, i.e. on QP0 and QP1. [mlnx: 5138]
The flags are:
0x0001 - print LRH
0x0002 - print BTH
0x0004 - print DETH
0x0008 - print GRH (it won't print id the GRH is absent)
0x0010 - print some WQE info
0x0020 - print some more UD header info
0x0040 - print some send WR info
0x0080 - MLX WQE dump

git-svn-id: svn://openib.tc.cornell.edu/gen1@2585 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

trunk/hw/mlx4/kernel/bus/drv/drv.c
trunk/hw/mlx4/kernel/bus/drv/precomp.h
trunk/hw/mlx4/kernel/bus/drv/sources
trunk/hw/mlx4/kernel/bus/drv/stat.c [new file with mode: 0644]
trunk/hw/mlx4/kernel/bus/drv/stat.h [new file with mode: 0644]
trunk/hw/mlx4/kernel/bus/ib/SOURCES
trunk/hw/mlx4/kernel/bus/ib/mlx4_ib.h
trunk/hw/mlx4/kernel/bus/ib/qp.c
trunk/hw/mlx4/kernel/bus/inc/qp.h
trunk/hw/mlx4/kernel/bus/net/mlx4.h
trunk/hw/mlx4/kernel/inc/l2w.h

index 2a8ff92dd0af278eb063198af926b61e10b74e8a..7a2f615610d8124ad1535b67fa853004a06b8df8 100644 (file)
@@ -582,6 +582,8 @@ EvtDeviceD0Exit(
        if (TargetState > WdfPowerDeviceD0)\r
                __stop_card( p_fdo );\r
 \r
+       st_dev_rmv( p_fdo->pci_dev.p_stat_dev );\r
+\r
        MLX4_EXIT( MLX4_DBG_DRV );\r
        return STATUS_SUCCESS;\r
 }\r
@@ -1154,6 +1156,14 @@ Return Value:
 \r
 #endif\r
 \r
+       // statistics\r
+       p_fdo->pci_dev.p_stat_dev = st_dev_add();\r
+       if ( p_fdo->pci_dev.p_stat_dev ) {\r
+               p_fdo->pci_dev.p_stat_dev->p_fdo = p_fdo;\r
+               p_fdo->pci_dev.p_stat_dev->h_wdf_device = device;\r
+               p_fdo->pci_dev.p_stat_dev->flags = g.mod_stat_flags;\r
+       }\r
+\r
        status = STATUS_SUCCESS;\r
 \r
 end:   \r
@@ -1234,6 +1244,9 @@ __read_registry(WDFDRIVER *hDriver)
        // "ProcessorAffinity"\r
        DECLARE_CONST_UNICODE_STRING(ProcessorAffinity, L"ProcessorAffinity");\r
 \r
+       // "Stat Flags"\r
+       DECLARE_CONST_UNICODE_STRING(StatFlags, L"StatFlags");\r
+\r
        ULONG value;\r
        WDFKEY hKey = NULL;\r
        NTSTATUS status = STATUS_SUCCESS;\r
@@ -1332,6 +1345,12 @@ __read_registry(WDFDRIVER *hDriver)
                else\r
                        g.mod_affinity = 0;\r
                \r
+               status = WdfRegistryQueryULong(hKey, &StatFlags, &value);\r
+               if (NT_SUCCESS (status)) \r
+                       g.mod_stat_flags = value;\r
+               else\r
+                       g.mod_stat_flags = 0;\r
+               \r
 \r
                WdfRegistryClose(hKey);\r
                status = STATUS_SUCCESS;\r
@@ -1424,6 +1443,11 @@ Return Value:
        //\r
        status = __read_registry(&hDriver);\r
 \r
+       // statistics\r
+       RtlZeroMemory( &g_stat, sizeof(g_stat) );\r
+       g_stat.drv.p_globals = &g;\r
+       g_stat.drv.h_wdf_driver = hDriver;\r
+       \r
        // we don't matter the failure in the work with Registry\r
        status = STATUS_SUCCESS;\r
        \r
index eefec2948b67743b320ca36328c5d27f16a3912d..d105332bb5934eee00d1a11f51cc1fc25b7596ab 100644 (file)
@@ -5,11 +5,12 @@
 #include <initguid.h> // required for GUID definitions\r
 #include "public.h"\r
 #include "l2w.h"\r
-#include "ib\mlx4_ib.h"\r
 #include "vip_dev.h"\r
 #include "drv.h"\r
 #include "driver.h"\r
 #include "cmd.h"\r
 #include <mlx4_debug.h>\r
+#include "ib\mlx4_ib.h"\r
+#include "stat.h"\r
 \r
 \r
index c8eb3b0a05ed8af2db60d98333a0ab0335bed3f6..16c17f20207c37bf1b24805192cf9b2fdc488e31 100644 (file)
@@ -20,6 +20,7 @@ SOURCES= \
        pci.c \\r
        pdo.c \\r
        wmi.c \\r
+       stat.c\r
 \r
 PRECOMPILED_INCLUDE=precomp.h\r
 \r
diff --git a/trunk/hw/mlx4/kernel/bus/drv/stat.c b/trunk/hw/mlx4/kernel/bus/drv/stat.c
new file mode 100644 (file)
index 0000000..10c3b11
--- /dev/null
@@ -0,0 +1,199 @@
+/*++
+
+Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved.
+
+Module Name:
+       bus_stat.h
+
+Abstract:
+       Statistics Collector header file
+
+Revision History:
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+
+MLX4_ST_STAT g_stat;
+
+static void __print_grh( struct mlx4_dev *mdev, struct ib_unpacked_grh *p)
+{
+       mlx4_dbg(mdev, "\n\t ========== GRH ==========\n");
+       mlx4_dbg(mdev, "\t ip_version        %02x", p->ip_version);
+       mlx4_dbg(mdev, "\t traffic_class     %02x", p->traffic_class);
+       mlx4_dbg(mdev, "\t flow_label        %08x", 
+               be32_to_cpu(p->flow_label));
+       mlx4_dbg(mdev, "\t payload_length    %04x", 
+               be16_to_cpu(p->payload_length));
+       mlx4_dbg(mdev, "\t next_header       %02x", p->next_header);
+       mlx4_dbg(mdev, "\t hop_limit         %02x", p->hop_limit);
+       mlx4_dbg(mdev, "\t source_gid        %08I64x:%08I64", 
+               be64_to_cpu(p->source_gid.global.subnet_prefix),
+               be64_to_cpu(p->source_gid.global.interface_id));
+       mlx4_dbg(mdev, "\t source_gid        %08I64x:%08I64", 
+               be64_to_cpu(p->destination_gid.global.subnet_prefix),
+               be64_to_cpu(p->destination_gid.global.interface_id));
+}
+
+static void __print_deth( struct mlx4_dev *mdev, struct ib_unpacked_deth *p)
+{
+       mlx4_dbg(mdev, "\n\t ========== DETH ==========\n");
+       mlx4_dbg(mdev, "\t qkey              %08x", 
+               be32_to_cpu(p->qkey));
+       mlx4_dbg(mdev, "\t source_qpn        %08x", 
+               be32_to_cpu(p->source_qpn));
+}
+
+static void __print_bth( struct mlx4_dev *mdev, struct ib_unpacked_bth *p)
+{
+       mlx4_dbg(mdev, "\n\t ========== BTH ==========\n");
+       mlx4_dbg(mdev, "\t opcode            %02x", p->opcode);
+       mlx4_dbg(mdev, "\t solicited_event   %02x", p->solicited_event);
+       mlx4_dbg(mdev, "\t mig_req           %02x", p->mig_req);
+       mlx4_dbg(mdev, "\t header_version    %02x", p->transport_header_version);
+       mlx4_dbg(mdev, "\t pkey              %04x", 
+               be16_to_cpu(p->pkey));
+       mlx4_dbg(mdev, "\t destination_qpn   %08x", 
+               be32_to_cpu(p->destination_qpn));
+       mlx4_dbg(mdev, "\t ack_req           %02x", p->ack_req);
+       mlx4_dbg(mdev, "\t psn               %08x", 
+               be32_to_cpu(p->psn));
+}
+
+static void __print_lrh( struct mlx4_dev *mdev, struct ib_unpacked_lrh *p)
+{
+       mlx4_dbg(mdev, "\n\t ========== LRH ==========\n");
+       mlx4_dbg(mdev, "\t virtual_lane      %02x", p->virtual_lane);
+       mlx4_dbg(mdev, "\t link_version      %02x", p->link_version);
+       mlx4_dbg(mdev, "\t service_level     %02x", p->service_level);
+       mlx4_dbg(mdev, "\t link_next_header  %02x", p->link_next_header);
+       mlx4_dbg(mdev, "\t destination_lid   %04x", 
+               be16_to_cpu(p->destination_lid));
+       mlx4_dbg(mdev, "\t packet_length     %04x", 
+               be16_to_cpu(p->packet_length));
+       mlx4_dbg(mdev, "\t source_lid        %04x", 
+               be16_to_cpu(p->source_lid));
+}
+
+static void __print_ud_header( struct mlx4_dev *mdev, struct ib_ud_header *p)
+{
+       mlx4_dbg(mdev, "\n\t ========== UD HEADER ==========\n");
+
+       mlx4_dbg(mdev, "\t grh_present %d, imm_present %d, imm %08x",
+               p->grh_present, p->immediate_present, be32_to_cpu(p->immediate_data) );
+
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_LRH )
+               __print_lrh( mdev, &p->lrh );
+
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_BTH )
+               __print_bth( mdev, &p->bth );
+       
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_DETH )
+               __print_deth( mdev, &p->deth );
+       
+       if ( p->grh_present && (mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_GRH) )
+               __print_grh( mdev, &p->grh );
+       
+}
+
+static void __print_mlx( struct mlx4_dev *mdev, struct mlx4_wqe_mlx_seg *p)
+{
+       mlx4_dbg(mdev, "\n\t ========== MLX WQE ==========\n");
+       mlx4_dbg(mdev, "\t owner             %02x", p->owner);
+       mlx4_dbg(mdev, "\t opcode            %02x", p->opcode);
+       mlx4_dbg(mdev, "\t size              %02x", p->size);
+       mlx4_dbg(mdev, "\t flags             %08x", 
+               be32_to_cpu(p->flags));
+       mlx4_dbg(mdev, "\t rlid              %04x", 
+               be16_to_cpu(p->rlid));
+}
+
+void st_print_mlx_header( struct mlx4_dev *mdev, struct mlx4_ib_sqp *sqp, struct mlx4_wqe_mlx_seg *mlx )
+{
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_UDH )
+       __print_ud_header( mdev, &sqp->ud_header );
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_WQE )
+               __print_mlx( mdev, mlx );
+}
+
+void st_print_mlx_send(struct mlx4_dev *mdev, struct ib_qp *ibqp, ib_send_wr_t *wr)
+{
+       struct mlx4_ib_qp *qp = to_mqp(ibqp);
+
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_WR ) {
+               mlx4_dbg(mdev, "\n\t ========== SEND WR on QP %#x (%#x) ==========\n",
+                       ibqp->qp_num, qp->mqp.qpn );
+               mlx4_dbg(mdev, "\t wr_type           %d", wr->wr_type);
+               mlx4_dbg(mdev, "\t wr_id             %08I64x", wr->wr_id);
+               mlx4_dbg(mdev, "\t send_opt          %x", wr->send_opt);
+               mlx4_dbg(mdev, "\t immediate_data    %x", be32_to_cpu(wr->immediate_data));
+               mlx4_dbg(mdev, "\t num_ds            %d", wr->num_ds);
+               mlx4_dbg(mdev, "\t ds[0].pa          %I64x", wr->ds_array[0].vaddr);
+               mlx4_dbg(mdev, "\t ds[0].length      %x", wr->ds_array[0].length);
+               mlx4_dbg(mdev, "\t ds[0].lkey        %x", wr->ds_array[0].lkey);
+       }
+}
+
+void st_dump_mlx_wqe(struct mlx4_dev *mdev, void *wqe, int size_in_dwords, ib_send_wr_t *wr)
+{
+       int j;
+       u32 *ptr = wqe;
+#if 0  
+       int i, size;
+#else  
+       UNUSED_PARAM(wr);
+#endif
+       
+       mlx4_dbg(mdev, "\n\t ========== MLX WQE at %p, size %#x ==========\n",
+               wqe, size_in_dwords*4 );
+       
+       if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_MLX_WQE_DUMP ) {
+               for ( j = 0; j < size_in_dwords; ++j ) {
+                       mlx4_warn( mdev, "\t %04x:      %08x %08x %08x %08x \n", 16*j, 
+                               be32_to_cpu(ptr[4*j]), be32_to_cpu(ptr[4*j + 1]),
+                               be32_to_cpu(ptr[4*j + 2]),be32_to_cpu(ptr[4*j + 3]) );
+               }
+       }
+
+#if 0
+       for ( j = 0; j < (int)wr->num_ds; ++j ) {
+               mlx4_dbg(mdev, "\n\t ========== SMP %d at pa %I64x, size %#x, lkey %#x ==========\n",
+                       j, wr->ds_array[0].vaddr, wr->ds_array[0].length, wr->ds_array[0].lkey );
+
+               //TODO: vaddr should be converted to virtual address
+               ptr = (PVOID)(ULONG_PTR)wr->ds_array[0].vaddr;
+               size = (wr->ds_array[0].length + 3) >> 2;
+               for ( i = 0; i < size; ++i ) {
+                       mlx4_warn( mdev, "%04x: %08x %08x %08x %08x \n", 16*i, 
+                               be32_to_cpu(ptr[4*i]), be32_to_cpu(ptr[4*i + 1]),
+                               be32_to_cpu(ptr[4*i + 2]),be32_to_cpu(ptr[4*i + 3]) );
+               }
+       }
+#endif 
+
+}
+
+
+void st_dev_rmv( PMLX4_ST_DEVICE p_stat )
+{
+       if ( p_stat )
+               p_stat->valid = FALSE;
+}
+
+PMLX4_ST_DEVICE st_dev_add()
+{
+       int i;
+
+       for ( i = 0; i < MLX4_ST_MAX_DEVICES; ++i ) {
+               if ( g_stat.dev[i].valid == FALSE ) {
+                       g_stat.dev[i].valid = TRUE;
+                       return &g_stat.dev[i];
+               }
+       }
+
+       return NULL;
+}
+
+
diff --git a/trunk/hw/mlx4/kernel/bus/drv/stat.h b/trunk/hw/mlx4/kernel/bus/drv/stat.h
new file mode 100644 (file)
index 0000000..e0f90df
--- /dev/null
@@ -0,0 +1,86 @@
+/*++
+
+Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved.
+
+Module Name:
+       bus_stat.h
+
+Abstract:
+       Statistics Collector header file
+
+Revision History:
+
+Notes:
+
+--*/
+
+#include <wdf.h>
+#include "l2w.h"
+#include "ib_pack.h"
+#include "qp.h"
+#include "device.h"
+
+//
+// restrictions
+//
+
+#define MLX4_ST_MAX_DEVICES                    8
+
+//
+// enums
+// 
+
+#define MLX4_MAD_TRACE_LRH                     (1 << 0)
+#define MLX4_MAD_TRACE_BTH                     (1 << 1)
+#define MLX4_MAD_TRACE_DETH                    (1 << 2)
+#define MLX4_MAD_TRACE_GRH                     (1 << 3)
+#define MLX4_MAD_TRACE_WQE                     (1 << 4)
+#define MLX4_MAD_TRACE_UDH                     (1 << 5)
+#define MLX4_MAD_TRACE_WR                      (1 << 6)
+#define MLX4_MAD_TRACE_MLX_WQE_DUMP    (1 << 7)
+
+
+
+//
+// structures
+//
+
+// device
+
+typedef struct _MLX4_ST_DEVICE
+{
+       boolean_t                       valid;
+       PFDO_DEVICE_DATA        p_fdo;
+       WDFDEVICE                       h_wdf_device;
+       ULONG                           flags;
+       
+} MLX4_ST_DEVICE, *PMLX4_ST_DEVICE;
+
+// driver
+typedef struct _MLX4_ST_DRIVER
+{
+       GLOBALS                         *p_globals;
+       WDFDRIVER                       h_wdf_driver;   
+       
+} MLX4_ST_DRIVER, *PMLX4_ST_DRIVER;
+
+// driver stack
+
+typedef struct _MLX4_ST_STAT
+{
+       MLX4_ST_DRIVER          drv;
+       MLX4_ST_DEVICE          dev[MLX4_ST_MAX_DEVICES];
+       
+} MLX4_ST_STAT, *PMLX4_ST_STAT;
+
+extern MLX4_ST_STAT g_stat;
+
+void st_print_mlx_header( struct mlx4_dev *mdev, struct mlx4_ib_sqp *sqp, struct mlx4_wqe_mlx_seg *mlx );
+
+void st_print_mlx_send(struct mlx4_dev *mdev, struct ib_qp *ibqp, ib_send_wr_t *wr);
+
+void st_dev_rmv( PMLX4_ST_DEVICE p_stat );
+
+PMLX4_ST_DEVICE st_dev_add();
+
+#pragma once
index 4a940f09d2c05433bd3588d381b770bbc9451500..ef658150f684af1f0812e7114bff1e3f5c043381 100644 (file)
@@ -21,7 +21,7 @@ SOURCES= ib.rc                \
        main.c                  \\r
        mr.c                    \\r
        qp.c                    \\r
-       srq.c                   \\r
+       srq.c                   \r
 \r
 INCLUDES=..;..\inc;..\..\inc;..\core\$O;..\..\..\inc;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel;\r
 \r
index ef6999fb6a4689e602f0b6759102c03e67c691fd..92255af5539185389ba1519424e9110f485edccb 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "device.h"
 #include "doorbell.h"
+#include "ib_pack.h"
 
 enum {
        MLX4_IB_DB_PER_PAGE     = PAGE_SIZE / 4
@@ -167,6 +168,22 @@ struct mlx4_ib_ah {
        struct mlx4_av          av;
 };
 
+enum {
+       /*
+        * Largest possible UD header: send with GRH and immediate data.
+        */
+       MLX4_IB_UD_HEADER_SIZE          = 72
+};
+
+struct mlx4_ib_sqp {
+       struct mlx4_ib_qp       qp;
+       int                     pkey_index;
+       u32                     qkey;
+       u32                     send_psn;
+       struct ib_ud_header     ud_header;
+       u8                      header_buf[MLX4_IB_UD_HEADER_SIZE];
+};
+
 struct mlx4_ib_dev {
        struct ib_device        ib_dev;
        struct mlx4_dev        *dev;
index 0a64de2bd0efd2625d51c30da0683293c41b1452..8ffca0f5fe26972f11825057f5f02b3ca9477013 100644 (file)
 #include "qp.h"\r
 #include "user.h"\r
 \r
+void st_print_mlx_header( struct mlx4_dev *mdev, struct mlx4_ib_sqp *sqp, struct mlx4_wqe_mlx_seg *mlx );\r
+void st_print_mlx_send(struct mlx4_dev *mdev, struct ib_qp *ibqp, ib_send_wr_t *wr);\r
+void st_dump_mlx_wqe(struct mlx4_dev *mdev, void *wqe, int size_in_dwords, ib_send_wr_t *wr);\r
+\r
 enum {\r
        MLX4_IB_ACK_REQ_FREQ    = 8,\r
 };\r
@@ -45,22 +49,6 @@ enum {
        MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f\r
 };\r
 \r
-enum {\r
-       /*\r
-        * Largest possible UD header: send with GRH and immediate data.\r
-        */\r
-       MLX4_IB_UD_HEADER_SIZE          = 72\r
-};\r
-\r
-struct mlx4_ib_sqp {\r
-       struct mlx4_ib_qp       qp;\r
-       int                     pkey_index;\r
-       u32                     qkey;\r
-       u32                     send_psn;\r
-       struct ib_ud_header     ud_header;\r
-       u8                      header_buf[MLX4_IB_UD_HEADER_SIZE];\r
-};\r
-\r
 enum {\r
        MLX4_IB_MIN_SQ_STRIDE = 6\r
 };\r
@@ -1412,6 +1400,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, ib_send_wr_t *wr,
 {\r
        enum ib_wr_opcode opcode;\r
        struct mlx4_ib_qp *qp = to_mqp(ibqp);\r
+       struct mlx4_dev *dev = to_mdev(ibqp->device)->dev;\r
        u8 *wqe /*, *wqe_start*/;\r
        struct mlx4_wqe_ctrl_seg *ctrl;\r
        struct mlx4_wqe_data_seg *dseg;\r
@@ -1542,6 +1531,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, ib_send_wr_t *wr,
                                        *bad_wr = wr;\r
                                goto out;\r
                        }\r
+                       \r
                        wqe  += err;\r
                        size += err / 16;\r
 \r
@@ -1591,6 +1581,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, ib_send_wr_t *wr,
                ctrl->owner_opcode = mlx4_ib_opcode[opcode] |\r
                        (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0);\r
 \r
+               // statistics\r
+               if ( ibqp->qp_type == IB_QPT_SMI || ibqp->qp_type == IB_QPT_GSI ) {\r
+                       st_print_mlx_send( dev, ibqp, wr);\r
+                       st_print_mlx_header( dev, to_msqp(qp), (void*)ctrl );\r
+                       st_dump_mlx_wqe( dev, ctrl, size*4, wr);\r
+               }\r
+\r
                /*\r
                 * We can improve latency by not stamping the last\r
                 * send queue WQE until after ringing the doorbell, so\r
index 4fbe077dfd9eebc18bd29d2c50a65f53afedeffa..89e32951200f4d0b37e2e7ae6578feebce13d129 100644 (file)
@@ -288,7 +288,6 @@ struct mlx4_wqe_inline_seg {
        __be32                  byte_count;
 };
 
-
 int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
                  struct mlx4_qp_context *context);
 
index 855e6b96069012090527563f89dff351734ace77..90f0722c990d40db9bf4b6f34e1c003adc844995 100644 (file)
@@ -93,6 +93,7 @@ typedef struct _GLOBALS {
        int mod_interrupt_from_first;
 
        int mod_affinity;
+       int mod_stat_flags;
        PFDO_DEVICE_DATA p_fdo[MAX_HCA_CARDS];  // for debug purposes
 } GLOBALS;
 #pragma warning(default:4201) // nameless struct/union
index b2f6fbb36a160a3821ca19a260147a87068c912c..819cb425da7b4425ce58184cd048afcdba6f4272 100644 (file)
@@ -162,6 +162,8 @@ struct msix_map {
        int                     ref_cnt;        /* number of users */
 };
 
+typedef struct _MLX4_ST_DEVICE *PMLX4_ST_DEVICE;
+
 // interface structure between Upper and Low Layers of the driver
 struct pci_dev
 {
@@ -200,6 +202,8 @@ struct pci_dev
        ULONG                                                   version;
        int                                                     legacy_connect;
 #endif 
+       // statistics
+       PMLX4_ST_DEVICE                                 p_stat_dev;
 };
 
 /* DPC */