[mlx4] Add code that replaces interrupts with a thread that is polling.
authortzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Thu, 25 Dec 2008 16:06:46 +0000 (16:06 +0000)
committertzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Thu, 25 Dec 2008 16:06:46 +0000 (16:06 +0000)
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@1800 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

hw/mlx4/kernel/bus/ib/main.c
hw/mlx4/kernel/bus/inc/ib_verbs_ex.h
hw/mlx4/kernel/bus/net/eq.c
hw/mlx4/kernel/bus/net/mlx4.h
hw/mlx4/kernel/hca/fw.c
hw/mlx4/kernel/inc/vc.h

index d7f3861..bc08c15 100644 (file)
 #include "ib_cache.h"
 #include "net\mlx4.h"
 
+#if    WORKAROUND_POLL_EQ
+void mlx4_poll_eq(struct ib_device *dev, BOOLEAN bStart);
+#endif
+
+
 static void init_query_mad(struct ib_smp *mad)
 {
        mad->base_version  = 1;
@@ -564,7 +569,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        ibdev->ib_dev.x.get_cached_pkey         = ib_get_cached_pkey;
        ibdev->ib_dev.x.register_ev_cb          = mlx4_reset_cb_register;
        ibdev->ib_dev.x.unregister_ev_cb        = mlx4_reset_cb_unregister;
-
+#if WORKAROUND_POLL_EQ
+       ibdev->ib_dev.x.poll_eq                         = mlx4_poll_eq;
+#endif
        if (mlx4_is_livefish(ibdev->dev))
                return ibdev;
 
@@ -674,3 +681,4 @@ void __exit mlx4_ib_cleanup(void)
 }
 
 
+
index 0bfd731..18b78fa 100644 (file)
@@ -52,6 +52,9 @@ struct ib_device_ex
                u8 port_num, __be16 pkey, u16 *index);
        int (*register_ev_cb) (struct ib_event_handler *event_handler);
        int (*unregister_ev_cb) (struct ib_event_handler *event_handler);
+#if WORKAROUND_POLL_EQ
+       void (*poll_eq)(struct ib_device *device, BOOLEAN bStart);
+#endif
 };
 
 
index 5f12eac..7ca721f 100644 (file)
@@ -255,6 +255,101 @@ static BOOLEAN mlx4_interrupt(
        return (BOOLEAN)work;
 }
 
+#if WORKAROUND_POLL_EQ
+
+BOOLEAN
+IsrSynchronizeRoutine(
+       IN PVOID  SynchronizeContext
+       )
+{
+       struct mlx4_dev *dev = (struct mlx4_dev *)SynchronizeContext;
+    
+       mlx4_interrupt(dev->pdev->int_obj,dev);
+    
+       return TRUE;
+}
+
+
+VOID eq_polling_thread(void *ctx) 
+{
+#define POLLING_INTERVAL_MS    50
+       NTSTATUS status;
+       struct mlx4_priv *priv = (struct mlx4_priv *)ctx;
+       PVOID wait_objects[2];
+       LARGE_INTEGER  wait_time;
+
+       wait_objects[0] = &priv->eq_table.thread_stop_event;
+       wait_objects[1] = &priv->eq_table.thread_start_event;
+
+       for(;;){
+
+               /* before start polling */
+               DbgPrint("Before polling.\n");
+               for (;;) {
+                       status = KeWaitForMultipleObjects( 2, wait_objects, 
+                                                                                          WaitAny, Executive, KernelMode, FALSE, NULL, NULL );
+
+                       if ( status == STATUS_WAIT_0 ){/* thread stopped */
+                               DbgPrint("Signaled to stop polling.\n");
+                               break;          
+                       }
+
+                       /* start polling */
+                       if ( status == STATUS_WAIT_1 ){
+                               DbgPrint("Signaled to start polling.\n");
+                               break;          
+                       }
+
+               }
+
+               if(priv->eq_table.bTerminated) break;
+               if ( status == STATUS_WAIT_0 ) continue;/* thread stopped, wait for start again */
+
+               /* polling */
+               DbgPrint("Start polling.\n");
+               wait_time.QuadPart = -(int64_t)(((uint64_t)POLLING_INTERVAL_MS) * 10000);
+               for (;;) {
+                       //mlx4_interrupt( NULL, &priv->dev );
+                       KeSynchronizeExecution(priv->dev.pdev->int_obj, IsrSynchronizeRoutine, &priv->dev);
+
+                       status = KeWaitForSingleObject( &priv->eq_table.thread_stop_event, 
+                                                                                       Executive, KernelMode, FALSE, &wait_time );
+                       if ( status == STATUS_SUCCESS ) {
+                               //KeClearEvent(&priv->eq_table.thread_stop_event);
+                               DbgPrint("Signaled to stop polling while in polling mode.\n");
+                               break;          /* thread stopped */
+                       }
+               }
+
+               if(priv->eq_table.bTerminated) break;
+       }
+
+       DbgPrint("Polling thread terminated.\n");
+       PsTerminateSystemThread(STATUS_SUCCESS);
+
+}
+
+
+void mlx4_poll_eq(struct ib_device *device, BOOLEAN bStart)
+{
+       LONG signalled=0;
+       struct mlx4_priv *priv = mlx4_priv(device->dma_device);
+
+       if(bStart){
+               /* signal start of polling */
+               signalled = KeSetEvent(         
+                       &priv->eq_table.thread_start_event, IO_NO_INCREMENT, FALSE );
+       }else{
+               /* signal end of polling */
+               signalled = KeSetEvent(         
+                       &priv->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE );
+       }
+
+}
+
+#endif
+
+
 #ifdef CONFIG_PCI_MSI
 
 /* not ported yet */
