[MLX4] added MSI-X support to MLX4 driver.
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Sun, 25 Jan 2009 09:32:03 +0000 (09:32 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Sun, 25 Jan 2009 09:32:03 +0000 (09:32 +0000)
This patch adds MSI-X support to MLX4 driver.
To remind, current driver creates 2 EQs (for commands/events and completions), which both use 1 legacy interrupt.
With this patch MLX4 requests (in inf file) 18 MSI-X interrupt vectors, spreaded across processors in round-robin way.
If the platform doesn't support MSI-X vectors, the driver uses legacy interrupts.

MSI-X support required some changes in the card reset mechanism, which are also found in the patch.

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

25 files changed:
hw/mlx4/kernel/bus/core/l2w.c
hw/mlx4/kernel/bus/drv/drv.c
hw/mlx4/kernel/bus/drv/drv.h
hw/mlx4/kernel/bus/drv/mlx4_bus.inx
hw/mlx4/kernel/bus/drv/pci.c
hw/mlx4/kernel/bus/ib/main.c
hw/mlx4/kernel/bus/inc/bus_intf.h
hw/mlx4/kernel/bus/inc/cmd.h
hw/mlx4/kernel/bus/inc/device.h
hw/mlx4/kernel/bus/inc/eq.h
hw/mlx4/kernel/bus/net/catas.c
hw/mlx4/kernel/bus/net/cmd.c
hw/mlx4/kernel/bus/net/eq.c
hw/mlx4/kernel/bus/net/icm.c
hw/mlx4/kernel/bus/net/main.c
hw/mlx4/kernel/bus/net/mlx4.h
hw/mlx4/kernel/bus/net/profile.c
hw/mlx4/kernel/bus/net/reset.c
hw/mlx4/kernel/inc/l2w.h
hw/mlx4/kernel/inc/l2w_sync.h
hw/mlx4/kernel/inc/vc.h
hw/mlx4/kernel/inc/vip_dev.h
hw/mthca/kernel/hca_pnp.c
inc/mthca/mthca_vc.h
tools/vstat/user/vstat_main.c

index 4b7599e..4569e81 100644 (file)
@@ -266,159 +266,239 @@ void core_cleanup()
 
 #ifdef USE_WDM_INTERRUPTS
 
-// TODO: put into Globals
-uint32_t g_processor_affinity = 0;
+void free_irq(struct mlx4_dev *dev)
+{
+       if (!dev->pdev->int_obj)
+               return;
+       
+#if (NTDDI_VERSION >= NTDDI_LONGHORN)
+       // Vista build environment
+       if (dev->pdev->legacy_connect)
+               IoDisconnectInterrupt( dev->pdev->int_obj );
+       else {
+               IO_DISCONNECT_INTERRUPT_PARAMETERS ctx;
+               MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV,
+                       ("IoDisconnectInterrupt: Version %d\n", dev->pdev->version)); 
+               ctx.Version = dev->pdev->version;
+               ctx.ConnectionContext.InterruptObject = dev->pdev->int_obj;
+               IoDisconnectInterruptEx( &ctx );
+       }
+
+#else
+       // legacy build environment
+       IoDisconnectInterrupt( dev->pdev->int_obj );
+#endif
+       dev->pdev->int_obj = NULL;
+}
+
 
 int request_irq(
        IN              struct mlx4_dev *       dev,            
-       IN              ULONG                           vector,         /* interrupt or MSI-X vector */
        IN              PKSERVICE_ROUTINE       isr,            /* Line ISR */
        IN              PVOID                           isr_ctx,        /* ISR context */
-       IN              dpc_t                           dpc,
-       IN              PVOID                           misr,           /* Message ISR */
+       IN              PKMESSAGE_SERVICE_ROUTINE       misr,           /* Message ISR */
        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 */
 
-       KeInitializeSpinLock( &pdev->isr_lock );
+#if (NTDDI_VERSION >= NTDDI_LONGHORN)
 
-#ifdef CONFIG_PCI_MSI
+       IO_CONNECT_INTERRUPT_PARAMETERS params;
+       PIO_INTERRUPT_MESSAGE_INFO p_msi_info;
 
-#if (NTDDI_VERSION >= NTDDI_LONGHORN)
+       KeInitializeSpinLock( &pdev->isr_lock );
+       pdev->n_msi_vectors = 0;  // not using MSI/MSI-X
 
        //
-       // Vista and later platforms build
+       // Vista and later platforms build environment
        //
 
-       do {
-               IO_CONNECT_INTERRUPT_PARAMETERS params;
+       RtlZeroMemory( &params, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS) );
+       if ( !(dev->flags & MLX4_FLAG_MSI_X) ) {
+               params.Version = CONNECT_FULLY_SPECIFIED;
+               goto get_legacy_int;
+       }
+               
+       //
+       // try to connect our Interrupt Message Service Rotuine to
+       // all Message-Signaled Interrupts our device has been granted,
+       // with automatic fallback to a single line-based interrupt.
+       //
+       
+       params.Version = CONNECT_MESSAGE_BASED;
+       params.MessageBased.PhysicalDeviceObject = pdev->pdo;
+       params.MessageBased.ConnectionContext.Generic = &p_msi_info;
+       params.MessageBased.MessageServiceRoutine = misr;
+       params.MessageBased.ServiceContext = isr_ctx;
+       params.MessageBased.SpinLock = NULL;
+       params.MessageBased.SynchronizeIrql = 0;
+       params.MessageBased.FloatingSave = FALSE;
+       // fallback to line-based ISR if there is no MSI support
+       params.MessageBased.FallBackServiceRoutine = isr;
+       
+       status = IoConnectInterruptEx(&params);
 
-               RtlZeroMemory( &params, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS) );
-                       
+       pdev->version = params.Version;
+       *int_obj = (PVOID)p_msi_info;
+       
+       if ( NT_SUCCESS(status) ) {
+       
                //
-               // try to connect our Interrupt Message Service Rotuine to
-               // all Message-Signaled Interrupts our device has been granted,
-               // with automatic fallback to a single line-based interrupt.
+               // It worked, so we're running on Vista or later.
                //
-               
-               params.Version = CONNECT_MESSAGE_BASED;
-               params.MessageBased.PhysicalDeviceObject = pdev->p_self_do;
-               params.MessageBased.MessageServiceRoutine = misr;
-               params.MessageBased.ServiceContext = isr_ctx;
-               params.MessageBased.SpinLock = &pdev->isr_lock;
-               params.MessageBased.SynchronizeIrql = (KIRQL)pdev->int_info.u.Interrupt.Level;
-               params.MessageBased.FloatingSave = FALSE;
-               // fallback to line-based ISR if there is no MSI support
-               params.MessageBased.FallBackServiceRoutine = isr;
-               
-               status = IoConnectInterruptEx(&params);
-               
-               if ( NT_SUCCESS(status) ) {
+       
+               if(params.Version == CONNECT_MESSAGE_BASED) {
+                       ULONG i;
                
                        //
-                       // It worked, so we're running on Vista or later.
+                       // Because we succeeded in connecting to one or more Message-Signaled
+                       // Interrupts, the connection context that was returned was
+                       // a pointer to an IO_INTERRUPT_MESSAGE_INFO structure.
                        //
-               
-               ... // Code goes here to identify if we were connected
-               ... //                  to a line-based interrupt, or one or more
-               ... //                          Message-Signaled Interrupts
-               
-               
+                       pdev->n_msi_vectors = (u8)p_msi_info->MessageCount;  // not using MSI/MSI-X
+                       // print it 
+                       MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV,
+                               ("request_irq: Granted %d MSI vectors ( UnifiedIrql %#x)\n", 
+                               p_msi_info->MessageCount, p_msi_info->UnifiedIrql ));
+                       for (i=0; i < p_msi_info->MessageCount; ++i) {
+                               MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV,
+                                       ("*** Vector %#x, Affinity %#x, Irql %#x, MsgAddr %I64x, MsgData %#x, Mode %d\n", 
+                                       p_msi_info->MessageInfo[i].Vector,
+                                       (ULONG)p_msi_info->MessageInfo[i].TargetProcessorSet,
+                                       p_msi_info->MessageInfo[i].Irql,
+                                       p_msi_info->MessageInfo[i].MessageAddress.QuadPart,
+                                       p_msi_info->MessageInfo[i].MessageData,
+                                       p_msi_info->MessageInfo[i].Mode ));
+                       }
+
+                       // sanity check
+                       if (pdev->n_msi_vectors_alloc != pdev->n_msi_vectors) {
+                               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT ,
+                                       ("Connected to %d interrupts from %d allocated to us !!!\n",
+                                       pdev->n_msi_vectors, pdev->n_msi_vectors_alloc ));
+                               ASSERT(pdev->n_msi_vectors_alloc == pdev->n_msi_vectors);
+                               *int_obj = NULL;
+                               return -EFAULT;         /* failed to connect interrupt */
+                       }
+
+                       // fill MSI-X map table
+                       for (i=0; i < p_msi_info->MessageCount; ++i) {
+                               pdev->p_msix_map[i].cpu = p_msi_info->MessageInfo[i].TargetProcessorSet;
+                       }
+
                } else {
-               
-                       //
-                       // We are on a legacy system and maybe can proceed
                        //
+                       // We are on Vista, but there is no HW MSI support
+                       // So we are connected to line interrupt
+                       ASSERT(params.Version == CONNECT_LINE_BASED);
+               }
+       
+       
+       } else {
+       
+               //
+               // We are on a legacy system and maybe can proceed
+               //
 
-                       pdev->msi_used = FALSE;  // not using MSI/MSI-X
-
-                       if (params.Version == CONNECT_FULLY_SPECIFIED) {
-               
-                               //
-                               // use IoConnectInterruptEx to connect our ISR to a
-                               // line-based interrupt.
-                               //
-
-                               params.FullySpecified.PhysicalDeviceObject = pdev->p_self_do;
-                               params.FullySpecified.InterruptObject  = int_obj;
-                               params.FullySpecified.ServiceRoutine  = isr;
-                               params.FullySpecified.ServiceContext = isr_ctx;
-                               params.FullySpecified.SpinLock = &pdev->isr_lock;
-                               params.FullySpecified.Vector = vector;
+               if (params.Version == CONNECT_FULLY_SPECIFIED) {
+       
+                       //
+                       // use IoConnectInterruptEx to connect our ISR to a
+                       // line-based interrupt.
+                       //
+get_legacy_int:
+                       params.FullySpecified.PhysicalDeviceObject = pdev->pdo;
+                       params.FullySpecified.InterruptObject  = int_obj;
+                       params.FullySpecified.ServiceRoutine  = isr;
+                       params.FullySpecified.ServiceContext = isr_ctx;
+                       params.FullySpecified.FloatingSave = FALSE;
+                       params.FullySpecified.SpinLock = NULL;
+
+                       if (pdev->int_info.Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
+                               // The resource is for a message-based interrupt. Use the u.MessageInterrupt.Translated member of IntResource.
+                               
+                               params.FullySpecified.Vector = pdev->int_info.u.MessageInterrupt.Translated.Vector;
+                               params.FullySpecified.Irql = (KIRQL)pdev->int_info.u.MessageInterrupt.Translated.Level;
+                               params.FullySpecified.SynchronizeIrql = (KIRQL)pdev->int_info.u.MessageInterrupt.Translated.Level;
+                               params.FullySpecified.ProcessorEnableMask = g.mod_affinity ? 
+                                       g.mod_affinity : pdev->int_info.u.MessageInterrupt.Translated.Affinity;
+                       } else {
+                               // The resource is for a line-based interrupt. Use the u.Interrupt member of IntResource.
+                               
+                               params.FullySpecified.Vector = pdev->int_info.u.Interrupt.Vector;
                                params.FullySpecified.Irql = (KIRQL)pdev->int_info.u.Interrupt.Level;
                                params.FullySpecified.SynchronizeIrql = (KIRQL)pdev->int_info.u.Interrupt.Level;
-                               params.FullySpecified.ProcessorEnableMask = g_processor_affinity ? 
-                                       g_processor_affinity : (KAFFINITY)pdev->int_info.u.Interrupt.Affinity,  /* interrupt affinity */
-                               params.FullySpecified.InterruptMode = LevelSensitive;
-                               params.FullySpecified.ShareVector = TRUE;
-                               params.FullySpecified.FloatingSave = FALSE;
-
-                               status = IoConnectInterruptEx(&params);
-                       }
-                       else {
-
-                               // Something wrong with IoConnectInterruptEx.
-                               // Lets try the usual way
-                               break;
+                               params.FullySpecified.ProcessorEnableMask = g.mod_affinity ? 
+                                       g.mod_affinity : pdev->int_info.u.Interrupt.Affinity;
                        }
+                       
+                       params.FullySpecified.InterruptMode = (pdev->int_info.Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive);
+                       params.FullySpecified.ShareVector = (BOOLEAN)(pdev->int_info.ShareDisposition == CmResourceShareShared);
 
+                       status = IoConnectInterruptEx(&params);
+                       pdev->version = params.Version;
                }
-               
-               if ( !NT_SUCCESS(status) ) {
-                       // Non-recoverable error calling IoConnectInterruptEx
-                       MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT ,("IoConnectInterruptEx  failed status %#x \n",status));
-                       return -EFAULT;         /* failed to connect interrupt */
+               else {
+
+                       // Something wrong with IoConnectInterruptEx.
+                       // Lets try the usual way
+                       status = IoConnectInterrupt(
+                               int_obj,                                                                                /* InterruptObject */
+                               isr,                                                                                    /* ISR */ 
+                               isr_ctx,                                                                                /* ISR context */
+                               &pdev->isr_lock,                                                                /* spinlock */
+                               pdev->int_info.u.Interrupt.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.mod_affinity ? g.mod_affinity : (KAFFINITY)pdev->int_info.u.Interrupt.Affinity,       /* interrupt affinity */
+                               FALSE                                                                                                                   /* whether to save Float registers */
+                               );
+                       pdev->legacy_connect = TRUE;
                }
 
-               // we should not be here
-               ASSERT(0);
-               return 0;
-       } while (0);
-
-#endif
+       }
 
 #else
 
