58c0910b04c6e0b8b15e11d230608ef6028ba40d
[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         // IB library\r
567         err = mlx4_ib_init();\r
568         if (err) {\r
569                 status = errno_to_ntstatus(err);\r
570                 goto err;\r
571         }\r
572 \r
573 #ifndef USE_WDM_INTERRUPTS\r
574         //\r
575         // complete filling interrupt context (for more efficiency)\r
576         //\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
581 \r
582                 p_isr_ctx->eq = &priv->eq_table.eq[i];\r
583         }\r
584 #endif\r
585 \r
586         //\r
587         // prepare MLX4 IB interface\r
588         //\r
589 \r
590         // fill the header\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
596 \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
601 \r
602         status = STATUS_SUCCESS;\r
603         \r
604 err:\r
605         MLX4_EXIT( MLX4_DBG_DRV );\r
606         return status;\r
607 }\r
608 \r
609 NTSTATUS\r
610 EvtReleaseHardware(\r
611         IN WDFDEVICE  Device,\r
612         IN WDFCMRESLIST  ResourcesTranslated\r
613         )\r
614 {\r
615         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
616 \r
617         UNUSED_PARAM(ResourcesTranslated);\r
618 \r
619         MLX4_ENTER(MLX4_DBG_DRV);\r
620 \r
621         mlx4_ib_cleanup();\r
622         mlx4_remove_one( &p_fdo->pci_dev );\r
623         __put_resources( p_fdo );\r
624 \r
625         MLX4_EXIT( MLX4_DBG_DRV );\r
626         return STATUS_SUCCESS;\r
627 }\r
628 \r
629 #ifndef USE_WDM_INTERRUPTS\r
630 \r
631 static\r
632 NTSTATUS \r
633 __create_interrupt(\r
634         IN WDFDEVICE                            device,\r
635         IN int                                          int_num,\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
640         )\r
641 {\r
642         NTSTATUS Status;\r
643 \r
644         WDF_INTERRUPT_CONFIG  interruptConfig;\r
645         WDF_OBJECT_ATTRIBUTES  interruptAttributes;\r
646         PINTERRUPT_DATA p_isr_ctx;\r
647 \r
648         MLX4_ENTER(MLX4_DBG_DRV);\r
649 \r
650         WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );\r
651         \r
652         interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;\r
653         interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;\r
654         \r
655         \r
656         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( \r
657                 &interruptAttributes, INTERRUPT_DATA );\r
658 \r
659         Status = WdfInterruptCreate( device,\r
660                 &interruptConfig, &interruptAttributes, p_int_obj );\r
661 \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
666 \r
667         // one can call WdfInterruptSetPolicy() to set the policy, affinity etc\r
668 \r
669         MLX4_EXIT( MLX4_DBG_DRV );\r
670         return Status;\r
671 }\r
672 \r
673 #endif\r
674 \r
675 inline void InitBusIsr(\r
676      struct VipBusIfc* pVipBusIfc\r
677     )\r
678 {\r
679     memset(pVipBusIfc, 0, sizeof(struct VipBusIfc));\r
680     KeInitializeEvent(&pVipBusIfc->NicData.ConfigChangeEvent, SynchronizationEvent, TRUE);\r
681 }\r
682 \r
683 NTSTATUS\r
684 EvtDeviceAdd(\r
685         IN WDFDRIVER        Driver,\r
686         IN PWDFDEVICE_INIT  DeviceInit\r
687         )\r
688 /*++\r
689 Routine Description:\r
690 \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
694 \r
695 Arguments:\r
696 \r
697         Driver - Handle to a framework driver object created in DriverEntry\r
698 \r
699         DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
700 \r
701 Return Value:\r
702 \r
703         NTSTATUS\r
704 \r
705 --*/\r
706 {\r
707 #ifndef USE_WDM_INTERRUPTS\r
708         int i;\r
709 #endif\r
710         WDF_OBJECT_ATTRIBUTES                   attributes;\r
711         NTSTATUS                                                status;\r
712         WDFDEVICE                                               device;\r
713         PFDO_DEVICE_DATA                                p_fdo;\r
714         PNP_BUS_INFORMATION                             busInfo;\r
715         WDF_PNPPOWER_EVENT_CALLBACKS    Callbacks;\r
716 \r
717         UNREFERENCED_PARAMETER(Driver);\r
718 \r
719         PAGED_CODE ();\r
720         MLX4_ENTER(MLX4_DBG_DRV);\r
721 \r
722         //\r
723         // register PnP & Power stuff\r
724         //\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
730 \r
731         WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );\r
732         \r
733         //\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
738         //\r
739         WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
740         WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r
741 \r
742         //\r
743         // Initialize attributes structure to specify size and accessor function\r
744         // for storing device context.\r
745         //\r
746         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);\r
747 \r
748         //\r
749         // Create a framework device object. In response to this call, framework\r
750         // creates a WDM deviceobject.\r
751         //\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
756                 goto end;\r
757         }\r
758 \r
759         //\r
760         // Get the device context.\r
761         //\r
762         p_fdo = FdoGetData(device);\r
763         RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
764         p_fdo->FdoDevice = device;\r
765 \r
766     //\r
767     // Init the BusIsr data\r
768     //\r
769     InitBusIsr(&p_fdo->mtnic_Ifc);\r
770 \r
771         //\r
772         // Init the BusIsr data\r
773         //\r
774         InitBusIsr(&p_fdo->mtnic_Ifc);\r
775 \r
776         //\r
777         // Purpose of this lock is documented in PlugInDevice routine below.\r
778         //\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
785                 goto end;\r
786         }\r
787 \r
788         //\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
792         //\r
793         busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;\r
794         busInfo.LegacyBusType = PNPBus;\r
795         busInfo.BusNumber = 0;\r
796 \r
797         WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
798 \r
799         //\r
800         // WMI\r
801         //\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
806                 goto end;\r
807         }\r
808 \r
809 #ifndef USE_WDM_INTERRUPTS\r
810 \r
811         //\r
812         // create interrupt objects\r
813         //\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
819                 else {\r
820                         MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,\r
821                                 ("WdfInterruptCreate failed %#x\n", status ));\r
822                         goto end;\r
823                 }\r
824         }\r
825 \r
826 #endif\r
827 \r
828         status = STATUS_SUCCESS;\r
829 \r
830 end:    \r
831         MLX4_EXIT( MLX4_DBG_DRV );\r
832         return status;\r
833 }\r
834 \r
835 \r
836 \r
837 void\r
838 EvtDriverUnload(\r
839         IN              WDFDRIVER  Driver\r
840         )\r
841 {\r
842         MLX4_ENTER( MLX4_DBG_DRV );\r
843 \r
844         UNUSED_PARAM( Driver );\r
845 \r
846         core_cleanup();\r
847 \r
848         MLX4_EXIT( MLX4_DBG_DRV );\r
849 #if defined(EVENT_TRACING)\r
850         WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));\r
851 #endif\r
852 \r
853 }\r
854 \r
855 static\r
856 NTSTATUS\r
857 __read_registry(WDFDRIVER *hDriver)\r
858 {\r
859         DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");\r
860         DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");\r
861 \r
862         // "log maximum number of QPs per HCA"\r
863         DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");\r
864 \r
865         // "log number of RDMARC buffers per QP"\r
866         DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");\r
867 \r
868         // "log maximum number of SRQs per HCA"\r
869         DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");\r
870 \r
871         // "log maximum number of CQs per HCA"\r
872         DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");\r
873 \r
874         // "log maximum number of multicast groups per HCA"\r
875         DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");\r
876 \r
877         // "log maximum number of memory protection table entries per HCA"\r
878         DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");\r
879 \r
880         // "log maximum number of memory translation table segments per HCA"\r
881         DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");     \r
882 \r
883         // "Enable Quality of Service support in the HCA if > 0, (default 1)"\r
884         DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");  \r
885 \r
886         // "Maximum number of MACs per ETH port (1-127, default 1"\r
887         DECLARE_CONST_UNICODE_STRING(numMac, L"NumMac");        \r
888 \r
889         // "Maximum number of VLANs per ETH port (0-126, default 0)"\r
890         DECLARE_CONST_UNICODE_STRING(numVlan, L"NumVlan");      \r
891 \r
892         // "Enable steering by VLAN priority on ETH ports (0/1, default 0)"\r
893         DECLARE_CONST_UNICODE_STRING(usePrio, L"UsePrio");      \r
894 \r
895         // "Block multicast loopback packets if > 0 (default 1)"\r
896         DECLARE_CONST_UNICODE_STRING(BlockMcastLB, L"BlockMcastLoopBack");      \r
897 \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
900 \r
901         \r
902         ULONG value;\r
903         WDFKEY hKey = NULL;\r
904         NTSTATUS status = STATUS_SUCCESS;\r
905 \r
906         UNICODE_STRING uvalue;\r
907 #define  MAX_UVALUE 100\r
908         WCHAR uvalue_data[MAX_UVALUE];\r
909         \r
910         status = WdfDriverOpenParametersRegistryKey( *hDriver,\r
911                 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );\r
912 \r
913         if (NT_SUCCESS (status)) {\r
914 \r
915                 //\r
916                 // Read general values\r
917                 //\r
918                 status = WdfRegistryQueryULong(hKey, &debugLevel, &value);\r
919                 if (NT_SUCCESS (status)) \r
920                         g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = value;\r
921                 \r
922                 status = WdfRegistryQueryULong(hKey, &debugFlags, &value);\r
923                 if (NT_SUCCESS (status)) \r
924                         g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = value;\r
925 \r
926                 status = WdfRegistryQueryULong(hKey, &numQp, &value);\r
927                 if (NT_SUCCESS (status)) \r
928                         g.mod_num_qp = value;\r
929 \r
930                 status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);\r
931                 if (NT_SUCCESS (status)) \r
932                         g.mod_rdmarc_per_qp = value;\r
933 \r
934                 status = WdfRegistryQueryULong(hKey, &numSrq, &value);\r
935                 if (NT_SUCCESS (status)) \r
936                         g.mod_num_srq = value;\r
937 \r
938                 status = WdfRegistryQueryULong(hKey, &numCq, &value);\r
939                 if (NT_SUCCESS (status)) \r
940                         g.mod_num_cq = value;\r
941 \r
942                 status = WdfRegistryQueryULong(hKey, &numMcg, &value);\r
943                 if (NT_SUCCESS (status)) \r
944                         g.mod_num_mcg = value;\r
945 \r
946                 status = WdfRegistryQueryULong(hKey, &numMpt, &value);\r
947                 if (NT_SUCCESS (status)) \r
948                         g.mod_num_mpt = value;\r
949                 \r
950                 status = WdfRegistryQueryULong(hKey, &numMtt, &value);\r
951                 if (NT_SUCCESS (status)) \r
952                         g.mod_num_mtt = value;\r
953 \r
954                 status = WdfRegistryQueryULong(hKey, &enableQoS, &value);\r
955                 if (NT_SUCCESS (status)) \r
956                         g.mod_enable_qos = value;\r
957                 else\r
958                         g.mod_enable_qos = 1;\r
959 \r
960                 status = WdfRegistryQueryULong(hKey, &numMac, &value);\r
961                 if (NT_SUCCESS (status)) \r
962                         g.mod_num_mac = value;\r
963                 else\r
964                         g.mod_num_mac = 1;\r
965 \r
966                 status = WdfRegistryQueryULong(hKey, &numVlan, &value);\r
967                 if (NT_SUCCESS (status)) \r
968                         g.mod_num_vlan= value;\r
969                 else\r
970                         g.mod_num_vlan = 0;\r
971 \r
972                 status = WdfRegistryQueryULong(hKey, &usePrio, &value);\r
973                 if (NT_SUCCESS (status)) \r
974                         g.mod_use_prio= value;\r
975                 else\r
976                         g.mod_use_prio = 0;\r
977 \r
978                 status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value);\r
979                 if (NT_SUCCESS (status)) \r
980                         g.mod_mlx4_blck_lb = value;\r
981                 else\r
982                         g.mod_mlx4_blck_lb = 1;\r
983 \r
984                 uvalue.Buffer = uvalue_data;\r
985                 uvalue.MaximumLength = MAX_UVALUE;\r
986                 uvalue.Length = 0;\r
987 \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
993                         } else\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
997                         } else\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
1001                         } else\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
1005                         }\r
1006                 }\r
1007                 else {\r
1008                         g.mod_port_type [0] = MLX4_PORT_TYPE_IB;\r
1009                         g.mod_port_type [1] = MLX4_PORT_TYPE_IB;\r
1010                 }\r
1011 \r
1012 \r
1013                 WdfRegistryClose(hKey);\r
1014                 status = STATUS_SUCCESS;\r
1015         }\r
1016 \r
1017         return status;\r
1018 }\r
1019 \r
1020 NTSTATUS\r
1021 DriverEntry(\r
1022         IN PDRIVER_OBJECT DriverObject,\r
1023         IN PUNICODE_STRING RegistryPath\r
1024         )\r
1025 /*++\r
1026 Routine Description:\r
1027 \r
1028         Initialize the call backs structure of Driver Framework.\r
1029 \r
1030 Arguments:\r
1031 \r
1032         DriverObject - pointer to the driver object\r
1033 \r
1034         RegistryPath - pointer to a unicode string representing the path,\r
1035                                 to driver-specific key in the registry.\r
1036 \r
1037 Return Value:\r
1038 \r
1039   NT Status Code\r
1040 \r
1041 --*/\r
1042 {\r
1043         int err;\r
1044         WDF_DRIVER_CONFIG   config;\r
1045         NTSTATUS            status;\r
1046         WDFDRIVER hDriver;\r
1047 \r
1048 #if defined(EVENT_TRACING)\r
1049         WPP_INIT_TRACING(DriverObject, RegistryPath);\r
1050 #endif\r
1051 \r
1052 \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
1056 \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
1061 \r
1062         mlx4_net_init();\r
1063         err = core_init();\r
1064         if (err) {\r
1065                 status = errno_to_ntstatus(err);\r
1066                 goto end;\r
1067         }\r
1068 \r
1069         //\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
1075         //\r
1076 \r
1077         WDF_DRIVER_CONFIG_INIT(\r
1078                 &config, EvtDeviceAdd );\r
1079         config.EvtDriverUnload = EvtDriverUnload;\r
1080 \r
1081         //\r
1082         // Create a framework driver object to represent our driver.\r
1083         //\r
1084         status = WdfDriverCreate(DriverObject,\r
1085                 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
1086                 &config, &hDriver);\r
1087 \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
1090                 goto end;\r
1091         }\r
1092 \r
1093         //\r
1094         // read registry parameters\r
1095         //\r
1096         status = __read_registry(&hDriver);\r
1097 \r
1098         // we don't matter the failure in the work with Registry\r
1099         status = STATUS_SUCCESS;\r
1100         \r
1101 end:\r
1102         MLX4_EXIT( MLX4_DBG_DRV );\r
1103         return status;\r
1104 \r
1105 }\r
1106 \r
1107 \r
1108 \r