@@ -648,6 +743,40 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
        for (i = 0; i < MLX4_NUM_EQ; ++i)
                eq_set_ci(&priv->eq_table.eq[i], 1);
 
+
+#if WORKAROUND_POLL_EQ
+       { /* Create a thread for polling EQs in case of missing interrupts from the card  */
+               NTSTATUS status;
+               OBJECT_ATTRIBUTES       attr;
+               HANDLE  handle;
+
+               KeInitializeEvent(&priv->eq_table.thread_start_event, SynchronizationEvent, FALSE);
+               KeInitializeEvent(&priv->eq_table.thread_stop_event, SynchronizationEvent, FALSE);
+               priv->eq_table.bTerminated = FALSE;
+               priv->eq_table.threadObject = NULL;
+               InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
+               status = PsCreateSystemThread( &handle, 
+                       THREAD_ALL_ACCESS, &attr, NULL, NULL, eq_polling_thread, priv );
+               if (NT_SUCCESS(status)) {
+                       status = ObReferenceObjectByHandle(
+                               handle,
+                               THREAD_ALL_ACCESS,
+                               NULL,
+                               KernelMode,
+                               &priv->eq_table.threadObject,
+                               NULL
+                               );
+
+                       ASSERT(status == STATUS_SUCCESS); //
+
+                       status = ZwClose(handle);
+
+                       ASSERT(NT_SUCCESS(status)); // Should always succeed
+
+               }
+       }
+#endif
+
        return 0;
 
 #ifdef USE_WDM_INTERRUPTS
@@ -737,6 +866,33 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
        struct mlx4_priv *priv = mlx4_priv(dev);
        int i;
 
+#if WORKAROUND_POLL_EQ
+       /* stop the EQ polling thread */
+       if (priv->eq_table.threadObject) { 
+               #define WAIT_TIME_MS    3000
+               NTSTATUS status;
+               LARGE_INTEGER  wait_time;
+               LONG signalled;
+
+               priv->eq_table.bTerminated = TRUE;
+
+               /* signal polling stopped in case it is not */
+               signalled = KeSetEvent(         
+                       &priv->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE );
+
+               /* wait for completion of the thread */
+               wait_time.QuadPart = -(int64_t)(((uint64_t)WAIT_TIME_MS) * 10000);
+               status = KeWaitForSingleObject( priv->eq_table.threadObject,
+                       Executive, KernelMode, FALSE, &wait_time );
+               ASSERT(status == STATUS_SUCCESS);
+
+               ObDereferenceObject(priv->eq_table.threadObject);
+
+               /* cleanup */
+               priv->eq_table.threadObject = NULL;
+       }
+#endif
+
        mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
                    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
 
index 092c4ab..8139f8f 100644 (file)
@@ -233,6 +233,12 @@ struct mlx4_eq_table {
        int                     have_irq;
        u8                      inta_pin;
        u8                                              max_extra_eqs;
+#if WORKAROUND_POLL_EQ
+       KEVENT          thread_start_event;
+       KEVENT          thread_stop_event;
+       BOOLEAN         bTerminated;
+       PVOID           threadObject;
+#endif
 };
 
 struct mlx4_srq_table {
index f242644..2c0df1f 100644 (file)
@@ -404,8 +404,24 @@ fw_access_ctrl(
        UNREFERENCED_PARAMETER(handle_array);\r
        UNREFERENCED_PARAMETER(num_handles);\r
 \r
-       if( !p_umv_buf )\r
+    if(!p_umv_buf ) {\r
+#if WORKAROUND_POLL_EQ\r
+               if ((p_ci_op->command == FW_POLL_EQ_START) || (p_ci_op->command == FW_POLL_EQ_STOP)){ // poll EQ (in case of missed interrupt) \r
+                       mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca;\r
+                       struct ib_device *p_ibdev = hca2ibdev(p_hca);\r
+                       if(p_ci_op->command == FW_POLL_EQ_START)\r
+                       {\r
+                               p_ibdev->x.poll_eq(p_ibdev,1);\r
+                       }else\r
+                       {\r
+                               p_ibdev->x.poll_eq(p_ibdev,0);\r
+                       }\r
+                       return IB_SUCCESS;\r
+               }\r
+               else\r
+#endif\r
                return IB_UNSUPPORTED;\r
+       }\r
 \r
        if ( !p_ci_op )\r
                return IB_INVALID_PARAMETER;\r
@@ -475,3 +491,4 @@ fw_access_ctrl(
        }\r
 }\r
 \r
+\r
index f7ccdd5..73f4dc7 100644 (file)
@@ -51,6 +51,11 @@ struct _map_crspace {
 #define FW_OPEN_IF             0xe7
 #define FW_CLOSE_IF            0x7e
 
+#if WORKAROUND_POLL_EQ
+#define FW_POLL_EQ_START               0x0D
+#define FW_POLL_EQ_STOP                0x0E
+#endif
+
 /* uplink info */
 typedef struct {
        uint8_t bus_type;       /* 1 - PCI, 2 - PCI-X, 3 - PCI_E */