-       UNUSED_PARAM(misr);
-
-#endif
-
        //
-       // Legacy (before Vista) platform build
+       // Legacy (before Vista) platform build environment
        //
 
+       UNUSED_PARAM(misr);
+
+       KeInitializeSpinLock( &pdev->isr_lock );
+       pdev->n_msi_vectors = 0;  // not using MSI/MSI-X
+
        status = IoConnectInterrupt(
-               int_obj,                                                                                /* InterruptObject */
+               int_obj,                                                                                /* InterruptObject */
                isr,                                                                                    /* ISR */ 
-               isr_ctx,                                                                                /* ISR context */
-               &pdev->isr_lock,                                                                /* spinlock */
-               vector,                                                                                 /* interrupt vector */
+               isr_ctx,                                                                                /* ISR context */
+               &pdev->isr_lock,                                                                /* spinlock */
+               pdev->int_info.u.Interrupt.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 */
+               (BOOLEAN)(pdev->int_info.ShareDisposition == CmResourceShareShared),    /* vector shared or not */
+               g.mod_affinity ? g.mod_affinity : (KAFFINITY)pdev->int_info.u.Interrupt.Affinity,       /* interrupt affinity */
+               FALSE                                                                                                                   /* whether to save Float registers */
                );
 
+#endif
+
        if (!NT_SUCCESS(status)) {
-               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT ,("IoConnectInterrupt  failed status %d (did you change the processor_affinity ? )\n",status));
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT ,
+                       ("Connect interrupt failed with status %#x, affinity %#x )\n",
+                       status, g.mod_affinity ? g.mod_affinity : (unsigned int)pdev->int_info.u.Interrupt.Affinity));
+               *int_obj = NULL;
                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
