3 Copyright (c) 2003 Microsoft Corporation All Rights Reserved
\r
11 This module contains routines to handle the function driver
\r
12 aspect of the bus driver. This sample is functionally
\r
13 equivalent to the WDM mxe bus driver.
\r
21 #include "precomp.h"
\r
22 #include <initguid.h>
\r
23 #include <wdmguid.h>
\r
25 #if defined (EVENT_TRACING)
\r
33 #define DRV_VERSION "1.0"
\r
34 #define DRV_RELDATE "02/01/2008"
\r
37 uint32_t g_mlx4_dbg_flags = 0xffff;
\r
38 uint32_t g_mlx4_dbg_level = TRACE_LEVEL_INFORMATION;
\r
39 WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ];
\r
40 UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ];
\r
42 #ifndef USE_WDM_INTERRUPTS
\r
46 PFDO_DEVICE_DATA p_fdo;
\r
47 struct mlx4_eq * eq;
\r
48 } INTERRUPT_DATA, *PINTERRUPT_DATA;
\r
50 WDF_DECLARE_CONTEXT_TYPE(INTERRUPT_DATA);
\r
53 EvtEnableInterrupt(
\r
54 IN WDFINTERRUPT Interrupt,
\r
55 IN WDFDEVICE AssociatedDevice
\r
58 UNUSED_PARAM(Interrupt);
\r
59 UNUSED_PARAM(AssociatedDevice);
\r
60 MLX4_ENTER(MLX4_DBG_DRV);
\r
61 MLX4_EXIT( MLX4_DBG_DRV );
\r
62 return STATUS_SUCCESS;
\r
66 EvtDisableInterrupt (
\r
67 IN WDFINTERRUPT Interrupt,
\r
68 IN WDFDEVICE AssociatedDevice
\r
71 UNUSED_PARAM(Interrupt);
\r
72 UNUSED_PARAM(AssociatedDevice);
\r
73 MLX4_ENTER(MLX4_DBG_DRV);
\r
74 MLX4_EXIT( MLX4_DBG_DRV );
\r
75 return STATUS_SUCCESS;
\r
80 IN WDFINTERRUPT Interrupt,
\r
84 BOOLEAN isr_handled = FALSE;
\r
85 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( Interrupt, INTERRUPT_DATA );
\r
87 UNUSED_PARAM(MessageID);
\r
89 // MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("Fdo %p\n", p_isr_ctx->p_fdo));
\r
90 if (p_isr_ctx->eq && p_isr_ctx->eq->isr)
\r
91 isr_handled = p_isr_ctx->eq->isr( p_isr_ctx->eq->eq_ix, p_isr_ctx->eq->ctx );
\r
101 __in WDFDEVICE Device,
\r
102 __in PWCHAR HardwareIds,
\r
103 __in PWCHAR DeviceDescription,
\r
104 __in ULONG SerialNo
\r
109 Routine Description:
\r
111 The user application has told us that a new device on the bus has arrived.
\r
113 We therefore need to create a new PDO, initialize it, add it to the list
\r
114 of PDOs for this FDO bus, and then tell Plug and Play that all of this
\r
115 happened so that it will start sending prodding IRPs.
\r
120 NTSTATUS status = STATUS_SUCCESS;
\r
121 BOOLEAN unique = TRUE;
\r
123 PPDO_DEVICE_DATA p_pdo;
\r
124 PFDO_DEVICE_DATA p_fdo;
\r
127 MLX4_ENTER(MLX4_DBG_DRV);
\r
130 // First make sure that we don't already have another device with the
\r
131 // same serial number.
\r
132 // Framework creates a collection of all the child devices we have
\r
133 // created so far. So acquire the handle to the collection and lock
\r
134 // it before walking the item.
\r
136 p_fdo = FdoGetData(Device);
\r
140 // We need an additional lock to synchronize addition because
\r
141 // WdfFdoLockStaticChildListForIteration locks against anyone immediately
\r
142 // updating the static child list (the changes are put on a queue until the
\r
143 // list has been unlocked). This type of lock does not enforce our concept
\r
144 // of unique IDs on the bus (ie SerialNo).
\r
146 // Without our additional lock, 2 threads could execute this function, both
\r
147 // find that the requested SerialNo is not in the list and attempt to add
\r
148 // it. If that were to occur, 2 PDOs would have the same unique SerialNo,
\r
149 // which is incorrect.
\r
151 // We must use a passive level lock because you can only call WdfDeviceCreate
\r
152 // at PASSIVE_LEVEL.
\r
154 WdfWaitLockAcquire(p_fdo->ChildLock, NULL);
\r
155 WdfFdoLockStaticChildListForIteration(Device);
\r
157 while ((hChild = WdfFdoRetrieveNextStaticChild(Device,
\r
158 hChild, WdfRetrieveAddedChildren)) != NULL) {
\r
160 // WdfFdoRetrieveNextStaticChild returns reported and to be reported
\r
161 // children (ie children who have been added but not yet reported to PNP).
\r
163 // A surprise removed child will not be returned in this list.
\r
165 p_pdo = PdoGetData(hChild);
\r
166 p_pdo->PdoDevice = hChild;
\r
167 p_pdo->p_fdo = p_fdo;
\r
170 // It's okay to plug in another device with the same serial number
\r
171 // as long as the previous one is in a surprise-removed state. The
\r
172 // previous one would be in that state after the device has been
\r
173 // physically removed, if somebody has an handle open to it.
\r
175 if (SerialNo == p_pdo->SerialNo) {
\r
177 status = STATUS_INVALID_PARAMETER;
\r
184 // Create a new child device. It is OK to create and add a child while
\r
185 // the list locked for enumeration. The enumeration lock applies only
\r
186 // to enumeration, not addition or removal.
\r
188 status = create_pdo(Device, HardwareIds, DeviceDescription, SerialNo);
\r
191 WdfFdoUnlockStaticChildListFromIteration(Device);
\r
192 WdfWaitLockRelease(p_fdo->ChildLock);
\r
194 MLX4_EXIT( MLX4_DBG_DRV );
\r
200 __do_static_enumeration(
\r
201 IN WDFDEVICE Device
\r
204 Routine Description:
\r
206 The routine enables you to statically enumerate child devices
\r
207 during start instead of running the enum.exe/notify.exe to
\r
208 enumerate mxe devices.
\r
210 In order to statically enumerate, user must specify the number
\r
211 of mxes in the Mxe Bus driver's device registry. The
\r
212 default value is 2.
\r
214 You can also configure this value in the Mxe Bus Inf file.
\r
219 NTSTATUS status = STATUS_SUCCESS;
\r
221 int number_of_ib_ports;
\r
222 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
223 struct mlx4_dev *mdev = p_fdo->pci_dev.dev;
\r
225 MLX4_ENTER(MLX4_DBG_DRV);
\r
227 if ( p_fdo->children_created )
\r
230 // eventually we'll have all information about children in Registry
\r
231 // DriverEntry will read it into a Global storage and
\r
232 // this routine will create all the children on base on this info
\r
233 number_of_ib_ports = mlx4_count_ib_ports(mdev);
\r
234 ASSERT(number_of_ib_ports >=0 && number_of_ib_ports <=2);
\r
236 if(number_of_ib_ports > 0) {
\r
237 status = __create_child(Device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 );
\r
238 if (!NT_SUCCESS(status)) {
\r
239 MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status));
\r
243 // Create ethernet ports if needed
\r
244 for (i = 0; i < MLX4_MAX_PORTS; i++) {
\r
245 if(mlx4_is_eth_port(mdev, i)) {
\r
246 status = __create_child(Device, ETH_HARDWARE_IDS, ETH_HARDWARE_DESCRIPTION, i+1 );
\r
247 if (!NT_SUCCESS(status)) {
\r
248 MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status));
\r
253 p_fdo->children_created = TRUE;
\r
256 MLX4_EXIT( MLX4_DBG_DRV );
\r
262 __read_dev_params(IN WDFDEVICE Device, struct mlx4_dev_params *dev_params)
\r
264 NTSTATUS status = STATUS_SUCCESS;
\r
265 WDFKEY hKey = NULL;
\r
266 WDFKEY hParamsKey = NULL;
\r
267 DECLARE_CONST_UNICODE_STRING(Parameters, L"Parameters");
\r
268 DECLARE_CONST_UNICODE_STRING(PortType, L"PortType");
\r
269 #define MAX_UVALUE 100
\r
270 WCHAR uvalue_data[MAX_UVALUE];
\r
271 UNICODE_STRING uvalue;
\r
272 status = WdfDeviceOpenRegistryKey(Device, PLUGPLAY_REGKEY_DRIVER,
\r
273 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey);
\r
274 if( !NT_SUCCESS( status ) ) {
\r
275 MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV ,("WdfDeviceOpenRegistryKey Failed status = 0x%x\n", status));
\r
279 status = WdfRegistryOpenKey(hKey, &Parameters, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hParamsKey);
\r
280 if( !NT_SUCCESS( status ) ) {
\r
281 MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV ,("WdfRegistryOpenKey Failed status = 0x%x\n", status));
\r
285 uvalue.Buffer = uvalue_data;
\r
286 uvalue.MaximumLength = MAX_UVALUE;
\r
289 status = WdfRegistryQueryUnicodeString(hParamsKey, &PortType, NULL, &uvalue);
\r
290 if (NT_SUCCESS (status)) {
\r
291 if (!wcscmp(uvalue_data, L"ib,ib")) {
\r
292 dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB;
\r
293 dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB;
\r
295 if (!wcscmp(uvalue_data, L"ib,eth")) {
\r
296 dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB;
\r
297 dev_params->mod_port_type[1] = MLX4_PORT_TYPE_ETH;
\r
299 if (!wcscmp(uvalue_data, L"eth,ib")) {
\r
300 dev_params->mod_port_type[0] = MLX4_PORT_TYPE_ETH;
\r
301 dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB;
\r
303 if (!wcscmp(uvalue_data, L"eth,eth")) {
\r
304 dev_params->mod_port_type[0] = MLX4_PORT_TYPE_ETH;
\r
305 dev_params->mod_port_type[1] = MLX4_PORT_TYPE_ETH;
\r
309 dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB;
\r
310 dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB;
\r
315 WdfRegistryClose(hKey);
\r
317 if (hParamsKey != NULL)
\r
318 WdfRegistryClose(hParamsKey);
\r
327 IN WDFDEVICE Device,
\r
328 IN PFDO_DEVICE_DATA p_fdo
\r
331 #ifndef USE_WDM_INTERRUPTS
\r
335 NTSTATUS status = STATUS_SUCCESS;
\r
336 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
337 struct mlx4_dev_params dev_params;
\r
339 MLX4_ENTER(MLX4_DBG_DRV);
\r
341 if ( p_fdo->card_started )
\r
344 status = __read_dev_params(Device, &dev_params);
\r
345 if( !NT_SUCCESS( status ) )
\r
349 status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );
\r
350 if( !NT_SUCCESS( status ) )
\r
357 #ifndef USE_WDM_INTERRUPTS
\r
358 // enable interrupts for start up
\r
359 for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i )
\r
360 WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);
\r
364 err = mlx4_init_one( &p_fdo->pci_dev, &dev_params );
\r
366 status = errno_to_ntstatus(err);
\r
370 #ifndef USE_WDM_INTERRUPTS
\r
372 // complete filling interrupt context (for more efficiency)
\r
374 for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {
\r
375 struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );
\r
376 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext(
\r
377 p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );
\r
379 p_isr_ctx->eq = &priv->eq_table.eq[i];
\r
384 // prepare MLX4 IB interface
\r
388 p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE);
\r
389 p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION;
\r
390 // Let the framework handle reference counting.
\r
391 p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
\r
392 p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
\r
394 p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;
\r
395 p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;
\r
396 p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);
\r
397 if ( p_fdo->bus_ib_ifc.is_livefish == 0 ) {
\r
398 p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;
\r
399 if ( p_fdo->bus_ib_ifc.pmlx4_dev->flags & MLX4_FLAG_MSI_X )
\r
400 p_fdo->bus_ib_ifc.n_msi_vectors = p_fdo->pci_dev.n_msi_vectors - 2;
\r
403 p_fdo->card_started = TRUE;
\r
406 MLX4_EXIT( MLX4_DBG_DRV );
\r
413 IN PFDO_DEVICE_DATA p_fdo
\r
416 if ( p_fdo->card_started ) {
\r
417 p_fdo->card_started = FALSE;
\r
418 mlx4_remove_one( &p_fdo->pci_dev, TRUE);
\r
425 IN WDFDEVICE Device,
\r
426 IN WDF_POWER_DEVICE_STATE PreviousState
\r
429 NTSTATUS status = STATUS_SUCCESS;
\r
430 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
431 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
432 struct mlx4_dev *mdev;
\r
434 MLX4_ENTER(MLX4_DBG_DRV);
\r
436 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));
\r
438 // start card (needed after Hibernetion)
\r
439 if (PreviousState > WdfPowerDeviceD0)
\r
440 __start_card( Device, p_fdo );
\r
443 // create child device
\r
444 status = __do_static_enumeration(Device);
\r
445 if (!NT_SUCCESS(status)) {
\r
446 MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__do_static_enumeration failed with 0x%x\n", status));
\r
450 // Log Success Message
\r
451 MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,
\r
452 ("Ven %x Dev %d Fw %d.%d.%d, IsBurnDevice %s\n",
\r
453 (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,
\r
454 (int) (mdev->caps.fw_ver >> 32),
\r
455 (int) (mdev->caps.fw_ver >> 16) & 0xffff,
\r
456 (int) (mdev->caps.fw_ver & 0xffff),
\r
457 mlx4_is_livefish(mdev) ? "Y" : "N"
\r
461 MLX4_EXIT( MLX4_DBG_DRV );
\r
467 IN WDFDEVICE Device,
\r
468 IN WDF_POWER_DEVICE_STATE TargetState
\r
471 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
473 MLX4_ENTER(MLX4_DBG_DRV);
\r
474 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState));
\r
476 if (TargetState > WdfPowerDeviceD0)
\r
477 __stop_card( p_fdo );
\r
479 MLX4_EXIT( MLX4_DBG_DRV );
\r
480 return STATUS_SUCCESS;
\r
485 /* Forwards the request to the HCA's PDO. */
\r
489 IN BUS_INTERFACE_STANDARD *pBusIfc )
\r
491 MLX4_ENTER(MLX4_DBG_DRV);
\r
492 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("pBusIfc=0x%p\n", pBusIfc));
\r
493 pBusIfc->InterfaceDereference( pBusIfc->Context );
\r
494 MLX4_EXIT( MLX4_DBG_DRV );
\r
500 IN PFDO_DEVICE_DATA const p_fdo,
\r
501 IN const GUID* const pGuid,
\r
502 OUT BUS_INTERFACE_STANDARD *pBusIfc )
\r
505 WDFDEVICE FdoDevice = p_fdo->FdoDevice;
\r
506 MLX4_ENTER(MLX4_DBG_DRV);
\r
508 status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc,
\r
509 sizeof(BUS_INTERFACE_STANDARD), 1, NULL );
\r
510 MLX4_EXIT( MLX4_DBG_DRV );
\r
517 IN PFDO_DEVICE_DATA p_fdo,
\r
518 IN PDMA_ADAPTER p_dma )
\r
520 UNUSED_PARAM(p_fdo);
\r
521 UNUSED_PARAM(p_dma);
\r
522 MLX4_ENTER(MLX4_DBG_DRV);
\r
523 MLX4_EXIT( MLX4_DBG_DRV );
\r
527 // this routine releases the resources, taken in __get_resources
\r
531 IN PFDO_DEVICE_DATA p_fdo
\r
534 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
536 MLX4_ENTER(MLX4_DBG_DRV);
\r
538 if (pdev->msix_info.valid)
\r
539 pci_free_msix_info_resources(&pdev->msix_info);
\r
541 if (p_fdo->dma_adapter_taken) {
\r
542 p_fdo->dma_adapter_taken = FALSE;
\r
543 __put_dma_adapter( p_fdo, pdev->p_dma_adapter );
\r
546 if (p_fdo->pci_bus_ifc_taken) {
\r
547 p_fdo->pci_bus_ifc_taken = FALSE;
\r
548 __put_bus_ifc(&pdev->bus_pci_ifc);
\r
551 if (pdev->p_msix_map)
\r
552 kfree(pdev->p_msix_map);
\r
555 MLX4_EXIT( MLX4_DBG_DRV );
\r
561 IN PFDO_DEVICE_DATA p_fdo,
\r
562 OUT PDMA_ADAPTER * pp_dma )
\r
565 WDF_DMA_ENABLER_CONFIG dmaConfig;
\r
567 MLX4_ENTER(MLX4_DBG_DRV);
\r
569 WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
\r
570 WdfDmaProfileScatterGather64, 0x80000000 - 1 );
\r
572 status = WdfDmaEnablerCreate( p_fdo->FdoDevice,
\r
573 &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &p_fdo->dma_enabler );
\r
574 if (!NT_SUCCESS (status)) {
\r
578 *pp_dma = WdfDmaEnablerWdmGetDmaAdapter(
\r
579 p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice );
\r
581 MLX4_EXIT( MLX4_DBG_DRV );
\r
585 // this routine fills pci_dev structure, containing all HW
\r
586 // and some other necessary common resources
\r
590 IN PFDO_DEVICE_DATA p_fdo,
\r
591 IN WDFCMRESLIST ResourcesRaw,
\r
592 IN WDFCMRESLIST ResourcesTranslated
\r
597 PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
\r
598 PCM_PARTIAL_RESOURCE_DESCRIPTOR desc_raw;
\r
599 BUS_INTERFACE_STANDARD bus_pci_ifc;
\r
600 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
602 MLX4_ENTER(MLX4_DBG_DRV);
\r
605 // Get PCI BUS interface
\r
607 status = __get_bus_ifc( p_fdo, &GUID_BUS_INTERFACE_STANDARD, &bus_pci_ifc );
\r
608 if( !NT_SUCCESS( status ) ) {
\r
609 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
610 ("failed: status=0x%x\n", status));
\r
613 RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );
\r
614 p_fdo->pci_bus_ifc_taken = TRUE;
\r
617 // get HW resources
\r
619 for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {
\r
621 desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );
\r
622 desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i );
\r
624 switch (desc->Type) {
\r
626 case CmResourceTypeMemory:
\r
627 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
628 ("EvtPrepareHardware(Raw): Desc %d: Memory: Start %#I64x, Length %#x\n",
\r
629 i, desc_raw->u.Memory.Start.QuadPart, desc_raw->u.Memory.Length ));
\r
630 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
631 ("EvtPrepareHardware: Desc %d: Memory: Start %#I64x, Length %#x\n",
\r
632 i, desc->u.Memory.Start.QuadPart, desc->u.Memory.Length ));
\r
635 pdev->bar[k].phys = desc->u.Memory.Start.QuadPart;
\r
636 pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length;
\r
641 #ifdef USE_WDM_INTERRUPTS
\r
642 case CmResourceTypeInterrupt:
\r
643 if (!pdev->n_msi_vectors_alloc)
\r
644 pdev->int_info = *desc;
\r
645 if (desc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
\r
646 pdev->n_msi_vectors_alloc = (u8)(pdev->n_msi_vectors_alloc+desc_raw->u.MessageInterrupt.Raw.MessageCount);
\r
647 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
648 ("EvtPrepareHardware: Desc %d: MsiInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n",
\r
649 i, desc->ShareDisposition, desc->Flags,
\r
650 desc->u.MessageInterrupt.Translated.Level,
\r
651 desc->u.MessageInterrupt.Translated.Vector,
\r
652 (u32)desc->u.MessageInterrupt.Translated.Affinity ));
\r
653 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
654 ("EvtPrepareHardware: Desc %d: RawMsiInterrupt: Share %d, Flags %#x, MessageCount %#hx, Vector %#x, Affinity %#x\n",
\r
655 i, desc_raw->ShareDisposition, desc_raw->Flags,
\r
656 desc_raw->u.MessageInterrupt.Raw.MessageCount,
\r
657 desc_raw->u.MessageInterrupt.Raw.Vector,
\r
658 (u32)desc_raw->u.MessageInterrupt.Raw.Affinity ));
\r
660 else { // line-based interrupt
\r
661 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
662 ("EvtPrepareHardware: Desc %d: LineInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n",
\r
663 i, desc->ShareDisposition, desc->Flags,
\r
664 desc->u.Interrupt.Level, desc->u.Interrupt.Vector,
\r
665 (u32)desc->u.Interrupt.Affinity ));
\r
672 // Ignore all other descriptors.
\r
678 // This means that no resources are found
\r
679 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("WdfCmResourceListGetCount: returned 0, quiting\n"));
\r
680 return STATUS_INSUFFICIENT_RESOURCES;
\r
684 // get uplink info.
\r
686 status = pci_save_config( &pdev->bus_pci_ifc,
\r
687 &pdev->pci_cfg_space );
\r
688 if( !NT_SUCCESS( status ) )
\r
690 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
691 ("Failed to save HCA config: status=0x%x\n", status));
\r
694 pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info );
\r
697 // allocate DMA adapter
\r
699 status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter );
\r
700 if( !NT_SUCCESS( status ) )
\r
702 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
703 ("Failed to get DMA adapter: status=0x%x\n", status));
\r
706 p_fdo->dma_adapter_taken = TRUE;
\r
709 // allocate MSI-X vector map table
\r
711 if ( pdev->n_msi_vectors_alloc )
\r
713 pdev->p_msix_map = kzalloc(sizeof(struct msix_map) * pdev->n_msi_vectors_alloc, GFP_KERNEL);
\r
714 if ( !pdev->p_msix_map )
\r
716 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
717 ("Failed to allocate MSI-X vector map table\n"));
\r
723 // fill more fields in pci_dev
\r
725 pdev->ven_id = pdev->pci_cfg_space.VendorID;
\r
726 pdev->dev_id = pdev->pci_cfg_space.DeviceID;
\r
727 pdev->sub_vendor_id = pdev->pci_cfg_space.u.type0.SubVendorID;
\r
728 pdev->sub_system_id = pdev->pci_cfg_space.u.type0.SubSystemID;
\r
729 pdev->p_self_do = WdfDeviceWdmGetDeviceObject(p_fdo->FdoDevice);
\r
730 pdev->pdo = WdfDeviceWdmGetPhysicalDevice(p_fdo->FdoDevice);
\r
732 MLX4_EXIT( MLX4_DBG_DRV );
\r
733 return STATUS_SUCCESS;
\r
735 __put_resources(p_fdo);
\r
736 MLX4_EXIT( MLX4_DBG_DRV );
\r
741 EvtPrepareHardware(
\r
742 IN WDFDEVICE Device,
\r
743 IN WDFCMRESLIST ResourcesRaw,
\r
744 IN WDFCMRESLIST ResourcesTranslated
\r
748 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
750 MLX4_ENTER(MLX4_DBG_DRV);
\r
753 status = __get_resources( p_fdo, ResourcesRaw, ResourcesTranslated );
\r
754 if( !NT_SUCCESS( status ) ) {
\r
755 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__get_resources failed: status=0x%x\n", status));
\r
760 status = __start_card(Device, p_fdo );
\r
763 MLX4_EXIT( MLX4_DBG_DRV );
\r
767 void fix_bus_ifc(struct pci_dev *pdev)
\r
769 PFDO_DEVICE_DATA p_fdo;
\r
771 p_fdo = CONTAINING_RECORD(pdev, FDO_DEVICE_DATA, pci_dev);
\r
772 p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;
\r
773 p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;
\r
774 p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);
\r
778 EvtReleaseHardware(
\r
779 IN WDFDEVICE Device,
\r
780 IN WDFCMRESLIST ResourcesTranslated
\r
783 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
785 UNUSED_PARAM(ResourcesTranslated);
\r
787 MLX4_ENTER(MLX4_DBG_DRV);
\r
789 __stop_card( p_fdo );
\r
790 __put_resources( p_fdo );
\r
792 MLX4_EXIT( MLX4_DBG_DRV );
\r
793 return STATUS_SUCCESS;
\r
796 #ifndef USE_WDM_INTERRUPTS
\r
800 __create_interrupt(
\r
801 IN WDFDEVICE device,
\r
803 IN PFN_WDF_INTERRUPT_ISR isr,
\r
804 IN PFN_WDF_INTERRUPT_DPC dpc,
\r
805 IN PFDO_DEVICE_DATA p_fdo,
\r
806 OUT WDFINTERRUPT * p_int_obj
\r
811 WDF_INTERRUPT_CONFIG interruptConfig;
\r
812 WDF_OBJECT_ATTRIBUTES interruptAttributes;
\r
813 PINTERRUPT_DATA p_isr_ctx;
\r
815 MLX4_ENTER(MLX4_DBG_DRV);
\r
817 WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );
\r
819 interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;
\r
820 interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;
\r
823 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
\r
824 &interruptAttributes, INTERRUPT_DATA );
\r
826 Status = WdfInterruptCreate( device,
\r
827 &interruptConfig, &interruptAttributes, p_int_obj );
\r
829 p_isr_ctx = WdfObjectGetTypedContext( *p_int_obj, INTERRUPT_DATA );
\r
830 p_isr_ctx->int_num = int_num;
\r
831 p_isr_ctx->p_fdo = p_fdo;
\r
832 p_isr_ctx->eq = NULL;
\r
834 // one can call WdfInterruptSetPolicy() to set the policy, affinity etc
\r
836 MLX4_EXIT( MLX4_DBG_DRV );
\r
842 inline void InitBusIsr(
\r
843 struct VipBusIfc* pVipBusIfc
\r
846 memset(pVipBusIfc, 0, sizeof(struct VipBusIfc));
\r
847 KeInitializeEvent(&pVipBusIfc->NicData.ConfigChangeEvent, SynchronizationEvent, TRUE);
\r
851 EvtDriverDeviceAdd(
\r
852 IN WDFDRIVER Driver,
\r
853 IN PWDFDEVICE_INIT DeviceInit
\r
856 Routine Description:
\r
858 EvtDriverDeviceAdd is called by the framework in response to AddDevice
\r
859 call from the PnP manager. We create and initialize a device object to
\r
860 represent a new instance of mxe bus.
\r
864 Driver - Handle to a framework driver object created in DriverEntry
\r
866 DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
\r
874 #ifndef USE_WDM_INTERRUPTS
\r
877 WDF_OBJECT_ATTRIBUTES attributes;
\r
880 PFDO_DEVICE_DATA p_fdo;
\r
881 PNP_BUS_INFORMATION busInfo;
\r
882 WDF_PNPPOWER_EVENT_CALLBACKS Callbacks;
\r
884 UNREFERENCED_PARAMETER(Driver);
\r
887 MLX4_ENTER(MLX4_DBG_DRV);
\r
890 // register PnP & Power stuff
\r
892 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
\r
893 Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware;
\r
894 Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;
\r
895 Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;
\r
896 Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;
\r
898 WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );
\r
901 // Initialize all the properties specific to the device.
\r
902 // Framework has default values for the one that are not
\r
903 // set explicitly here. So please read the doc and make sure
\r
904 // you are okay with the defaults.
\r
906 WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
\r
907 WdfDeviceInitSetExclusive(DeviceInit, TRUE);
\r
910 // Initialize attributes structure to specify size and accessor function
\r
911 // for storing device context.
\r
913 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);
\r
916 // Create a framework device object. In response to this call, framework
\r
917 // creates a WDM deviceobject.
\r
919 status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
\r
920 if (!NT_SUCCESS(status)) {
\r
921 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
922 ("WdfDeviceCreate failed with 0x%x\n", status));
\r
927 // Get the device context.
\r
929 p_fdo = FdoGetData(device);
\r
930 RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));
\r
931 p_fdo->FdoDevice = device;
\r
936 // Init the BusIsr data
\r
938 InitBusIsr(&p_fdo->mtnic_Ifc);
\r
941 // Purpose of this lock is documented in PlugInDevice routine below.
\r
943 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
\r
944 attributes.ParentObject = device;
\r
945 status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock);
\r
946 if (!NT_SUCCESS(status)) {
\r
947 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
948 ("WdfWaitLockCreate failed with 0x%x\n", status));
\r
953 // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION
\r
954 // for the child devices. This is an optional information provided to
\r
955 // uniquely identify the bus the device is connected.
\r
957 busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;
\r
958 busInfo.LegacyBusType = PNPBus;
\r
959 busInfo.BusNumber = 0;
\r
961 WdfDeviceSetBusInformationForChildren(device, &busInfo);
\r
966 status = WmiRegistration(device);
\r
967 if (!NT_SUCCESS(status)) {
\r
968 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
969 ("WmiRegistration failed with 0x%x\n", status));
\r
973 #ifndef USE_WDM_INTERRUPTS
\r
976 // create interrupt objects
\r
978 for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {
\r
979 status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr,
\r
980 NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt );
\r
981 if (NT_SUCCESS(status))
\r
982 p_fdo->interrupt[i].valid = TRUE;
\r
984 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
985 ("WdfInterruptCreate failed %#x\n", status ));
\r
992 status = STATUS_SUCCESS;
\r
995 MLX4_EXIT( MLX4_DBG_DRV );
\r
1003 IN WDFDRIVER Driver
\r
1006 MLX4_ENTER( MLX4_DBG_DRV );
\r
1008 UNUSED_PARAM( Driver );
\r
1010 mlx4_ib_cleanup();
\r
1013 MLX4_EXIT( MLX4_DBG_DRV );
\r
1014 #if defined(EVENT_TRACING)
\r
1015 WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));
\r
1022 __read_registry(WDFDRIVER *hDriver)
\r
1024 DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");
\r
1025 DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");
\r
1027 // "log maximum number of QPs per HCA"
\r
1028 DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");
\r
1030 // "log number of RDMARC buffers per QP"
\r
1031 DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");
\r
1033 // "log maximum number of SRQs per HCA"
\r
1034 DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");
\r
1036 // "log maximum number of CQs per HCA"
\r
1037 DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");
\r
1039 // "log maximum number of multicast groups per HCA"
\r
1040 DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");
\r
1042 // "log maximum number of memory protection table entries per HCA"
\r
1043 DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");
\r
1045 // "log maximum number of memory translation table segments per HCA"
\r
1046 DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");
\r
1048 // "Maximum number of MACs per ETH port (1-127, default 1"
\r
1049 DECLARE_CONST_UNICODE_STRING(numMac, L"NumMac");
\r
1051 // "Maximum number of VLANs per ETH port (0-126, default 0)"
\r
1052 DECLARE_CONST_UNICODE_STRING(numVlan, L"NumVlan");
\r
1054 // "Enable steering by VLAN priority on ETH ports (0/1, default 0)"
\r
1055 DECLARE_CONST_UNICODE_STRING(usePrio, L"UsePrio");
\r
1057 // "Enable Quality of Service support in the HCA if > 0, (default 1)"
\r
1058 DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");
\r
1060 // "Block multicast loopback packets if > 0 (default 1)"
\r
1061 DECLARE_CONST_UNICODE_STRING(BlockMcastLB, L"BlockMcastLoopBack");
\r
1063 // "Measure the interrupt from the first packet (default 1)"
\r
1064 DECLARE_CONST_UNICODE_STRING(InterruptFromFirstPacket, L"InterruptFromFirstPacket");
\r
1066 // "ProcessorAffinity"
\r
1067 DECLARE_CONST_UNICODE_STRING(ProcessorAffinity, L"ProcessorAffinity");
\r
1070 WDFKEY hKey = NULL;
\r
1071 NTSTATUS status = STATUS_SUCCESS;
\r
1073 status = WdfDriverOpenParametersRegistryKey( *hDriver,
\r
1074 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );
\r
1076 if (NT_SUCCESS (status)) {
\r
1079 // Read general values
\r
1081 status = WdfRegistryQueryULong(hKey, &debugLevel, &value);
\r
1082 if (NT_SUCCESS (status))
\r
1083 g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = value;
\r
1085 status = WdfRegistryQueryULong(hKey, &debugFlags, &value);
\r
1086 if (NT_SUCCESS (status))
\r
1087 g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = value;
\r
1089 status = WdfRegistryQueryULong(hKey, &numQp, &value);
\r
1090 if (NT_SUCCESS (status))
\r
1091 g.mod_num_qp = value;
\r
1093 status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);
\r
1094 if (NT_SUCCESS (status))
\r
1095 g.mod_rdmarc_per_qp = value;
\r
1097 status = WdfRegistryQueryULong(hKey, &numSrq, &value);
\r
1098 if (NT_SUCCESS (status))
\r
1099 g.mod_num_srq = value;
\r
1101 status = WdfRegistryQueryULong(hKey, &numCq, &value);
\r
1102 if (NT_SUCCESS (status))
\r
1103 g.mod_num_cq = value;
\r
1105 status = WdfRegistryQueryULong(hKey, &numMcg, &value);
\r
1106 if (NT_SUCCESS (status))
\r
1107 g.mod_num_mcg = value;
\r
1109 status = WdfRegistryQueryULong(hKey, &numMpt, &value);
\r
1110 if (NT_SUCCESS (status))
\r
1111 g.mod_num_mpt = value;
\r
1113 status = WdfRegistryQueryULong(hKey, &numMtt, &value);
\r
1114 if (NT_SUCCESS (status))
\r
1115 g.mod_num_mtt = value;
\r
1117 status = WdfRegistryQueryULong(hKey, &numMac, &value);
\r
1118 if (NT_SUCCESS (status))
\r
1119 g.mod_num_mac = value;
\r
1121 g.mod_num_mac = 1;
\r
1123 status = WdfRegistryQueryULong(hKey, &numVlan, &value);
\r
1124 if (NT_SUCCESS (status))
\r
1125 g.mod_num_vlan= value;
\r
1127 g.mod_num_vlan = 0;
\r
1129 status = WdfRegistryQueryULong(hKey, &usePrio, &value);
\r
1130 if (NT_SUCCESS (status))
\r
1131 g.mod_use_prio= value;
\r
1133 g.mod_use_prio = 0;
\r
1135 status = WdfRegistryQueryULong(hKey, &enableQoS, &value);
\r
1136 if (NT_SUCCESS (status))
\r
1137 g.mod_enable_qos = value;
\r
1139 g.mod_enable_qos = 0;
\r
1142 status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value);
\r
1143 if (NT_SUCCESS (status))
\r
1144 g.mod_mlx4_blck_lb = value;
\r
1146 g.mod_mlx4_blck_lb = 1;
\r
1148 status = WdfRegistryQueryULong(hKey, &InterruptFromFirstPacket, &value);
\r
1149 if (NT_SUCCESS (status))
\r
1150 g.mod_interrupt_from_first = value;
\r
1152 g.mod_interrupt_from_first = 1;
\r
1155 status = WdfRegistryQueryULong(hKey, &ProcessorAffinity, &value);
\r
1156 if (NT_SUCCESS (status))
\r
1157 g.mod_affinity = value;
\r
1159 g.mod_affinity = 0;
\r
1162 WdfRegistryClose(hKey);
\r
1163 status = STATUS_SUCCESS;
\r
1171 IN PDRIVER_OBJECT DriverObject,
\r
1172 IN PUNICODE_STRING RegistryPath
\r
1175 Routine Description:
\r
1177 Initialize the call backs structure of Driver Framework.
\r
1181 DriverObject - pointer to the driver object
\r
1183 RegistryPath - pointer to a unicode string representing the path,
\r
1184 to driver-specific key in the registry.
\r
1193 WDF_DRIVER_CONFIG config;
\r
1195 WDFDRIVER hDriver;
\r
1197 #if defined(EVENT_TRACING)
\r
1198 WPP_INIT_TRACING(DriverObject, RegistryPath);
\r
1202 // global initializations
\r
1203 RtlZeroMemory( &g, sizeof(g) );
\r
1204 g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = TRACE_LEVEL_VERBOSE;
\r
1205 g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = 0xffff;
\r
1207 MLX4_ENTER(MLX4_DBG_DRV);
\r
1208 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV,
\r
1209 ("Built %s %s, Version %s, RelDate %s\n",
\r
1210 __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE));
\r
1213 err = core_init();
\r
1215 status = errno_to_ntstatus(err);
\r
1218 err = mlx4_ib_init();
\r
1220 status = errno_to_ntstatus(err);
\r
1225 // Initiialize driver config to control the attributes that
\r
1226 // are global to the driver. Note that framework by default
\r
1227 // provides a driver unload routine. If you create any resources
\r
1228 // in the DriverEntry and want to be cleaned in driver unload,
\r
1229 // you can override that by specifing one in the Config structure.
\r
1232 WDF_DRIVER_CONFIG_INIT(
\r
1233 &config, EvtDriverDeviceAdd );
\r
1234 config.EvtDriverUnload = EvtDriverUnload;
\r
1237 // Create a framework driver object to represent our driver.
\r
1239 status = WdfDriverCreate(DriverObject,
\r
1240 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
\r
1241 &config, &hDriver);
\r
1243 if (!NT_SUCCESS(status)) {
\r
1244 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status));
\r
1249 // read registry parameters
\r
1251 status = __read_registry(&hDriver);
\r
1253 // we don't matter the failure in the work with Registry
\r
1254 status = STATUS_SUCCESS;
\r
1257 MLX4_EXIT( MLX4_DBG_DRV );
\r