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
30 #pragma alloc_text (INIT, DriverEntry)
\r
31 #pragma alloc_text (PAGE, EvtDeviceAdd)
\r
32 #pragma alloc_text (PAGE, EvtDriverUnload)
\r
33 #pragma alloc_text (PAGE, EvtDeviceD0Entry)
\r
34 #pragma alloc_text (PAGE, EvtDeviceD0Exit)
\r
35 #pragma alloc_text (PAGE, EvtPrepareHardware)
\r
36 #pragma alloc_text (PAGE, EvtReleaseHardware)
\r
39 #define DRV_VERSION "1.0"
\r
40 #define DRV_RELDATE "02/01/2008"
\r
43 uint32_t g_mlx4_dbg_flags = 0xffff;
\r
44 uint32_t g_mlx4_dbg_level = TRACE_LEVEL_INFORMATION;
\r
45 WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ];
\r
46 UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ];
\r
48 #ifndef USE_WDM_INTERRUPTS
\r
52 PFDO_DEVICE_DATA p_fdo;
\r
53 struct mlx4_eq * eq;
\r
54 } INTERRUPT_DATA, *PINTERRUPT_DATA;
\r
56 WDF_DECLARE_CONTEXT_TYPE(INTERRUPT_DATA);
\r
59 EvtEnableInterrupt(
\r
60 IN WDFINTERRUPT Interrupt,
\r
61 IN WDFDEVICE AssociatedDevice
\r
64 UNUSED_PARAM(Interrupt);
\r
65 UNUSED_PARAM(AssociatedDevice);
\r
66 MLX4_ENTER(MLX4_DBG_DRV);
\r
67 MLX4_EXIT( MLX4_DBG_DRV );
\r
68 return STATUS_SUCCESS;
\r
72 EvtDisableInterrupt (
\r
73 IN WDFINTERRUPT Interrupt,
\r
74 IN WDFDEVICE AssociatedDevice
\r
77 UNUSED_PARAM(Interrupt);
\r
78 UNUSED_PARAM(AssociatedDevice);
\r
79 MLX4_ENTER(MLX4_DBG_DRV);
\r
80 MLX4_EXIT( MLX4_DBG_DRV );
\r
81 return STATUS_SUCCESS;
\r
86 IN WDFINTERRUPT Interrupt,
\r
90 BOOLEAN isr_handled = FALSE;
\r
91 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( Interrupt, INTERRUPT_DATA );
\r
93 UNUSED_PARAM(MessageID);
\r
95 // MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("Fdo %p\n", p_isr_ctx->p_fdo));
\r
96 if (p_isr_ctx->eq && p_isr_ctx->eq->isr)
\r
97 isr_handled = p_isr_ctx->eq->isr( p_isr_ctx->eq->eq_ix, p_isr_ctx->eq->ctx );
\r
106 __in WDFDEVICE Device,
\r
107 __in PWCHAR HardwareIds,
\r
108 __in PWCHAR DeviceDescription,
\r
109 __in ULONG SerialNo
\r
114 Routine Description:
\r
116 The user application has told us that a new device on the bus has arrived.
\r
118 We therefore need to create a new PDO, initialize it, add it to the list
\r
119 of PDOs for this FDO bus, and then tell Plug and Play that all of this
\r
120 happened so that it will start sending prodding IRPs.
\r
125 NTSTATUS status = STATUS_SUCCESS;
\r
126 BOOLEAN unique = TRUE;
\r
128 PPDO_DEVICE_DATA p_pdo;
\r
129 PFDO_DEVICE_DATA p_fdo;
\r
132 MLX4_ENTER(MLX4_DBG_DRV);
\r
135 // First make sure that we don't already have another device with the
\r
136 // same serial number.
\r
137 // Framework creates a collection of all the child devices we have
\r
138 // created so far. So acquire the handle to the collection and lock
\r
139 // it before walking the item.
\r
141 p_fdo = FdoGetData(Device);
\r
145 // We need an additional lock to synchronize addition because
\r
146 // WdfFdoLockStaticChildListForIteration locks against anyone immediately
\r
147 // updating the static child list (the changes are put on a queue until the
\r
148 // list has been unlocked). This type of lock does not enforce our concept
\r
149 // of unique IDs on the bus (ie SerialNo).
\r
151 // Without our additional lock, 2 threads could execute this function, both
\r
152 // find that the requested SerialNo is not in the list and attempt to add
\r
153 // it. If that were to occur, 2 PDOs would have the same unique SerialNo,
\r
154 // which is incorrect.
\r
156 // We must use a passive level lock because you can only call WdfDeviceCreate
\r
157 // at PASSIVE_LEVEL.
\r
159 WdfWaitLockAcquire(p_fdo->ChildLock, NULL);
\r
160 WdfFdoLockStaticChildListForIteration(Device);
\r
162 while ((hChild = WdfFdoRetrieveNextStaticChild(Device,
\r
163 hChild, WdfRetrieveAddedChildren)) != NULL) {
\r
165 // WdfFdoRetrieveNextStaticChild returns reported and to be reported
\r
166 // children (ie children who have been added but not yet reported to PNP).
\r
168 // A surprise removed child will not be returned in this list.
\r
170 p_pdo = PdoGetData(hChild);
\r
171 p_pdo->PdoDevice = hChild;
\r
172 p_pdo->p_fdo = p_fdo;
\r
175 // It's okay to plug in another device with the same serial number
\r
176 // as long as the previous one is in a surprise-removed state. The
\r
177 // previous one would be in that state after the device has been
\r
178 // physically removed, if somebody has an handle open to it.
\r
180 if (SerialNo == p_pdo->SerialNo) {
\r
182 status = STATUS_INVALID_PARAMETER;
\r
189 // Create a new child device. It is OK to create and add a child while
\r
190 // the list locked for enumeration. The enumeration lock applies only
\r
191 // to enumeration, not addition or removal.
\r
193 status = create_pdo(Device, HardwareIds, DeviceDescription, SerialNo);
\r
196 WdfFdoUnlockStaticChildListFromIteration(Device);
\r
197 WdfWaitLockRelease(p_fdo->ChildLock);
\r
199 MLX4_EXIT( MLX4_DBG_DRV );
\r
204 __do_static_enumeration(
\r
205 IN WDFDEVICE Device
\r
208 Routine Description:
\r
210 The routine enables you to statically enumerate child devices
\r
211 during start instead of running the enum.exe/notify.exe to
\r
212 enumerate mxe devices.
\r
214 In order to statically enumerate, user must specify the number
\r
215 of mxes in the Mxe Bus driver's device registry. The
\r
216 default value is 2.
\r
218 You can also configure this value in the Mxe Bus Inf file.
\r
223 NTSTATUS status = STATUS_SUCCESS;
\r
225 int number_of_ib_ports;
\r
227 // TODO:Need to add an event log in the case of errors
\r
229 MLX4_ENTER(MLX4_DBG_DRV);
\r
231 // eventually we'll have all information about children in Registry
\r
232 // DriverEntry will read it into a Global storage and
\r
233 // this routine will create all the children on base on this info
\r
234 number_of_ib_ports = mlx4_count_ib_ports();
\r
235 ASSERT(number_of_ib_ports >=0 && number_of_ib_ports <=2);
\r
237 if(number_of_ib_ports > 0) {
\r
238 status = __create_child(Device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 );
\r
239 if (!NT_SUCCESS(status)) {
\r
240 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status));
\r
244 // Create ethernet ports if needed
\r
245 for (i = 0; i < MLX4_MAX_PORTS; i++) {
\r
246 if(mlx4_is_eth_port(i)) {
\r
247 status = __create_child(Device, ETH_HARDWARE_IDS, ETH_HARDWARE_DESCRIPTION, i+1 );
\r
248 if (!NT_SUCCESS(status)) {
\r
249 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status));
\r
254 MLX4_EXIT( MLX4_DBG_DRV );
\r
260 IN WDFDEVICE Device,
\r
261 IN WDF_POWER_DEVICE_STATE PreviousState
\r
264 NTSTATUS status = STATUS_SUCCESS;
\r
266 UNUSED_PARAM(Device);
\r
267 UNUSED_PARAM(PreviousState);
\r
269 MLX4_ENTER(MLX4_DBG_DRV);
\r
271 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));
\r
273 status = __do_static_enumeration(Device);
\r
274 if (!NT_SUCCESS(status)) {
\r
275 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__do_static_enumeration failed with 0x%x\n", status));
\r
279 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
280 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
281 struct mlx4_dev *mdev = pdev->dev;
\r
283 MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,
\r
284 ("Ven %x Dev %d Fw %d.%d.%d Drv %s (%s), BD %s\n",
\r
285 (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,
\r
286 (int) (mdev->caps.fw_ver >> 32),
\r
287 (int) (mdev->caps.fw_ver >> 16) & 0xffff,
\r
288 (int) (mdev->caps.fw_ver & 0xffff),
\r
289 DRV_VERSION, DRV_RELDATE,
\r
290 mlx4_is_livefish(mdev) ? "Y" : "N"
\r
294 MLX4_EXIT( MLX4_DBG_DRV );
\r
295 return STATUS_SUCCESS;
\r
300 IN WDFDEVICE Device,
\r
301 IN WDF_POWER_DEVICE_STATE TargetState
\r
304 UNUSED_PARAM(Device);
\r
305 UNUSED_PARAM(TargetState);
\r
306 MLX4_ENTER(MLX4_DBG_DRV);
\r
307 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState));
\r
308 MLX4_EXIT( MLX4_DBG_DRV );
\r
309 return STATUS_SUCCESS;
\r
314 /* Forwards the request to the HCA's PDO. */
\r
318 IN BUS_INTERFACE_STANDARD *pBusIfc )
\r
320 MLX4_ENTER(MLX4_DBG_DRV);
\r
321 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("pBusIfc=0x%p\n", pBusIfc));
\r
322 pBusIfc->InterfaceDereference( pBusIfc->Context );
\r
323 MLX4_EXIT( MLX4_DBG_DRV );
\r
329 IN PFDO_DEVICE_DATA const p_fdo,
\r
330 IN const GUID* const pGuid,
\r
331 OUT BUS_INTERFACE_STANDARD *pBusIfc )
\r
334 WDFDEVICE FdoDevice = p_fdo->FdoDevice;
\r
335 MLX4_ENTER(MLX4_DBG_DRV);
\r
337 status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc,
\r
338 sizeof(BUS_INTERFACE_STANDARD), 1, NULL );
\r
339 MLX4_EXIT( MLX4_DBG_DRV );
\r
346 IN PFDO_DEVICE_DATA p_fdo,
\r
347 IN PDMA_ADAPTER p_dma )
\r
349 UNUSED_PARAM(p_fdo);
\r
350 UNUSED_PARAM(p_dma);
\r
351 MLX4_ENTER(MLX4_DBG_DRV);
\r
352 MLX4_EXIT( MLX4_DBG_DRV );
\r
356 // this routine releases the resources, taken in __get_resources
\r
360 IN PFDO_DEVICE_DATA p_fdo
\r
363 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
364 MLX4_ENTER(MLX4_DBG_DRV);
\r
366 if (p_fdo->dma_adapter_taken) {
\r
367 p_fdo->dma_adapter_taken = FALSE;
\r
368 __put_dma_adapter( p_fdo, pdev->p_dma_adapter );
\r
371 if (p_fdo->pci_bus_ifc_taken) {
\r
372 p_fdo->pci_bus_ifc_taken = FALSE;
\r
373 __put_bus_ifc(&pdev->bus_pci_ifc);
\r
375 MLX4_EXIT( MLX4_DBG_DRV );
\r
381 IN PFDO_DEVICE_DATA p_fdo,
\r
382 OUT PDMA_ADAPTER * pp_dma )
\r
385 WDF_DMA_ENABLER_CONFIG dmaConfig;
\r
387 MLX4_ENTER(MLX4_DBG_DRV);
\r
389 WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
\r
390 WdfDmaProfileScatterGather64, 0x80000000 - 1 );
\r
392 status = WdfDmaEnablerCreate( p_fdo->FdoDevice,
\r
393 &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &p_fdo->dma_enabler );
\r
394 if (!NT_SUCCESS (status)) {
\r
398 *pp_dma = WdfDmaEnablerWdmGetDmaAdapter(
\r
399 p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice );
\r
401 MLX4_EXIT( MLX4_DBG_DRV );
\r
405 // this routine fills pci_dev structure, containing all HW
\r
406 // and some other necessary common resources
\r
410 IN PFDO_DEVICE_DATA p_fdo,
\r
411 IN WDFCMRESLIST ResourcesRaw,
\r
412 IN WDFCMRESLIST ResourcesTranslated
\r
417 PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
\r
418 PCM_PARTIAL_RESOURCE_DESCRIPTOR desc_raw;
\r
419 BUS_INTERFACE_STANDARD bus_pci_ifc;
\r
420 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
422 MLX4_ENTER(MLX4_DBG_DRV);
\r
425 // Get PCI BUS interface
\r
427 status = __get_bus_ifc( p_fdo, &GUID_BUS_INTERFACE_STANDARD, &bus_pci_ifc );
\r
428 if( !NT_SUCCESS( status ) ) {
\r
429 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
430 ("failed: status=0x%x\n", status));
\r
433 RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );
\r
434 p_fdo->pci_bus_ifc_taken = TRUE;
\r
437 // get HW resources
\r
439 for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {
\r
441 desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );
\r
442 desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i );
\r
444 switch (desc->Type) {
\r
446 case CmResourceTypeMemory:
\r
447 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
448 ("EvtPrepareHardware(Raw): Desc %d: Memory: Start %#I64x, Length %#x\n",
\r
449 i, desc_raw->u.Memory.Start.QuadPart, desc_raw->u.Memory.Length ));
\r
450 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
451 ("EvtPrepareHardware: Desc %d: Memory: Start %#I64x, Length %#x\n",
\r
452 i, desc->u.Memory.Start.QuadPart, desc->u.Memory.Length ));
\r
455 pdev->bar[k].phys = desc->u.Memory.Start.QuadPart;
\r
456 pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length;
\r
461 #ifdef USE_WDM_INTERRUPTS
\r
462 case CmResourceTypeInterrupt:
\r
463 pdev->int_info = *desc;
\r
469 // Ignore all other descriptors.
\r
475 // This means that no resources are found
\r
476 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("WdfCmResourceListGetCount: returned 0, quiting\n"));
\r
477 return STATUS_INSUFFICIENT_RESOURCES;
\r
481 // get uplink info.
\r
483 status = pci_save_config( &pdev->bus_pci_ifc, &pdev->pci_cfg_space);
\r
484 if( !NT_SUCCESS( status ) )
\r
486 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
487 ("Failed to save HCA config: status=0x%x\n", status));
\r
490 pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info );
\r
493 // allocate DMA adapter
\r
495 status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter );
\r
496 if( !NT_SUCCESS( status ) )
\r
498 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
499 ("Failed to get DMA adapter: status=0x%x\n", status));
\r
502 p_fdo->dma_adapter_taken = TRUE;
\r
505 // fill more fields in pci_dev
\r
507 pdev->ven_id = pdev->pci_cfg_space.VendorID;
\r
508 pdev->dev_id = pdev->pci_cfg_space.DeviceID;
\r
509 pdev->p_self_do = WdfDeviceWdmGetDeviceObject(p_fdo->FdoDevice);
\r
511 MLX4_EXIT( MLX4_DBG_DRV );
\r
512 return STATUS_SUCCESS;
\r
514 __put_resources(p_fdo);
\r
515 MLX4_EXIT( MLX4_DBG_DRV );
\r
521 EvtPrepareHardware(
\r
522 IN WDFDEVICE Device,
\r
523 IN WDFCMRESLIST ResourcesRaw,
\r
524 IN WDFCMRESLIST ResourcesTranslated
\r
527 #ifndef USE_WDM_INTERRUPTS
\r
532 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
533 struct pci_dev *pdev = &p_fdo->pci_dev;
\r
535 MLX4_ENTER(MLX4_DBG_DRV);
\r
538 status = __get_resources( p_fdo, ResourcesRaw, ResourcesTranslated );
\r
539 if( !NT_SUCCESS( status ) ) {
\r
540 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__get_resources failed: status=0x%x\n", status));
\r
545 status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );
\r
546 if( !NT_SUCCESS( status ) )
\r
553 #ifndef USE_WDM_INTERRUPTS
\r
554 // enable interrupts for start up
\r
555 for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i )
\r
556 WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);
\r
560 err = mlx4_init_one( &p_fdo->pci_dev );
\r
562 status = errno_to_ntstatus(err);
\r
567 err = mlx4_ib_init();
\r
569 status = errno_to_ntstatus(err);
\r
573 #ifndef USE_WDM_INTERRUPTS
\r
575 // complete filling interrupt context (for more efficiency)
\r
577 for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {
\r
578 struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );
\r
579 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext(
\r
580 p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );
\r
582 p_isr_ctx->eq = &priv->eq_table.eq[i];
\r
587 // prepare MLX4 IB interface
\r
591 p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE);
\r
592 p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION;
\r
593 // Let the framework handle reference counting.
\r
594 p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
\r
595 p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
\r
597 p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;
\r
598 p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;
\r
599 p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;
\r
600 p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);
\r
602 status = STATUS_SUCCESS;
\r
605 MLX4_EXIT( MLX4_DBG_DRV );
\r
610 EvtReleaseHardware(
\r
611 IN WDFDEVICE Device,
\r
612 IN WDFCMRESLIST ResourcesTranslated
\r
615 PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);
\r
617 UNUSED_PARAM(ResourcesTranslated);
\r
619 MLX4_ENTER(MLX4_DBG_DRV);
\r
622 mlx4_remove_one( &p_fdo->pci_dev );
\r
623 __put_resources( p_fdo );
\r
625 MLX4_EXIT( MLX4_DBG_DRV );
\r
626 return STATUS_SUCCESS;
\r
629 #ifndef USE_WDM_INTERRUPTS
\r
633 __create_interrupt(
\r
634 IN WDFDEVICE device,
\r
636 IN PFN_WDF_INTERRUPT_ISR isr,
\r
637 IN PFN_WDF_INTERRUPT_DPC dpc,
\r
638 IN PFDO_DEVICE_DATA p_fdo,
\r
639 OUT WDFINTERRUPT * p_int_obj
\r
644 WDF_INTERRUPT_CONFIG interruptConfig;
\r
645 WDF_OBJECT_ATTRIBUTES interruptAttributes;
\r
646 PINTERRUPT_DATA p_isr_ctx;
\r
648 MLX4_ENTER(MLX4_DBG_DRV);
\r
650 WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );
\r
652 interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;
\r
653 interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;
\r
656 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
\r
657 &interruptAttributes, INTERRUPT_DATA );
\r
659 Status = WdfInterruptCreate( device,
\r
660 &interruptConfig, &interruptAttributes, p_int_obj );
\r
662 p_isr_ctx = WdfObjectGetTypedContext( *p_int_obj, INTERRUPT_DATA );
\r
663 p_isr_ctx->int_num = int_num;
\r
664 p_isr_ctx->p_fdo = p_fdo;
\r
665 p_isr_ctx->eq = NULL;
\r
667 // one can call WdfInterruptSetPolicy() to set the policy, affinity etc
\r
669 MLX4_EXIT( MLX4_DBG_DRV );
\r
675 inline void InitBusIsr(
\r
676 struct VipBusIfc* pVipBusIfc
\r
679 memset(pVipBusIfc, 0, sizeof(struct VipBusIfc));
\r
680 KeInitializeEvent(&pVipBusIfc->NicData.ConfigChangeEvent, SynchronizationEvent, TRUE);
\r
685 IN WDFDRIVER Driver,
\r
686 IN PWDFDEVICE_INIT DeviceInit
\r
689 Routine Description:
\r
691 EvtDeviceAdd is called by the framework in response to AddDevice
\r
692 call from the PnP manager. We create and initialize a device object to
\r
693 represent a new instance of mxe bus.
\r
697 Driver - Handle to a framework driver object created in DriverEntry
\r
699 DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
\r
707 #ifndef USE_WDM_INTERRUPTS
\r
710 WDF_OBJECT_ATTRIBUTES attributes;
\r
713 PFDO_DEVICE_DATA p_fdo;
\r
714 PNP_BUS_INFORMATION busInfo;
\r
715 WDF_PNPPOWER_EVENT_CALLBACKS Callbacks;
\r
717 UNREFERENCED_PARAMETER(Driver);
\r
720 MLX4_ENTER(MLX4_DBG_DRV);
\r
723 // register PnP & Power stuff
\r
725 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
\r
726 Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware;
\r
727 Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;
\r
728 Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;
\r
729 Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;
\r
731 WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );
\r
734 // Initialize all the properties specific to the device.
\r
735 // Framework has default values for the one that are not
\r
736 // set explicitly here. So please read the doc and make sure
\r
737 // you are okay with the defaults.
\r
739 WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
\r
740 WdfDeviceInitSetExclusive(DeviceInit, TRUE);
\r
743 // Initialize attributes structure to specify size and accessor function
\r
744 // for storing device context.
\r
746 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);
\r
749 // Create a framework device object. In response to this call, framework
\r
750 // creates a WDM deviceobject.
\r
752 status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
\r
753 if (!NT_SUCCESS(status)) {
\r
754 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
755 ("WdfDeviceCreate failed with 0x%x\n", status));
\r
760 // Get the device context.
\r
762 p_fdo = FdoGetData(device);
\r
763 RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));
\r
764 p_fdo->FdoDevice = device;
\r
767 // Init the BusIsr data
\r
769 InitBusIsr(&p_fdo->mtnic_Ifc);
\r
772 // Init the BusIsr data
\r
774 InitBusIsr(&p_fdo->mtnic_Ifc);
\r
777 // Purpose of this lock is documented in PlugInDevice routine below.
\r
779 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
\r
780 attributes.ParentObject = device;
\r
781 status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock);
\r
782 if (!NT_SUCCESS(status)) {
\r
783 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
784 ("WdfWaitLockCreate failed with 0x%x\n", status));
\r
789 // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION
\r
790 // for the child devices. This is an optional information provided to
\r
791 // uniquely identify the bus the device is connected.
\r
793 busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;
\r
794 busInfo.LegacyBusType = PNPBus;
\r
795 busInfo.BusNumber = 0;
\r
797 WdfDeviceSetBusInformationForChildren(device, &busInfo);
\r
802 status = WmiRegistration(device);
\r
803 if (!NT_SUCCESS(status)) {
\r
804 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,
\r
805 ("WmiRegistration failed with 0x%x\n", status));
\r
809 #ifndef USE_WDM_INTERRUPTS
\r
812 // create interrupt objects
\r
814 for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {
\r
815 status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr,
\r
816 NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt );
\r
817 if (NT_SUCCESS(status))
\r
818 p_fdo->interrupt[i].valid = TRUE;
\r
820 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,
\r
821 ("WdfInterruptCreate failed %#x\n", status ));
\r
828 status = STATUS_SUCCESS;
\r
831 MLX4_EXIT( MLX4_DBG_DRV );
\r
839 IN WDFDRIVER Driver
\r
842 MLX4_ENTER( MLX4_DBG_DRV );
\r
844 UNUSED_PARAM( Driver );
\r
848 MLX4_EXIT( MLX4_DBG_DRV );
\r
849 #if defined(EVENT_TRACING)
\r
850 WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));
\r
857 __read_registry(WDFDRIVER *hDriver)
\r
859 DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");
\r
860 DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");
\r
862 // "log maximum number of QPs per HCA"
\r
863 DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");
\r
865 // "log number of RDMARC buffers per QP"
\r
866 DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");
\r
868 // "log maximum number of SRQs per HCA"
\r
869 DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");
\r
871 // "log maximum number of CQs per HCA"
\r
872 DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");
\r
874 // "log maximum number of multicast groups per HCA"
\r
875 DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");
\r
877 // "log maximum number of memory protection table entries per HCA"
\r
878 DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");
\r
880 // "log maximum number of memory translation table segments per HCA"
\r
881 DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");
\r
883 // "Enable Quality of Service support in the HCA if > 0, (default 1)"
\r
884 DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");
\r
886 // "Maximum number of MACs per ETH port (1-127, default 1"
\r
887 DECLARE_CONST_UNICODE_STRING(numMac, L"NumMac");
\r
889 // "Maximum number of VLANs per ETH port (0-126, default 0)"
\r
890 DECLARE_CONST_UNICODE_STRING(numVlan, L"NumVlan");
\r
892 // "Enable steering by VLAN priority on ETH ports (0/1, default 0)"
\r
893 DECLARE_CONST_UNICODE_STRING(usePrio, L"UsePrio");
\r
895 // "Block multicast loopback packets if > 0 (default 1)"
\r
896 DECLARE_CONST_UNICODE_STRING(BlockMcastLB, L"BlockMcastLoopBack");
\r
898 // "Ports L2 type (ib/eth/auto, entry per port, comma seperated, default ib for all)"
\r
899 DECLARE_CONST_UNICODE_STRING(PortType, L"PortType");
\r
903 WDFKEY hKey = NULL;
\r
904 NTSTATUS status = STATUS_SUCCESS;
\r
906 UNICODE_STRING uvalue;
\r
907 #define MAX_UVALUE 100
\r
908 WCHAR uvalue_data[MAX_UVALUE];
\r
910 status = WdfDriverOpenParametersRegistryKey( *hDriver,
\r
911 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );
\r
913 if (NT_SUCCESS (status)) {
\r
916 // Read general values
\r
918 status = WdfRegistryQueryULong(hKey, &debugLevel, &value);
\r
919 if (NT_SUCCESS (status))
\r
920 g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = value;
\r
922 status = WdfRegistryQueryULong(hKey, &debugFlags, &value);
\r
923 if (NT_SUCCESS (status))
\r
924 g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = value;
\r
926 status = WdfRegistryQueryULong(hKey, &numQp, &value);
\r
927 if (NT_SUCCESS (status))
\r
928 g.mod_num_qp = value;
\r
930 status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);
\r
931 if (NT_SUCCESS (status))
\r
932 g.mod_rdmarc_per_qp = value;
\r
934 status = WdfRegistryQueryULong(hKey, &numSrq, &value);
\r
935 if (NT_SUCCESS (status))
\r
936 g.mod_num_srq = value;
\r
938 status = WdfRegistryQueryULong(hKey, &numCq, &value);
\r
939 if (NT_SUCCESS (status))
\r
940 g.mod_num_cq = value;
\r
942 status = WdfRegistryQueryULong(hKey, &numMcg, &value);
\r
943 if (NT_SUCCESS (status))
\r
944 g.mod_num_mcg = value;
\r
946 status = WdfRegistryQueryULong(hKey, &numMpt, &value);
\r
947 if (NT_SUCCESS (status))
\r
948 g.mod_num_mpt = value;
\r
950 status = WdfRegistryQueryULong(hKey, &numMtt, &value);
\r
951 if (NT_SUCCESS (status))
\r
952 g.mod_num_mtt = value;
\r
954 status = WdfRegistryQueryULong(hKey, &enableQoS, &value);
\r
955 if (NT_SUCCESS (status))
\r
956 g.mod_enable_qos = value;
\r
958 g.mod_enable_qos = 1;
\r
960 status = WdfRegistryQueryULong(hKey, &numMac, &value);
\r
961 if (NT_SUCCESS (status))
\r
962 g.mod_num_mac = value;
\r
966 status = WdfRegistryQueryULong(hKey, &numVlan, &value);
\r
967 if (NT_SUCCESS (status))
\r
968 g.mod_num_vlan= value;
\r
970 g.mod_num_vlan = 0;
\r
972 status = WdfRegistryQueryULong(hKey, &usePrio, &value);
\r
973 if (NT_SUCCESS (status))
\r
974 g.mod_use_prio= value;
\r
976 g.mod_use_prio = 0;
\r
978 status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value);
\r
979 if (NT_SUCCESS (status))
\r
980 g.mod_mlx4_blck_lb = value;
\r
982 g.mod_mlx4_blck_lb = 1;
\r
984 uvalue.Buffer = uvalue_data;
\r
985 uvalue.MaximumLength = MAX_UVALUE;
\r
988 status = WdfRegistryQueryUnicodeString(hKey, &PortType, NULL, &uvalue);
\r
989 if (NT_SUCCESS (status)) {
\r
990 if (!wcscmp(uvalue_data, L"ib,ib")) {
\r
991 g.mod_port_type [0] = MLX4_PORT_TYPE_IB;
\r
992 g.mod_port_type [1] = MLX4_PORT_TYPE_IB;
\r
994 if (!wcscmp(uvalue_data, L"ib,eth")) {
\r
995 g.mod_port_type [0] = MLX4_PORT_TYPE_IB;
\r
996 g.mod_port_type [1] = MLX4_PORT_TYPE_ETH;
\r
998 if (!wcscmp(uvalue_data, L"eth,ib")) {
\r
999 g.mod_port_type [0] = MLX4_PORT_TYPE_ETH;
\r
1000 g.mod_port_type [1] = MLX4_PORT_TYPE_IB;
\r
1002 if (!wcscmp(uvalue_data, L"eth,eth")) {
\r
1003 g.mod_port_type [0] = MLX4_PORT_TYPE_ETH;
\r
1004 g.mod_port_type [1] = MLX4_PORT_TYPE_ETH;
\r
1008 g.mod_port_type [0] = MLX4_PORT_TYPE_IB;
\r
1009 g.mod_port_type [1] = MLX4_PORT_TYPE_IB;
\r
1013 WdfRegistryClose(hKey);
\r
1014 status = STATUS_SUCCESS;
\r
1022 IN PDRIVER_OBJECT DriverObject,
\r
1023 IN PUNICODE_STRING RegistryPath
\r
1026 Routine Description:
\r
1028 Initialize the call backs structure of Driver Framework.
\r
1032 DriverObject - pointer to the driver object
\r
1034 RegistryPath - pointer to a unicode string representing the path,
\r
1035 to driver-specific key in the registry.
\r
1044 WDF_DRIVER_CONFIG config;
\r
1046 WDFDRIVER hDriver;
\r
1048 #if defined(EVENT_TRACING)
\r
1049 WPP_INIT_TRACING(DriverObject, RegistryPath);
\r
1053 // global initializations
\r
1054 g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = TRACE_LEVEL_VERBOSE;
\r
1055 g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = 0xffff;
\r
1057 MLX4_ENTER(MLX4_DBG_DRV);
\r
1058 MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV,
\r
1059 ("Built %s %s, Version %s, RelDate %s\n",
\r
1060 __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE));
\r
1063 err = core_init();
\r
1065 status = errno_to_ntstatus(err);
\r
1070 // Initiialize driver config to control the attributes that
\r
1071 // are global to the driver. Note that framework by default
\r
1072 // provides a driver unload routine. If you create any resources
\r
1073 // in the DriverEntry and want to be cleaned in driver unload,
\r
1074 // you can override that by specifing one in the Config structure.
\r
1077 WDF_DRIVER_CONFIG_INIT(
\r
1078 &config, EvtDeviceAdd );
\r
1079 config.EvtDriverUnload = EvtDriverUnload;
\r
1082 // Create a framework driver object to represent our driver.
\r
1084 status = WdfDriverCreate(DriverObject,
\r
1085 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
\r
1086 &config, &hDriver);
\r
1088 if (!NT_SUCCESS(status)) {
\r
1089 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status));
\r
1094 // read registry parameters
\r
1096 status = __read_registry(&hDriver);
\r
1098 // we don't matter the failure in the work with Registry
\r
1099 status = STATUS_SUCCESS;
\r
1102 MLX4_EXIT( MLX4_DBG_DRV );
\r