index 54bb925..28ebb49 100644 (file)
@@ -334,6 +334,8 @@ __start_card(
        p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
        p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;\r
        p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
+       if ( p_fdo->bus_ib_ifc.pmlx4_dev->flags & MLX4_FLAG_MSI_X )\r
+               p_fdo->bus_ib_ifc.n_msi_vectors = p_fdo->pci_dev.n_msi_vectors - 2;\r
 \r
        p_fdo->card_started = TRUE;\r
 \r
@@ -350,7 +352,7 @@ __stop_card(
 {\r
        if ( p_fdo->card_started ) {\r
                p_fdo->card_started = FALSE;\r
-               mlx4_remove_one( &p_fdo->pci_dev );\r
+               mlx4_remove_one( &p_fdo->pci_dev, TRUE);\r
        }\r
 }\r
 \r
@@ -467,8 +469,12 @@ __put_resources(
        )\r
 {\r
        struct pci_dev *pdev = &p_fdo->pci_dev;\r
+\r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
+       if (pdev->msix_info.valid) \r
+               pci_free_msix_info_resources(&pdev->msix_info);\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
@@ -478,6 +484,11 @@ __put_resources(
                p_fdo->pci_bus_ifc_taken = FALSE;\r
                __put_bus_ifc(&pdev->bus_pci_ifc);\r
        }\r
+\r
+       if (pdev->p_msix_map)\r
+               kfree(pdev->p_msix_map);\r
+\r
+       \r
        MLX4_EXIT( MLX4_DBG_DRV );\r
 }\r
 \r
@@ -566,8 +577,10 @@ __get_resources(
 \r
 #ifdef USE_WDM_INTERRUPTS\r
                        case CmResourceTypeInterrupt:\r
-                               pdev->int_info = *desc;\r
+                               if (!pdev->n_msi_vectors_alloc)\r
+                                       pdev->int_info = *desc;\r
                                if (desc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {\r
+                                       pdev->n_msi_vectors_alloc = (u8)(pdev->n_msi_vectors_alloc+desc_raw->u.MessageInterrupt.Raw.MessageCount);\r
                                        MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV,\r
                                                ("EvtPrepareHardware: Desc %d: MsiInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n", \r
                                                i, desc->ShareDisposition, desc->Flags,\r
@@ -607,7 +620,8 @@ __get_resources(
        //\r
        // get uplink info. \r
        //\r
-       status = pci_save_config( &pdev->bus_pci_ifc, &pdev->pci_cfg_space);\r
+       status = pci_save_config( &pdev->bus_pci_ifc, \r
+               &pdev->pci_cfg_space );\r
        if( !NT_SUCCESS( status ) )\r
        {\r
                MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
@@ -627,6 +641,20 @@ __get_resources(
                goto err;\r
        }\r
        p_fdo->dma_adapter_taken = TRUE;\r
+\r
+       //\r
+       // allocate MSI-X vector map table\r
+       //\r
+       if ( pdev->n_msi_vectors_alloc )\r
+       {\r
+               pdev->p_msix_map = kzalloc(sizeof(struct msix_map) * pdev->n_msi_vectors_alloc, GFP_KERNEL);\r
+               if ( !pdev->p_msix_map )\r
+               {\r
+                       MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
+                               ("Failed to allocate MSI-X vector map table\n"));\r
+                       goto err;\r
+               }\r
+       }\r
        \r
        //\r
        // fill more fields in pci_dev\r
@@ -634,6 +662,7 @@ __get_resources(
        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
+       pdev->pdo = WdfDeviceWdmGetPhysicalDevice(p_fdo->FdoDevice);\r
        \r
        MLX4_EXIT( MLX4_DBG_DRV );\r
        return STATUS_SUCCESS;\r
@@ -835,6 +864,8 @@ Return Value:
        p_fdo = FdoGetData(device);\r
        RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
        p_fdo->FdoDevice = device;\r
+       if (!g.p_fdo)\r
+               g.p_fdo = p_fdo;\r
 \r
        //\r
        // Init the BusIsr data\r
@@ -970,12 +1001,9 @@ __read_registry(WDFDRIVER *hDriver)
        // "Ports L2 type (ib/eth/auto, entry per port, comma seperated, default ib for all)"\r
        DECLARE_CONST_UNICODE_STRING(PortType, L"PortType");\r
 \r
-       // "MSI is supported"\r
-       DECLARE_CONST_UNICODE_STRING(MsiEnable, L"MsiEnable");\r
+       // "ProcessorAffinity"\r
+       DECLARE_CONST_UNICODE_STRING(ProcessorAffinity, L"ProcessorAffinity");\r
 \r
-       // "max number of interrupt vectors, supported"\r
-       DECLARE_CONST_UNICODE_STRING(MsiNumVector, L"MsiNumVector");\r
-       \r
        ULONG value;\r
        WDFKEY hKey = NULL;\r
        NTSTATUS status = STATUS_SUCCESS;\r
@@ -1050,7 +1078,7 @@ __read_registry(WDFDRIVER *hDriver)
                if (NT_SUCCESS (status)) \r
                        g.mod_enable_qos = value;\r
                else\r
-                       g.mod_enable_qos = 1;\r
+                       g.mod_enable_qos = 0;\r
 \r
 \r
                status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value);\r
@@ -1066,18 +1094,12 @@ __read_registry(WDFDRIVER *hDriver)
                        g.mod_interrupt_from_first = 1;\r
 \r
 \r
-               status = WdfRegistryQueryULong(hKey, &MsiEnable, &value);\r
+               status = WdfRegistryQueryULong(hKey, &ProcessorAffinity, &value);\r
                if (NT_SUCCESS (status)) \r
-                       g.mod_msi_enable = value;\r
+                       g.mod_affinity = value;\r
                else\r
-                       g.mod_msi_enable = 0;\r
+                       g.mod_affinity = 0;\r
                \r
-               status = WdfRegistryQueryULong(hKey, &MsiNumVector, &value);\r
-               if (NT_SUCCESS (status)) \r
-                       g.mod_msi_num_vector = value;\r
-               else\r
-                       g.mod_msi_num_vector = 8;\r
-\r
                uvalue.Buffer = uvalue_data;\r
                uvalue.MaximumLength = MAX_UVALUE;\r
                uvalue.Length = 0;\r
@@ -1209,3 +1231,4 @@ end:
 \r
 \r
 \r
+\r
index 2873a24..30dbd59 100644 (file)
@@ -45,7 +45,7 @@ Environment:
 #endif\r
 \r
 \r
-#define MLX4_MAX_INTERRUPTS            MLX4_NUM_EQ\r
+#define MLX4_MAX_INTERRUPTS            MLX4_NUM_EQS\r
 \r
 typedef struct {\r
        WDFINTERRUPT                            WdfInterrupt;\r
@@ -190,20 +190,27 @@ EvtDeviceD0Entry(
 // pci.c\r
 //\r
 \r
+void\r
+pci_free_msix_info_resources(\r
+       IN struct msix_saved_info *     pMsixInfo\r
+       );\r
+\r
 NTSTATUS\r
 pci_save_config(\r
        IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
-               OUT                     PCI_COMMON_CONFIG* const        pConfig );\r
+               OUT                     PCI_COMMON_CONFIG* const        pConfig\r
+       );\r
 \r
 NTSTATUS\r
 pci_hca_reset( \r
        IN              struct pci_dev *pdev\r
-);\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
+       OUT                     uplink_info_t *                 p_uplink_info\r
+       );\r
 \r
 NTSTATUS\r
 pci_hca_enable(\r
@@ -224,3 +231,4 @@ create_pdo(
 );\r
 \r
 \r
+\r
index 762b6d4..b6ce7e0 100644 (file)
@@ -111,13 +111,13 @@ AddReg = MLX4BUS.HwReg
 AddReg = MLX4BUS.HwReg\r
 \r
 [MLX4BUS.HwReg]\r
-HKR,"Interrupt Management", 0x00000010\r
-HKR,"Interrupt Management\MessageSignaledInterruptProperties",0x00000010\r
+HKR,"Interrupt Management",,0x00000010\r
+HKR,"Interrupt Management\MessageSignaledInterruptProperties",,0x00000010\r
 \r
-; MSI/MSI-X support\r
-HKR,"Interrupt Management\MessageSignaledInterruptProperties",MSISupported,0x00010001,0\r
-HKR,"Interrupt Management\MessageSignaledInterruptProperties",MessageNumberLimit,0x00010001,8\r
-HKR,"Interrupt Management\Affinity Policy",0x00000010\r
+; MSI-X support\r
+HKR,"Interrupt Management\MessageSignaledInterruptProperties",MSISupported,0x00010001,1\r
+HKR,"Interrupt Management\MessageSignaledInterruptProperties",MessageNumberLimit,0x00010001,18\r
+HKR,"Interrupt Management\Affinity Policy",,0x00000010\r
 \r
 ; AssignmentSetOverride - processors KAFFINITY mask  \r
 HKR,"Interrupt Management\Affinity Policy",AssignmentSetOverride,0x00000001,0x0\r
@@ -127,13 +127,14 @@ HKR,"Interrupt Management\Affinity Policy",AssignmentSetOverride,0x00000001,0x0
 ; IrqPolicyOneCloseProcessor (2) - connect interrupts to one processor\r
 ; IrqPolicyAllProcessorsInMachine (3) - connect interrupts to all processors in the machine\r
 ; IrqPolicySpecifiedProcessors (4) - connects interrupts according to AssignmentSetOverride\r
-HKR,"Interrupt Management\Affinity Policy",DevicePolicy,0x00010001,0x0\r
+; IrqPolicySpreadMessagesAcrossAllProcessors (5) - assign different message-based interrupts to different processors\r
+HKR,"Interrupt Management\Affinity Policy",DevicePolicy,0x00010001,0x5\r
 \r
 ; IrqArbPriorityUndefined (0) - no interrupt priority policy. \r
 ; IrqArbPriorityLow (1) - device can tolerate low IRQL\r
 ; IrqArbPriorityNormal (2) - device expects normal interrupt latencies\r
 ; IrqArbPriorityHigh (3) - device requires the lowest possible interrupt latency\r
-HKR,"Interrupt Management\Affinity Policy",DevicePriority,0x00010001,0x0\r
+HKR,"Interrupt Management\Affinity Policy",DevicePriority,0x00010001,0x3\r
 \r
 [MLX4BUS.DDInstall.ntx86]\r
 CopyFiles = MLX4BUS.CopyFiles\r
index d007fd5..b8c0e6c 100644 (file)
 #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
+//#define PCI_CAPABILITY_ID_VPD                                0x03\r
+//#define PCI_CAPABILITY_ID_PCIX                               0x07\r
+//#define PCI_CAPABILITY_ID_PCI_EXPRESS                        0x10\r
+//#define PCI_CAPABILITY_ID_MSIX                       0x11\r
 \r
+/*\r
+ * MSI-X Capability\r
+ */\r
+typedef struct _PCI_MSIX_CAPABILITY {\r
+\r
+       PCI_CAPABILITIES_HEADER Header;\r
+\r
+       USHORT          Flags;\r
+       ULONG           Table_Offset;\r
+       ULONG           PBA_Offset;\r
+       \r
+} PCI_MSIX_CAPABILITY, *PPCI_MSIX_CAPABILITY;\r
+\r
+#define MSIX_FLAGS_MSIX_ENABLE(flags)                  (((flags)>>15)&1)       /* MSI-X is enabled */\r
+#define MSIX_FLAGS_MSIX_FUNCTION_MASK(flags)   (((flags)>>14)&1)       /* all interrupts masked */\r
+#define MSIX_FLAGS_SUPPORTED(flags)                            ((flags)&0x07ff)        /* vector table size */\r
+#define MSIX_OFFSET_BIR(offset)                                        ((offset)&7)            /* BAR index register */\r
+#define MSIX_OFFSET_ADDR(offset)                               ((offset)&0xfffffff8)           /* offset */\r
+\r
+/* this structure describes one MSI-X vector from N */\r
+typedef struct _PCI_MSIX_VECTOR {\r
+\r
+       ULONGLONG       Addr;\r
+       ULONG           Data;\r
+       ULONG           Flags;\r
+       \r
+} PCI_MSIX_VECTOR, *PPCI_MSIX_VECTOR;\r
+\r
+#define MSIX_VECTOR_MASKED(flags)                      ((flags)&1)     /* this vector is masked */\r
+\r
+/* this structure pending state of 64 MSI-X vectors from N */\r
+typedef struct _PCI_MSIX_PENDING {\r
+\r
+       ULONGLONG       Mask;\r
+       \r
+} PCI_MSIX_PENDING, *PPCI_MSIX_PENDING;\r
 \r
 /*\r
  * Vital Product Data Capability\r
@@ -149,6 +186,58 @@ __find_capability(
        return offset;\r
 }\r
 \r
+\r
+static NTSTATUS\r
+__pci_restore_msix_info(\r
+       IN                              struct pci_dev *pdev,\r
+       struct msix_saved_info *                p_info\r
+       )\r
+{\r
+       int i;\r
+       int offset;\r
+       NTSTATUS status = STATUS_SUCCESS;\r
+       PCI_MSIX_CAPABILITY     *pPciMsix;\r
+       PPCI_MSIX_VECTOR p_cvector, p_svector;\r
+       PBUS_INTERFACE_STANDARD p_ifc = &pdev->bus_pci_ifc;\r
+       PCI_COMMON_CONFIG* p_cfg = &pdev->pci_cfg_space;\r
+\r
+       if ( p_info->valid ) {\r
+\r
+               /* restore PBA Table */\r
+               p_info->valid = 0;\r
+               memcpy( p_info->mca, p_info->msa, p_info->msz );\r
+               kfree( p_info->msa );\r
+               MmUnmapIoSpace( p_info->mca, p_info->msz );\r
+\r
+               /* restore Vector Table */\r
+               p_svector = p_info->vsa;\r
+               p_cvector = p_info->vca;\r
+               for (i=0; i<p_info->num; i++) \r
+                       p_cvector[i].Flags = p_svector[i].Flags;\r
+               kfree( p_info->vsa );\r
+               MmUnmapIoSpace( p_info->vca, p_info->vsz );\r
+\r
+               /* restore MSI-X Capability */\r
+               offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
+               pPciMsix = (PCI_MSIX_CAPABILITY*)(((UCHAR*)p_cfg) + offset);\r
+               if (offset) { \r
+                       /* restore MSI-X control register */\r
+                       if ( sizeof( pPciMsix->Flags) != p_ifc->SetBusData( \r
+                               p_ifc->Context, PCI_WHICHSPACE_CONFIG,\r
+                               &pPciMsix->Flags,       offset + \r
+                               offsetof( PCI_MSIX_CAPABILITY, Flags),\r
+                               sizeof( pPciMsix->Flags ) )) {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
+                                       ("Couldn't restore MSI-X Control register, aborting.\n"));\r
+                               status = STATUS_UNSUCCESSFUL;\r
+                               goto end;\r
+                       }\r
+               }\r
+       }\r
+end:   \r
+       return status;\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
@@ -163,21 +252,19 @@ __restore_pci_config(
 {\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
+               int offset;\r
+               PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
 \r
-               if (hca_pcix_cap) {\r
+               /* PCI-X */\r
+               offset = __find_capability( pConfig, PCI_CAPABILITY_ID_PCIX );\r
+               if (offset) {\r
                        if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
-                               &pci_hdr[hca_pcix_cap/4], hca_pcix_cap, 4) ) {\r
+                               &pci_hdr[offset/4], offset, 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
@@ -185,11 +272,14 @@ __restore_pci_config(
                        }\r
                }\r
 \r
-               if (hca_pcie_cap) {\r
+               /* PCI-Express */\r
+               offset = __find_capability( pConfig, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
+               pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)pConfig) + offset);\r
+               if (offset) {\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
+                               &pPciExpCap->DevControl,        offset + \r
                                offsetof( PCI_PCIEXP_CAPABILITY, DevControl),\r
                                sizeof( pPciExpCap->DevControl ) )) {\r
                                MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
@@ -200,7 +290,7 @@ __restore_pci_config(
                        /* 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
+                               &pPciExpCap->LinkControl,       offset + \r
                                offsetof( PCI_PCIEXP_CAPABILITY, LinkControl),\r
                                sizeof( pPciExpCap->LinkControl ) )) {\r
                                MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
@@ -237,15 +327,121 @@ out:
        return status;\r
 }\r
 \r
+\r
+static int\r
+__save_msix_info(\r
+       IN                              PCI_COMMON_CONFIG *             p_cfg,\r
+       OUT                             struct msix_saved_info *p_info )\r
+{\r
+       u64 bar;\r
+       int n_supported;\r
+       PHYSICAL_ADDRESS pa;\r
+       ULONG capOffset, bir;\r
+       PPCI_MSIX_CAPABILITY pPciMsixCap;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+\r
+       /* find capability */\r
+       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
+       if( !capOffset ) {\r
+               p_info->valid = 0;\r
+               return 0;\r
+       }       \r
+       pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset);\r
+       n_supported = MSIX_FLAGS_SUPPORTED(pPciMsixCap->Flags) + 1;\r
+       p_info->num = n_supported;\r
+\r
+       /* map memory for vectors */\r
+       p_info->vsz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR));\r
+       bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset);\r
+       bar = *(u64*)&p_cfg->u.type1.BaseAddresses[bir] & ~0x0f;\r
+       pa.QuadPart = bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset);\r
+       p_info->vca = MmMapIoSpace( pa, p_info->vsz, MmNonCached ); \r
+       if ( p_info->vca == NULL) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                       ("Failed kernel mapping of MSI-X vector table.\n") );\r
+               goto end;\r
+       }\r
+\r
+       /* alloc memory for vector table */\r
+       p_info->vsa = kmalloc(p_info->vsz, GFP_KERNEL);\r
+       if ( !p_info->vsa ) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                       ("Failed allocate memory for MSI-X vector table \n") );\r
+               goto err_alloc_vectors;\r
+       }\r
+       memcpy( p_info->vsa, p_info->vca, p_info->vsz );\r
+\r
+       /* map memory for mask table */\r
+       bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset);\r
+       bar = *(u64*)&p_cfg->u.type1.BaseAddresses[bir] & ~0x0f;\r
+       p_info->msz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64);\r
+       pa.QuadPart = bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset);\r
+       p_info->mca = MmMapIoSpace( pa, p_info->msz, MmNonCached ); \r
+       if ( p_info->mca == NULL) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                       ("Failed kernel mapping of MSI-X mask table.\n") );\r
+               goto err_map_masks;\r
+       }\r
+\r
+       /* alloc memory for mask table */\r
+       p_info->msa = kmalloc(p_info->msz, GFP_KERNEL);\r
+       if ( !p_info->msa ) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                       ("Failed allocate memory for MSI-X vector table \n") );\r
+               goto err_alloc_masks;\r
+       }\r
+       memcpy( p_info->msa, p_info->mca, p_info->msz );\r
+\r
+       p_info->valid = 1;\r
+       return 0;\r
+\r
+err_alloc_masks:\r
+       MmUnmapIoSpace( p_info->mca, p_info->msz );\r
+    p_info->mca = NULL;\r
+\r
+err_map_masks:\r
+       kfree(p_info->vsa);\r
+    p_info->vsa = NULL;\r
+\r
+err_alloc_vectors:\r
+       MmUnmapIoSpace( p_info->vca, p_info->vsz );\r
+    p_info->vca = NULL;\r
+\r
+end:   \r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+       return -EFAULT;\r
+}\r
+\r
+void\r
+pci_free_msix_info_resources(\r
+       IN struct msix_saved_info *     pMsixInfo\r
+       )\r
+{\r
+       if (pMsixInfo->vca && pMsixInfo->vsz)\r
+               MmUnmapIoSpace( pMsixInfo->vca, pMsixInfo->vsz );\r
+\r
+       if (pMsixInfo->mca && pMsixInfo->msz)\r
+               MmUnmapIoSpace( pMsixInfo->mca, pMsixInfo->msz );\r
+\r
+       if (pMsixInfo->msa)\r
+               kfree(pMsixInfo->msa);\r
+\r
+       if (pMsixInfo->vsa)\r
+               kfree(pMsixInfo->vsa);\r
+\r
+       memset(pMsixInfo,0,sizeof(struct msix_saved_info));\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
+ * as directed in PRM , Appendix A. Software Reset.\r
  */\r
 NTSTATUS\r
 pci_save_config(\r
        IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
-               OUT                     PCI_COMMON_CONFIG* const        pConfig )\r
+               OUT                     PCI_COMMON_CONFIG* const        pConfig)\r
 {\r
        ULONG                                   len;\r
        UINT32                                  *pBuf;\r
@@ -280,18 +476,142 @@ pci_save_config(
 }\r
 \r
 \r
+/*\r
+ * Store Card's PCI Config space and print current MSI-X capabilities\r
+ */\r
+void\r
+pci_get_msi_info(\r
+       IN                              struct pci_dev                  *pdev,\r
+               OUT                     PCI_COMMON_CONFIG *             p_cfg,\r
+               OUT                     uplink_info_t *                 p_uplink_info )\r
+{\r
+       ULONG                                   capOffset;\r
+       NTSTATUS                                status;\r
+       BUS_INTERFACE_STANDARD  *pBusIfc = &pdev->bus_pci_ifc;\r
+\r
+       MLX4_ENTER( MLX4_DBG_PNP );\r
+\r
+       status = pci_save_config( pBusIfc, p_cfg );\r
+       if (!NT_SUCCESS(status)) {\r
+               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                       ("Failed to read PCI configuration of the card.\n") );\r
+               goto end;\r
+       }\r
+\r
+       // PCI MSI-X Capability\r
+       memset( &p_uplink_info->x, 0, sizeof(p_uplink_info->x) );\r
+       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
+       if( capOffset ) {\r
+               PVOID ka;\r
+               ULONG sz;\r
+               PHYSICAL_ADDRESS pa;\r
+               PPCI_MSIX_VECTOR p_vector;\r
+               PPCI_MSIX_PENDING p_pend;\r
+               ULONG granted_mask = 0;\r
+               PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset);\r
+               USHORT flags = pPciMsixCap->Flags;\r
+               ULONG table_bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset);\r
+               ULONG pend_bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset);\r
+               u64 table_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[table_bir] & ~0x0f;\r
+               u64 pend_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[pend_bir] & ~0x0f;\r
+               int i, n_supported = MSIX_FLAGS_SUPPORTED(flags) + 1;\r
+\r
+               /* print capabilities structure */\r
+               MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
+                       ("MSI-X Capability: Enabled - %d, Function Masked %d, Vectors Supported %d, Addr_Offset(BIR) %#x(%d), Pend_Offset(BIR) %#x(%d)\n",\r
+                       MSIX_FLAGS_MSIX_ENABLE(flags),\r
+                       MSIX_FLAGS_MSIX_FUNCTION_MASK(flags),\r
+                       n_supported, \r
+                       MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset), MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset), \r
+                       MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset), MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset) ));\r
+\r
+               /* fill info */\r
+               p_uplink_info->x.valid = 1;\r
+               p_uplink_info->x.enabled= MSIX_FLAGS_MSIX_ENABLE(flags);\r
+               p_uplink_info->x.masked = MSIX_FLAGS_MSIX_FUNCTION_MASK(flags);\r
+               p_uplink_info->x.requested = n_supported;\r
+\r
+               if (pdev->n_msi_vectors_alloc) {\r
+\r
+                       /* map memory */\r
+                       sz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR));\r
+                       pa.QuadPart = table_bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset);\r
+                       ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
+                       if ( ka == NULL) {\r
+                               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                                       ("Failed kernel mapping of MSI-X vector table.\n") );\r
+                               goto end;\r
+                       }\r
+                       \r
+                       p_vector = ka;\r
+                       /* print (allocated+2) vectors */\r
+                       for (i=0; i<pdev->n_msi_vectors_alloc+2; i++) {\r
+                               MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
+                                       ("MSI-X Vectors: Id %d, Masked %d, Addr %#I64x, Data %#x\n",\r
+                                       i, MSIX_VECTOR_MASKED(p_vector[i].Flags),\r
+                                       p_vector[i].Addr, p_vector[i].Data ));\r
+                       }\r
+\r
+                       p_uplink_info->x.granted = pdev->n_msi_vectors_alloc;\r
+                       p_uplink_info->x.granted_mask = granted_mask;\r
+                       MmUnmapIoSpace( ka, sz );\r
+\r
+                       /* map memory */\r
+                       sz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64);\r
+                       pa.QuadPart = pend_bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset);\r
+                       ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
+                       if ( ka == NULL) {\r
+                               MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
+                                       ("Failed kernel mapping of MSI-X mask table.\n") );\r
+                               goto end;\r
+                       }\r
+\r
+                       /* print first pending register (64 vectors) */\r
+                       p_pend = ka;\r
+                       for (i=0; i<1; i++) {\r
+                               MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
+                                       ("MSI-X Pending: Id %d, Pend %#I64x\n", i, p_pend[i].Mask ));\r
+                       }\r
+                       p_uplink_info->x.pending_mask = *(u32*)&p_pend[0].Mask;\r
+                       MmUnmapIoSpace( ka, sz );\r
+               }\r
+               else {\r
+                       MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
+                               ("MSI-X Vectors: Allocated 0 vectors\n") );\r
+               }\r
+\r
+       }\r
+\r
+end:   \r
+       MLX4_EXIT( MLX4_DBG_PNP );\r
+}\r
+\r
 NTSTATUS\r
 pci_hca_reset( \r
        IN              struct pci_dev *pdev\r
 )\r
 {\r
-       u32 sem;\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
+       struct msix_saved_info          msix_info;\r
+       ULONG                                           len;\r
 \r
        MLX4_ENTER( MLX4_DBG_PNP );\r
 \r
+       /* save Card Config Space including MSI-X capabilities */\r
+       pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info );\r
+\r
+       /* save MSI-X info, if any */\r
+       len = __save_msix_info( p_cfg, &msix_info );\r
+       if (len) {\r
+               MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to save MSI-X config.\n"));\r
+               return STATUS_DEVICE_NOT_READY;\r
+       }\r
+\r
+       /* reset the card */    \r
+       MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("\nResetting HCA ... \n\n"));\r
        {\r
                u64 end;\r
                PUCHAR  p_reset;\r
@@ -386,11 +706,21 @@ pci_hca_reset(
                }\r
        }\r
 \r
