[mlx4] Added the latest revision of the mlx4 to the trunk.
[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 ULONG      SerialNo\r
109         )\r
110 \r
111 /*++\r
112 \r
113 Routine Description:\r
114 \r
115         The user application has told us that a new device on the bus has arrived.\r
116 \r
117         We therefore need to create a new PDO, initialize it, add it to the list\r
118         of PDOs for this FDO bus, and then tell Plug and Play that all of this\r
119         happened so that it will start sending prodding IRPs.\r
120 \r
121 --*/\r
122 \r
123 {\r
124         NTSTATUS                        status = STATUS_SUCCESS;\r
125         BOOLEAN                         unique = TRUE;\r
126         WDFDEVICE                       hChild;\r
127         PPDO_DEVICE_DATA        p_pdo;\r
128         PFDO_DEVICE_DATA        p_fdo;\r
129 \r
130         PAGED_CODE ();\r
131         MLX4_ENTER(MLX4_DBG_DRV);\r
132 \r
133         //\r
134         // First make sure that we don't already have another device with the\r
135         // same serial number.\r
136         // Framework creates a collection of all the child devices we have\r
137         // created so far. So acquire the handle to the collection and lock\r
138         // it before walking the item.\r
139         //\r
140         p_fdo = FdoGetData(Device);\r
141         hChild = NULL;\r
142 \r
143         //\r
144         // We need an additional lock to synchronize addition because\r
145         // WdfFdoLockStaticChildListForIteration locks against anyone immediately\r
146         // updating the static child list (the changes are put on a queue until the\r
147         // list has been unlocked).  This type of lock does not enforce our concept\r
148         // of unique IDs on the bus (ie SerialNo).\r
149         //\r
150         // Without our additional lock, 2 threads could execute this function, both\r
151         // find that the requested SerialNo is not in the list and attempt to add\r
152         // it.  If that were to occur, 2 PDOs would have the same unique SerialNo,\r
153         // which is incorrect.\r
154         //\r
155         // We must use a passive level lock because you can only call WdfDeviceCreate\r
156         // at PASSIVE_LEVEL.\r
157         //\r
158         WdfWaitLockAcquire(p_fdo->ChildLock, NULL);\r
159         WdfFdoLockStaticChildListForIteration(Device);\r
160 \r
161         while ((hChild = WdfFdoRetrieveNextStaticChild(Device,\r
162                 hChild, WdfRetrieveAddedChildren)) != NULL) {\r
163                 //\r
164                 // WdfFdoRetrieveNextStaticChild returns reported and to be reported\r
165                 // children (ie children who have been added but not yet reported to PNP).\r
166                 //\r
167                 // A surprise removed child will not be returned in this list.\r
168                 //\r
169                 p_pdo = PdoGetData(hChild);\r
170                 p_pdo->PdoDevice = hChild;\r
171                 p_pdo->p_fdo = p_fdo;\r
172 \r
173                 //\r
174                 // It's okay to plug in another device with the same serial number\r
175                 // as long as the previous one is in a surprise-removed state. The\r
176                 // previous one would be in that state after the device has been\r
177                 // physically removed, if somebody has an handle open to it.\r
178                 //\r
179                 if (SerialNo == p_pdo->SerialNo) {\r
180                 unique = FALSE;\r
181                 status = STATUS_INVALID_PARAMETER;\r
182                 break;\r
183                 }\r
184         }\r
185 \r
186         if (unique) {\r
187                 //\r
188                 // Create a new child device.  It is OK to create and add a child while\r
189                 // the list locked for enumeration.  The enumeration lock applies only\r
190                 // to enumeration, not addition or removal.\r
191                 //\r
192                 status = create_pdo(Device, HardwareIds, SerialNo);\r
193         }\r
194 \r
195         WdfFdoUnlockStaticChildListFromIteration(Device);\r
196         WdfWaitLockRelease(p_fdo->ChildLock);\r
197 \r
198         MLX4_EXIT( MLX4_DBG_DRV );\r
199         return status;\r
200 }\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;\r
224 \r
225         MLX4_ENTER(MLX4_DBG_DRV);\r
226 \r
227         // eventually we'll have all information about children in Registry\r
228         // DriverEntry will read it into a Global storage and\r
229         // this routine will create all the children on base on this info\r
230 \r
231         status = __create_child(Device, BUS_HARDWARE_IDS, 0 );\r
232 \r
233         MLX4_EXIT( MLX4_DBG_DRV );\r
234         return status;\r
235 }\r
236 \r
237 NTSTATUS\r
238 EvtDeviceD0Entry(\r
239         IN WDFDEVICE  Device,\r
240         IN WDF_POWER_DEVICE_STATE  PreviousState\r
241         )\r
242 {\r
243         NTSTATUS status = STATUS_SUCCESS;\r
244         \r
245         UNUSED_PARAM(Device);\r
246         UNUSED_PARAM(PreviousState);\r
247 \r
248         MLX4_ENTER(MLX4_DBG_DRV);\r
249 \r
250         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));\r
251 \r
252         status = __do_static_enumeration(Device);\r
253         if (!NT_SUCCESS(status)) {\r
254                  MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("DoStaticEnumeration failed with 0x%x\n", status));\r
255         }\r
256 \r
257         {\r
258                 PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
259                 struct pci_dev *pdev    = &p_fdo->pci_dev;\r
260                 struct mlx4_dev *mdev   = pdev->dev;\r
261 \r
262                 MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,\r
263                         ("Ven %x Dev %d Fw %d.%d.%d Drv %s (%s), BD %s\n", \r
264                         (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,\r
265                         (int) (mdev->caps.fw_ver >> 32),\r
266                         (int) (mdev->caps.fw_ver >> 16) & 0xffff, \r
267                         (int) (mdev->caps.fw_ver & 0xffff),\r
268                         DRV_VERSION, DRV_RELDATE, \r
269                         mlx4_is_livefish(mdev) ? "Y" : "N"\r
270                         ));\r
271         }\r
272 \r
273         MLX4_EXIT( MLX4_DBG_DRV );\r
274         return STATUS_SUCCESS;\r
275 }\r
276 \r
277 NTSTATUS\r
278 EvtDeviceD0Exit(\r
279         IN WDFDEVICE  Device,\r
280         IN WDF_POWER_DEVICE_STATE  TargetState\r
281         )\r
282 {\r
283         UNUSED_PARAM(Device);\r
284         UNUSED_PARAM(TargetState);\r
285         MLX4_ENTER(MLX4_DBG_DRV);\r
286         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState));\r
287         MLX4_EXIT( MLX4_DBG_DRV );\r
288         return STATUS_SUCCESS;\r
289 }\r
290 \r
291 \r
292 \r
293 /* Forwards the request to the HCA's PDO. */\r
294 static \r
295 void\r
296 __put_bus_ifc(\r
297                 IN      BUS_INTERFACE_STANDARD          *pBusIfc )\r
298 {\r
299         MLX4_ENTER(MLX4_DBG_DRV);\r
300         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("pBusIfc=0x%p\n", pBusIfc));\r
301         pBusIfc->InterfaceDereference( pBusIfc->Context );\r
302         MLX4_EXIT( MLX4_DBG_DRV );\r
303 }\r
304 \r
305 static \r
306 NTSTATUS\r
307 __get_bus_ifc(\r
308         IN                              PFDO_DEVICE_DATA const  p_fdo,\r
309         IN              const   GUID* const                             pGuid,\r
310         OUT                     BUS_INTERFACE_STANDARD  *pBusIfc )\r
311 {\r
312         NTSTATUS status;\r
313         WDFDEVICE  FdoDevice = p_fdo->FdoDevice;\r
314         MLX4_ENTER(MLX4_DBG_DRV);\r
315         \r
316         status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc,\r
317                 sizeof(BUS_INTERFACE_STANDARD), 1, NULL );\r
318         MLX4_EXIT( MLX4_DBG_DRV );\r
319         return status;\r
320 }\r
321 \r
322 static\r
323 void\r
324 __put_dma_adapter(\r
325         IN PFDO_DEVICE_DATA p_fdo,\r
326         IN PDMA_ADAPTER         p_dma )\r
327 {\r
328         UNUSED_PARAM(p_fdo);\r
329         UNUSED_PARAM(p_dma);\r
330         MLX4_ENTER(MLX4_DBG_DRV);\r
331         MLX4_EXIT( MLX4_DBG_DRV );\r
332 }\r
333 \r
334 \r
335 // this routine releases the resources, taken in __get_resources\r
336 static\r
337 void \r
338 __put_resources(\r
339         IN PFDO_DEVICE_DATA p_fdo\r
340         )\r
341 {\r
342         struct pci_dev *pdev = &p_fdo->pci_dev;\r
343         MLX4_ENTER(MLX4_DBG_DRV);\r
344 \r
345         if (p_fdo->dma_adapter_taken) {\r
346                 p_fdo->dma_adapter_taken = FALSE;\r
347                 __put_dma_adapter( p_fdo, pdev->p_dma_adapter );\r
348         }\r
349 \r
350         if (p_fdo->pci_bus_ifc_taken) {\r
351                 p_fdo->pci_bus_ifc_taken = FALSE;\r
352                 __put_bus_ifc(&pdev->bus_pci_ifc);\r
353         }\r
354         MLX4_EXIT( MLX4_DBG_DRV );\r
355 }\r
356 \r
357 static\r
358 NTSTATUS \r
359 __get_dma_adapter(\r
360         IN PFDO_DEVICE_DATA p_fdo,\r
361         OUT PDMA_ADAPTER *      pp_dma )\r
362 {\r
363         NTSTATUS status;\r
364         WDF_DMA_ENABLER_CONFIG  dmaConfig;\r
365         \r
366         MLX4_ENTER(MLX4_DBG_DRV);\r
367 \r
368         WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,\r
369                 WdfDmaProfileScatterGather64, 0x80000000 - 1 );\r
370 \r
371         status = WdfDmaEnablerCreate( p_fdo->FdoDevice,\r
372                 &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &p_fdo->dma_enabler );\r
373         if (!NT_SUCCESS (status)) {\r
374                 return status;\r
375         }\r
376         \r
377         *pp_dma = WdfDmaEnablerWdmGetDmaAdapter( \r
378                 p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice );\r
379 \r
380         MLX4_EXIT( MLX4_DBG_DRV );\r
381         return status;\r
382 }\r
383 \r
384 // this routine fills pci_dev structure, containing all HW \r
385 // and some other necessary common resources\r
386 static\r
387 NTSTATUS \r
388 __get_resources(\r
389         IN PFDO_DEVICE_DATA p_fdo,\r
390         IN WDFCMRESLIST  ResourcesRaw,\r
391         IN WDFCMRESLIST  ResourcesTranslated\r
392         )\r
393 {\r
394         NTSTATUS status;\r
395         ULONG i, k=0;\r
396         PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc;\r
397         PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc_raw;\r
398         BUS_INTERFACE_STANDARD  bus_pci_ifc;\r
399         struct pci_dev *pdev = &p_fdo->pci_dev;\r
400 \r
401         MLX4_ENTER(MLX4_DBG_DRV);\r
402 \r
403         //\r
404         // Get PCI BUS interface\r
405         // \r
406         status = __get_bus_ifc( p_fdo, &GUID_BUS_INTERFACE_STANDARD, &bus_pci_ifc );\r
407         if( !NT_SUCCESS( status ) ) {\r
408                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
409                         ("failed: status=0x%x\n", status));\r
410                 return status;\r
411         }\r
412         RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );\r
413         p_fdo->pci_bus_ifc_taken = TRUE;\r
414 \r
415         // \r
416         // get HW resources\r
417         //\r
418         for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {\r
419 \r
420                 desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );\r
421                 desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i );\r
422 \r
423                 switch (desc->Type) {\r
424 \r
425                         case CmResourceTypeMemory:\r
426                                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
427                                         ("EvtPrepareHardware(Raw): Desc %d: Memory: Start %#I64x, Length %#x\n", \r
428                                         i, desc_raw->u.Memory.Start.QuadPart, desc_raw->u.Memory.Length ));\r
429                                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
430                                         ("EvtPrepareHardware: Desc %d: Memory: Start %#I64x, Length %#x\n", \r
431                                         i, desc->u.Memory.Start.QuadPart, desc->u.Memory.Length ));\r
432 \r
433                                 if (k < N_BARS) {\r
434                                         pdev->bar[k].phys = desc->u.Memory.Start.QuadPart;\r
435                                         pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length;\r
436                                 }\r
437                                 k++;\r
438                                 break;\r
439 \r
440 #ifdef USE_WDM_INTERRUPTS\r
441                         case CmResourceTypeInterrupt:\r
442                                 pdev->int_info = *desc;\r
443                                 break;\r
444 #endif\r
445 \r
446                         default:\r
447                                 //\r
448                                 // Ignore all other descriptors.\r
449                                 //\r
450                                 break;\r
451                 }\r
452         }\r
453         if (i ==0) {\r
454                 // This means that no resources are found\r
455                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("WdfCmResourceListGetCount: returned 0, quiting\n"));\r
456                 return STATUS_INSUFFICIENT_RESOURCES;\r
457         }\r
458 \r
459         //\r
460         // get uplink info. \r
461         //\r
462         status = pci_save_config( &pdev->bus_pci_ifc, &pdev->pci_cfg_space);\r
463         if( !NT_SUCCESS( status ) )\r
464         {\r
465                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
466                         ("Failed to save HCA config: status=0x%x\n", status));\r
467                 goto err;\r
468         }\r
469         pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info );\r
470 \r
471         //\r
472         // allocate DMA adapter\r
473         //\r
474         status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter );\r
475         if( !NT_SUCCESS( status ) )\r
476         {\r
477                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
478                         ("Failed to get DMA adapter: status=0x%x\n", status));\r
479                 goto err;\r
480         }\r
481         p_fdo->dma_adapter_taken = TRUE;\r
482         \r
483         //\r
484         // fill more fields in pci_dev\r
485         //\r
486         pdev->ven_id = pdev->pci_cfg_space.VendorID;\r
487         pdev->dev_id = pdev->pci_cfg_space.DeviceID;\r
488         pdev->p_self_do = WdfDeviceWdmGetDeviceObject(p_fdo->FdoDevice);\r
489         \r
490         MLX4_EXIT( MLX4_DBG_DRV );\r
491         return STATUS_SUCCESS;\r
492 err:\r
493         __put_resources(p_fdo);\r
494         MLX4_EXIT( MLX4_DBG_DRV );\r
495         return status;\r
496 }\r
497 \r
498 \r
499 NTSTATUS\r
500 EvtPrepareHardware(\r
501         IN WDFDEVICE  Device,\r
502         IN WDFCMRESLIST  ResourcesRaw,\r
503         IN WDFCMRESLIST  ResourcesTranslated\r
504         )\r
505 {\r
506 #ifndef USE_WDM_INTERRUPTS\r
507         int i;\r
508 #endif\r
509         int err;\r
510         NTSTATUS status;\r
511         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
512         struct pci_dev *pdev = &p_fdo->pci_dev;\r
513 \r
514         MLX4_ENTER(MLX4_DBG_DRV);\r
515 \r
516         // get resources\r
517         status = __get_resources( p_fdo, ResourcesRaw, ResourcesTranslated );\r
518         if( !NT_SUCCESS( status ) ) {\r
519                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__get_bus_ifc failed: status=0x%x\n", status));\r
520                 goto err;\r
521         }\r
522 \r
523         // enable the card\r
524         status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );\r
525         if( !NT_SUCCESS( status ) ) \r
526                 goto err;\r
527 \r
528         //\r
529         // init the card\r
530         //\r
531 \r
532 #ifndef USE_WDM_INTERRUPTS\r
533         // enable interrupts for start up\r
534         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) \r
535                 WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);\r
536 #endif  \r
537 \r
538         // NET library\r
539         err = mlx4_init_one( &p_fdo->pci_dev );\r
540         if (err) {\r
541                 status = errno_to_ntstatus(err);\r
542                 goto err;\r
543         }\r
544 \r
545         // IB library\r
546         err = mlx4_ib_init();\r
547         if (err) {\r
548                 status = errno_to_ntstatus(err);\r
549                 goto err;\r
550         }\r
551 \r
552 #ifndef USE_WDM_INTERRUPTS\r
553         //\r
554         // complete filling interrupt context (for more efficiency)\r
555         //\r
556         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
557                 struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );\r
558                 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( \r
559                         p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );\r
560 \r
561                 p_isr_ctx->eq = &priv->eq_table.eq[i];\r
562         }\r
563 #endif\r
564 \r
565         //\r
566         // prepare MLX4 IB interface\r
567         //\r
568 \r
569         // fill the header\r
570         p_fdo->bus_ib_ifc.Size = sizeof(MLX4_BUS_IB_INTERFACE);\r
571         p_fdo->bus_ib_ifc.Version = MLX4_BUS_IB_INTERFACE_VERSION;\r
572         // Let the framework handle reference counting.\r
573         p_fdo->bus_ib_ifc.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
574         p_fdo->bus_ib_ifc.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
575 \r
576         p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;\r
577         p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
578         p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
579 \r
580         status = STATUS_SUCCESS;\r
581         \r
582 err:\r
583         MLX4_EXIT( MLX4_DBG_DRV );\r
584         return status;\r
585 }\r
586 \r
587 NTSTATUS\r
588 EvtReleaseHardware(\r
589         IN WDFDEVICE  Device,\r
590         IN WDFCMRESLIST  ResourcesTranslated\r
591         )\r
592 {\r
593         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
594 \r
595         UNUSED_PARAM(ResourcesTranslated);\r
596 \r
597         MLX4_ENTER(MLX4_DBG_DRV);\r
598 \r
599         mlx4_ib_cleanup();\r
600         mlx4_remove_one( &p_fdo->pci_dev );\r
601         __put_resources( p_fdo );\r
602 \r
603         MLX4_EXIT( MLX4_DBG_DRV );\r
604         return STATUS_SUCCESS;\r
605 }\r
606 \r
607 #ifndef USE_WDM_INTERRUPTS\r
608 \r
609 static\r
610 NTSTATUS \r
611 __create_interrupt(\r
612         IN WDFDEVICE                            device,\r
613         IN int                                          int_num,\r
614         IN PFN_WDF_INTERRUPT_ISR        isr,\r
615         IN PFN_WDF_INTERRUPT_DPC        dpc,\r
616         IN PFDO_DEVICE_DATA                     p_fdo,\r
617         OUT WDFINTERRUPT                *       p_int_obj\r
618         )\r
619 {\r
620         NTSTATUS Status;\r
621 \r
622         WDF_INTERRUPT_CONFIG  interruptConfig;\r
623         WDF_OBJECT_ATTRIBUTES  interruptAttributes;\r
624         PINTERRUPT_DATA p_isr_ctx;\r
625 \r
626         MLX4_ENTER(MLX4_DBG_DRV);\r
627 \r
628         WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );\r
629         \r
630         interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;\r
631         interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;\r
632         \r
633         \r
634         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( \r
635                 &interruptAttributes, INTERRUPT_DATA );\r
636 \r
637         Status = WdfInterruptCreate( device,\r
638                 &interruptConfig, &interruptAttributes, p_int_obj );\r
639 \r
640         p_isr_ctx = WdfObjectGetTypedContext( *p_int_obj, INTERRUPT_DATA );\r
641         p_isr_ctx->int_num = int_num;\r
642         p_isr_ctx->p_fdo = p_fdo;\r
643         p_isr_ctx->eq = NULL;\r
644 \r
645         // one can call WdfInterruptSetPolicy() to set the policy, affinity etc\r
646 \r
647         MLX4_EXIT( MLX4_DBG_DRV );\r
648         return Status;\r
649 }\r
650 \r
651 #endif\r
652 \r
653 NTSTATUS\r
654 EvtDeviceAdd(\r
655         IN WDFDRIVER        Driver,\r
656         IN PWDFDEVICE_INIT  DeviceInit\r
657         )\r
658 /*++\r
659 Routine Description:\r
660 \r
661         EvtDeviceAdd is called by the framework in response to AddDevice\r
662         call from the PnP manager. We create and initialize a device object to\r
663         represent a new instance of mxe bus.\r
664 \r
665 Arguments:\r
666 \r
667         Driver - Handle to a framework driver object created in DriverEntry\r
668 \r
669         DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
670 \r
671 Return Value:\r
672 \r
673         NTSTATUS\r
674 \r
675 --*/\r
676 {\r
677 #ifndef USE_WDM_INTERRUPTS\r
678         int i;\r
679 #endif\r
680         WDF_OBJECT_ATTRIBUTES                   attributes;\r
681         NTSTATUS                                                status;\r
682         WDFDEVICE                                               device;\r
683         PFDO_DEVICE_DATA                                p_fdo;\r
684         PNP_BUS_INFORMATION                             busInfo;\r
685         WDF_PNPPOWER_EVENT_CALLBACKS    Callbacks;\r
686 \r
687         UNREFERENCED_PARAMETER(Driver);\r
688 \r
689         PAGED_CODE ();\r
690         MLX4_ENTER(MLX4_DBG_DRV);\r
691 \r
692         //\r
693         // register PnP & Power stuff\r
694         //\r
695         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);\r
696         Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware;\r
697         Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;\r
698         Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;\r
699         Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;\r
700 \r
701         WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );\r
702         \r
703         //\r
704         // Initialize all the properties specific to the device.\r
705         // Framework has default values for the one that are not\r
706         // set explicitly here. So please read the doc and make sure\r
707         // you are okay with the defaults.\r
708         //\r
709         WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
710         WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r
711 \r
712         //\r
713         // Initialize attributes structure to specify size and accessor function\r
714         // for storing device context.\r
715         //\r
716         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);\r
717 \r
718         //\r
719         // Create a framework device object. In response to this call, framework\r
720         // creates a WDM deviceobject.\r
721         //\r
722         status = WdfDeviceCreate(&DeviceInit, &attributes, &device);\r
723         if (!NT_SUCCESS(status)) {\r
724                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
725                         ("WdfDeviceCreate failed with 0x%x\n", status));\r
726                 goto end;\r
727         }\r
728 \r
729         //\r
730         // Get the device context.\r
731         //\r
732         p_fdo = FdoGetData(device);\r
733         RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
734         p_fdo->FdoDevice = device;\r
735 \r
736         //\r
737         // Purpose of this lock is documented in PlugInDevice routine below.\r
738         //\r
739         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r
740         attributes.ParentObject = device;\r
741         status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock);\r
742         if (!NT_SUCCESS(status)) {\r
743                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
744                         ("WdfWaitLockCreate failed with 0x%x\n", status));\r
745                 goto end;\r
746         }\r
747 \r
748         //\r
749         // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION\r
750         // for the child devices. This is an optional information provided to\r
751         // uniquely identify the bus the device is connected.\r
752         //\r
753         busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;\r
754         busInfo.LegacyBusType = PNPBus;\r
755         busInfo.BusNumber = 0;\r
756 \r
757         WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
758 \r
759         //\r
760         // WMI\r
761         //\r
762         status = WmiRegistration(device);\r
763         if (!NT_SUCCESS(status)) {\r
764                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
765                         ("WmiRegistration failed with 0x%x\n", status));\r
766                 goto end;\r
767         }\r
768 \r
769 #ifndef USE_WDM_INTERRUPTS\r
770 \r
771         //\r
772         // create interrupt objects\r
773         //\r
774         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
775                 status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr,\r
776                         NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt );\r
777                 if (NT_SUCCESS(status)) \r
778                         p_fdo->interrupt[i].valid = TRUE;\r
779                 else {\r
780                         MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,\r
781                                 ("WdfInterruptCreate failed %#x\n", status ));\r
782                         goto end;\r
783                 }\r
784         }\r
785 \r
786 #endif\r
787 \r
788         status = STATUS_SUCCESS;\r
789 \r
790 end:    \r
791         MLX4_EXIT( MLX4_DBG_DRV );\r
792         return status;\r
793 }\r
794 \r
795 \r
796 \r
797 void\r
798 EvtDriverUnload(\r
799         IN              WDFDRIVER  Driver\r
800         )\r
801 {\r
802         MLX4_ENTER( MLX4_DBG_DRV );\r
803 \r
804         UNUSED_PARAM( Driver );\r
805 \r
806         core_cleanup();\r
807 \r
808         MLX4_EXIT( MLX4_DBG_DRV );\r
809 #if defined(EVENT_TRACING)\r
810         WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));\r
811 #endif\r
812 \r
813 }\r
814 \r
815 static\r
816 NTSTATUS\r
817 __read_registry(WDFDRIVER *hDriver)\r
818 {\r
819         DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");\r
820         DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");\r
821 \r
822         // "log maximum number of QPs per HCA"\r
823         DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");\r
824 \r
825         // "log number of RDMARC buffers per QP"\r
826         DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");\r
827 \r
828         // "log maximum number of SRQs per HCA"\r
829         DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");\r
830 \r
831         // "log maximum number of CQs per HCA"\r
832         DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");\r
833 \r
834         // "log maximum number of multicast groups per HCA"\r
835         DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");\r
836 \r
837         // "log maximum number of memory protection table entries per HCA"\r
838         DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");\r
839 \r
840         // "log maximum number of memory translation table segments per HCA"\r
841         DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");     \r
842 \r
843         // "Enable Quality of Service support in the HCA if > 0, (default 1)"\r
844         DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");  \r
845 \r
846         ULONG value;\r
847         WDFKEY hKey = NULL;\r
848         NTSTATUS status = STATUS_SUCCESS;\r
849         \r
850         status = WdfDriverOpenParametersRegistryKey( *hDriver,\r
851                 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );\r
852 \r
853         if (NT_SUCCESS (status)) {\r
854 \r
855                 //\r
856                 // Read general values\r
857                 //\r
858                 status = WdfRegistryQueryULong(hKey, &debugLevel, &value);\r
859                 if (NT_SUCCESS (status)) \r
860                         g_mlx4_dbg_level = g.DebugPrintLevel = value;\r
861                 \r
862                 status = WdfRegistryQueryULong(hKey, &debugFlags, &value);\r
863                 if (NT_SUCCESS (status)) \r
864                         g_mlx4_dbg_flags = g.DebugPrintFlags = value;\r
865 \r
866                 status = WdfRegistryQueryULong(hKey, &numQp, &value);\r
867                 if (NT_SUCCESS (status)) \r
868                         g.mod_num_qp = value;\r
869 \r
870                 status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);\r
871                 if (NT_SUCCESS (status)) \r
872                         g.mod_rdmarc_per_qp = value;\r
873 \r
874                 status = WdfRegistryQueryULong(hKey, &numSrq, &value);\r
875                 if (NT_SUCCESS (status)) \r
876                         g.mod_num_srq = value;\r
877 \r
878                 status = WdfRegistryQueryULong(hKey, &numCq, &value);\r
879                 if (NT_SUCCESS (status)) \r
880                         g.mod_num_cq = value;\r
881 \r
882                 status = WdfRegistryQueryULong(hKey, &numMcg, &value);\r
883                 if (NT_SUCCESS (status)) \r
884                         g.mod_num_mcg = value;\r
885 \r
886                 status = WdfRegistryQueryULong(hKey, &numMpt, &value);\r
887                 if (NT_SUCCESS (status)) \r
888                         g.mod_num_mpt = value;\r
889                 \r
890                 status = WdfRegistryQueryULong(hKey, &numMtt, &value);\r
891                 if (NT_SUCCESS (status)) \r
892                         g.mod_num_mtt = value;\r
893 \r
894                 status = WdfRegistryQueryULong(hKey, &enableQoS, &value);\r
895                 if (NT_SUCCESS (status)) \r
896                         g.enable_qos = value;\r
897                 else\r
898                         g.enable_qos = 1;\r
899 \r
900                 WdfRegistryClose(hKey);\r
901                 status = STATUS_SUCCESS;\r
902         }\r
903 \r
904         return status;\r
905 }\r
906 \r
907 NTSTATUS\r
908 DriverEntry(\r
909         IN PDRIVER_OBJECT DriverObject,\r
910         IN PUNICODE_STRING RegistryPath\r
911         )\r
912 /*++\r
913 Routine Description:\r
914 \r
915         Initialize the call backs structure of Driver Framework.\r
916 \r
917 Arguments:\r
918 \r
919         DriverObject - pointer to the driver object\r
920 \r
921         RegistryPath - pointer to a unicode string representing the path,\r
922                                 to driver-specific key in the registry.\r
923 \r
924 Return Value:\r
925 \r
926   NT Status Code\r
927 \r
928 --*/\r
929 {\r
930         int err;\r
931         WDF_DRIVER_CONFIG   config;\r
932         NTSTATUS            status;\r
933         WDFDRIVER hDriver;\r
934 \r
935 #if defined(EVENT_TRACING)\r
936         WPP_INIT_TRACING(DriverObject, RegistryPath);\r
937 #endif\r
938 \r
939 \r
940         // global initializations\r
941         g_mlx4_dbg_level = g.DebugPrintLevel = TRACE_LEVEL_VERBOSE;\r
942         g_mlx4_dbg_flags = g.DebugPrintFlags = 0xffff;\r
943 \r
944         MLX4_ENTER(MLX4_DBG_DRV);\r
945         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, \r
946                 ("Built %s %s, Version %s, RelDate %s\n", \r
947                 __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE));\r
948 \r
949         mlx4_net_init();\r
950         err = core_init();\r
951         if (err) {\r
952                 status = errno_to_ntstatus(err);\r
953                 goto end;\r
954         }\r
955 \r
956         //\r
957         // Initiialize driver config to control the attributes that\r
958         // are global to the driver. Note that framework by default\r
959         // provides a driver unload routine. If you create any resources\r
960         // in the DriverEntry and want to be cleaned in driver unload,\r
961         // you can override that by specifing one in the Config structure.\r
962         //\r
963 \r
964         WDF_DRIVER_CONFIG_INIT(\r
965                 &config, EvtDeviceAdd );\r
966         config.EvtDriverUnload = EvtDriverUnload;\r
967 \r
968         //\r
969         // Create a framework driver object to represent our driver.\r
970         //\r
971         status = WdfDriverCreate(DriverObject,\r
972                 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
973                 &config, &hDriver);\r
974 \r
975         if (!NT_SUCCESS(status)) {\r
976                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status));\r
977                 goto end;\r
978         }\r
979 \r
980         //\r
981         // read registry parameters\r
982         //\r
983         status = __read_registry(&hDriver);\r
984 \r
985         // we don't matter the failure in the work with Registry\r
986         status = STATUS_SUCCESS;\r
987         \r
988 end:\r
989         MLX4_EXIT( MLX4_DBG_DRV );\r
990         return status;\r
991 \r
992 }\r
993 \r
994 \r