From 9a2a05426e7c45e21171a69a4c4f36f761aeb378 Mon Sep 17 00:00:00 2001 From: leonidk Date: Sun, 18 Jan 2009 13:47:55 +0000 Subject: [PATCH] [MLTHCA] added polling mode support. This patch is a second part of a workaround, added in rev. 1800 for MLX4. It adds polling mode support for MTHCA. This is needed for example in the case, when interrupts stop to be conveyed to the driver for some HW problem. (Xsigo saw such case). This patch additionally "actualize" the workaround (by off-commenting #if WORKAROUND_POLL_EQ) to enable polling mode without re-building the drivers. Signed-off-by: James Yang [jyang@xsigo.com] git-svn-id: svn://openib.tc.cornell.edu/gen1@1841 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- trunk/hw/mlx4/kernel/bus/ib/main.c | 4 +- trunk/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h | 2 +- trunk/hw/mlx4/kernel/bus/net/eq.c | 6 +- trunk/hw/mlx4/kernel/bus/net/mlx4.h | 2 +- trunk/hw/mlx4/kernel/hca/fw.c | 2 +- trunk/hw/mlx4/kernel/inc/vc.h | 3 +- trunk/hw/mthca/kernel/hca_driver.c | 23 ++- trunk/hw/mthca/kernel/hca_driver.h | 5 + trunk/hw/mthca/kernel/mthca_dev.h | 6 + trunk/hw/mthca/kernel/mthca_eq.c | 155 +++++++++++++++++++++ 10 files changed, 198 insertions(+), 10 deletions(-) diff --git a/trunk/hw/mlx4/kernel/bus/ib/main.c b/trunk/hw/mlx4/kernel/bus/ib/main.c index bc08c152..8eed2069 100644 --- a/trunk/hw/mlx4/kernel/bus/ib/main.c +++ b/trunk/hw/mlx4/kernel/bus/ib/main.c @@ -38,7 +38,7 @@ #include "ib_cache.h" #include "net\mlx4.h" -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ void mlx4_poll_eq(struct ib_device *dev, BOOLEAN bStart); #endif @@ -569,7 +569,7 @@ 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 +#if 1//WORKAROUND_POLL_EQ ibdev->ib_dev.x.poll_eq = mlx4_poll_eq; #endif if (mlx4_is_livefish(ibdev->dev)) diff --git a/trunk/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h b/trunk/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h index 18b78fa4..6ad4ad7e 100644 --- a/trunk/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h +++ b/trunk/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h @@ -52,7 +52,7 @@ 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 +#if 1//WORKAROUND_POLL_EQ void (*poll_eq)(struct ib_device *device, BOOLEAN bStart); #endif }; diff --git a/trunk/hw/mlx4/kernel/bus/net/eq.c b/trunk/hw/mlx4/kernel/bus/net/eq.c index 7ca721fc..2864f0ec 100644 --- a/trunk/hw/mlx4/kernel/bus/net/eq.c +++ b/trunk/hw/mlx4/kernel/bus/net/eq.c @@ -255,7 +255,7 @@ static BOOLEAN mlx4_interrupt( return (BOOLEAN)work; } -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ BOOLEAN IsrSynchronizeRoutine( @@ -744,7 +744,7 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) eq_set_ci(&priv->eq_table.eq[i], 1); -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ { /* Create a thread for polling EQs in case of missing interrupts from the card */ NTSTATUS status; OBJECT_ATTRIBUTES attr; @@ -866,7 +866,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); int i; -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ /* stop the EQ polling thread */ if (priv->eq_table.threadObject) { #define WAIT_TIME_MS 3000 diff --git a/trunk/hw/mlx4/kernel/bus/net/mlx4.h b/trunk/hw/mlx4/kernel/bus/net/mlx4.h index 8139f8fd..bc3d055a 100644 --- a/trunk/hw/mlx4/kernel/bus/net/mlx4.h +++ b/trunk/hw/mlx4/kernel/bus/net/mlx4.h @@ -233,7 +233,7 @@ struct mlx4_eq_table { int have_irq; u8 inta_pin; u8 max_extra_eqs; -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ KEVENT thread_start_event; KEVENT thread_stop_event; BOOLEAN bTerminated; diff --git a/trunk/hw/mlx4/kernel/hca/fw.c b/trunk/hw/mlx4/kernel/hca/fw.c index 2c0df1f2..678bb5b6 100644 --- a/trunk/hw/mlx4/kernel/hca/fw.c +++ b/trunk/hw/mlx4/kernel/hca/fw.c @@ -405,7 +405,7 @@ fw_access_ctrl( UNREFERENCED_PARAMETER(num_handles); if(!p_umv_buf ) { -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ if ((p_ci_op->command == FW_POLL_EQ_START) || (p_ci_op->command == FW_POLL_EQ_STOP)){ // poll EQ (in case of missed interrupt) mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; struct ib_device *p_ibdev = hca2ibdev(p_hca); diff --git a/trunk/hw/mlx4/kernel/inc/vc.h b/trunk/hw/mlx4/kernel/inc/vc.h index 73f4dc74..fdfe9a2a 100644 --- a/trunk/hw/mlx4/kernel/inc/vc.h +++ b/trunk/hw/mlx4/kernel/inc/vc.h @@ -51,7 +51,7 @@ struct _map_crspace { #define FW_OPEN_IF 0xe7 #define FW_CLOSE_IF 0x7e -#if WORKAROUND_POLL_EQ +#if 1//WORKAROUND_POLL_EQ #define FW_POLL_EQ_START 0x0D #define FW_POLL_EQ_STOP 0x0E #endif @@ -79,3 +79,4 @@ typedef struct { } uplink_info_t; + diff --git a/trunk/hw/mthca/kernel/hca_driver.c b/trunk/hw/mthca/kernel/hca_driver.c index d41a3254..a43877ff 100644 --- a/trunk/hw/mthca/kernel/hca_driver.c +++ b/trunk/hw/mthca/kernel/hca_driver.c @@ -85,6 +85,7 @@ UNICODE_STRING g_param_path; char mlnx_uvp_lib_name[MAX_LIB_NAME] = {"mthcau"}; void reregister_hca( hca_dev_ext_t *p_ext ); +void mlnx_poll_eq(struct ib_device *device, BOOLEAN bStart); NTSTATUS @@ -671,7 +672,27 @@ fw_access_ctrl( UNREFERENCED_PARAMETER(num_handles); if( !p_umv_buf ) - return IB_UNSUPPORTED; + { +#if 1//WORKAROUND_POLL_EQ + if ((p_ci_op->command == FW_POLL_EQ_START) || (p_ci_op->command == FW_POLL_EQ_STOP)) + { // poll EQ (in case of missed interrupt) + struct ib_device *ib_dev; + p_hob = (mlnx_hob_t *)h_ca; + ib_dev = IBDEV_FROM_HOB( p_hob ); + + if(p_ci_op->command == FW_POLL_EQ_START) + { + mlnx_poll_eq(ib_dev,1); + }else + { + mlnx_poll_eq(ib_dev,0); + } + return IB_SUCCESS; + } + else +#endif + return IB_UNSUPPORTED; + } p_context = (struct ib_ucontext *)h_ca; p_hob = HOB_FROM_IBDEV( p_context->device ); diff --git a/trunk/hw/mthca/kernel/hca_driver.h b/trunk/hw/mthca/kernel/hca_driver.h index 4e8fc3b6..6fa4d437 100644 --- a/trunk/hw/mthca/kernel/hca_driver.h +++ b/trunk/hw/mthca/kernel/hca_driver.h @@ -214,6 +214,11 @@ Firmware Update definitions #define FW_OPEN_IF 0xe7 #define FW_CLOSE_IF 0x7e +#if 1//WORKAROUND_POLL_EQ +#define FW_POLL_EQ_START 0x0D +#define FW_POLL_EQ_STOP 0x0E +#endif + #define FW_SIGNATURE (0x5a445a44) #define FW_SECT_SIZE (0x10000) diff --git a/trunk/hw/mthca/kernel/mthca_dev.h b/trunk/hw/mthca/kernel/mthca_dev.h index a3dd1774..41fae6fb 100644 --- a/trunk/hw/mthca/kernel/mthca_dev.h +++ b/trunk/hw/mthca/kernel/mthca_dev.h @@ -229,6 +229,12 @@ struct mthca_eq_table { int have_irq; u8 inta_pin; KLOCK_QUEUE_HANDLE lockh; +#if 1//WORKAROUND_POLL_EQ + KEVENT thread_start_event; + KEVENT thread_stop_event; + BOOLEAN bTerminated; + PVOID threadObject; +#endif }; struct mthca_cq_table { diff --git a/trunk/hw/mthca/kernel/mthca_eq.c b/trunk/hw/mthca/kernel/mthca_eq.c index 111dea71..a431ed09 100644 --- a/trunk/hw/mthca/kernel/mthca_eq.c +++ b/trunk/hw/mthca/kernel/mthca_eq.c @@ -596,6 +596,101 @@ static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr, } #endif +#if 1//WORKAROUND_POLL_EQ + +BOOLEAN +IsrSynchronizeRoutine( + IN PVOID SynchronizeContext + ) +{ + struct mthca_dev *dev = (struct mthca_dev *)SynchronizeContext; + + //Is this always correct? + mthca_arbel_interrupt(dev->ext->int_obj,dev); + + return TRUE; +} + + +VOID eq_polling_thread(void *ctx) +{ +#define POLLING_INTERVAL_MS 50 + NTSTATUS status; + struct mthca_dev *dev = (struct mthca_dev *)ctx; + PVOID wait_objects[2]; + LARGE_INTEGER wait_time; + + wait_objects[0] = &dev->eq_table.thread_stop_event; + wait_objects[1] = &dev->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(dev->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(dev->ext->int_obj, IsrSynchronizeRoutine, dev); + + status = KeWaitForSingleObject( &dev->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(dev->eq_table.bTerminated) break; + } + + DbgPrint("Polling thread terminated.\n"); + PsTerminateSystemThread(STATUS_SUCCESS); + +} + + +void mlnx_poll_eq(struct ib_device *device, BOOLEAN bStart) +{ + LONG signalled=0; + struct mthca_dev *dev = (struct mthca_dev *)(device); + + if(bStart){ + /* signal start of polling */ + signalled = KeSetEvent( + &dev->eq_table.thread_start_event, IO_NO_INCREMENT, FALSE ); + }else{ + /* signal end of polling */ + signalled = KeSetEvent( + &dev->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE ); + } + +} + +#endif + static int mthca_create_eq(struct mthca_dev *dev, int nent, u8 intr, @@ -1061,6 +1156,39 @@ int mthca_init_eq_table(struct mthca_dev *dev) else tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); +#if 1//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(&dev->eq_table.thread_start_event, SynchronizationEvent, FALSE); + KeInitializeEvent(&dev->eq_table.thread_stop_event, SynchronizationEvent, FALSE); + dev->eq_table.bTerminated = FALSE; + dev->eq_table.threadObject = NULL; + InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); + status = PsCreateSystemThread( &handle, + THREAD_ALL_ACCESS, &attr, NULL, NULL, eq_polling_thread, dev ); + if (NT_SUCCESS(status)) { + status = ObReferenceObjectByHandle( + handle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &dev->eq_table.threadObject, + NULL + ); + + ASSERT(status == STATUS_SUCCESS); // + + status = ZwClose(handle); + + ASSERT(NT_SUCCESS(status)); // Should always succeed + + } + } +#endif + return 0; err_out_cmd: @@ -1086,6 +1214,33 @@ void mthca_cleanup_eq_table(struct mthca_dev *dev) u8 status; int i; +#if 1//WORKAROUND_POLL_EQ + /* stop the EQ polling thread */ + if (dev->eq_table.threadObject) { + #define WAIT_TIME_MS 3000 + NTSTATUS status; + LARGE_INTEGER wait_time; + LONG signalled; + + dev->eq_table.bTerminated = TRUE; + + /* signal polling stopped in case it is not */ + signalled = KeSetEvent( + &dev->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( dev->eq_table.threadObject, + Executive, KernelMode, FALSE, &wait_time ); + ASSERT(status == STATUS_SUCCESS); + + ObDereferenceObject(dev->eq_table.threadObject); + + /* cleanup */ + dev->eq_table.threadObject = NULL; + } +#endif + mthca_free_irqs(dev); mthca_MAP_EQ(dev, async_mask(dev), -- 2.46.0