-       MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP , ("HCA is reset ! \n"));\r
+       /* restore MSI-X info after reset */\r
+       status = __pci_restore_msix_info( pdev, &msix_info );\r
+       if (!NT_SUCCESS(status))\r
+               goto err;\r
+\r
+       /* check, whether MSI-X capabilities were restore */\r
+       pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info );\r
+\r
+       MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("HCA has been reset ! \n"));\r
 \r
        status = STATUS_SUCCESS;\r
 \r
 err:\r
+       if (pdev->msix_info.valid) \r
+               pci_free_msix_info_resources(&pdev->msix_info);\r
        MLX4_EXIT( MLX4_DBG_PNP );\r
        return status;\r
 }\r
@@ -422,7 +752,7 @@ pci_get_uplink_info(
        }\r
 \r
        // PCI Express Capability\r
-       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIEXP );\r
+       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
        if( capOffset ) {\r
                pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
 \r
@@ -439,6 +769,7 @@ pci_get_uplink_info(
        MLX4_EXIT( MLX4_DBG_PNP );\r
 }\r
 \r
+\r
 NTSTATUS\r
 pci_hca_enable(\r
        IN              PBUS_INTERFACE_STANDARD         p_ifc,\r
@@ -466,3 +797,4 @@ pci_hca_enable(
                return status;\r
 }\r
 \r
+\r
index 8eed206..a6001ab 100644 (file)
@@ -572,8 +572,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
 #if 1//WORKAROUND_POLL_EQ
        ibdev->ib_dev.x.poll_eq                         = mlx4_poll_eq;
 #endif
-       if (mlx4_is_livefish(ibdev->dev))
+       if (mlx4_is_livefish(ibdev->dev)) {
+               if (ib_register_device(&ibdev->ib_dev))
+                       goto err_dealloc;
                return ibdev;
+       }
 
        if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
                goto err_dealloc;
index 5d5c5e5..a4dbe81 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#define MLX4_BUS_IB_INTERFACE_VERSION          2
+#define MLX4_BUS_IB_INTERFACE_VERSION          3
 
 #include <ib_verbs.h>
 //
@@ -107,8 +107,8 @@ BOOLEAN
 
 
 typedef int (*MLX4_ADD_EQ) (struct mlx4_dev *dev, int nent,
-                         u8 intr, PISR_FUNC func, PVOID func_context ,
-                         u8* p_eq_num, struct mlx4_eq ** p_eq);
+       KAFFINITY cpu, PISR_FUNC func, PVOID func_context ,
+       u8* p_eq_num, struct mlx4_eq ** p_eq);
 
 typedef void (*MLX4_REMOVE_EQ) (struct mlx4_dev *dev, u8 eq_num);
 
@@ -182,8 +182,10 @@ typedef struct _MLX4_BUS_IB_INTERFACE{
        int                                                     is_livefish;
        u8                                                      port_id;
        struct VipBusIfc                        *pVipBusIfc;
+       int                                                     n_msi_vectors;
        
 } MLX4_BUS_IB_INTERFACE, *PMLX4_BUS_IB_INTERFACE;
 
 
 
+
index 8efef0f..2828527 100644 (file)
@@ -121,9 +121,9 @@ enum {
 };
 
 enum {
-       MLX4_CMD_TIME_CLASS_A   = 60000,
-       MLX4_CMD_TIME_CLASS_B   = 60000,
-       MLX4_CMD_TIME_CLASS_C   = 60000,
+       MLX4_CMD_TIME_CLASS_A   = 5000,
+       MLX4_CMD_TIME_CLASS_B   = 5000,
+       MLX4_CMD_TIME_CLASS_C   = 5000,
 };
 
 enum {
index 3522323..5f60bb9 100644 (file)
@@ -39,7 +39,9 @@ enum {
        MLX4_FLAG_LIVEFISH              = 1 << 10,
        MLX4_FLAG_RESET_CLIENT  = 1 << 11,
        MLX4_FLAG_RESET_DRIVER  = 1 << 12,
-       MLX4_FLAG_RESET_STARTED = 1 << 13
+       MLX4_FLAG_RESET_STARTED = 1 << 13,
+       MLX4_FLAG_CARD_IS_DEAD  = 1 << 14,
+       MLX4_FLAG_BUSY_WAIT             = 1 << 15
 };
 
 enum {
@@ -334,7 +336,10 @@ struct mlx4_av {
        u8                      dgid[16];
 };
 
+#define MLX4_DEV_SIGNATURE     0xf1b34a6e
+
 struct mlx4_dev {
+       u32                     signature;
        struct pci_dev         *pdev;
        unsigned long           flags;
        struct mlx4_caps        caps;
index cc0087d..85c5e07 100644 (file)
 #ifndef MLX4_EQ_H\r
 #define MLX4_EQ_H\r
 \r
-enum {
-       MLX4_NUM_ASYNC_EQE      = 0x100,
-       MLX4_NUM_SPARE_EQE      = 0x80,
-       MLX4_EQ_ENTRY_SIZE      = 0x20
+enum {\r
+       MLX4_NUM_ASYNC_EQE      = 0x100,\r
+       MLX4_NUM_SPARE_EQE      = 0x80,\r
+       MLX4_EQ_ENTRY_SIZE      = 0x20\r
 };\r
 \r
-struct mlx4_eq {
-       struct mlx4_dev        *dev;
-       void __iomem           *doorbell;
-       int                     eqn;
-       u32                     cons_index;
-       u16                     irq;
-       u16                     have_irq;
-       int                     nent;
-       struct mlx4_buf_list   *page_list;
-       struct mlx4_mtt         mtt;
-       // Windows
-       KDPC            dpc;            /* DPC routine */
-       spinlock_t      lock;           /* spinlock for simult DPCs */
-       int                     eq_ix;          /* EQ index - 0..MLX4_NUM_EQ */
-       BOOLEAN (*isr)(void*);  /* isr */
-       void *          ctx;            /* isr ctx */
-       USHORT eq_no_progress;  /* used to look for stacked card */
-};
+struct mlx4_eq {\r
+       struct mlx4_dev        *dev;\r
+       void __iomem           *doorbell;\r
+       int                     eqn;\r
+       u32                     cons_index;\r
+       u16                     irq;\r
+       u16                     have_irq;\r
+       int                     nent;\r
+       struct mlx4_buf_list   *page_list;\r
+       struct mlx4_mtt         mtt;\r
+       // Windows\r
+       KDPC            dpc;            /* DPC routine */\r
+       spinlock_t      lock;           /* spinlock for simult DPCs */\r
+       int                     eq_ix;          /* EQ index - 0..MLX4_NUM_EQ */\r
+       BOOLEAN (*isr)(void*);  /* isr */\r
+       void *          ctx;            /* isr ctx */\r
+       USHORT eq_no_progress;  /* used to look for stacked card */\r
+       KAFFINITY       cpu;            /* CPU, this MSI-X vector is connected to */\r
+       int                     valid;\r
+};\r
+\r
+\r
 \r
+#pragma pack(push,1)\r
+struct mlx4_eqe {\r
+       u8                      reserved1;\r
+       u8                      type;\r
+       u8                      reserved2;\r
+       u8                      subtype;\r
+       union {\r
+               u32             raw[6];\r
+               struct {\r
+                       __be32  cqn;\r
+               } __attribute__((packed)) comp;\r
+               struct {\r
+                       u16     reserved1;\r
+                       __be16  token;\r
+                       u32     reserved2;\r
+                       u8      reserved3[3];\r
+                       u8      status;\r
+                       __be64  out_param;\r
+               } __attribute__((packed)) cmd;\r
+               struct {\r
+                       __be32  qpn;\r
+               } __attribute__((packed)) qp;\r
+               struct {\r
+                       __be32  srqn;\r
+               } __attribute__((packed)) srq;\r
+               struct {\r
+                       __be32  cqn;\r
+                       u32     reserved1;\r
+                       u8      reserved2[3];\r
+                       u8      syndrome;\r
+               } __attribute__((packed)) cq_err;\r
+               struct {\r
+                       u32     reserved1[2];\r
+                       __be32  port;\r
+               } __attribute__((packed)) port_change;\r
+       }                       event;\r
+       u8                      reserved3[3];\r
+       u8                      owner;\r
+} __attribute__((packed));\r
+#pragma pack(pop)\r
 \r
+static void eq_set_ci(struct mlx4_eq *eq, int req_not)\r
+{\r
+       __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) |\r
+                                              req_not << 31),\r
+                    eq->doorbell);\r
+       /* We still want ordering, just not swabbing, so add a barrier */\r
+       mb();\r
+}\r
 \r
-#pragma pack(push,1)
-struct mlx4_eqe {
-       u8                      reserved1;
-       u8                      type;
-       u8                      reserved2;
-       u8                      subtype;
-       union {
-               u32             raw[6];
-               struct {
-                       __be32  cqn;
-               } __attribute__((packed)) comp;
-               struct {
-                       u16     reserved1;
-                       __be16  token;
-                       u32     reserved2;
-                       u8      reserved3[3];
-                       u8      status;
-                       __be64  out_param;
-               } __attribute__((packed)) cmd;
-               struct {
-                       __be32  qpn;
-               } __attribute__((packed)) qp;
-               struct {
-                       __be32  srqn;
-               } __attribute__((packed)) srq;
-               struct {
-                       __be32  cqn;
-                       u32     reserved1;
-                       u8      reserved2[3];
-                       u8      syndrome;
-               } __attribute__((packed)) cq_err;
-               struct {
-                       u32     reserved1[2];
-                       __be32  port;
-               } __attribute__((packed)) port_change;
-       }                       event;
-       u8                      reserved3[3];
-       u8                      owner;
-} __attribute__((packed));
-#pragma pack(pop)
-
-static void eq_set_ci(struct mlx4_eq *eq, int req_not)
-{
-       __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) |
-                                              req_not << 31),
-                    eq->doorbell);
-       /* We still want ordering, just not swabbing, so add a barrier */
-       mb();
-}
-
-static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry)
-{
-       unsigned long off = (entry & (eq->nent - 1)) * MLX4_EQ_ENTRY_SIZE;
-       return (struct mlx4_eqe *)(eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE);
-}
-
-static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq)
-{
-       struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index);
-       return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe;
-}
+static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry)\r
+{\r
+       unsigned long off = (entry & (eq->nent - 1)) * MLX4_EQ_ENTRY_SIZE;\r
+       return (struct mlx4_eqe *)(eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE);\r
+}\r
+\r
+static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq)\r
+{\r
+       struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index);\r
+       return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe;\r
+}\r
 \r
 \r
 \r
 #endif /* MLX4_EQ_H */\r
 \r
 \r
