f88b2d16479c724226eb87db11ca63eb8e03d19a
[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 #ifdef offsetof\r
27 #undef offsetof\r
28 #endif\r
29 #include "drv.tmh"\r
30 #endif \r
31 \r
32 \r
33 #define DRV_VERSION     "1.0"\r
34 #define DRV_RELDATE     "02/01/2008"\r
35 \r
36 GLOBALS g = {0};\r
37 uint32_t g_mlx4_dbg_flags = 0xffff;\r
38 uint32_t g_mlx4_dbg_level = TRACE_LEVEL_INFORMATION;\r
39 WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ];\r
40 UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ];\r
41 \r
42 #ifndef USE_WDM_INTERRUPTS\r
43 \r
44 typedef struct {\r
45         int                                     int_num;\r
46         PFDO_DEVICE_DATA        p_fdo;\r
47         struct mlx4_eq *        eq;\r
48 } INTERRUPT_DATA, *PINTERRUPT_DATA;\r
49 \r
50 WDF_DECLARE_CONTEXT_TYPE(INTERRUPT_DATA);\r
51 \r
52 NTSTATUS    \r
53 EvtEnableInterrupt(     \r
54         IN WDFINTERRUPT  Interrupt,\r
55         IN WDFDEVICE  AssociatedDevice\r
56         )\r
57 {\r
58         UNUSED_PARAM(Interrupt);\r
59         UNUSED_PARAM(AssociatedDevice);\r
60         MLX4_ENTER(MLX4_DBG_DRV);\r
61         MLX4_EXIT( MLX4_DBG_DRV );\r
62         return STATUS_SUCCESS;\r
63 }\r
64 \r
65 NTSTATUS\r
66 EvtDisableInterrupt (\r
67         IN WDFINTERRUPT  Interrupt,\r
68         IN WDFDEVICE  AssociatedDevice\r
69         )\r
70 {\r
71         UNUSED_PARAM(Interrupt);\r
72         UNUSED_PARAM(AssociatedDevice);\r
73         MLX4_ENTER(MLX4_DBG_DRV);\r
74         MLX4_EXIT( MLX4_DBG_DRV );\r
75         return STATUS_SUCCESS;\r
76 }\r
77 \r
78 BOOLEAN\r
79 EvtInterruptIsr(\r
80         IN WDFINTERRUPT  Interrupt,\r
81         IN ULONG  MessageID\r
82         )\r
83 {\r
84         BOOLEAN isr_handled = FALSE;\r
85         PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( Interrupt, INTERRUPT_DATA );\r
86 \r
87         UNUSED_PARAM(MessageID);\r
88 \r
89 //      MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("Fdo %p\n", p_isr_ctx->p_fdo));\r
90         if (p_isr_ctx->eq && p_isr_ctx->eq->isr)\r
91                 isr_handled = p_isr_ctx->eq->isr( p_isr_ctx->eq->eq_ix, p_isr_ctx->eq->ctx );\r
92         \r
93         return isr_handled;\r
94 }\r
95 \r
96 #endif\r
97 \r
98 static \r
99 NTSTATUS\r
100 __create_child(\r
101         __in WDFDEVICE  Device,\r
102         __in PWCHAR     HardwareIds,\r
103         __in PWCHAR     DeviceDescription,\r
104         __in ULONG      SerialNo\r
105         )\r
106 \r
107 /*++\r
108 \r
109 Routine Description:\r
110 \r
111         The user application has told us that a new device on the bus has arrived.\r
112 \r
113         We therefore need to create a new PDO, initialize it, add it to the list\r
114         of PDOs for this FDO bus, and then tell Plug and Play that all of this\r
115         happened so that it will start sending prodding IRPs.\r
116 \r
117 --*/\r
118 \r
119 {\r
120         NTSTATUS                        status = STATUS_SUCCESS;\r
121         BOOLEAN                         unique = TRUE;\r
122         WDFDEVICE                       hChild;\r
123         PPDO_DEVICE_DATA        p_pdo;\r
124         PFDO_DEVICE_DATA        p_fdo;\r
125 \r
126         PAGED_CODE ();\r
127         MLX4_ENTER(MLX4_DBG_DRV);\r
128 \r
129         //\r
130         // First make sure that we don't already have another device with the\r
131         // same serial number.\r
132         // Framework creates a collection of all the child devices we have\r
133         // created so far. So acquire the handle to the collection and lock\r
134         // it before walking the item.\r
135         //\r
136         p_fdo = FdoGetData(Device);\r
137         hChild = NULL;\r
138 \r
139         //\r
140         // We need an additional lock to synchronize addition because\r
141         // WdfFdoLockStaticChildListForIteration locks against anyone immediately\r
142         // updating the static child list (the changes are put on a queue until the\r
143         // list has been unlocked).  This type of lock does not enforce our concept\r
144         // of unique IDs on the bus (ie SerialNo).\r
145         //\r
146         // Without our additional lock, 2 threads could execute this function, both\r
147         // find that the requested SerialNo is not in the list and attempt to add\r
148         // it.  If that were to occur, 2 PDOs would have the same unique SerialNo,\r
149         // which is incorrect.\r
150         //\r
151         // We must use a passive level lock because you can only call WdfDeviceCreate\r
152         // at PASSIVE_LEVEL.\r
153         //\r
154         WdfWaitLockAcquire(p_fdo->ChildLock, NULL);\r
155         WdfFdoLockStaticChildListForIteration(Device);\r
156 \r
157         while ((hChild = WdfFdoRetrieveNextStaticChild(Device,\r
158                 hChild, WdfRetrieveAddedChildren)) != NULL) {\r
159                 //\r
160                 // WdfFdoRetrieveNextStaticChild returns reported and to be reported\r
161                 // children (ie children who have been added but not yet reported to PNP).\r
162                 //\r
163                 // A surprise removed child will not be returned in this list.\r
164                 //\r
165                 p_pdo = PdoGetData(hChild);\r
166                 p_pdo->PdoDevice = hChild;\r
167                 p_pdo->p_fdo = p_fdo;\r
168 \r
169                 //\r
170                 // It's okay to plug in another device with the same serial number\r
171                 // as long as the previous one is in a surprise-removed state. The\r
172                 // previous one would be in that state after the device has been\r
173                 // physically removed, if somebody has an handle open to it.\r
174                 //\r
175                 if (SerialNo == p_pdo->SerialNo) {\r
176                 unique = FALSE;\r
177                 status = STATUS_INVALID_PARAMETER;\r
178                 break;\r
179                 }\r
180         }\r
181 \r
182         if (unique) {\r
183                 //\r
184                 // Create a new child device.  It is OK to create and add a child while\r
185                 // the list locked for enumeration.  The enumeration lock applies only\r
186                 // to enumeration, not addition or removal.\r
187                 //\r
188                 status = create_pdo(Device, HardwareIds, DeviceDescription, SerialNo, p_fdo->pci_dev.location);\r
189         }\r
190 \r
191         WdfFdoUnlockStaticChildListFromIteration(Device);\r
192         WdfWaitLockRelease(p_fdo->ChildLock);\r
193 \r
194         MLX4_EXIT( MLX4_DBG_DRV );\r
195         return status;\r
196 }\r
197 \r
198 static \r
199 NTSTATUS\r
200 __do_static_enumeration(\r
201         IN WDFDEVICE Device\r
202         )\r
203 /*++\r
204 Routine Description:\r
205 \r
206         The routine enables you to statically enumerate child devices\r
207         during start instead of running the enum.exe/notify.exe to\r
208         enumerate mxe devices.\r
209 \r
210         In order to statically enumerate, user must specify the number\r
211         of mxes in the Mxe Bus driver's device registry. The\r
212         default value is 2.\r
213 \r
214         You can also configure this value in the Mxe Bus Inf file.\r
215 \r
216 --*/\r
217 \r
218 {\r
219         NTSTATUS status = STATUS_SUCCESS;\r
220         int i;\r
221         int number_of_ib_ports;\r
222         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
223         struct mlx4_dev *mdev   = p_fdo->pci_dev.dev;\r
224 \r
225         MLX4_ENTER(MLX4_DBG_DRV);\r
226 \r
227         if ( p_fdo->children_created )\r
228                 goto end;\r
229         \r
230         // eventually we'll have all information about children in Registry\r
231         // DriverEntry will read it into a Global storage and\r
232         // this routine will create all the children on base on this info\r
233         number_of_ib_ports = mlx4_count_ib_ports(mdev);\r
234         ASSERT(number_of_ib_ports >=0 && number_of_ib_ports <=2);\r
235         \r
236         if(number_of_ib_ports > 0) {\r
237                 status = __create_child(Device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 );\r
238                 if (!NT_SUCCESS(status)) {\r
239                          MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status));\r
240                 }\r
241         }\r
242 \r
243         // Create ethernet ports if needed\r
244         for (i = 0; i < MLX4_MAX_PORTS; i++) {\r
245                 if(mlx4_is_eth_port(mdev, i)) {\r
246                         status = __create_child(Device, ETH_HARDWARE_IDS, ETH_HARDWARE_DESCRIPTION, i+1 );\r
247                         if (!NT_SUCCESS(status)) {\r
248                                  MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status));\r
249                         }\r
250                 }\r
251         }\r
252 \r
253         p_fdo->children_created = TRUE;\r
254         \r
255 end:\r
256         MLX4_EXIT( MLX4_DBG_DRV );\r
257         return status;\r
258 }\r
259 \r
260  \r
261 NTSTATUS\r
262 __read_dev_params(IN WDFDEVICE  Device, struct mlx4_dev_params *dev_params)\r
263 {\r
264         NTSTATUS status = STATUS_SUCCESS;\r
265         WDFKEY hKey = NULL;\r
266         WDFKEY hParamsKey = NULL;\r
267         DECLARE_CONST_UNICODE_STRING(Parameters, L"Parameters");\r
268         DECLARE_CONST_UNICODE_STRING(PortType, L"PortType");\r
269 #define  MAX_UVALUE 100\r
270         WCHAR uvalue_data[MAX_UVALUE];\r
271         UNICODE_STRING uvalue;\r
272         status = WdfDeviceOpenRegistryKey(Device, PLUGPLAY_REGKEY_DRIVER, \r
273                 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey);\r
274         if( !NT_SUCCESS( status ) ) {\r
275                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_DEV  ,("WdfDeviceOpenRegistryKey Failed status = 0x%x\n", status));\r
276                 goto err;\r
277         }\r
278 \r
279         status = WdfRegistryOpenKey(hKey, &Parameters, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hParamsKey);\r
280         if( !NT_SUCCESS( status ) ) {\r
281                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_DEV  ,("WdfRegistryOpenKey Failed status = 0x%x\n", status));\r
282                 goto err;\r
283         }\r
284 \r
285         uvalue.Buffer = uvalue_data;\r
286         uvalue.MaximumLength = MAX_UVALUE;\r
287         uvalue.Length = 0;\r
288 \r
289         status = WdfRegistryQueryUnicodeString(hParamsKey, &PortType, NULL, &uvalue);\r
290         if (NT_SUCCESS (status)) {\r
291                 if (!wcscmp(uvalue_data, L"ib,ib")) {\r
292                         dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB;\r
293                         dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB;\r
294                 } else\r
295                 if (!wcscmp(uvalue_data, L"ib,eth")) {\r
296                         dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB;\r
297                         dev_params->mod_port_type[1] = MLX4_PORT_TYPE_ETH;\r
298                 } else\r
299                 if (!wcscmp(uvalue_data, L"eth,ib")) {\r
300                         dev_params->mod_port_type[0] = MLX4_PORT_TYPE_ETH;\r
301                         dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB;\r
302                 } else\r
303                 if (!wcscmp(uvalue_data, L"eth,eth")) {\r
304                         dev_params->mod_port_type[0] = MLX4_PORT_TYPE_ETH;\r
305                         dev_params->mod_port_type[1] = MLX4_PORT_TYPE_ETH;\r
306                 }\r
307         }\r
308         else {\r
309                 dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB;\r
310                 dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB;\r
311         }\r
312 \r
313 err:\r
314         if (hKey != NULL) \r
315                 WdfRegistryClose(hKey);\r
316 \r
317         if (hParamsKey != NULL) \r
318                 WdfRegistryClose(hParamsKey);\r
319 \r
320         return status;\r
321 }\r
322 \r
323 \r
324 static \r
325 NTSTATUS\r
326 __start_card(\r
327         IN WDFDEVICE  Device,\r
328         IN PFDO_DEVICE_DATA p_fdo \r
329         )\r
330 {\r
331 #ifndef USE_WDM_INTERRUPTS\r
332                 int i;\r
333 #endif\r
334         int err;\r
335         NTSTATUS status = STATUS_SUCCESS;\r
336         struct pci_dev *pdev = &p_fdo->pci_dev;\r
337         struct mlx4_dev_params dev_params;\r
338 \r
339         MLX4_ENTER(MLX4_DBG_DRV);\r
340 \r
341         if ( p_fdo->card_started )\r
342                 goto err; \r
343 \r
344         status = __read_dev_params(Device, &dev_params);\r
345         if( !NT_SUCCESS( status ) ) \r
346                 goto err;\r
347 \r
348         // enable the card\r
349         status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );\r
350         if( !NT_SUCCESS( status ) ) \r
351                 goto err;\r
352 \r
353         //\r
354         // init the card\r
355         //\r
356 \r
357 #ifndef USE_WDM_INTERRUPTS\r
358         // enable interrupts for start up\r
359         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) \r
360                 WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);\r
361 #endif  \r
362 \r
363         // NET library\r
364         err = mlx4_init_one( &p_fdo->pci_dev, &dev_params );\r
365         if (err) {\r
366                 status = errno_to_ntstatus(err);\r
367                 goto err;\r
368         }\r
369 \r
370 #ifndef USE_WDM_INTERRUPTS\r
371         //\r
372         // complete filling interrupt context (for more efficiency)\r
373         //\r
374         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
375                 struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );\r
376                 PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( \r
377                         p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );\r
378 \r
379                 p_isr_ctx->eq = &priv->eq_table.eq[i];\r
380         }\r
381 #endif\r
382 \r
383         //\r
384         // prepare MLX4 IB interface\r
385         //\r
386 \r
387         // fill the header\r
388         p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE);\r
389         p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION;\r
390         // Let the framework handle reference counting.\r
391         p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
392         p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
393 \r
394         p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;\r
395         p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
396         p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);    \r
397         if ( p_fdo->bus_ib_ifc.is_livefish == 0 ) {\r
398                 p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;    \r
399                 if ( p_fdo->bus_ib_ifc.pmlx4_dev->flags & MLX4_FLAG_MSI_X )\r
400                         p_fdo->bus_ib_ifc.n_msi_vectors = p_fdo->pci_dev.n_msi_vectors - 2;\r
401         }\r
402 \r
403         p_fdo->card_started = TRUE;\r
404 \r
405 err:\r
406         MLX4_EXIT( MLX4_DBG_DRV );\r
407         return status;\r
408 }\r
409 \r
410 static\r
411 void\r
412 __stop_card(\r
413         IN PFDO_DEVICE_DATA p_fdo\r
414         )\r
415 {\r
416         if ( p_fdo->card_started ) {\r
417                 p_fdo->card_started = FALSE;\r
418                 mlx4_remove_one( &p_fdo->pci_dev, TRUE);\r
419         }\r
420 }\r
421 \r
422 \r
423 NTSTATUS\r
424 EvtDeviceD0Entry(\r
425         IN WDFDEVICE  Device,\r
426         IN WDF_POWER_DEVICE_STATE  PreviousState\r
427         )\r
428 {\r
429         NTSTATUS status = STATUS_SUCCESS;\r
430         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
431         struct pci_dev *pdev    = &p_fdo->pci_dev;\r
432         struct mlx4_dev *mdev;\r
433 \r
434         MLX4_ENTER(MLX4_DBG_DRV);\r
435 \r
436         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));\r
437 \r
438         // start card (needed after Hibernetion)\r
439         if (PreviousState > WdfPowerDeviceD0)\r
440                 status = __start_card( Device, p_fdo );\r
441         if ( !NT_SUCCESS( status ) ) \r
442                 goto err;\r
443         mdev = pdev->dev;\r
444 \r
445         // create child device\r
446         status = __do_static_enumeration(Device);\r
447                 if (!NT_SUCCESS(status)) {\r
448                         MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__do_static_enumeration failed with 0x%x\n", status));\r
449                         goto err;\r
450                 }\r
451 \r
452         // Log Success Message\r
453         MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,\r
454                 ("Ven %x Dev %d Fw %d.%d.%d, IsBurnDevice %s\n", \r
455                 (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,\r
456                 (int) (mdev->caps.fw_ver >> 32),\r
457                 (int) (mdev->caps.fw_ver >> 16) & 0xffff, \r
458                 (int) (mdev->caps.fw_ver & 0xffff),\r
459                 mlx4_is_livefish(mdev) ? "Y" : "N"\r
460                 ));\r
461 \r
462 err:\r
463         MLX4_EXIT( MLX4_DBG_DRV );\r
464         return status;\r
465 }\r
466 \r
467 NTSTATUS\r
468 EvtDeviceD0Exit(\r
469         IN WDFDEVICE  Device,\r
470         IN WDF_POWER_DEVICE_STATE  TargetState\r
471         )\r
472 {\r
473         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
474         \r
475         MLX4_ENTER(MLX4_DBG_DRV);\r
476         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState));\r
477 \r
478         if (TargetState > WdfPowerDeviceD0)\r
479                 __stop_card( p_fdo );\r
480 \r
481         MLX4_EXIT( MLX4_DBG_DRV );\r
482         return STATUS_SUCCESS;\r
483 }\r
484 \r
485 \r
486 \r
487 /* Forwards the request to the HCA's PDO. */\r
488 static \r
489 void\r
490 __put_bus_ifc(\r
491                 IN      BUS_INTERFACE_STANDARD          *pBusIfc )\r
492 {\r
493         MLX4_ENTER(MLX4_DBG_DRV);\r
494         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("pBusIfc=0x%p\n", pBusIfc));\r
495         pBusIfc->InterfaceDereference( pBusIfc->Context );\r
496         MLX4_EXIT( MLX4_DBG_DRV );\r
497 }\r
498 \r
499 static \r
500 NTSTATUS\r
501 __get_bus_ifc(\r
502         IN                              PFDO_DEVICE_DATA const  p_fdo,\r
503         IN              const   GUID* const                             pGuid,\r
504         OUT                     BUS_INTERFACE_STANDARD  *pBusIfc )\r
505 {\r
506         NTSTATUS status;\r
507         WDFDEVICE  FdoDevice = p_fdo->FdoDevice;\r
508         MLX4_ENTER(MLX4_DBG_DRV);\r
509         \r
510         status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc,\r
511                 sizeof(BUS_INTERFACE_STANDARD), 1, NULL );\r
512         MLX4_EXIT( MLX4_DBG_DRV );\r
513         return status;\r
514 }\r
515 \r
516 static\r
517 void\r
518 __put_dma_adapter(\r
519         IN PFDO_DEVICE_DATA p_fdo,\r
520         IN PDMA_ADAPTER         p_dma )\r
521 {\r
522         UNUSED_PARAM(p_fdo);\r
523         UNUSED_PARAM(p_dma);\r
524         MLX4_ENTER(MLX4_DBG_DRV);\r
525         MLX4_EXIT( MLX4_DBG_DRV );\r
526 }\r
527 \r
528 \r
529 // this routine releases the resources, taken in __get_resources\r
530 static\r
531 void \r
532 __put_resources(\r
533         IN PFDO_DEVICE_DATA p_fdo\r
534         )\r
535 {\r
536         struct pci_dev *pdev = &p_fdo->pci_dev;\r
537 \r
538         MLX4_ENTER(MLX4_DBG_DRV);\r
539 \r
540         if (pdev->msix_info.valid) \r
541                 pci_free_msix_info_resources(&pdev->msix_info);\r
542 \r
543         if (p_fdo->dma_adapter_taken) {\r
544                 p_fdo->dma_adapter_taken = FALSE;\r
545                 __put_dma_adapter( p_fdo, pdev->p_dma_adapter );\r
546         }\r
547 \r
548         if (p_fdo->pci_bus_ifc_taken) {\r
549                 p_fdo->pci_bus_ifc_taken = FALSE;\r
550                 __put_bus_ifc(&pdev->bus_pci_ifc);\r
551         }\r
552 \r
553         if (pdev->p_msix_map)\r
554                 kfree(pdev->p_msix_map);\r
555 \r
556         \r
557         MLX4_EXIT( MLX4_DBG_DRV );\r
558 }\r
559 \r
560 static\r
561 NTSTATUS \r
562 __get_dma_adapter(\r
563         IN PFDO_DEVICE_DATA p_fdo,\r
564         OUT PDMA_ADAPTER *      pp_dma )\r
565 {\r
566         NTSTATUS status;\r
567         WDF_DMA_ENABLER_CONFIG  dmaConfig;\r
568         \r
569         MLX4_ENTER(MLX4_DBG_DRV);\r
570 \r
571         WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,\r
572                 WdfDmaProfileScatterGather64, 0x80000000 - 1 );\r
573 \r
574         status = WdfDmaEnablerCreate( p_fdo->FdoDevice,\r
575                 &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &p_fdo->dma_enabler );\r
576         if (!NT_SUCCESS (status)) {\r
577                 return status;\r
578         }\r
579         \r
580         *pp_dma = WdfDmaEnablerWdmGetDmaAdapter( \r
581                 p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice );\r
582 \r
583         MLX4_EXIT( MLX4_DBG_DRV );\r
584         return status;\r
585 }\r
586 \r
587 // this routine fills pci_dev structure, containing all HW \r
588 // and some other necessary common resources\r
589 static\r
590 NTSTATUS \r
591 __get_resources(\r
592         IN PFDO_DEVICE_DATA p_fdo,\r
593         IN WDFCMRESLIST  ResourcesRaw,\r
594         IN WDFCMRESLIST  ResourcesTranslated\r
595         )\r
596 {\r
597         NTSTATUS status;\r
598         ULONG i, k=0;\r
599         PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc;\r
600         PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc_raw;\r
601         BUS_INTERFACE_STANDARD  bus_pci_ifc;\r
602         struct pci_dev *pdev = &p_fdo->pci_dev;\r
603 \r
604         MLX4_ENTER(MLX4_DBG_DRV);\r
605 \r
606         //\r
607         // Get PCI BUS interface\r
608         // \r
609         status = __get_bus_ifc( p_fdo, &GUID_BUS_INTERFACE_STANDARD, &bus_pci_ifc );\r
610         if( !NT_SUCCESS( status ) ) {\r
611                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
612                         ("failed: status=0x%x\n", status));\r
613                 return status;\r
614         }\r
615         RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) );\r
616         p_fdo->pci_bus_ifc_taken = TRUE;\r
617 \r
618         // \r
619         // get HW resources\r
620         //\r
621         for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {\r
622 \r
623                 desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );\r
624                 desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i );\r
625 \r
626                 switch (desc->Type) {\r
627 \r
628                         case CmResourceTypeMemory:\r
629                                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
630                                         ("EvtPrepareHardware(Raw): Desc %d: Memory: Start %#I64x, Length %#x\n", \r
631                                         i, desc_raw->u.Memory.Start.QuadPart, desc_raw->u.Memory.Length ));\r
632                                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
633                                         ("EvtPrepareHardware: Desc %d: Memory: Start %#I64x, Length %#x\n", \r
634                                         i, desc->u.Memory.Start.QuadPart, desc->u.Memory.Length ));\r
635 \r
636                                 if (k < N_BARS) {\r
637                                         pdev->bar[k].phys = desc->u.Memory.Start.QuadPart;\r
638                                         pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length;\r
639                                 }\r
640                                 k++;\r
641                                 break;\r
642 \r
643 #ifdef USE_WDM_INTERRUPTS\r
644                         case CmResourceTypeInterrupt:\r
645                                 if (!pdev->n_msi_vectors_alloc)\r
646                                         pdev->int_info = *desc;\r
647                                 if (desc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {\r
648                                         pdev->n_msi_vectors_alloc = (u8)(pdev->n_msi_vectors_alloc+desc_raw->u.MessageInterrupt.Raw.MessageCount);\r
649                                         MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
650                                                 ("EvtPrepareHardware: Desc %d: MsiInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n", \r
651                                                 i, desc->ShareDisposition, desc->Flags,\r
652                                                 desc->u.MessageInterrupt.Translated.Level, \r
653                                                 desc->u.MessageInterrupt.Translated.Vector, \r
654                                                 (u32)desc->u.MessageInterrupt.Translated.Affinity ));\r
655                                         MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
656                                                 ("EvtPrepareHardware: Desc %d: RawMsiInterrupt: Share %d, Flags %#x, MessageCount %#hx, Vector %#x, Affinity %#x\n", \r
657                                                 i, desc_raw->ShareDisposition, desc_raw->Flags,\r
658                                                 desc_raw->u.MessageInterrupt.Raw.MessageCount, \r
659                                                 desc_raw->u.MessageInterrupt.Raw.Vector,\r
660                                                 (u32)desc_raw->u.MessageInterrupt.Raw.Affinity ));\r
661                                 }\r
662                                 else { // line-based interrupt\r
663                                         MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV,\r
664                                                 ("EvtPrepareHardware: Desc %d: LineInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n", \r
665                                                 i, desc->ShareDisposition, desc->Flags,\r
666                                                 desc->u.Interrupt.Level, desc->u.Interrupt.Vector, \r
667                                                 (u32)desc->u.Interrupt.Affinity ));\r
668                                 }\r
669                                 break;\r
670 #endif\r
671 \r
672                         default:\r
673                                 //\r
674                                 // Ignore all other descriptors.\r
675                                 //\r
676                                 break;\r
677                 }\r
678         }\r
679         if (i ==0) {\r
680                 // This means that no resources are found\r
681                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("WdfCmResourceListGetCount: returned 0, quiting\n"));\r
682                 return STATUS_INSUFFICIENT_RESOURCES;\r
683         }\r
684 \r
685         //\r
686         // get uplink info. \r
687         //\r
688         status = pci_save_config( &pdev->bus_pci_ifc, \r
689                 &pdev->pci_cfg_space );\r
690         if( !NT_SUCCESS( status ) )\r
691         {\r
692                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
693                         ("Failed to save HCA config: status=0x%x\n", status));\r
694                 goto err;\r
695         }\r
696         pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info );\r
697 \r
698         //\r
699         // allocate DMA adapter\r
700         //\r
701         status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter );\r
702         if( !NT_SUCCESS( status ) )\r
703         {\r
704                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
705                         ("Failed to get DMA adapter: status=0x%x\n", status));\r
706                 goto err;\r
707         }\r
708         p_fdo->dma_adapter_taken = TRUE;\r
709 \r
710         //\r
711         // allocate MSI-X vector map table\r
712         //\r
713         if ( pdev->n_msi_vectors_alloc )\r
714         {\r
715                 pdev->p_msix_map = kzalloc(sizeof(struct msix_map) * pdev->n_msi_vectors_alloc, GFP_KERNEL);\r
716                 if ( !pdev->p_msix_map )\r
717                 {\r
718                         MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
719                                 ("Failed to allocate MSI-X vector map table\n"));\r
720                         goto err;\r
721                 }\r
722         }\r
723         \r
724         //\r
725         // fill more fields in pci_dev\r
726         //\r
727         pdev->ven_id = pdev->pci_cfg_space.VendorID;\r
728         pdev->dev_id = pdev->pci_cfg_space.DeviceID;\r
729         pdev->sub_vendor_id = pdev->pci_cfg_space.u.type0.SubVendorID;\r
730         pdev->sub_system_id = pdev->pci_cfg_space.u.type0.SubSystemID;\r
731         pdev->p_self_do = WdfDeviceWdmGetDeviceObject(p_fdo->FdoDevice);\r
732         pdev->pdo = WdfDeviceWdmGetPhysicalDevice(p_fdo->FdoDevice);\r
733         \r
734         MLX4_EXIT( MLX4_DBG_DRV );\r
735         return STATUS_SUCCESS;\r
736 err:\r
737         __put_resources(p_fdo);\r
738         MLX4_EXIT( MLX4_DBG_DRV );\r
739         return status;\r
740 }\r
741 \r
742 NTSTATUS\r
743 EvtPrepareHardware(\r
744         IN WDFDEVICE  Device,\r
745         IN WDFCMRESLIST  ResourcesRaw,\r
746         IN WDFCMRESLIST  ResourcesTranslated\r
747         )\r
748 {\r
749         NTSTATUS status;\r
750         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
751         struct pci_dev *pdev = &p_fdo->pci_dev;\r
752         struct mlx4_dev *mdev;\r
753         WDFMEMORY  memory;\r
754         WDF_OBJECT_ATTRIBUTES  attributes;\r
755 \r
756         MLX4_ENTER(MLX4_DBG_DRV);\r
757 \r
758         // get resources\r
759         status = __get_resources( p_fdo, ResourcesRaw, ResourcesTranslated );\r
760         if( !NT_SUCCESS( status ) ) {\r
761                 MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__get_resources failed: status=0x%x\n", status));\r
762                 goto err;\r
763         }\r
764 \r
765         // start the card\r
766         status = __start_card(Device, p_fdo );\r
767         if( !NT_SUCCESS( status ) ) \r
768                 goto err;\r
769         mdev = pdev->dev;\r
770 \r
771         // get VPD \r
772         status = pci_get_vpd( &pdev->bus_pci_ifc, \r
773                 &pdev->pci_cfg_space, &pdev->vpd, &pdev->vpd_size );\r
774         if( !NT_SUCCESS( status ) )\r
775         {\r
776                 MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
777                         ("pci_get_vpd failed,  status=0x%x\n", status));\r
778                 goto err;\r
779         }\r
780 \r
781         // get card location\r
782         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r
783         attributes.ParentObject = Device;\r
784         status = WdfDeviceAllocAndQueryProperty( Device,\r
785                 DevicePropertyLocationInformation, NonPagedPool,\r
786                 &attributes, &memory );\r
787         if( NT_SUCCESS( status ) ) {\r
788                 UCHAR *ptr;\r
789 \r
790                 // get location\r
791                 ptr = WdfMemoryGetBuffer(memory, NULL);\r
792                 status = RtlStringCbCopyW( (LPWSTR)p_fdo->pci_dev.location, \r
793                         sizeof(p_fdo->pci_dev.location), (LPCWSTR)ptr );\r
794                 WdfObjectDelete(memory);\r
795                 if( !NT_SUCCESS( status ) ) {\r
796                         MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
797                                 ("Failed to move location string '%S',  status=0x%x\n", ptr, status));\r
798                 }\r
799         }\r
800         else {\r
801                 MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
802                         ("WdfDeviceAllocAndQueryProperty failed,  status=0x%x\n", status));\r
803         }\r
804         \r
805 err:\r
806         MLX4_EXIT( MLX4_DBG_DRV );\r
807         return status;\r
808 }\r
809 \r
810 void fix_bus_ifc(struct pci_dev *pdev)\r
811 {\r
812         PFDO_DEVICE_DATA p_fdo;\r
813 \r
814         p_fdo =  CONTAINING_RECORD(pdev, FDO_DEVICE_DATA, pci_dev);\r
815         p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
816         p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;\r
817         p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
818 }\r
819 \r
820 NTSTATUS\r
821 EvtReleaseHardware(\r
822         IN WDFDEVICE  Device,\r
823         IN WDFCMRESLIST  ResourcesTranslated\r
824         )\r
825 {\r
826         PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
827         struct pci_dev *pdev = &p_fdo->pci_dev;\r
828         int i;\r
829 \r
830         UNUSED_PARAM(ResourcesTranslated);\r
831 \r
832         MLX4_ENTER(MLX4_DBG_DRV);\r
833 \r
834         if ( pdev->vpd ) {\r
835                 kfree( pdev->vpd );\r
836                 pdev->vpd = NULL;\r
837                 pdev->vpd_size = 0;\r
838         }\r
839         __stop_card( p_fdo );\r
840         __put_resources( p_fdo );\r
841         for (i=0; i<MAX_HCA_CARDS; ++i) {\r
842                 if ( g.p_fdo[i] == p_fdo) {\r
843                         g.p_fdo[i] = NULL;\r
844                         break;\r
845                 }\r
846         }\r
847 \r
848         MLX4_EXIT( MLX4_DBG_DRV );\r
849         return STATUS_SUCCESS;\r
850 }\r
851 \r
852 #ifndef USE_WDM_INTERRUPTS\r
853 \r
854 static\r
855 NTSTATUS \r
856 __create_interrupt(\r
857         IN WDFDEVICE                            device,\r
858         IN int                                          int_num,\r
859         IN PFN_WDF_INTERRUPT_ISR        isr,\r
860         IN PFN_WDF_INTERRUPT_DPC        dpc,\r
861         IN PFDO_DEVICE_DATA                     p_fdo,\r
862         OUT WDFINTERRUPT                *       p_int_obj\r
863         )\r
864 {\r
865         NTSTATUS Status;\r
866 \r
867         WDF_INTERRUPT_CONFIG  interruptConfig;\r
868         WDF_OBJECT_ATTRIBUTES  interruptAttributes;\r
869         PINTERRUPT_DATA p_isr_ctx;\r
870 \r
871         MLX4_ENTER(MLX4_DBG_DRV);\r
872 \r
873         WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, isr, dpc );\r
874         \r
875         interruptConfig.EvtInterruptEnable = EvtEnableInterrupt;\r
876         interruptConfig.EvtInterruptDisable = EvtDisableInterrupt;\r
877         \r
878         \r
879         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( \r
880                 &interruptAttributes, INTERRUPT_DATA );\r
881 \r
882         Status = WdfInterruptCreate( device,\r
883                 &interruptConfig, &interruptAttributes, p_int_obj );\r
884 \r
885         p_isr_ctx = WdfObjectGetTypedContext( *p_int_obj, INTERRUPT_DATA );\r
886         p_isr_ctx->int_num = int_num;\r
887         p_isr_ctx->p_fdo = p_fdo;\r
888         p_isr_ctx->eq = NULL;\r
889 \r
890         // one can call WdfInterruptSetPolicy() to set the policy, affinity etc\r
891 \r
892         MLX4_EXIT( MLX4_DBG_DRV );\r
893         return Status;\r
894 }\r
895 \r
896 #endif\r
897 \r
898 inline void InitBusIsr(\r
899      struct VipBusIfc* pVipBusIfc\r
900     )\r
901 {\r
902     memset(pVipBusIfc, 0, sizeof(struct VipBusIfc));\r
903     KeInitializeEvent(&pVipBusIfc->NicData.ConfigChangeEvent, SynchronizationEvent, TRUE);\r
904 }\r
905 \r
906 NTSTATUS\r
907 EvtDriverDeviceAdd(\r
908         IN WDFDRIVER        Driver,\r
909         IN PWDFDEVICE_INIT  DeviceInit\r
910         )\r
911 /*++\r
912 Routine Description:\r
913 \r
914         EvtDriverDeviceAdd is called by the framework in response to AddDevice\r
915         call from the PnP manager. We create and initialize a device object to\r
916         represent a new instance of mxe bus.\r
917 \r
918 Arguments:\r
919 \r
920         Driver - Handle to a framework driver object created in DriverEntry\r
921 \r
922         DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r
923 \r
924 Return Value:\r
925 \r
926         NTSTATUS\r
927 \r
928 --*/\r
929 {\r
930 #ifndef USE_WDM_INTERRUPTS\r
931         int i;\r
932 #endif\r
933         WDF_OBJECT_ATTRIBUTES                   attributes;\r
934         NTSTATUS                                                status;\r
935         WDFDEVICE                                               device;\r
936         PFDO_DEVICE_DATA                                p_fdo;\r
937         PNP_BUS_INFORMATION                             busInfo;\r
938         WDF_PNPPOWER_EVENT_CALLBACKS    Callbacks;\r
939         int i;\r
940 \r
941         UNREFERENCED_PARAMETER(Driver);\r
942 \r
943         PAGED_CODE ();\r
944         MLX4_ENTER(MLX4_DBG_DRV);\r
945 \r
946         //\r
947         // register PnP & Power stuff\r
948         //\r
949         WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);\r
950         Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware;\r
951         Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;\r
952         Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;\r
953         Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;\r
954 \r
955         WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks );\r
956         \r
957         //\r
958         // Initialize all the properties specific to the device.\r
959         // Framework has default values for the one that are not\r
960         // set explicitly here. So please read the doc and make sure\r
961         // you are okay with the defaults.\r
962         //\r
963         WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);\r
964         WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r
965 \r
966         //\r
967         // Initialize attributes structure to specify size and accessor function\r
968         // for storing device context.\r
969         //\r
970         WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);\r
971 \r
972         //\r
973         // Create a framework device object. In response to this call, framework\r
974         // creates a WDM deviceobject.\r
975         //\r
976         status = WdfDeviceCreate(&DeviceInit, &attributes, &device);\r
977         if (!NT_SUCCESS(status)) {\r
978                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
979                         ("WdfDeviceCreate failed with 0x%x\n", status));\r
980                 goto end;\r
981         }\r
982 \r
983         //\r
984         // Get the device context.\r
985         //\r
986         p_fdo = FdoGetData(device);\r
987         RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA));\r
988         p_fdo->FdoDevice = device; \r
989         for (i=0; i<MAX_HCA_CARDS; ++i) {\r
990                 if (!g.p_fdo[i]) {\r
991                         g.p_fdo[i] = p_fdo;\r
992                         break;\r
993                 }\r
994         }\r
995 \r
996         //\r
997         // Init the BusIsr data\r
998         //\r
999         InitBusIsr(&p_fdo->mtnic_Ifc);\r
1000 \r
1001         //\r
1002         // Purpose of this lock is documented in PlugInDevice routine below.\r
1003         //\r
1004         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r
1005         attributes.ParentObject = device;\r
1006         status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock);\r
1007         if (!NT_SUCCESS(status)) {\r
1008                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
1009                         ("WdfWaitLockCreate failed with 0x%x\n", status));\r
1010                 goto end;\r
1011         }\r
1012 \r
1013         //\r
1014         // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION\r
1015         // for the child devices. This is an optional information provided to\r
1016         // uniquely identify the bus the device is connected.\r
1017         //\r
1018         busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID;\r
1019         busInfo.LegacyBusType = PNPBus;\r
1020         busInfo.BusNumber = 0;\r
1021 \r
1022         WdfDeviceSetBusInformationForChildren(device, &busInfo);\r
1023 \r
1024         //\r
1025         // WMI\r
1026         //\r
1027         status = WmiRegistration(device);\r
1028         if (!NT_SUCCESS(status)) {\r
1029                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, \r
1030                         ("WmiRegistration failed with 0x%x\n", status));\r
1031                 goto end;\r
1032         }\r
1033 \r
1034 #ifndef USE_WDM_INTERRUPTS\r
1035 \r
1036         //\r
1037         // create interrupt objects\r
1038         //\r
1039         for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
1040                 status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr,\r
1041                         NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt );\r
1042                 if (NT_SUCCESS(status)) \r
1043                         p_fdo->interrupt[i].valid = TRUE;\r
1044                 else {\r
1045                         MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV,\r
1046                                 ("WdfInterruptCreate failed %#x\n", status ));\r
1047                         goto end;\r
1048                 }\r
1049         }\r
1050 \r
1051 #endif\r
1052 \r
1053         status = STATUS_SUCCESS;\r
1054 \r
1055 end:    \r
1056         MLX4_EXIT( MLX4_DBG_DRV );\r
1057         return status;\r
1058 }\r
1059 \r
1060 \r
1061 \r
1062 void\r
1063 EvtDriverUnload(\r
1064         IN              WDFDRIVER  Driver\r
1065         )\r
1066 {\r
1067         MLX4_ENTER( MLX4_DBG_DRV );\r
1068 \r
1069         UNUSED_PARAM( Driver );\r
1070 \r
1071         mlx4_ib_cleanup();\r
1072         core_cleanup();\r
1073 \r
1074         MLX4_EXIT( MLX4_DBG_DRV );\r
1075 #if defined(EVENT_TRACING)\r
1076         WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));\r
1077 #endif\r
1078 \r
1079 }\r
1080 \r
1081 static\r
1082 NTSTATUS\r
1083 __read_registry(WDFDRIVER *hDriver)\r
1084 {\r
1085         DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel");\r
1086         DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags");\r
1087 \r
1088         // "log maximum number of QPs per HCA"\r
1089         DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp");\r
1090 \r
1091         // "log number of RDMARC buffers per QP"\r
1092         DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc");\r
1093 \r
1094         // "log maximum number of SRQs per HCA"\r
1095         DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq");\r
1096 \r
1097         // "log maximum number of CQs per HCA"\r
1098         DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq");\r
1099 \r
1100         // "log maximum number of multicast groups per HCA"\r
1101         DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg");\r
1102 \r
1103         // "log maximum number of memory protection table entries per HCA"\r
1104         DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt");\r
1105 \r
1106         // "log maximum number of memory translation table segments per HCA"\r
1107         DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt");     \r
1108 \r
1109         // "Maximum number of MACs per ETH port (1-127, default 1"\r
1110         DECLARE_CONST_UNICODE_STRING(numMac, L"NumMac");        \r
1111 \r
1112         // "Maximum number of VLANs per ETH port (0-126, default 0)"\r
1113         DECLARE_CONST_UNICODE_STRING(numVlan, L"NumVlan");      \r
1114 \r
1115         // "Enable steering by VLAN priority on ETH ports (0/1, default 0)"\r
1116         DECLARE_CONST_UNICODE_STRING(usePrio, L"UsePrio");      \r
1117 \r
1118         // "Enable Quality of Service support in the HCA if > 0, (default 1)"\r
1119         DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS");  \r
1120 \r
1121         // "Block multicast loopback packets if > 0 (default 1)"\r
1122         DECLARE_CONST_UNICODE_STRING(BlockMcastLB, L"BlockMcastLoopBack");      \r
1123 \r
1124         // "Measure the interrupt from the first packet (default 1)"\r
1125         DECLARE_CONST_UNICODE_STRING(InterruptFromFirstPacket, L"InterruptFromFirstPacket");    \r
1126 \r
1127         // "ProcessorAffinity"\r
1128         DECLARE_CONST_UNICODE_STRING(ProcessorAffinity, L"ProcessorAffinity");\r
1129 \r
1130         ULONG value;\r
1131         WDFKEY hKey = NULL;\r
1132         NTSTATUS status = STATUS_SUCCESS;\r
1133         \r
1134         status = WdfDriverOpenParametersRegistryKey( *hDriver,\r
1135                 STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey );\r
1136 \r
1137         if (NT_SUCCESS (status)) {\r
1138 \r
1139                 //\r
1140                 // Read general values\r
1141                 //\r
1142                 status = WdfRegistryQueryULong(hKey, &debugLevel, &value);\r
1143                 if (NT_SUCCESS (status)) \r
1144                         g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = value;\r
1145                 \r
1146                 status = WdfRegistryQueryULong(hKey, &debugFlags, &value);\r
1147                 if (NT_SUCCESS (status)) \r
1148                         g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = value;\r
1149 \r
1150                 status = WdfRegistryQueryULong(hKey, &numQp, &value);\r
1151                 if (NT_SUCCESS (status)) \r
1152                         g.mod_num_qp = value;\r
1153 \r
1154                 status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value);\r
1155                 if (NT_SUCCESS (status)) \r
1156                         g.mod_rdmarc_per_qp = value;\r
1157 \r
1158                 status = WdfRegistryQueryULong(hKey, &numSrq, &value);\r
1159                 if (NT_SUCCESS (status)) \r
1160                         g.mod_num_srq = value;\r
1161 \r
1162                 status = WdfRegistryQueryULong(hKey, &numCq, &value);\r
1163                 if (NT_SUCCESS (status)) \r
1164                         g.mod_num_cq = value;\r
1165 \r
1166                 status = WdfRegistryQueryULong(hKey, &numMcg, &value);\r
1167                 if (NT_SUCCESS (status)) \r
1168                         g.mod_num_mcg = value;\r
1169 \r
1170                 status = WdfRegistryQueryULong(hKey, &numMpt, &value);\r
1171                 if (NT_SUCCESS (status)) \r
1172                         g.mod_num_mpt = value;\r
1173                 \r
1174                 status = WdfRegistryQueryULong(hKey, &numMtt, &value);\r
1175                 if (NT_SUCCESS (status)) \r
1176                         g.mod_num_mtt = value;\r
1177 \r
1178                 status = WdfRegistryQueryULong(hKey, &numMac, &value);\r
1179                 if (NT_SUCCESS (status)) \r
1180                         g.mod_num_mac = value;\r
1181                 else\r
1182                         g.mod_num_mac = 1;\r
1183 \r
1184                 status = WdfRegistryQueryULong(hKey, &numVlan, &value);\r
1185                 if (NT_SUCCESS (status)) \r
1186                         g.mod_num_vlan= value;\r
1187                 else\r
1188                         g.mod_num_vlan = 0;\r
1189 \r
1190                 status = WdfRegistryQueryULong(hKey, &usePrio, &value);\r
1191                 if (NT_SUCCESS (status)) \r
1192                         g.mod_use_prio= value;\r
1193                 else\r
1194                         g.mod_use_prio = 0;\r
1195 \r
1196                 status = WdfRegistryQueryULong(hKey, &enableQoS, &value);\r
1197                 if (NT_SUCCESS (status)) \r
1198                         g.mod_enable_qos = value;\r
1199                 else\r
1200                         g.mod_enable_qos = 0;\r
1201 \r
1202 \r
1203                 status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value);\r
1204                 if (NT_SUCCESS (status)) \r
1205                         g.mod_mlx4_blck_lb = value;\r
1206                 else\r
1207                         g.mod_mlx4_blck_lb = 1;\r
1208 \r
1209                 status = WdfRegistryQueryULong(hKey, &InterruptFromFirstPacket, &value);\r
1210                 if (NT_SUCCESS (status)) \r
1211                         g.mod_interrupt_from_first = value;\r
1212                 else\r
1213                         g.mod_interrupt_from_first = 1;\r
1214 \r
1215 \r
1216                 status = WdfRegistryQueryULong(hKey, &ProcessorAffinity, &value);\r
1217                 if (NT_SUCCESS (status)) \r
1218                         g.mod_affinity = value;\r
1219                 else\r
1220                         g.mod_affinity = 0;\r
1221                 \r
1222 \r
1223                 WdfRegistryClose(hKey);\r
1224                 status = STATUS_SUCCESS;\r
1225         }\r
1226 \r
1227         return status;\r
1228 }\r
1229 \r
1230 NTSTATUS\r
1231 DriverEntry(\r
1232         IN PDRIVER_OBJECT DriverObject,\r
1233         IN PUNICODE_STRING RegistryPath\r
1234         )\r
1235 /*++\r
1236 Routine Description:\r
1237 \r
1238         Initialize the call backs structure of Driver Framework.\r
1239 \r
1240 Arguments:\r
1241 \r
1242         DriverObject - pointer to the driver object\r
1243 \r
1244         RegistryPath - pointer to a unicode string representing the path,\r
1245                                 to driver-specific key in the registry.\r
1246 \r
1247 Return Value:\r
1248 \r
1249   NT Status Code\r
1250 \r
1251 --*/\r
1252 {\r
1253         int err;\r
1254         WDF_DRIVER_CONFIG   config;\r
1255         NTSTATUS            status;\r
1256         WDFDRIVER hDriver;\r
1257 \r
1258 #if defined(EVENT_TRACING)\r
1259         WPP_INIT_TRACING(DriverObject, RegistryPath);\r
1260 #endif\r
1261 \r
1262 \r
1263         // global initializations\r
1264         RtlZeroMemory( &g, sizeof(g) );\r
1265         g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = TRACE_LEVEL_VERBOSE;\r
1266         g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = 0xffff;\r
1267 \r
1268         MLX4_ENTER(MLX4_DBG_DRV);\r
1269         MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, \r
1270                 ("Built %s %s, Version %s, RelDate %s\n", \r
1271                 __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE));\r
1272 \r
1273         mlx4_net_init();\r
1274         err = core_init();\r
1275         if (err) {\r
1276                 status = errno_to_ntstatus(err);\r
1277                 goto end;\r
1278         }\r
1279         err = mlx4_ib_init();\r
1280         if (err) {\r
1281                 status = errno_to_ntstatus(err);\r
1282                 goto end;\r
1283         }\r
1284 \r
1285         //\r
1286         // Initiialize driver config to control the attributes that\r
1287         // are global to the driver. Note that framework by default\r
1288         // provides a driver unload routine. If you create any resources\r
1289         // in the DriverEntry and want to be cleaned in driver unload,\r
1290         // you can override that by specifing one in the Config structure.\r
1291         //\r
1292 \r
1293         WDF_DRIVER_CONFIG_INIT(\r
1294                 &config, EvtDriverDeviceAdd );\r
1295         config.EvtDriverUnload = EvtDriverUnload;\r
1296 \r
1297         //\r
1298         // Create a framework driver object to represent our driver.\r
1299         //\r
1300         status = WdfDriverCreate(DriverObject,\r
1301                 RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
1302                 &config, &hDriver);\r
1303 \r
1304         if (!NT_SUCCESS(status)) {\r
1305                 MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status));\r
1306                 goto end;\r
1307         }\r
1308 \r
1309         //\r
1310         // read registry parameters\r
1311         //\r
1312         status = __read_registry(&hDriver);\r
1313 \r
1314         // we don't matter the failure in the work with Registry\r
1315         status = STATUS_SUCCESS;\r
1316         \r
1317 end:\r
1318         MLX4_EXIT( MLX4_DBG_DRV );\r
1319         return status;\r
1320 \r
1321 }\r
1322 \r
1323 \r
1324 \r
1325 \r