#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( ¶ms, 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(¶ms);
- RtlZeroMemory( ¶ms, 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(¶ms);
-
- 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(¶ms);
- }
- 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(¶ms);
+ 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
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
{\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
)\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
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
\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
//\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
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
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
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
// "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
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
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
\r
\r
\r
+\r
#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
// 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
);\r
\r
\r
+\r
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
; 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
#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
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
{\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
}\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
/* 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
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
}\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
}\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
}\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
MLX4_EXIT( MLX4_DBG_PNP );\r
}\r
\r
+\r
NTSTATUS\r
pci_hca_enable(\r
IN PBUS_INTERFACE_STANDARD p_ifc,\r
return status;\r
}\r
\r
+\r
#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;
#pragma once
-#define MLX4_BUS_IB_INTERFACE_VERSION 2
+#define MLX4_BUS_IB_INTERFACE_VERSION 3
#include <ib_verbs.h>
//
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);
int is_livefish;
u8 port_id;
struct VipBusIfc *pVipBusIfc;
+ int n_msi_vectors;
} MLX4_BUS_IB_INTERFACE, *PMLX4_BUS_IB_INTERFACE;
+
};
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 {
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 {
u8 dgid[16];
};
+#define MLX4_DEV_SIGNATURE 0xf1b34a6e
+
struct mlx4_dev {
+ u32 signature;
struct pci_dev *pdev;
unsigned long flags;
struct mlx4_caps caps;
#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
// "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;
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)));
}
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 );
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
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;
* SOFTWARE.
*/
+#include <complib/cl_thread.h>
#include "mlx4.h"
#include "cmd.h"
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];
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);
}
}
cmd->free_head = (int)(context - cmd->context);
spin_unlock(&cmd->context_lock);
+exit:
up(&cmd->event_sem);
return err;
}
op_modifier, op, timeout);
}
+
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]) ) {
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
#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)
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;
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;
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);
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);
kfree(eq->page_list);
kfree(dma_list);
+err_malloc:
+ mlx4_free_msi_irqn(dev, eq->irq);
+
err_out:
return err;
}
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;
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)
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)
{
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
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;
}
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);
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;
}
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;
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;
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
+
}
}
#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;
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 */
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)
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;
}
{
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;
}
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)
return 0;
err_close:
- mlx4_close_hca(dev);
+ mlx4_CLOSE_HCA(dev,0);
err_free_icm:
mlx4_free_icms(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 {
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
}
* 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;
/* deal with livefish, if any */
dev = &priv->dev;
+ dev->signature = MLX4_DEV_SIGNATURE;
dev->pdev = pdev;
pdev->dev = dev;
if (id->driver_data == 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;
}
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);
}
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:
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);
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:
int mlx4_restart_one(struct pci_dev *pdev)
{
- mlx4_remove_one(pdev);
+ mlx4_remove_one(pdev, FALSE);
return mlx4_init_one(pdev);
}
}
+
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
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
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;
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);
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 */
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;
-/*
- * 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;
-}
// OS
#include <ntddk.h>
-#include <iointex.h>
+//#include <iointex.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
} 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
// 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];
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
#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
};
// 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 */
);
}
+
#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
uint8_t link_width; /* x1, x2, x4, x8, x12, x16, x32 */
} pci_e;
} u;
+ struct msix_info x;
} uplink_info_t;
\r
\r
#define MTNIC_MAX_PORTS 2\r
+#define MAX_MSIX_VECTORES 18\r
\r
#define MXE_INTERFACE_VERSION 2\r
\r
\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
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
#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
}\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
#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 */
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 */
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
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
}\r
\r
\r
+\r