+\r
index e48ecf8..d7a0f30 100644 (file)
@@ -43,7 +43,7 @@ static LIST_HEAD(catas_list);
 // "Reset device on internal errors if non-zero (default 1)")
 int g_internal_err_reset = 0;
 
-static void dispatch_event(struct ib_device *ibdev, enum ib_event_type type)
+void mlx4_dispatch_reset_event(struct ib_device *ibdev, enum ib_event_type type)
 {
        unsigned long flags;
        struct ib_event event;
@@ -103,7 +103,7 @@ static void dump_err_buf(struct mlx4_dev *dev)
 
        mlx4_err(dev, "Internal error detected:\n");
        for (i = 0; i < priv->fw.catas_size; ++i)
-               mlx4_err(dev, "  buf[%02x]: %08x\n",
+               mlx4_warn(dev, "  buf[%02x]: %08x\n",
                         i, swab32(readl(priv->catas_err.map + i)));
 }
 
@@ -147,13 +147,14 @@ static void poll_catas(struct mlx4_dev *dev)
        if (readl(priv->catas_err.map)) {
                dump_err_buf(dev);
 
-               mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
-
                // bar the device
                dev->flags |= MLX4_FLAG_RESET_DRIVER;
 
+               // relay the event
+               mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+
                // notify the clients
-               dispatch_event(dev->pdev->ib_dev, IB_EVENT_RESET_DRIVER);
+               mlx4_dispatch_reset_event(dev->pdev->ib_dev, IB_EVENT_RESET_DRIVER);
 
                if (g_internal_err_reset) {
                        PIO_WORKITEM catas_work = IoAllocateWorkItem( dev->pdev->p_self_do );
@@ -284,14 +285,18 @@ int mlx4_reset_execute( struct ib_event_handler *event_handler )
        get_event_handlers(ibdev, &tlist);
 
        // restart the device
+       mlx4_err(pdev->dev, "\n Performing HCA restart ... \n\n");
        err = mlx4_restart_one(pdev);
-       if (err) {
+       if (err || mlx4_is_livefish(pdev->dev)) {
+               mlx4_err(pdev->dev, "\n HCA restart failed ! \n\n");
                event.event = IB_EVENT_RESET_FAILED;
+               mlx4_err(pdev->dev, "\n HCa restart failed. \n\n");
        }
        else {
                // recreate interfaces
                fix_bus_ifc(pdev);
                event.event = IB_EVENT_RESET_END;
+               mlx4_err(pdev->dev, "\n HCA restart finished. Notifying the clients ... \n\n");
        }
 
        // notify the clients
@@ -317,14 +322,22 @@ card_reset_wi(
        IoFreeWorkItem( event_handler->rsrv_ptr );
 
        // notify the clients
-       dispatch_event(ibdev, IB_EVENT_RESET_CLIENT);
+       mlx4_dispatch_reset_event(ibdev, IB_EVENT_RESET_CLIENT);
 }
 
 int mlx4_reset_request( struct ib_event_handler *event_handler )
 {
-       struct ib_device *ibdev = event_handler->device;
-       struct mlx4_dev *dev = ibdev->dma_device;
-       
+       struct ib_device *ibdev;
+       struct mlx4_dev *dev;
+
+    ibdev = event_handler->device;
+    if (ibdev == NULL)
+        return -EFAULT;
+
+    dev = ibdev->dma_device;
+    if (ibdev == NULL)
+        return -EFAULT;
+        
        // set device to RESET_PENDING mode
        if (!mlx4_is_barred(dev)) {
                PIO_WORKITEM reset_work;
index b754946..87b66c2 100644 (file)
@@ -32,6 +32,7 @@
  * SOFTWARE.
  */
 
+#include <complib/cl_thread.h>
 #include "mlx4.h"
 #include "cmd.h"
 
@@ -271,9 +272,16 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
        struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
        struct mlx4_cmd_context *context;
        int err = 0;
+       u64 out_prm = out_param ? *out_param : 0;
 
        down(&cmd->event_sem);
 
+       if ( dev->flags & MLX4_FLAG_CARD_IS_DEAD ) {
+               err = -EBUSY;
+               mlx4_warn(dev, "mlx4_cmd_wait: Command %02x is skipped because the card is stuck \n", op);
+               goto exit;
+       }
+
        spin_lock(&cmd->context_lock);
        BUG_ON(cmd->free_head < 0);
        context = &cmd->context[cmd->free_head];
@@ -283,17 +291,30 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
 
        init_completion(&context->done);
 
-       mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
-                     in_modifier, op_modifier, op, context->token, 1);
+       mlx4_cmd_post(dev, in_param, out_prm,
+               in_modifier, op_modifier, op, context->token, 1);
 
        if (wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) {
                if (!context->done.done) {
-                       static int spam_limit = 5;
+
+                       /* report failure */
                        err = -EBUSY;
-                       if (spam_limit-- > 0)
-                               mlx4_err(dev, "mlx4_cmd_wait: Command %02x completed with timeout after %d secs \n",
-                                 op, timeout/1000);
-                       goto out;
+                       mlx4_err(dev, "mlx4_cmd_wait: Command %02x completed with timeout after %d msecs \n",
+                                 op, timeout);
+
+                       /* for debug purposes */
+                       ASSERT(FALSE);
+                       /* for enabling busy-wait loop, add MLX4_FLAG_BUSY_WAIT (0x8000) to dev->flags */
+                       while (dev) {
+                               u32 wait_ms =2000; /* wait interval in msecs */
+                               if (!(dev->flags & MLX4_FLAG_BUSY_WAIT))
+                                       break;
+                               cl_thread_suspend( wait_ms ); 
+                       }
+
+                       /* try to solve the problem */
+                       dev->flags |= MLX4_FLAG_RESET_DRIVER | MLX4_FLAG_CARD_IS_DEAD;
+                       mlx4_dispatch_reset_event(dev->pdev->ib_dev, IB_EVENT_RESET_DRIVER);
                }
        }
 
@@ -310,6 +331,7 @@ out:
        cmd->free_head = (int)(context - cmd->context);
        spin_unlock(&cmd->context_lock);
 
+exit:
        up(&cmd->event_sem);
        return err;
 }
@@ -542,3 +564,4 @@ int imlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm
                          op_modifier, op, timeout);
 }
 
+
index 2864f0e..2165894 100644 (file)
@@ -207,19 +207,11 @@ static void mlx4_dpc( PRKDPC dpc,
        spin_unlock_dpc(&eq->lock);
 }
 
-static BOOLEAN mlx4_interrupt(
-       IN struct _KINTERRUPT *Interrupt,
-       IN PVOID ServiceContext
-       )
+static BOOLEAN legacy_isr(struct mlx4_dev *dev)
 {
-       struct mlx4_dev *dev = ServiceContext;
-       struct mlx4_priv *priv = mlx4_priv(dev);
-       int work = 0;
        int i;
-
-       UNUSED_PARAM(Interrupt);
-       
-       writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
+       int work = 0;
+       struct mlx4_priv *priv = mlx4_priv(dev);
 
        for (i = 0; i < MLX4_NUM_EQ; ++i) {
                if ( next_eqe_sw(&priv->eq_table.eq[i]) ) {
@@ -255,6 +247,32 @@ static BOOLEAN mlx4_interrupt(
        return (BOOLEAN)work;
 }
 
+static BOOLEAN mlx4_interrupt(
+       IN struct _KINTERRUPT *Interrupt,
+       IN PVOID ServiceContext
+       )
+{
+       struct mlx4_dev *dev = ServiceContext;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       UNUSED_PARAM(Interrupt);
+       writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
+       return legacy_isr(dev);
+}
+
+static void mlx4_dpc_msix( PRKDPC dpc, 
+       PVOID ctx, PVOID arg1, PVOID arg2 )
+{
+       struct mlx4_eq *eq  = ctx;
+
+       UNREFERENCED_PARAMETER(dpc);
+       UNREFERENCED_PARAMETER(arg1);
+       UNREFERENCED_PARAMETER(arg2);
+
+       mlx4_eq_int(eq->dev, eq);
+}
+
+
 #if 1//WORKAROUND_POLL_EQ
 
 BOOLEAN
@@ -350,21 +368,43 @@ void mlx4_poll_eq(struct ib_device *device, BOOLEAN bStart)
 #endif
 
 
-#ifdef CONFIG_PCI_MSI
-
-/* not ported yet */
-static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
+BOOLEAN
+mlx4_msi_x_interrupt (
+       IN PKINTERRUPT  Interrupt,
+       IN PVOID  ServiceContext,
+       IN ULONG  MessageId 
+       )
 {
-       struct mlx4_eq  *eq  = eq_ptr;
-       struct mlx4_dev *dev = eq->dev;
+       int eq_ix;
+       struct mlx4_eq *eq;
+       struct mlx4_priv *priv;
+       struct mlx4_dev *dev = ServiceContext;
 
-       mlx4_eq_int(dev, eq);
+       UNUSED_PARAM(Interrupt);
+       
+       // Check, that it is our interrupt
+       if ( dev->signature != MLX4_DEV_SIGNATURE)
+               return FALSE;
 
-       /* MSI-X vectors always belong to us */
-       return IRQ_HANDLED;
-}
+       if (dev->flags & MLX4_FLAG_MSI_X) {
+               // MSI-X mode
+               priv = mlx4_priv(dev);
+               eq_ix = dev->pdev->p_msix_map[MessageId].eq_ix;
+               eq = &priv->eq_table.eq[eq_ix];
+               if (eq_ix >= MLX4_NUM_EQ) {
+                       if (eq->isr) 
+                               eq->isr(eq->ctx);
+                       else 
+                               eq_set_ci(eq, 1);
+               }
+               else
+                       KeInsertQueueDpc(&eq->dpc, NULL, NULL);
+               return TRUE;
+       }
 
-#endif
+       // legacy mode
+       return mlx4_interrupt(NULL,dev);
+}
 
 static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
                        int eq_num)
@@ -409,8 +449,50 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
        return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
 }
 
+/* for legacy interrupts the function returns 0 */
+/* for MSI-X - one vector per EQ */
+/* if cpu=0, it selects the first free vector */
+/* otherwise it returns free vector, allocated to this cpu */
+/* if cpu=0 and all vectors are taken it returns the first vector */
+/* if cpu!=0 and free vector for that cpu was not found - returns MLX4_NUM_UNKNOWN */
+int mlx4_alloc_msi_irqn(struct mlx4_dev *dev, KAFFINITY cpu, int eq_ix )
+{
+       int i;
+       struct pci_dev *pdev = dev->pdev;
+
+       if (!(dev->flags & MLX4_FLAG_MSI_X)) {
+               if (pdev->p_msix_map) {
+                       pdev->p_msix_map[0].ref_cnt++;
+                       pdev->p_msix_map[0].eq_ix = eq_ix;
+               }
+               return 0;
+       }
+               
+       for (i=0; i < pdev->n_msi_vectors_alloc; ++i) {
+               if (pdev->p_msix_map[i].ref_cnt)
+                       continue;
+               if (!cpu || (pdev->p_msix_map[i].cpu & cpu)) {
+                       pdev->p_msix_map[i].ref_cnt++;
+                       pdev->p_msix_map[i].eq_ix = eq_ix;
+                       return i;
+               }
+       }
+
+       /* all vectors are taken - return error  */
+    ASSERT(0);
+       return MLX4_NUM_UNKNOWN;
+}
+
+void mlx4_free_msi_irqn(struct mlx4_dev *dev, int intr)
+{
+       if (dev->pdev->p_msix_map) {
+               dev->pdev->p_msix_map[intr].ref_cnt--;
+               ASSERT(dev->pdev->p_msix_map[intr].ref_cnt>=0);
+       }
+}
+
 static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
-                         u8 intr, struct mlx4_eq *eq)
+               KAFFINITY cpu, int eq_ix, struct mlx4_eq *eq)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_cmd_mailbox *mailbox;
@@ -421,15 +503,24 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
        u64 mtt_addr;
        int err = -ENOMEM;
        int i;
