[MLX4] fixed incorrect mlx4\kernel\bus\ib module initialization, which caused BSOD...
[mirror/winof/.git] / hw / mlx4 / kernel / bus / drv / drv.c
1 /*++\r
2 \r
3 Copyright (c) 2003  Microsoft Corporation All Rights Reserved\r
4 \r
5 Module Name:\r
6 \r
7     BUSENUM.C\r
8 \r
9 Abstract:\r
10 \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
14 \r
15 Environment:\r
16 \r
17     kernel mode only\r
18 \r
19 --*/\r
20 \r
21 #include "precomp.h"\r
22 #include <initguid.h>\r
23 #include <wdmguid.h>\r
24 \r
25 #if defined(EVENT_TRACING)\r
26 #include "drv.tmh"\r
27 #endif \r
28 \r
29 #ifdef ALLOC_PRAGMA\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
37 #endif\r
38 \r
39 #define DRV_VERSION     "1.0"\r
40 #define DRV_RELDATE     "02/01/2008"\r
41 \r
42 GLOBALS g = {0};\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
47 \r
48 #ifndef USE_WDM_INTERRUPTS\r
49 \r
50 typedef struct {\r
51         int                                     int_num;\r
52         PFDO_DEVICE_DATA        p_fdo;\r
53         struct mlx4_eq *        eq;\r
54 } INTERRUPT_DATA, *PINTERRUPT_DATA;\r
55 \r
56 WDF_DECLARE_CONTEXT_TYPE(INTERRUPT_DATA);\r
57 \r
58 NTSTATUS    \r
59 EvtEnableInterrupt(     \r
60         IN WDFINTERRUPT  Interrupt,\r
61         IN WDFDEVICE  AssociatedDevice\r
62         )\r
63 {\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
69 }\r
70 \r
71 NTSTATUS\r
72 EvtDisableInterrupt (\r
73         IN WDFINTERRUPT  Interrupt,\r
74         IN WDFDEVICE  AssociatedDevice\r
75         )\r
76 {\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
82 }\r
83 \r
84 BOOLEAN\r
85 EvtInterruptIsr(\r
86         IN WDFINTERRUPT  Interrupt,\r
87         IN ULONG  MessageID\r
88         )\r
89 {\r
90         BOOLEAN isr_handled = FALSE;\r
91         PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( Interrupt, INTERRUPT_DATA );\r
92 \r
93         UNUSED_PARAM(MessageID);\r
94 \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
98         \r
99         return isr_handled;\r
100 }\r
101 \r
102 #endif\r
103 \r
104 NTSTATUS\r
105 __create_child(\r
106         __in WDFDEVICE  Device,\r
107         __in PWCHAR     HardwareIds,\r
108         __in PWCHAR     DeviceDescription,\r
109         __in ULONG      SerialNo\r
110         )\r
111 \r
112 /*++\r
113 \r
114 Routine Description:\r
115 \r
116         The user application has told us that a new device on the bus has arrived.\r
117 \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
121 \r
122 --*/\r
123 \r
124 {\r
125         NTSTATUS                        status = STATUS_SUCCESS;\r
126         BOOLEAN                         unique = TRUE;\r
127         WDFDEVICE                       hChild;\r
128         PPDO_DEVICE_DATA        p_pdo;\r
129         PFDO_DEVICE_DATA        p_fdo;\r
130 \r
131         PAGED_CODE ();\r
132         MLX4_ENTER(MLX4_DBG_DRV);\r
133 \r
134         //\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
140         //\r
141         p_fdo = FdoGetData(Device);\r
142         hChild = NULL;\r
143 \r
144         //\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
150         //\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
155         //\r
156         // We must use a passive level lock because you can only call WdfDeviceCreate\r
157         // at PASSIVE_LEVEL.\r
158         //\r
159         WdfWaitLockAcquire(p_fdo->ChildLock, NULL);\r
160         WdfFdoLockStaticChildListForIteration(Device);\r
161 \r
162         while ((hChild = WdfFdoRetrieveNextStaticChild(Device,\r
163                 hChild, WdfRetrieveAddedChildren)) != NULL) {\r
164                 //\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
167                 //\r
168                 // A surprise removed child will not be returned in this list.\r
169                 //\r
170                 p_pdo = PdoGetData(hChild);\r
171                 p_pdo->PdoDevice = hChild;\r
172                 p_pdo->p_fdo = p_fdo;\r
173 \r
174                 //\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
179                 //\r
180                 if (SerialNo == p_pdo->SerialNo) {\r
181                 unique = FALSE;\r
182                 status = STATUS_INVALID_PARAMETER;\r
183                 break;\r
184                 }\r
185         }\r
186 \r
187         if (unique) {\r
188                 //\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
192                 //\r
193                 status = create_pdo(Device, HardwareIds, DeviceDescription, SerialNo);\r
194         }\r
195 \r
196         WdfFdoUnlockStaticChildListFromIteration(Device);\r
197         WdfWaitLockRelease(p_fdo->ChildLock);\r
198 \r
199         MLX4_EXIT( MLX4_DBG_DRV );\r
200         return status;\r
201 }\r
202 \r
203 NTSTATUS\r
204 __do_static_enumeration(\r
205         IN WDFDEVICE Device\r
206         )\r
207 /*++\r
208 Routine Description:\r
209 \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
213 \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
217 \r
218         You can also configure this value in the Mxe Bus Inf file.\r
219 \r
220 --*/\r
221 \r
222 {\r
223         NTSTATUS status = STATUS_SUCCESS;\r
224         int i;\r
225         int number_of_ib_ports;\r
226 \r
227         // TODO:Need to add an event log in the case of errors\r
228 \r
229         MLX4_ENTER(MLX4_DBG_DRV);\r
230 \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
236         \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
241                 }\r
242         }\r
243 \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
250                         }\r
251                 }\r
252         }\r
253 \r
254         MLX4_EXIT( MLX4_DBG_DRV );\r
255         return status;\r
256 }\r
257 \r
258 NTSTATUS\r
259 EvtDeviceD0Entry(\r
260         IN WDFDEVICE  Device,\r
261         IN WDF_POWER_DEVICE_STATE  PreviousState\r
262         )\r
263 {\r
264         NTSTATUS status = STATUS_SUCCESS;\r
265         \r
266         UNUSED_PARAM(Device);\r
267         UNUSED_PARAM(PreviousState);\r
268 \r
269         MLX4_ENTER(MLX4_DBG_DRV);\r
270 \r
271         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));\r
272 \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
276         }\r
277 \r
278         {\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
282 \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
291                         ));\r
292         }\r
293 \r
294         MLX4_EXIT( MLX4_DBG_DRV );\r
295         return STATUS_SUCCESS;\r
296 }\r
297 \r
298 NTSTATUS\r
299 EvtDeviceD0Exit(\r
300         IN WDFDEVICE  Device,\r
301         IN WDF_POWER_DEVICE_STATE  TargetState\r
302         )\r
303 {\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
310 }\r
311 \r
312 \r
313 \r
314 /* Forwards the request to the HCA's PDO. */\r
315 static \r
316 void\r
317 __put_bus_ifc(\r
318                 IN      BUS_INTERFACE_STANDARD          *pBusIfc )\r
319 {\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
324 }\r
325 \r
326 static \r
327 NTSTATUS\r
328 __get_bus_ifc(\r
329         IN                              PFDO_DEVICE_DATA const  p_fdo,\r
330         IN              const   GUID* const                             pGuid,\r
331         OUT                     BUS_INTERFACE_STANDARD  *pBusIfc )\r
332 {\r
333         NTSTATUS status;\r
334         WDFDEVICE  FdoDevice = p_fdo->FdoDevice;\r
335         MLX4_ENTER(MLX4_DBG_DRV);\r
336         \r
337         status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc,\r
338                 sizeof(BUS_INTERFACE_STANDARD), 1, NULL );\r
339         MLX4_EXIT( MLX4_DBG_DRV );\r
340         return status;\r
341 }\r
342 \r
343 static\r
344 void\r
345 __put_dma_adapter(\r
346         IN PFDO_DEVICE_DATA p_fdo,\r
347         IN PDMA_ADAPTER         p_dma )\r
348 {\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
353 }\r
354 \r
355 \r
356 // this routine releases the resources, taken in __get_resources\r
357 static\r
358 void \r
359 __put_resources(\r
360         IN PFDO_DEVICE_DATA p_fdo\r
361         )\r
362 {\r
363         struct pci_dev *pdev = &p_fdo->pci_dev;\r
364         MLX4_ENTER(MLX4_DBG_DRV);\r
365 \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
369         }\r
370 \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
374         }\r
375         MLX4_EXIT( MLX4_DBG_DRV );\r
376 }\r
377 \r
378 static\r
379 NTSTATUS \r
380 __get_dma_adapter(\r
381         IN PFDO_DEVICE_DATA p_fdo,\r
382         OUT PDMA_ADAPTER *      pp_dma )\r
383 {\r
384         NTSTATUS status;\r
385         WDF_DMA_ENABLER_CONFIG  dmaConfig;\r
386         \r
387         MLX4_ENTER(MLX4_DBG_DRV);\r
388 \r
389         WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,\r
390                 WdfDmaProfileScatterGather64, 0x80000000 - 1 );\r
391 \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
395                 return status;\r
396         }\r
397         \r
398         *pp_dma = WdfDmaEnablerWdmGetDmaAdapter( \r
399                 p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice );\r
400 \r
401         MLX4_EXIT( MLX4_DBG_DRV );\r
402         return status;\r
403 }\r
404 \r
405 // this routine fills pci_dev structure, containing all HW \r
406 // and some other necessary common resources\r
407 static\r
408 NTSTATUS \r
409 __get_resources(\r
410         IN PFDO_DEVICE_DATA p_fdo,\r
411         IN WDFCMRESLIST  ResourcesRaw,\r
412         IN WDFCMRESLIST  ResourcesTranslated\r
413         )\r
414 {\r
415         NTSTATUS status;\r
416         ULONG i, k=0;\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
421 \r
422         MLX4_ENTER(MLX4_DBG_DRV);\r
423 \r
424         //\r
425         // Get PCI BUS interface\r
426         // \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
431                 return status;\r
432         }\r
433         RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );\r
434         p_fdo->pci_bus_ifc_taken = TRUE;\r
435 \r
436         // \r
437         // get HW resources\r
438         //\r
439         for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {\r
440 \r
441                 desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );\r
442                 desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i );\r
443 \r
444                 switch (desc->Type) {\r
445 \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
453 \r
454                                 if (k < N_BARS) {\r
455                                         pdev->bar[k].phys = desc->u.Memory.Start.QuadPart;\r
456                                         pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length;\r
457                                 }\r
458                                 k++;\r
459                                 break;\r
460 \r
461 #ifdef USE_WDM_INTERRUPTS\r
462                         case CmResourceTypeInterrupt:\r
463                                 pdev->int_info = *desc;\r
464                                 break;\r
465 #endif\r
466 \r
467                         default:\r
468                                 //\r
469                                 // Ignore all other descriptors.\r
470                                 //\r
471                                 break;\r
472                 }\r
473         }\r
474         if (i ==0) {\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
478         }\r
479 \r
480         //\r
481         // get uplink info. \r
482         //\r
483         status = pci_save_config( &pdev->bus_pci_ifc, &pdev->pci_cfg_space);\r
484         if( !NT_SUCCESS( status ) )\r
485         {\r
486                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
487                         ("Failed to save HCA config: status=0x%x\n", status));\r
488                 goto err;\r
489         }\r
490         pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info );\r
491 \r
492         //\r
493         // allocate DMA adapter\r
494         //\r
495         status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter );\r
496         if( !NT_SUCCESS( status ) )\r
497         {\r
498                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
499                         ("Failed to get DMA adapter: status=0x%x\n", status));\r
500                 goto err;\r
501         }\r
502         p_fdo->dma_adapter_taken = TRUE;\r
503         \r
504         //\r
505         // fill more fields in pci_dev\r
506         //\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
510         \r
511         MLX4_EXIT( MLX4_DBG_DRV );\r
512         return STATUS_SUCCESS;\r
513 err:\r
514         __put_resources(p_fdo);\r
515         MLX4_EXIT( MLX4_DBG_DRV );\r
516         return status;\r
517 }\r
518 \r
519 \r
520 NTSTATUS\r
521 EvtPrepareHardware(\r
522         IN WDFDEVICE  Device,\r
523         IN WDFCMRESLIST  ResourcesRaw,\r
524         IN WDFCMRESLIST  ResourcesTranslated\r
525         )\r
526 {\r
527 #ifndef USE_WDM_INTERRUPTS\r
528         int i;\r
529 #endif\r
530         int err;\r
531         NTSTATUS status;\r
532         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
533         struct pci_dev *pdev = &p_fdo->pci_dev;\r
534 \r
535         MLX4_ENTER(MLX4_DBG_DRV);\r
536 \r
537         // get resources\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
541                 goto err;\r
542         }\r
543 \r
544         // enable the card\r
545         status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );\r
546         if( !NT_SUCCESS( status ) ) \r
547                 goto err;\r
548 \r
549         //\r
550         // init the card\r
551         //\r
552 \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
557 #endif  \r
558 \r
559         // NET library\r
560         err = mlx4_init_one( &p_fdo->pci_dev );\r
561         if (err) {\r
562                 status = errno_to_ntstatus(err);\r
563                 goto err;\r
564         }\r
565 \r
566 #ifndef USE_WDM_INTERRUPTS\r
567         //\r
568         // complete filling interrupt context (for more efficiency)\r
569         //\r
570         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
571                 struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );\r
572                 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( \r
573                         p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );\r
574 \r
575                 p_isr_ctx->eq = &priv->eq_table.eq[i];\r
576         }\r
577 #endif\r
578 \r
579         //\r
580         // prepare MLX4 IB interface\r
581         //\r
582 \r
583         // fill the header\r
584         p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE);\r
585         p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION;\r
586         // Let the framework handle reference counting.\r
587         p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
588         p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
589 \r
590         p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;\r
591         p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
592         p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;\r
593         p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
594 \r
595         status = STATUS_SUCCESS;\r
596         \r
597 err:\r
598         MLX4_EXIT( MLX4_DBG_DRV );\r
599         return status;\r
600 }\r
601 \r
602 NTSTATUS\r
603 EvtReleaseHardware(\r
604         IN WDFDEVICE  Device,\r
605         IN WDFCMRESLIST  ResourcesTranslated\r
606         )\r
607 {\r
608         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
609 \r
610         UNUSED_PARAM(ResourcesTranslated);\r
611 \r
612         MLX4_ENTER(MLX4_DBG_DRV);\r
613 \r
614         mlx4_remove_one( &p_fdo->pci_dev );\r
615         __put_resources( p_fdo );\r
616 \r
617         MLX4_EXIT( MLX4_DBG_DRV );\r
618         return STATUS_SUCCESS;\r
619 }\r
620 \r
621 #ifndef USE_WDM_INTERRUPTS\r
622 \r
623 static\r
624 NTSTATUS \r
625 __create_interrupt(\r
626         IN WDFDEVICE                            device,\r
627         IN int                                          int_num,\r
628         IN PFN_WDF_INTERRUPT_ISR        isr,\r
629         IN PFN_WDF_INTERRUPT_DPC        dpc,\r
630         IN PFDO_DEVICE_DATA                     p_fdo,\r
631         OUT WDFINTERRUPT                *       p_int_obj\r
632         )\r
633 {\r
634         NTSTATUS Status;\r
635 \r
636         WDF_INTERRUPT_CONFIG  interruptConfig;\r
637         WDF_OBJECT_ATTRIBUTES  interruptAttributes;\r
638         PINTERRUPT_DATA p_isr_ctx;\r
639 \r
640         MLX4_ENTER(MLX4_DBG_DRV);\r
641 \r
642         WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );\r
643         \r
644         interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;\r
645         interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;\r
646         \r
647         \r
648         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( \r
649                 &interruptAttributes, INTERRUPT_DATA );\r
650 \r
651         Status = WdfInterruptCreate( device,\r
652                 &interruptConfig, &interruptAttributes, p_int_obj );\r
653 \r
654         p_isr_ctx = WdfObjectGetTypedContext( *p_int_obj, INTERRUPT_DATA );\r
655         p_isr_ctx->int_num = int_num;\r
656         p_isr_ctx->p_fdo = p_fdo;\r
657         p_isr_ctx->eq = NULL;\r
658 \r
659         // one can call WdfInterruptSetPolicy() to set the policy, affinity etc\r
660 \r
661         MLX4_EXIT( MLX4_DBG_DRV );\r
662         return Status;\r
663 }\r
664 \r
665 #endif\r
666 \r
667 inline void InitBusIsr(\r
668      struct VipBusIfc* pVipBusIfc\r
669     )\r
670 {\r
671     memset(pVipBusIfc, 0, sizeof(struct VipBusIfc));\r
672     KeInitializeEvent(&pVipBusIfc->NicData.ConfigChangeEvent, SynchronizationEvent, TRUE);\r
673 }\r
674 \r
675 NTSTATUS\r
676 EvtDeviceAdd(\r
677         IN WDFDRIVER        Driver,\r
678         IN PWDFDEVICE_INIT  DeviceInit\r
679         )\r
680 /*++\r
681 Routine Description:\r
682 \r
683         EvtDeviceAdd is called by the framework in response to AddDevice\r
684         call from the PnP manager. We create and initialize a device object to\r
685         represent a new instance of mxe bus.\r
686 \r
687 Arguments:\r
688 \r
689         Driver - Handle to a framework driver object created in DriverEntry\r
690 \r
691         DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
692 \r
693 Return Value:\r
694 \r
695         NTSTATUS\r
696 \r
697 --*/\r
698 {\r
699 #ifndef USE_WDM_INTERRUPTS\r
700         int i;\r
701 #endif\r
702         WDF_OBJECT_ATTRIBUTES                   attributes;\r
703         NTSTATUS                                                status;\r
704         WDFDEVICE                                               device;\r
705         PFDO_DEVICE_DATA                                p_fdo;\r
706         PNP_BUS_INFORMATION                             busInfo;\r
707         WDF_PNPPOWER_EVENT_CALLBACKS    Callbacks;\r
708 \r
709         UNREFERENCED_PARAMETER(Driver);\r
710 \r
711         PAGED_CODE ();\r
712         MLX4_ENTER(MLX4_DBG_DRV);\r
713 \r
714         //\r
715         // register PnP & Power stuff\r
716         //\r
717         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);\r
718         Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware;\r
719         Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;\r
720         Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;\r
721         Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;\r
722 \r
723         WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );\r
724         \r
725         //\r
726         // Initialize all the properties specific to the device.\r
727         // Framework has default values for the one that are not\r
728         // set explicitly here. So please read the doc and make sure\r
729         // you are okay with the defaults.\r
730         //\r
731         WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
732         WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r
733 \r
734         //\r
735         // Initialize attributes structure to specify size and accessor function\r
736         // for storing device context.\r
737         //\r
738         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);\r
739 \r
740         //\r
741         // Create a framework device object. In response to this call, framework\r
742         // creates a WDM deviceobject.\r
743         //\r
744         status = WdfDeviceCreate(&DeviceInit, &attributes, &device);\r
745         if (!NT_SUCCESS(status)) {\r
746                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
747                         ("WdfDeviceCreate failed with 0x%x\n", status));\r
748                 goto end;\r
749         }\r
750 \r
751         //\r
752         // Get the device context.\r
753         //\r
754         p_fdo = FdoGetData(device);\r
755         RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
756         p_fdo->FdoDevice = device;\r
757 \r
758     //\r
759     // Init the BusIsr data\r
760     //\r
761     InitBusIsr(&p_fdo->mtnic_Ifc);\r
762 \r
763         //\r
764         // Init the BusIsr data\r
765         //\r
766         InitBusIsr(&p_fdo->mtnic_Ifc);\r
767 \r
768         //\r
769         // Purpose of this lock is documented in PlugInDevice routine below.\r
770         //\r
771         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r
772         attributes.ParentObject = device;\r
773         status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock);\r
774         if (!NT_SUCCESS(status)) {\r
775                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
776                         ("WdfWaitLockCreate failed with 0x%x\n", status));\r
777                 goto end;\r
778         }\r
779 \r
780         //\r
781         // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION\r
782         // for the child devices. This is an optional information provided to\r
783         // uniquely identify the bus the device is connected.\r
784         //\r
785         busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;\r
786         busInfo.LegacyBusType = PNPBus;\r
787         busInfo.BusNumber = 0;\r
788 \r
789         WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
790 \r
791         //\r
792         // WMI\r
793         //\r
794         status = WmiRegistration(device);\r
795         if (!NT_SUCCESS(status)) {\r
796                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
797                         ("WmiRegistration failed with 0x%x\n", status));\r
798                 goto end;\r
799         }\r
800 \r
801 #ifndef USE_WDM_INTERRUPTS\r
802 \r
803         //\r
804         // create interrupt objects\r
805         //\r
806         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
807                 status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr,\r
808                         NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt );\r
809                 if (NT_SUCCESS(status)) \r
810                         p_fdo->interrupt[i].valid = TRUE;\r
811                 else {\r
812                         MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,\r
813                                 ("WdfInterruptCreate failed %#x\n", status ));\r
814                         goto end;\r
815                 }\r
816         }\r
817 \r
818 #endif\r
819 \r
820         status = STATUS_SUCCESS;\r
821 \r
822 end:    \r
823         MLX4_EXIT( MLX4_DBG_DRV );\r
824         return status;\r
825 }\r
826 \r
827 \r
828 \r
829 void\r
830 EvtDriverUnload(\r
831         IN              WDFDRIVER  Driver\r
832         )\r
833 {\r
834         MLX4_ENTER( MLX4_DBG_DRV );\r
835 \r
836         UNUSED_PARAM( Driver );\r
837 \r
838         mlx4_ib_cleanup();\r
839         core_cleanup();\r
840 \r
841         MLX4_EXIT( MLX4_DBG_DRV );\r
842 #if defined(EVENT_TRACING)\r
843         WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));\r
844 #endif\r
845 \r
846 }\r
847 \r
848 static\r
849 NTSTATUS\r
850 __read_registry(WDFDRIVER *hDriver)\r
851 {\r
852         DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");\r
853         DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");\r
854 \r
855         // "log maximum number of QPs per HCA"\r
856         DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");\r
857 \r
858         // "log number of RDMARC buffers per QP"\r
859         DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");\r
860 \r
861         // "log maximum number of SRQs per HCA"\r
862         DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");\r
863 \r
864         // "log maximum number of CQs per HCA"\r
865         DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");\r
866 \r
867         // "log maximum number of multicast groups per HCA"\r
868         DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");\r
869 \r
870         // "log maximum number of memory protection table entries per HCA"\r
871         DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");\r
872 \r
873         // "log maximum number of memory translation table segments per HCA"\r
874         DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");     \r
875 \r
876         // "Enable Quality of Service support in the HCA if > 0, (default 1)"\r
877         DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");  \r
878 \r
879         // "Maximum number of MACs per ETH port (1-127, default 1"\r
880         DECLARE_CONST_UNICODE_STRING(numMac, L"NumMac");        \r
881 \r
882         // "Maximum number of VLANs per ETH port (0-126, default 0)"\r
883         DECLARE_CONST_UNICODE_STRING(numVlan, L"NumVlan");      \r
884 \r
885         // "Enable steering by VLAN priority on ETH ports (0/1, default 0)"\r
886         DECLARE_CONST_UNICODE_STRING(usePrio, L"UsePrio");      \r
887 \r
888         // "Block multicast loopback packets if > 0 (default 1)"\r
889         DECLARE_CONST_UNICODE_STRING(BlockMcastLB, L"BlockMcastLoopBack");      \r
890 \r
891         // "Ports L2 type (ib/eth/auto, entry per port, comma seperated, default ib for all)"\r
892         DECLARE_CONST_UNICODE_STRING(PortType, L"PortType");\r
893 \r
894         \r
895         ULONG value;\r
896         WDFKEY hKey = NULL;\r
897         NTSTATUS status = STATUS_SUCCESS;\r
898 \r
899         UNICODE_STRING uvalue;\r
900 #define  MAX_UVALUE 100\r
901         WCHAR uvalue_data[MAX_UVALUE];\r
902         \r
903         status = WdfDriverOpenParametersRegistryKey( *hDriver,\r
904                 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );\r
905 \r
906         if (NT_SUCCESS (status)) {\r
907 \r
908                 //\r
909                 // Read general values\r
910                 //\r
911                 status = WdfRegistryQueryULong(hKey, &debugLevel, &value);\r
912                 if (NT_SUCCESS (status)) \r
913                         g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = value;\r
914                 \r
915                 status = WdfRegistryQueryULong(hKey, &debugFlags, &value);\r
916                 if (NT_SUCCESS (status)) \r
917                         g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = value;\r
918 \r
919                 status = WdfRegistryQueryULong(hKey, &numQp, &value);\r
920                 if (NT_SUCCESS (status)) \r
921                         g.mod_num_qp = value;\r
922 \r
923                 status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);\r
924                 if (NT_SUCCESS (status)) \r
925                         g.mod_rdmarc_per_qp = value;\r
926 \r
927                 status = WdfRegistryQueryULong(hKey, &numSrq, &value);\r
928                 if (NT_SUCCESS (status)) \r
929                         g.mod_num_srq = value;\r
930 \r
931                 status = WdfRegistryQueryULong(hKey, &numCq, &value);\r
932                 if (NT_SUCCESS (status)) \r
933                         g.mod_num_cq = value;\r
934 \r
935                 status = WdfRegistryQueryULong(hKey, &numMcg, &value);\r
936                 if (NT_SUCCESS (status)) \r
937                         g.mod_num_mcg = value;\r
938 \r
939                 status = WdfRegistryQueryULong(hKey, &numMpt, &value);\r
940                 if (NT_SUCCESS (status)) \r
941                         g.mod_num_mpt = value;\r
942                 \r
943                 status = WdfRegistryQueryULong(hKey, &numMtt, &value);\r
944                 if (NT_SUCCESS (status)) \r
945                         g.mod_num_mtt = value;\r
946 \r
947                 status = WdfRegistryQueryULong(hKey, &enableQoS, &value);\r
948                 if (NT_SUCCESS (status)) \r
949                         g.mod_enable_qos = value;\r
950                 else\r
951                         g.mod_enable_qos = 1;\r
952 \r
953                 status = WdfRegistryQueryULong(hKey, &numMac, &value);\r
954                 if (NT_SUCCESS (status)) \r
955                         g.mod_num_mac = value;\r
956                 else\r
957                         g.mod_num_mac = 1;\r
958 \r
959                 status = WdfRegistryQueryULong(hKey, &numVlan, &value);\r
960                 if (NT_SUCCESS (status)) \r
961                         g.mod_num_vlan= value;\r
962                 else\r
963                         g.mod_num_vlan = 0;\r
964 \r
965                 status = WdfRegistryQueryULong(hKey, &usePrio, &value);\r
966                 if (NT_SUCCESS (status)) \r
967                         g.mod_use_prio= value;\r
968                 else\r
969                         g.mod_use_prio = 0;\r
970 \r
971                 status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value);\r
972                 if (NT_SUCCESS (status)) \r
973                         g.mod_mlx4_blck_lb = value;\r
974                 else\r
975                         g.mod_mlx4_blck_lb = 1;\r
976 \r
977                 uvalue.Buffer = uvalue_data;\r
978                 uvalue.MaximumLength = MAX_UVALUE;\r
979                 uvalue.Length = 0;\r
980 \r
981                 status = WdfRegistryQueryUnicodeString(hKey, &PortType, NULL, &uvalue);\r
982                 if (NT_SUCCESS (status)) {\r
983                         if (!wcscmp(uvalue_data, L"ib,ib")) {\r
984                                 g.mod_port_type [0] = MLX4_PORT_TYPE_IB;\r
985                                 g.mod_port_type [1] = MLX4_PORT_TYPE_IB;\r
986                         } else\r
987                         if (!wcscmp(uvalue_data, L"ib,eth")) {\r
988                                 g.mod_port_type [0] = MLX4_PORT_TYPE_IB;\r
989                                 g.mod_port_type [1] = MLX4_PORT_TYPE_ETH;\r
990                         } else\r
991                         if (!wcscmp(uvalue_data, L"eth,ib")) {\r
992                                 g.mod_port_type [0] = MLX4_PORT_TYPE_ETH;\r
993                                 g.mod_port_type [1] = MLX4_PORT_TYPE_IB;\r
994                         } else\r
995                         if (!wcscmp(uvalue_data, L"eth,eth")) {\r
996                                 g.mod_port_type [0] = MLX4_PORT_TYPE_ETH;\r
997                                 g.mod_port_type [1] = MLX4_PORT_TYPE_ETH;\r
998                         }\r
999                 }\r
1000                 else {\r
1001                         g.mod_port_type [0] = MLX4_PORT_TYPE_IB;\r
1002                         g.mod_port_type [1] = MLX4_PORT_TYPE_IB;\r
1003                 }\r
1004 \r
1005 \r
1006                 WdfRegistryClose(hKey);\r
1007                 status = STATUS_SUCCESS;\r
1008         }\r
1009 \r
1010         return status;\r
1011 }\r
1012 \r
1013 NTSTATUS\r
1014 DriverEntry(\r
1015         IN PDRIVER_OBJECT DriverObject,\r
1016         IN PUNICODE_STRING RegistryPath\r
1017         )\r
1018 /*++\r
1019 Routine Description:\r
1020 \r
1021         Initialize the call backs structure of Driver Framework.\r
1022 \r
1023 Arguments:\r
1024 \r
1025         DriverObject - pointer to the driver object\r
1026 \r
1027         RegistryPath - pointer to a unicode string representing the path,\r
1028                                 to driver-specific key in the registry.\r
1029 \r
1030 Return Value:\r
1031 \r
1032   NT Status Code\r
1033 \r
1034 --*/\r
1035 {\r
1036         int err;\r
1037         WDF_DRIVER_CONFIG   config;\r
1038         NTSTATUS            status;\r
1039         WDFDRIVER hDriver;\r
1040 \r
1041 #if defined(EVENT_TRACING)\r
1042         WPP_INIT_TRACING(DriverObject, RegistryPath);\r
1043 #endif\r
1044 \r
1045 \r
1046         // global initializations\r
1047         g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = TRACE_LEVEL_VERBOSE;\r
1048         g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = 0xffff;\r
1049 \r
1050         MLX4_ENTER(MLX4_DBG_DRV);\r
1051         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, \r
1052                 ("Built %s %s, Version %s, RelDate %s\n", \r
1053                 __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE));\r
1054 \r
1055         mlx4_net_init();\r
1056         err = core_init();\r
1057         if (err) {\r
1058                 status = errno_to_ntstatus(err);\r
1059                 goto end;\r
1060         }\r
1061         err = mlx4_ib_init();\r
1062         if (err) {\r
1063                 status = errno_to_ntstatus(err);\r
1064                 goto end;\r
1065         }\r
1066 \r
1067         //\r
1068         // Initiialize driver config to control the attributes that\r
1069         // are global to the driver. Note that framework by default\r
1070         // provides a driver unload routine. If you create any resources\r
1071         // in the DriverEntry and want to be cleaned in driver unload,\r
1072         // you can override that by specifing one in the Config structure.\r
1073         //\r
1074 \r
1075         WDF_DRIVER_CONFIG_INIT(\r
1076                 &config, EvtDeviceAdd );\r
1077         config.EvtDriverUnload = EvtDriverUnload;\r
1078 \r
1079         //\r
1080         // Create a framework driver object to represent our driver.\r
1081         //\r
1082         status = WdfDriverCreate(DriverObject,\r
1083                 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
1084                 &config, &hDriver);\r
1085 \r
1086         if (!NT_SUCCESS(status)) {\r
1087                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status));\r
1088                 goto end;\r
1089         }\r
1090 \r
1091         //\r
1092         // read registry parameters\r
1093         //\r
1094         status = __read_registry(&hDriver);\r
1095 \r
1096         // we don't matter the failure in the work with Registry\r
1097         status = STATUS_SUCCESS;\r
1098         \r
1099 end:\r
1100         MLX4_EXIT( MLX4_DBG_DRV );\r
1101         return status;\r
1102 \r
1103 }\r
1104 \r
1105 \r
1106 \r