+       int intr;
 
+       eq->valid = 0;
+       intr = mlx4_alloc_msi_irqn(dev, cpu, eq_ix);
+       if (intr == MLX4_NUM_UNKNOWN) {
+               err = -ENOENT;
+               goto err_out;
+       }
        eq->dev   = dev;
+       eq->irq = (u16)intr;
        eq->nent  = roundup_pow_of_two(max(nent, 2));
+       eq->cpu = cpu;
        npages = (int)(NEXT_PAGE_ALIGN(eq->nent * MLX4_EQ_ENTRY_SIZE) / PAGE_SIZE);
 
        eq->page_list = kmalloc(npages * sizeof *eq->page_list,
                                GFP_KERNEL);
        if (!eq->page_list)
-               goto err_out;
+               goto err_malloc;
 
        for (i = 0; i < npages; ++i)
                eq->page_list[i].buf = NULL;
@@ -477,7 +568,7 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
        eq_context->flags         = cpu_to_be32(MLX4_EQ_STATUS_OK   |
                                                MLX4_EQ_STATE_ARMED);
        eq_context->log_eq_size   = (u8)ilog2(eq->nent);
-       eq_context->intr          = intr;
+       eq_context->intr          = (u8)intr;
        eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT;
 
        mtt_addr = mlx4_mtt_addr(dev, &eq->mtt);
@@ -490,12 +581,16 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
                goto err_out_free_mtt;
        }
 
+       mlx4_dbg(dev, "EQ created: EQN %d, size %d(%d), MSI ID %d, CPU %#x\n", 
+               eq->eqn, nent, eq->nent, intr, cpu );
+
        kfree(dma_list);
        mlx4_free_cmd_mailbox(dev, mailbox);
 
        eq->cons_index = 0;
+       eq->valid = 1;
 
-       return err;
+       return 0;
 
 err_out_free_mtt:
        mlx4_mtt_cleanup(dev, &eq->mtt);
@@ -516,6 +611,9 @@ err_out_free:
        kfree(eq->page_list);
        kfree(dma_list);
 
+err_malloc:
+       mlx4_free_msi_irqn(dev, eq->irq);
+
 err_out:
        return err;
 }
@@ -529,6 +627,10 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
        int npages = (int)(NEXT_PAGE_ALIGN(MLX4_EQ_ENTRY_SIZE * eq->nent) / PAGE_SIZE);
        int i;
 
+       if (!eq->valid)
+               return;
+       eq->valid = 0;
+       
        mailbox = mlx4_alloc_cmd_mailbox(dev);
        if (IS_ERR(mailbox)) 
                mailbox = NULL;
@@ -560,6 +662,7 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
        kfree(eq->page_list);
        mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn);
        mlx4_free_cmd_mailbox(dev, mailbox);
+       mlx4_free_msi_irqn(dev, eq->irq);
 }
 
 static void mlx4_free_irqs(struct mlx4_dev *dev)
@@ -567,16 +670,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
        struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table;
 
        if (eq_table->have_irq)
-               free_irq(dev->pdev->int_obj);
-
-#ifdef CONFIG_PCI_MSI
-       {
-               int i;
-               for (i = 0; i < MLX4_NUM_EQ; ++i)
-                       if (eq_table->eq[i].have_irq)
-                               free_irq(eq_table->eq[i].irq, eq_table->eq + i);
-       }
-#endif         
+               free_irq(dev);
 }
 
 static int mlx4_map_clr_int(struct mlx4_dev *dev)
@@ -597,13 +691,14 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
 
-       iounmap(priv->clr_base, MLX4_CLR_INT_SIZE);
+       if (priv->clr_base) 
+               iounmap(priv->clr_base, MLX4_CLR_INT_SIZE);
 }
 
 int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int ret;
+       int ret = -ENOMEM;
 
        /*
         * We assume that mapping one page is enough for the whole EQ
@@ -614,22 +709,27 @@ int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
        priv->eq_table.icm_virt = icm_virt;
        priv->eq_table.icm_page = alloc_page(dev->pdev, GFP_HIGHUSER);
        if (!priv->eq_table.icm_page.da)
-               return -ENOMEM;
+               goto err_out;
+
        priv->eq_table.icm_dma  = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0,
-                                              PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       if (pci_dma_mapping_error(priv->eq_table.icm_dma)) {
-               __free_page(dev->pdev, priv->eq_table.icm_page);
-               return -ENOMEM;
-       }
+               PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(priv->eq_table.icm_dma)) 
+               goto err_dma_map;
 
        ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma.da, icm_virt);
-       if (ret) {
-               pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
-                              PCI_DMA_BIDIRECTIONAL);
-               __free_page(dev->pdev, priv->eq_table.icm_page);
-       }
+       if (ret) 
+               goto err_icm_map;
        mlx4_dbg(dev,"mlx4_MAP_ICM_page: dma %#I64x, icm_virt %#I64x\n", priv->eq_table.icm_dma.da, icm_virt);
 
+       return 0;
+
+err_icm_map:
+       pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       
+err_dma_map:
+       __free_page(dev->pdev, priv->eq_table.icm_page);
+       
+err_out:
        return ret;
 }
 
@@ -666,89 +766,61 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
        priv->eq_table.clr_int  = priv->clr_base +
                (priv->eq_table.inta_pin < 32 ? 4 : 0);
 
-       err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
-                            (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_COMP : 0,
-                            &priv->eq_table.eq[MLX4_EQ_COMP]);
+       /* EQ creation should be in this order because of MSI-X vector allocation way */
+       err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
+               0, MLX4_EQ_ASYNC, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
        if (err)
                goto err_out_unmap;
 
-       err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
-                            (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_ASYNC : 0,
-                            &priv->eq_table.eq[MLX4_EQ_ASYNC]);
+       err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
+               0, MLX4_EQ_COMP, &priv->eq_table.eq[MLX4_EQ_COMP]);
        if (err)
                goto err_out_comp;
 
-#ifdef CONFIG_PCI_MSI
-       if (dev->flags & MLX4_FLAG_MSI_X) {
-               static const char *eq_name[] = {
-                       [MLX4_EQ_COMP]  = DRV_NAME " (comp)",
-                       [MLX4_EQ_ASYNC] = DRV_NAME " (async)"
-               };
-
-#ifdef USE_WDM_INTERRUPTS
-
-                       for (i = 0; i < MLX4_NUM_EQ; ++i) {
-                               err = request_irq( dev, 
-                                       dev->pdev->int_info.u.Interrupt.Vector,
-                                       mlx4_interrupt, dev, 
-                                       mlx4_dpc, mlx4_msi_x_interrupt,
-                                       &dev->pdev->int_obj );
-                               if (err)
-                                       goto err_out_async;
-
-                               err = request_irq(priv->eq_table.eq[i].irq,
-                                                 mlx4_msi_x_interrupt,
-                                                 priv->eq_table.eq + i, eq_name[i], );
-                               if (err)
-                                       goto err_out_async;
-                       
-                               priv->eq_table.eq[i].have_irq = 1;
-                       }
-
-#else
-                       #error MSI support is not implemented for WDF model
-#endif         
+       /* init DPC stuff */
+       dev->pdev->dpc_lock = 0;
+       for (i = 0; i < MLX4_NUM_EQS; ++i) {
+               spin_lock_init( &priv->eq_table.eq[i].lock );   
+               KeInitializeDpc( &priv->eq_table.eq[i].dpc, 
+                       (dev->flags & MLX4_FLAG_MSI_X) ? mlx4_dpc_msix : mlx4_dpc, 
+                       &priv->eq_table.eq[i]);
+               priv->eq_table.eq[i].eq_ix = i;
+       }
 
-       } else 
-#endif
-       {
+       // connect interrupts
 #ifdef USE_WDM_INTERRUPTS
        err = request_irq( dev, 
-               dev->pdev->int_info.u.Interrupt.Vector,
                mlx4_interrupt, dev, 
-               mlx4_dpc, NULL,
+               mlx4_msi_x_interrupt,
                &dev->pdev->int_obj );
        if (err)
                goto err_out_async;
 #else
-               dev->pdev->dpc_lock = 0;
-               for (i = 0; i < MLX4_NUM_EQ; ++i) {
-                       struct mlx4_eq * eq = &priv->eq_table.eq[i];
-                       spin_lock_init( &eq->lock );    
-                       eq->isr = mlx4_interrupt;
-                       eq->ctx = dev;
-                       KeInitializeDpc( &eq->dpc, mlx4_dpc, eq);
-                       eq->eq_ix = i;
-               }
+       // not implemented - prevent compilation
+       #error Interrupts in WDF style are not implemented !
+       goto err_out_async;
 #endif         
-               priv->eq_table.have_irq = 1;
-       }
+       priv->eq_table.have_irq = 1;
 
        err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
                          priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
-       if (err)
+       if (err) {
                mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
                           priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
+               goto err_map_eq;
+       }
+
+       mlx4_dbg(dev, "Commands and async events are mapped to EQ %d\n",
+               priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
 
        for (i = 0; i < MLX4_NUM_EQ; ++i)
                eq_set_ci(&priv->eq_table.eq[i], 1);
 
-
 #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;
+               OBJECT_ATTRIBUTES   attr;
+               HANDLE  handle;
 
                KeInitializeEvent(&priv->eq_table.thread_start_event, SynchronizationEvent, FALSE);
                KeInitializeEvent(&priv->eq_table.thread_stop_event, SynchronizationEvent, FALSE);
@@ -779,39 +851,36 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
 
        return 0;
 
-#ifdef USE_WDM_INTERRUPTS
+err_map_eq:
+       mlx4_free_irqs(dev);
+
 err_out_async:
-       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
-#endif
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]);
 
 err_out_comp:
-       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]);
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
 
 err_out_unmap:
        mlx4_unmap_clr_int(dev);
-       mlx4_free_irqs(dev);
 
 err_out_free:
        mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
        return err;
 }
 
-
 int mlx4_add_eq(struct mlx4_dev *dev, int nent,
-                         u8 intr, PISR_FUNC func, PVOID func_context ,
-                         u8* p_eq_num, struct mlx4_eq ** p_eq)
+       KAFFINITY cpu, PISR_FUNC func, PVOID func_context ,
+       u8* p_eq_num, struct mlx4_eq ** p_eq)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        int err;
        u8 i, new_eq = 0;
 
-    UNREFERENCED_PARAMETER(intr);
-       
        if ( mlx4_is_barred(dev) )
                return -EFAULT;
        
-       for (i = MLX4_NUM_EQ; i < MLX4_NUM_EQ + MLX4_MAX_EXTRA_EQS ; i++) {
-               if(priv->eq_table.eq[MLX4_NUM_EQ].isr == NULL) {
+       for (i = MLX4_NUM_EQ; i < MLX4_NUM_EQS; i++) {
+               if(priv->eq_table.eq[i].isr == NULL) {
                        new_eq = i;
                        break;
                }
@@ -820,10 +889,10 @@ int mlx4_add_eq(struct mlx4_dev *dev, int nent,
                return -ENOMEM;
 
        err = mlx4_create_eq(dev, nent,
-                            (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_COMP : 0,
-                            &priv->eq_table.eq[new_eq]);
-       if (err)
+               cpu, new_eq, &priv->eq_table.eq[new_eq]);
+       if (err) {
                return err;
+       }
 
        *p_eq = &priv->eq_table.eq[new_eq ];
        *p_eq_num = new_eq;
@@ -836,7 +905,6 @@ int mlx4_add_eq(struct mlx4_dev *dev, int nent,
 void mlx4_remove_eq(struct mlx4_dev *dev, u8 eq_num)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int err;
        struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table;
 
        priv->eq_table.eq[eq_num].isr = NULL;
@@ -849,15 +917,27 @@ void mlx4_remove_eq(struct mlx4_dev *dev, u8 eq_num)
 
 
        if (eq_table->have_irq) {
-               free_irq(dev->pdev->int_obj);
-
+               int err;
+               
+               free_irq(dev);
 
+       #ifdef USE_WDM_INTERRUPTS
                err = request_irq( dev, 
-                       dev->pdev->int_info.u.Interrupt.Vector,
                        mlx4_interrupt, dev, 
-                       mlx4_dpc, NULL,
+                       mlx4_msi_x_interrupt,
                        &dev->pdev->int_obj );
-               // BUGBUG: how should the error be propogated ?
+               if (err) {
+                       mlx4_err(dev, "request_irq failed (%d)\n",
+                               err);
+                       ASSERT(0);
+               }
+               else
+                       priv->eq_table.have_irq = 1;
+       #else
+               // not implemented - prevent compilation
+               #error Interrupts in WDF style are not implemented !
+       #endif          
+
        }
 }
 
@@ -869,7 +949,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
 #if 1//WORKAROUND_POLL_EQ
        /* stop the EQ polling thread */
        if (priv->eq_table.threadObject) { 
-               #define WAIT_TIME_MS    3000
+       #define WAIT_TIME_MS    3000
                NTSTATUS status;
                LARGE_INTEGER  wait_time;
                LONG signalled;
@@ -877,7 +957,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
                priv->eq_table.bTerminated = TRUE;
 
                /* signal polling stopped in case it is not */
-               signalled = KeSetEvent(         
+               signalled = KeSetEvent(
                        &priv->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE );
 
                /* wait for completion of the thread */
@@ -892,15 +972,13 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
                priv->eq_table.threadObject = NULL;
        }
 #endif
-
+    
        mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
                    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
 
        mlx4_free_irqs(dev);
-
-       for (i = 0; i < MLX4_NUM_EQ; ++i)
-               mlx4_free_eq(dev, &priv->eq_table.eq[i]);
-
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]);
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
        mlx4_unmap_clr_int(dev);
 
        for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i)
index a87fa1c..d0ba893 100644 (file)
@@ -426,13 +426,16 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
        return 0;
 
 err:
-       for (i = 0; i < num_icm; ++i)
+       for (i = 0; i < num_icm; ++i) {
                if (table->icm[i]) {
                        mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE,
                                       MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
                        mlx4_free_icm(dev, table->icm[i], use_coherent);
                }
-
+       }
+    
+    kfree(table->icm);
+    table->icm = NULL;
        return -ENOMEM;
 }
 
@@ -440,12 +443,18 @@ void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table)
 {
        int i;
 
+    if (table->icm == NULL) {
+        return;
+    }
+    
        for (i = 0; i < table->num_icm; ++i)
                if (table->icm[i]) {
                        mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
                                       MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
                        mlx4_free_icm(dev, table->icm[i], table->coherent);
+            table->icm[i] = NULL;
                }
 
        kfree(table->icm);
+    table->icm = NULL;
 }
index 8ea460e..7742af7 100644 (file)
@@ -612,6 +612,7 @@ static void mlx4_free_icms(struct mlx4_dev *dev)
 
        mlx4_UNMAP_ICM_AUX(dev);
        mlx4_free_icm(dev, priv->fw.aux_icm, 0);
+    priv->fw.aux_icm = NULL;
 }
 
 static void mlx4_close_hca(struct mlx4_dev *dev)
@@ -683,7 +684,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
        return 0;
 
 err_close:
-       mlx4_close_hca(dev);
+       mlx4_CLOSE_HCA(dev,0);
 
 err_free_icm:
        mlx4_free_icms(dev);
@@ -756,7 +757,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
        if (err) {
                if (dev->flags & MLX4_FLAG_MSI_X) {
                        mlx4_warn(dev, "NOP command failed to generate MSI-X "
-                                 "interrupt IRQ %d).\n",
+                                 "interrupt IRQ %d.\n",
                                  priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
                        mlx4_warn(dev, "Trying again without MSI-X.\n");
                } else {
@@ -850,38 +851,25 @@ err_uar_table_free:
 
 static void __devinit mlx4_enable_msi_x(struct mlx4_dev *dev)
 {
-#ifdef CONFIG_PCI_MSI
-       struct mlx4_priv *priv = mlx4_priv(dev);
-       struct msix_entry entries[MLX4_NUM_EQ];
-       int err;
-       int i;
-
-       if (g.mod_msi_num_vector) {
-               for (i = 0; i < MLX4_NUM_EQ; ++i)
-                       entries[i].entry = i;
-
-               err = pci_enable_msix(dev->pdev, entries, ARRAY_SIZE(entries));
-               if (err) {
-                       if (err > 0)
-                               mlx4_info(dev, "Only %d MSI-X vectors available, "
-                                         "not using MSI-X\n", err);
-                       goto no_msi;
-               }
-
-               for (i = 0; i < MLX4_NUM_EQ; ++i)
-                       priv->eq_table.eq[i].irq = entries[i].vector;
+       int i, n_cpus;
+       u64 cpus;
+
+       /* calculate the number of processors */
+       cpus = (u64)KeQueryActiveProcessors();
+       for (i=0,n_cpus=0; i<(sizeof(KAFFINITY)<<3); i++) {
+               if ((1I64<<i) & cpus)
+                       n_cpus++;
+       }
 
+       /* decide on the mode */
+       if (dev->pdev->n_msi_vectors_alloc >= (n_cpus+2))
                dev->flags |= MLX4_FLAG_MSI_X;
-               return;
-       }
 
-no_msi:
-       for (i = 0; i < MLX4_NUM_EQ; ++i)
-               priv->eq_table.eq[i].irq = dev->pdev->irq;
+       MLX4_PRINT(TRACE_LEVEL_WARNING ,MLX4_DBG_LOW ,
+               ("Interrupt mode '%s', n_vectors %d, n_cpus %d, Affinity %#I64x\n",
+               (dev->flags & MLX4_FLAG_MSI_X) ? "MSI-X" : "Legacy", 
+               dev->pdev->n_msi_vectors_alloc, n_cpus, cpus));
 
-#else
-       UNUSED_PARAM(dev);
-#endif
 }
 
 
@@ -926,13 +914,13 @@ int mlx4_init_one(struct pci_dev *pdev)
         * be present)
         */
        if (pci_resource_len(pdev, 0) != 1 << 20) {
-               MLX4_PRINT(TRACE_LEVEL_INFORMATION ,MLX4_DBG_LOW ,
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW ,
                        ("Missing DCS, aborting.\n"));
                err = -ENODEV;
                goto err;
        }
        if (!pci_resource_len(pdev, 1)) {
-               MLX4_PRINT(TRACE_LEVEL_INFORMATION ,MLX4_DBG_LOW ,
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW ,
                        ("Missing UAR, aborting.\n"));
                err = -ENODEV;
                goto err;
@@ -956,6 +944,7 @@ run_as_livefish:
 
        /* deal with livefish, if any */
        dev       = &priv->dev;
+       dev->signature = MLX4_DEV_SIGNATURE;
        dev->pdev = pdev;
        pdev->dev = dev;
        if (id->driver_data == LIVEFISH)
@@ -964,10 +953,12 @@ run_as_livefish:
                err = mlx4_register_device(dev);
                if (err) {
                        MLX4_PRINT(TRACE_LEVEL_INFORMATION ,MLX4_DBG_LOW ,
-                               ("mlx4_register_device for livefish failed, trying to proceed.\n"));
+                               ("mlx4_register_device for livefish failed, return with error.\n"));
                        pdev->dev = NULL;
                        kfree(priv);
                }
+               MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW ,
+                       ("MLX4_BUS started in \"livefish\" mode !!!.\n"));
                goto end;
        }
 
@@ -996,10 +987,7 @@ run_as_livefish:
 
        err = mlx4_setup_hca(dev);
        if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) {
-#ifdef CONFIG_PCI_MSI
                dev->flags &= ~MLX4_FLAG_MSI_X;
-               pci_disable_msix(pdev);
-#endif         
                err = mlx4_setup_hca(dev);
        }
 
@@ -1025,11 +1013,6 @@ err_cleanup:
        mlx4_cleanup_uar_table(dev);
 
 err_close:
-#ifdef CONFIG_PCI_MSI
-       if (dev->flags & MLX4_FLAG_MSI_X)
-               pci_disable_msix(pdev);
-#endif
-
        mlx4_close_hca(dev);
 
 err_cmd:
@@ -1052,7 +1035,7 @@ end:
        return err;
 }
 
-void mlx4_remove_one(struct pci_dev *pdev)
+void mlx4_remove_one(struct pci_dev *pdev, int reset)
 {
        struct mlx4_dev  *dev  = pdev->dev;
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -1081,12 +1064,8 @@ void mlx4_remove_one(struct pci_dev *pdev)
                mlx4_close_hca(dev);
                mlx4_cmd_cleanup(dev);
 
-#ifdef CONFIG_PCI_MSI
-               if (dev->flags & MLX4_FLAG_MSI_X)
-                       pci_disable_msix(pdev);
-#endif
-
-               mlx4_reset(dev);
+               if (reset)
+                       mlx4_reset(dev);
                mlx4_dbg(dev, "MLX4_BUS: NET device (dev_id=%d) is REMOVED ! \n", (int)pdev->dev_id);
                pdev->dev = NULL;
 done:
@@ -1096,7 +1075,7 @@ done:
 
 int mlx4_restart_one(struct pci_dev *pdev)
 {
-       mlx4_remove_one(pdev);
+       mlx4_remove_one(pdev, FALSE);
        return mlx4_init_one(pdev);
 }
 
@@ -1106,3 +1085,4 @@ void mlx4_net_init()
 }
 
 
+
index bc3d055..b0c1ec3 100644 (file)
@@ -86,8 +86,8 @@ typedef struct _GLOBALS {
        enum mlx4_port_type mod_port_type[MLX4_MAX_PORTS];
        int mod_interrupt_from_first;
 
-       int mod_msi_enable;
-       int mod_msi_num_vector;
+       int mod_affinity;
+       PFDO_DEVICE_DATA p_fdo; // for debug purposes
 } GLOBALS;
 #pragma warning(default:4201) // nameless struct/union
 
@@ -111,8 +111,10 @@ enum {
        MLX4_EQ_COMP,
        MLX4_NUM_EQ
 };
+#define MLX4_NUM_UNKNOWN       -1
 
-#define MLX4_MAX_EXTRA_EQS 5
+#define MLX4_MAX_EXTRA_EQS 16
+#define MLX4_NUM_EQS (MLX4_NUM_EQ + MLX4_MAX_EXTRA_EQS)
 
 enum {
        MLX4_NUM_PDS            = 1 << 15
@@ -223,9 +225,9 @@ struct mlx4_cq_table {
 struct mlx4_eq_table {
        struct mlx4_bitmap      bitmap;
        void __iomem           *clr_int;
-       u8 __iomem             *uar_map[(MLX4_NUM_EQ + 6) / 4];
+       u8 __iomem             *uar_map[(MLX4_NUM_EQS + 6) / 4];
        u32                     clr_mask;
-       struct mlx4_eq          eq[MLX4_NUM_EQ + MLX4_MAX_EXTRA_EQS];
+       struct mlx4_eq          eq[MLX4_NUM_EQS];
        u64                     icm_virt;
        dma_addr_t      icm_page;
        dma_addr_t              icm_dma;
@@ -421,14 +423,14 @@ void mlx4_handle_catas_err(struct mlx4_dev *dev);
 
 int mlx4_init_one(struct pci_dev *pdev);
 
-void mlx4_remove_one(struct pci_dev *pdev);
+void mlx4_remove_one(struct pci_dev *pdev, int reset);
 
 #define ETH_FCS_LEN    4               /* Frame Check Sequence Length   */
 #define ETH_HLEN 14
 
 int mlx4_add_eq(struct mlx4_dev *dev, int nent,
-                         u8 intr, PISR_FUNC func,PVOID func_context ,
-                         u8* p_eq_num, struct mlx4_eq ** p_eq);
+       KAFFINITY cpu, PISR_FUNC func, PVOID func_context ,
+       u8* p_eq_num, struct mlx4_eq ** p_eq);
 
 void mlx4_remove_eq(struct mlx4_dev *dev, u8 eq_num);
 
@@ -442,6 +444,7 @@ int mlx4_reset_cb_unregister( struct ib_event_handler *event_handler );
 
 void fix_bus_ifc(struct pci_dev *pdev);
 
+void mlx4_dispatch_reset_event(struct ib_device *ibdev, enum ib_event_type type);
 
 
 #endif /* MLX4_H */
index 4f14c0f..a456da7 100644 (file)
@@ -105,7 +105,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
        profile[MLX4_RES_AUXC].num    = request->num_qp;
        profile[MLX4_RES_SRQ].num     = request->num_srq;
        profile[MLX4_RES_CQ].num      = request->num_cq;
-       profile[MLX4_RES_EQ].num      = MLX4_NUM_EQ + dev_cap->reserved_eqs;
+       profile[MLX4_RES_EQ].num      = MLX4_NUM_EQS + dev_cap->reserved_eqs;
        profile[MLX4_RES_DMPT].num    = request->num_mpt;
        profile[MLX4_RES_CMPT].num    = MLX4_NUM_CMPTS;
        profile[MLX4_RES_MTT].num     = request->num_mtt;
index a46a3bf..e69de29 100644 (file)
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2006, 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 <linux/init.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-
-#include "mlx4.h"
-
-int mlx4_reset(struct mlx4_dev *dev)
-{
-       void __iomem *reset;
-       u32 *hca_header = NULL;
-       int pcie_cap;
-       u16 devctl;
-       u16 linkctl;
-       u16 vendor;
-       unsigned long end;
-       u32 sem;
-       int i;
-       int err = 0;
-
-#define MLX4_RESET_BASE                0xf0000
-#define MLX4_RESET_SIZE                  0x400
-#define MLX4_SEM_OFFSET                  0x3fc
-#define MLX4_RESET_OFFSET         0x10
-#define MLX4_RESET_VALUE       swab32(1)
-
-#define MLX4_SEM_TIMEOUT_JIFFIES       (10 * HZ)
-#define MLX4_RESET_TIMEOUT_JIFFIES     (2 * HZ)
-
-       /*
-        * Reset the chip.  This is somewhat ugly because we have to
-        * save off the PCI header before reset and then restore it
-        * after the chip reboots.  We skip config space offsets 22
-        * and 23 since those have a special meaning.
-        */
-
-       /* Do we need to save off the full 4K PCI Express header?? */
-       hca_header = kmalloc(256, GFP_KERNEL);
-       if (!hca_header) {
-               err = -ENOMEM;
-               mlx4_err(dev, "Couldn't allocate memory to save HCA "
-                         "PCI header, aborting.\n");
-               goto out;
-       }
-
-       pcie_cap = pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
-
-       for (i = 0; i < 64; ++i) {
-               if (i == 22 || i == 23)
-                       continue;
-               if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) {
-                       err = -ENODEV;
-                       mlx4_err(dev, "Couldn't save HCA "
-                                 "PCI header, aborting.\n");
-                       goto out;
-               }
-       }
-
-       reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE,
-                       MLX4_RESET_SIZE);
-       if (!reset) {
-               err = -ENOMEM;
-               mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n");
-               goto out;
-       }
-
-       /* grab HW semaphore to lock out flash updates */
-       end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;
-       do {
-               sem = readl(reset + MLX4_SEM_OFFSET);
-               if (!sem)
-                       break;
-
-               msleep(1);
-       } while (time_before(jiffies, end));
-
-       if (sem) {
-               mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n");
-               err = -EAGAIN;
-               iounmap(reset, MLX4_RESET_SIZE);
-               goto out;
-       }
-
-       /* actually hit reset */
-       writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);
-       iounmap(reset, MLX4_RESET_SIZE);
-
-       /* Docs say to wait one second before accessing device */
-       msleep(1000);
-
-       end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;
-       do {
-               if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) &&
-                   vendor != 0xffff)
-                       break;
-
-               msleep(1);
-       } while (time_before(jiffies, end));
-
-       if (vendor == 0xffff) {
-               err = -ENODEV;
-               mlx4_err(dev, "PCI device did not come back after reset, "
-                         "aborting.\n");
-               goto out;
-       }
-
-       /* Now restore the PCI headers */
-       if (pcie_cap) {
-               devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];
-               if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_DEVCTL,
-                                          devctl)) {
-                       err = -ENODEV;
-                       mlx4_err(dev, "Couldn't restore HCA PCI Express "
-                                "Device Control register, aborting.\n");
-                       goto out;
-               }
-               linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];
-               if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_LNKCTL,
-                                          linkctl)) {
-                       err = -ENODEV;
-                       mlx4_err(dev, "Couldn't restore HCA PCI Express "
-                                "Link control register, aborting.\n");
-                       goto out;
-               }
-       }
-
-       for (i = 0; i < 16; ++i) {
-               if (i * 4 == PCI_COMMAND)
-                       continue;
-
-               if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) {
-                       err = -ENODEV;
-                       mlx4_err(dev, "Couldn't restore HCA reg %x, "
-                                 "aborting.\n", i);
-                       goto out;
-               }
-       }
-
-       if (pci_write_config_dword(dev->pdev, PCI_COMMAND,
-                                  hca_header[PCI_COMMAND / 4])) {
-               err = -ENODEV;
-               mlx4_err(dev, "Couldn't restore HCA COMMAND, "
-                         "aborting.\n");
-               goto out;
-       }
-
-out:
-       kfree(hca_header);
-
-       return err;
-}
index bb12de9..fee2eca 100644 (file)
@@ -11,7 +11,7 @@
 
 // OS
 #include <ntddk.h>
-#include <iointex.h>
+//#include <iointex.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -138,6 +138,22 @@ typedef struct _hca_bar
 
 }      hca_bar_t;
 
+struct msix_saved_info {
+       PVOID   vca;            /* MSI-X Vector Table card address */
+       PVOID   mca;            /* MSI-X Mask Table card address */
+       PVOID   vsa;            /* MSI-X Vector Table saved address */
+       PVOID   msa;            /* MSI-X Mask Table saved address */
+       ULONG   vsz;            /* MSI-X Vector Table size */
+       ULONG   msz;            /* MSI-X Mask Table size */
+       int             num;            /* number of supported MSI-X vectors */
+       int             valid;          /* the structure is valid */
+};
+
+struct msix_map {
+       KAFFINITY       cpu;            /* affinity of this MSI-X vector */
+       int                     eq_ix;          /* EQ index in the array of EQs */
+       int                     ref_cnt;        /* number of users */
+};
 
 // interface structure between Upper and Low Layers of the driver
 struct pci_dev
@@ -145,6 +161,8 @@ struct pci_dev
        // driver: OS/platform resources
        BUS_INTERFACE_STANDARD                  bus_pci_ifc;
        PCI_COMMON_CONFIG                               pci_cfg_space;
+       struct msix_saved_info                  msix_info;
+       struct msix_map*                                p_msix_map;
        uplink_info_t                                   uplink_info;
        // driver: card resources
        hca_bar_t                                               bar[N_BARS];
@@ -153,7 +171,8 @@ struct pci_dev
        USHORT                                                  ven_id;
        USHORT                                                  dev_id;
        DMA_ADAPTER             *                               p_dma_adapter;  /* HCA adapter object */
-       DEVICE_OBJECT   *                               p_self_do;              /* mlx4 FDO */
+       DEVICE_OBJECT   *                               p_self_do;              /* mlx4_bus's FDO */
+       DEVICE_OBJECT   *                               pdo;                    /* mlx4_bus's PDO */
        // mlx4_ib: various objects and info    
        struct ib_device *                              ib_dev;
        // mlx4_net: various objects and info   
@@ -162,7 +181,11 @@ struct pci_dev
 #ifdef USE_WDM_INTERRUPTS
        PKINTERRUPT                                             int_obj;                /* HCA interrupt object */
        KSPIN_LOCK                                              isr_lock;               /* lock for the ISR */
-       int                                                             msi_used;               /* connected to MSI interrupts */
+       // MSI-X interrupts
+       u8                                                              n_msi_vectors_alloc;/* number of allocated MSI vectors */
+       u8                                                              n_msi_vectors;          /* number of MSI vectors; 0 - no MSI */
+       ULONG                                                   version;
+       int                                                     legacy_connect;
 #endif 
 };
 
index 1a32c29..1c1c841 100644 (file)
@@ -136,18 +136,13 @@ static inline void complete( struct completion * compl )
 // IRQ wrapper
 //
 
-static inline void free_irq(PKINTERRUPT int_obj)
-{
-       IoDisconnectInterrupt( int_obj );
-}
+void free_irq(struct mlx4_dev *dev);
 
 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                           misr,           /* Message ISR */
+       IN              PKMESSAGE_SERVICE_ROUTINE       misr,           /* Message ISR */
        OUT             PKINTERRUPT             *       int_obj         /* interrupt object */
        );
 
@@ -166,3 +161,4 @@ static inline void synchronize_irq(unsigned int irq)
 }
 
 
+
index fdfe9a2..bc90e92 100644 (file)
@@ -51,7 +51,18 @@ struct _map_crspace {
 #define FW_OPEN_IF             0xe7
 #define FW_CLOSE_IF            0x7e
 
-#if 1//WORKAROUND_POLL_EQ
+/* MSI-X info */
+struct msix_info {
+       int     valid;
+       int     enabled;
+       int     masked;
+       int requested;
+       int granted;
+       unsigned granted_mask;
+       unsigned pending_mask;
+} ;
+
+#if 1 //WORKAROUND_POLL_EQ
 #define FW_POLL_EQ_START               0x0D
 #define FW_POLL_EQ_STOP                0x0E
 #endif
@@ -76,6 +87,7 @@ typedef struct {
                        uint8_t link_width;             /* x1, x2, x4, x8, x12, x16, x32 */
                } pci_e;
        } u;
+       struct msix_info x;
 } uplink_info_t;
 
 
index 83729a3..08041f8 100644 (file)
@@ -24,6 +24,7 @@ Notes:
 \r
 \r
 #define MTNIC_MAX_PORTS     2\r
+#define MAX_MSIX_VECTORES   18\r
 \r
 #define MXE_INTERFACE_VERSION  2\r
 \r
@@ -36,6 +37,13 @@ enum mtnic_state {
 \r
 struct _MP_PORT;\r
 \r
+struct mlx4_en_eq_info {\r
+    struct VipBusIfc * pVipBusIfc;\r
+    struct mlx4_eq* eq;\r
+    u8 eq_number;\r
+    BOOLEAN fUseMsix;\r
+};\r
+\r
 typedef struct {\r
     enum mtnic_state     state;\r
     KEVENT          ConfigChangeEvent; \r
@@ -48,8 +56,8 @@ typedef struct {
     struct mlx4_mr          mr;\r
     spinlock_t              uar_lock;\r
 \r
-    struct mlx4_eq *        eq;\r
-    u8                      eq_number;\r
+    BOOLEAN                 use_msix;\r
+    struct mlx4_en_eq_info  eq_info[MAX_MSIX_VECTORES];\r
 } NicData_t;\r
 \r
 struct VipBusIfc\r
index f1235fc..ee6e4fe 100644 (file)
@@ -28,6 +28,7 @@
 #define MTHCA_VERBS_MAX_VERSION                2\r
 \r
 extern const char *mthca_version;\r
+hca_dev_ext_t *g_ext = NULL;\r
 \r
 static NTSTATUS\r
 hca_start(\r
@@ -233,6 +234,8 @@ hca_add_device(
        }\r
 \r
        p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r
+       if (!g_ext)\r
+               g_ext = p_ext;\r
        cl_memclr( p_ext, sizeof(hca_dev_ext_t) );\r
        cl_spinlock_init( &p_ext->uctx_lock );\r
        cl_qlist_init( &p_ext->uctx_list );\r
index 0636d72..d5c514d 100644 (file)
@@ -53,6 +53,16 @@ struct _map_crspace {
 #define FW_OPEN_IF             0xe7
 #define FW_CLOSE_IF            0x7e
 
+struct msix_info {
+       int     valid;
+       int     enabled;
+       int     masked;
+       int requested;
+       int granted;
+       unsigned granted_mask;
+       unsigned pending_mask;
+} ;
+
 /* uplink info */
 typedef struct {
        uint8_t bus_type;       /* 1 - PCI, 2 - PCI-X, 3 - PCI_E */
@@ -73,6 +83,7 @@ typedef struct {
                        uint8_t link_width;             /* x1, x2, x4, x8, x12, x16, x32 */
                } pci_e;
        } u;
+       struct msix_info x;
 } uplink_info_t;
 
 /* Defines for get data for vendor specific */
index 81b7807..c351b39 100644 (file)
@@ -302,7 +302,7 @@ void print_uplink_info(ib_ca_attr_t* ca_attr)
                        else\r
                                freq = 66;\r
                        printf("\tuplink={BUS=%s, CAPS=%d MHz}\n", bus_type, freq ); \r
-                       return;\r
+                       break;\r
 \r
                case UPLINK_BUS_PCIE:\r
                        cap = p_uplink_info->u.pci_e.capabilities;\r
@@ -316,8 +316,14 @@ void print_uplink_info(ib_ca_attr_t* ca_attr)
                        printf("\tuplink={BUS=%s, SPEED=%s, WIDTH=x%d, CAPS=%s*x%d}\n",\r
                                bus_type, link_speed, p_uplink_info->u.pci_e.link_width,\r
                                (cap&1) ? "2.5" : "5", cap>>2 ); \r
-                       return;\r
+                       break;\r
        }\r
+\r
+       /* MSI-X */\r
+       if (p_uplink_info->x.valid)\r
+               printf("\tMSI-X={ENABLED=%d, SUPPORTED=%d, GRANTED=%d, ALL_MASKED=%s}\n",\r
+                       p_uplink_info->x.enabled, p_uplink_info->x.requested,\r
+                       p_uplink_info->x.granted, p_uplink_info->x.masked ? "Y" : "N"); \r
 }\r
 \r
 void vstat_print_ca_attr(int idx,  ib_ca_attr_t* ca_attr, ib_port_info_t* vstat_port_info, BOOLEAN fullPrint){\r
@@ -707,3 +713,4 @@ main(
 }\r
 \r
 \r
+\r