[MTHCA] feature: added new Registry parameter - TunePci - which is set by default...
[mirror/winof/.git] / hw / mthca / kernel / hca_driver.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id: hca_driver.c 46 2005-05-30 17:55:53Z sleybo $\r
30  */\r
31 \r
32 \r
33 /*\r
34  * Provides the driver entry points for the Tavor VPD.\r
35  */\r
36 \r
37 #include <mt_utils.h>\r
38 #include "hca_driver.h"\r
39 #include "hca_debug.h"\r
40 \r
41 #include "mthca_log.h"\r
42 #if defined(EVENT_TRACING)\r
43 #ifdef offsetof\r
44 #undef offsetof\r
45 #endif\r
46 #include "hca_driver.tmh"\r
47 #endif\r
48 #include "mthca_dev.h"\r
49 #include <wdmguid.h>\r
50 #include <initguid.h>\r
51 #pragma warning( push, 3 )\r
52 //#include "MdCard.h"\r
53 #pragma warning( pop )\r
54 #include <iba/ib_ci_ifc.h>\r
55 #include "mthca/mthca_vc.h"\r
56 \r
57 /* from \inc\platform\evntrace.h\r
58 #define TRACE_LEVEL_NONE        0   // Tracing is not on\r
59 #define TRACE_LEVEL_FATAL       1   // Abnormal exit or termination\r
60 #define TRACE_LEVEL_ERROR       2   // Severe errors that need logging\r
61 #define TRACE_LEVEL_WARNING     3   // Warnings such as allocation failure\r
62 #define TRACE_LEVEL_INFORMATION 4   // Includes non-error cases(e.g.,Entry-Exit)\r
63 #define TRACE_LEVEL_VERBOSE     5   // Detailed traces from intermediate steps\r
64 */\r
65 uint32_t g_mthca_dbg_level = TRACE_LEVEL_INFORMATION;\r
66 uint32_t g_mthca_dbg_flags= 0xffff;\r
67 WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ];\r
68 UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ];\r
69 uint32_t g_skip_tavor_reset=0;          /* skip reset for Tavor cards */\r
70 uint32_t g_disable_tavor_reset=1;               /* disable Tavor reset for the next driver load */\r
71 uint32_t g_tune_pci=0;                          /* 0 - skip tuning PCI configuration space of HCAs */\r
72 UNICODE_STRING                          g_param_path;\r
73 \r
74 \r
75 /*\r
76  * UVP name does not include file extension.  For debug builds, UAL\r
77  * will append "d.dll".  For release builds, UAL will append ".dll"\r
78  */\r
79 char                    mlnx_uvp_lib_name[MAX_LIB_NAME] = {"mthcau"};\r
80 \r
81 void reregister_hca( hca_dev_ext_t *p_ext );\r
82 \r
83 \r
84 NTSTATUS\r
85 DriverEntry(\r
86         IN                              PDRIVER_OBJECT                          p_driver_obj,\r
87         IN                              PUNICODE_STRING                         p_registry_path );\r
88 \r
89 static NTSTATUS\r
90 __read_registry(\r
91         IN                              UNICODE_STRING* const           p_Param_Path );\r
92 \r
93 static void\r
94 hca_drv_unload(\r
95         IN                              PDRIVER_OBJECT                          p_driver_obj );\r
96 \r
97 static NTSTATUS\r
98 hca_sysctl(\r
99         IN                              PDEVICE_OBJECT                          p_dev_obj,\r
100         IN                              PIRP                                            p_irp );\r
101 \r
102 static NTSTATUS\r
103 __pnp_notify_target(\r
104         IN                              TARGET_DEVICE_REMOVAL_NOTIFICATION      *p_notify,\r
105         IN                              void                                            *context );\r
106 \r
107 static NTSTATUS\r
108 __pnp_notify_ifc(\r
109         IN                              DEVICE_INTERFACE_CHANGE_NOTIFICATION    *p_notify,\r
110         IN                              void                                            *context );\r
111 \r
112 static NTSTATUS\r
113 fw_access_pciconf (\r
114                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
115                 IN              ULONG                                                   op_flag,\r
116                 IN              PVOID                                                   p_buffer,\r
117                 IN              ULONG                                                   offset,\r
118                 IN              ULONG POINTER_ALIGNMENT                 length );\r
119 \r
120 static NTSTATUS\r
121 fw_flash_write_data (\r
122                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
123                 IN              PVOID                                                   p_buffer,\r
124                 IN              ULONG                                                   offset,\r
125                 IN              ULONG POINTER_ALIGNMENT                 length );\r
126 \r
127 static NTSTATUS\r
128 fw_flash_read_data (\r
129                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
130                 IN              PVOID                                                   p_buffer,\r
131                 IN              ULONG                                                   offset,\r
132                 IN              ULONG POINTER_ALIGNMENT                 length );\r
133 \r
134 static NTSTATUS\r
135 fw_flash_read4( \r
136         IN                      BUS_INTERFACE_STANDARD  *p_BusInterface,\r
137         IN                      uint32_t                                addr, \r
138         IN      OUT             uint32_t                                *p_data);\r
139 \r
140 static NTSTATUS\r
141 fw_flash_readbuf(\r
142         IN              BUS_INTERFACE_STANDARD  *p_BusInterface,\r
143         IN              uint32_t                                offset,\r
144         IN OUT  void                                    *p_data,\r
145         IN              uint32_t                                len);\r
146 static NTSTATUS\r
147 fw_set_bank(\r
148         IN              BUS_INTERFACE_STANDARD  *p_BusInterface,\r
149         IN              uint32_t                                bank );\r
150 \r
151 static NTSTATUS\r
152 fw_flash_init(\r
153                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface  );\r
154 \r
155 static NTSTATUS\r
156 fw_flash_deinit(\r
157                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface  );\r
158 \r
159 #ifdef ALLOC_PRAGMA\r
160 #pragma alloc_text (INIT, DriverEntry)\r
161 #pragma alloc_text (INIT, __read_registry)\r
162 #pragma alloc_text (PAGE, hca_drv_unload)\r
163 #pragma alloc_text (PAGE, hca_sysctl)\r
164 #endif\r
165 \r
166 NTSTATUS\r
167 DriverEntry(\r
168         IN                              PDRIVER_OBJECT                  p_driver_obj,\r
169         IN                              PUNICODE_STRING                 p_registry_path )\r
170 {\r
171         NTSTATUS                        status;\r
172         cl_status_t                     cl_status;\r
173 #if defined(EVENT_TRACING)\r
174         WPP_INIT_TRACING(p_driver_obj ,p_registry_path);\r
175 #endif\r
176         HCA_ENTER( HCA_DBG_DEV );\r
177 \r
178         /* init common mechanisms */\r
179         fill_bit_tbls();\r
180 \r
181         status = __read_registry( p_registry_path );\r
182         if( !NT_SUCCESS( status ) )\r
183         {\r
184                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, \r
185                         ("__read_registry_path returned 0x%X.\n", status));\r
186                 return status;\r
187         }\r
188 \r
189         /* Initialize Adapter DB */\r
190         cl_status = mlnx_hcas_init();\r
191         if( cl_status != CL_SUCCESS )\r
192         {\r
193                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,\r
194                         ("mlnx_hcas_init returned %s.\n", cl_status_text[cl_status]));\r
195                 return cl_to_ntstatus( cl_status );\r
196         }\r
197 //      cl_memclr( mlnx_hca_array, MLNX_MAX_HCA * sizeof(ci_interface_t) );\r
198 \r
199         /*leo:  init function table */\r
200         hca_init_vfptr();\r
201         \r
202         p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
203         p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
204         p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = hca_sysctl;\r
205         p_driver_obj->DriverUnload = hca_drv_unload;\r
206         p_driver_obj->DriverExtension->AddDevice = hca_add_device;\r
207 \r
208         /* init core */\r
209         if (ib_core_init()) {\r
210                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("Failed to init core, aborting.\n"));\r
211                 return STATUS_UNSUCCESSFUL;\r
212         }\r
213 \r
214         /* init uverbs module */\r
215         if (ib_uverbs_init()) {\r
216                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("Failed ib_uverbs_init, aborting.\n"));\r
217                 return STATUS_UNSUCCESSFUL;\r
218         }\r
219         HCA_EXIT( HCA_DBG_DEV );\r
220         return STATUS_SUCCESS;\r
221 }\r
222 \r
223 \r
224 static NTSTATUS\r
225 __read_registry(\r
226         IN                              UNICODE_STRING* const   p_registry_path )\r
227 {\r
228         NTSTATUS                                        status;\r
229         /* Remember the terminating entry in the table below. */\r
230         RTL_QUERY_REGISTRY_TABLE        table[6];\r
231 \r
232         HCA_ENTER( HCA_DBG_DEV );\r
233 \r
234         RtlInitUnicodeString( &g_param_path, NULL );\r
235         g_param_path.MaximumLength = p_registry_path->Length + \r
236                 sizeof(L"\\Parameters");\r
237         g_param_path.Buffer = cl_zalloc( g_param_path.MaximumLength );\r
238         if( !g_param_path.Buffer )\r
239         {\r
240                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, \r
241                         ("Failed to allocate parameters path buffer.\n"));\r
242                 return STATUS_INSUFFICIENT_RESOURCES;\r
243         }\r
244 \r
245         RtlAppendUnicodeStringToString( &g_param_path, p_registry_path );\r
246         RtlAppendUnicodeToString( &g_param_path, L"\\Parameters" );\r
247 \r
248         /*\r
249          * Clear the table.  This clears all the query callback pointers,\r
250          * and sets up the terminating table entry.\r
251          */\r
252         cl_memclr( table, sizeof(table) );\r
253 \r
254         /* Setup the table entries. */\r
255         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
256         table[0].Name = L"DebugLevel";\r
257         table[0].EntryContext = &g_mthca_dbg_level;\r
258         table[0].DefaultType = REG_DWORD;\r
259         table[0].DefaultData = &g_mthca_dbg_level;\r
260         table[0].DefaultLength = sizeof(ULONG);\r
261 \r
262         \r
263         table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
264         table[1].Name = L"DebugFlags";\r
265         table[1].EntryContext = &g_mthca_dbg_flags;\r
266         table[1].DefaultType = REG_DWORD;\r
267         table[1].DefaultData = &g_mthca_dbg_flags;\r
268         table[1].DefaultLength = sizeof(ULONG);\r
269 \r
270         table[2].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
271         table[2].Name = L"SkipTavorReset";\r
272         table[2].EntryContext = &g_skip_tavor_reset;\r
273         table[2].DefaultType = REG_DWORD;\r
274         table[2].DefaultData = &g_skip_tavor_reset;\r
275         table[2].DefaultLength = sizeof(ULONG);\r
276 \r
277         table[3].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
278         table[3].Name = L"DisableTavorResetOnFailure";\r
279         table[3].EntryContext = &g_disable_tavor_reset;\r
280         table[3].DefaultType = REG_DWORD;\r
281         table[3].DefaultData = &g_disable_tavor_reset;\r
282         table[3].DefaultLength = sizeof(ULONG);\r
283 \r
284         table[4].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
285         table[4].Name = L"TunePci";\r
286         table[4].EntryContext = &g_tune_pci;\r
287         table[4].DefaultType = REG_DWORD;\r
288         table[4].DefaultData = &g_tune_pci;\r
289         table[4].DefaultLength = sizeof(ULONG);\r
290 \r
291         /* Have at it! */\r
292         status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
293                 g_param_path.Buffer, table, NULL, NULL );\r
294 \r
295         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_INIT, \r
296                 ("debug level  %d debug flags  0x%.8x SkipTavorReset %d DisableTavorReset %d TunePci %d\n",\r
297                 g_mthca_dbg_level ,     g_mthca_dbg_flags,\r
298                 g_skip_tavor_reset, g_disable_tavor_reset,\r
299                 g_tune_pci ));\r
300 \r
301         HCA_EXIT( HCA_DBG_DEV );\r
302         return status;\r
303 }\r
304 \r
305 void set_skip_tavor_reset()\r
306 {\r
307         NTSTATUS status;\r
308         HANDLE key_handle;\r
309         UNICODE_STRING key_name;\r
310         ULONG val = 1;\r
311         OBJECT_ATTRIBUTES oa;\r
312 \r
313         HCA_ENTER( HCA_DBG_DEV );\r
314 \r
315         InitializeObjectAttributes( &oa, &g_param_path, \r
316                 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );\r
317 \r
318 \r
319         status = ZwOpenKey( &key_handle, GENERIC_WRITE, &oa );\r
320         if( !NT_SUCCESS( status ) ) {\r
321                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW, \r
322                         ("ZwOpenKey failed (%#x)\n", status));\r
323                 goto err_open_key;\r
324         }\r
325 \r
326         RtlInitUnicodeString( &key_name, L"SkipTavorReset" );\r
327         status = ZwSetValueKey( key_handle, &key_name, 0, \r
328                 REG_DWORD, &val, sizeof(ULONG) );\r
329         if( !NT_SUCCESS( status ) ) {\r
330                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW, \r
331                         ("ZwSetValueKey failed (%#x)\n", status));\r
332         }\r
333 \r
334         ZwClose( key_handle );\r
335 \r
336 err_open_key:\r
337         HCA_EXIT( HCA_DBG_DEV );\r
338 }\r
339 \r
340 static void\r
341 hca_drv_unload(\r
342         IN                              PDRIVER_OBJECT                  p_driver_obj )\r
343 {\r
344         HCA_ENTER( HCA_DBG_DEV );\r
345 \r
346         UNUSED_PARAM( p_driver_obj );\r
347 \r
348         ib_uverbs_cleanup();\r
349         ib_core_cleanup();\r
350         cl_free( g_param_path.Buffer );\r
351         \r
352         HCA_EXIT( HCA_DBG_DEV );\r
353 #if defined(EVENT_TRACING)\r
354         WPP_CLEANUP(p_driver_obj);\r
355 #endif\r
356 \r
357 }\r
358 \r
359 \r
360 static NTSTATUS\r
361 hca_sysctl(\r
362         IN                              PDEVICE_OBJECT                          p_dev_obj,\r
363         IN                              PIRP                                            p_irp )\r
364 {\r
365         NTSTATUS                status;\r
366         hca_dev_ext_t   *p_ext;\r
367 \r
368         HCA_ENTER( HCA_DBG_DEV );\r
369 \r
370         p_ext = p_dev_obj->DeviceExtension;\r
371 \r
372         IoSkipCurrentIrpStackLocation( p_irp );\r
373         status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
374 \r
375         HCA_EXIT( HCA_DBG_DEV );\r
376         return status;\r
377 }\r
378 \r
379 typedef struct Primary_Sector{\r
380         uint32_t fi_addr;\r
381         uint32_t fi_size;\r
382         uint32_t signature;\r
383         uint32_t fw_reserved[5];\r
384         uint32_t vsd[56];\r
385         uint32_t branch_to;\r
386         uint32_t crc016;\r
387 } primary_sector_t;\r
388 \r
389 static uint32_t old_dir;\r
390 static uint32_t old_pol;\r
391 static uint32_t old_mod;\r
392 static uint32_t old_dat;\r
393 \r
394 static NTSTATUS\r
395 fw_access_pciconf (\r
396                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
397                 IN              ULONG                                                   op_flag,\r
398                 IN              PVOID                                                   p_buffer,\r
399                 IN              ULONG                                                   offset,\r
400                 IN              ULONG POINTER_ALIGNMENT                 length )\r
401 {\r
402 \r
403         ULONG                           bytes;  \r
404         NTSTATUS                        status = STATUS_SUCCESS;\r
405 \r
406         PAGED_CODE();\r
407 \r
408         if( !p_buffer )\r
409                 return STATUS_INVALID_PARAMETER;\r
410 \r
411         if (p_BusInterface)\r
412         {\r
413 \r
414                 bytes = p_BusInterface->SetBusData(\r
415                                                 p_BusInterface->Context,\r
416                                                 PCI_WHICHSPACE_CONFIG,\r
417                                                 (PVOID)&offset,\r
418                                                 PCI_CONF_ADDR,\r
419                                                 sizeof(ULONG) );\r
420 \r
421                 if( op_flag == 0 )\r
422                 {\r
423                         if ( bytes )\r
424                                 bytes = p_BusInterface->GetBusData(\r
425                                                         p_BusInterface->Context,\r
426                                                         PCI_WHICHSPACE_CONFIG,\r
427                                                         p_buffer,\r
428                                                         PCI_CONF_DATA,\r
429                                                         length );\r
430                         if ( !bytes )\r
431                                 status = STATUS_NOT_SUPPORTED;\r
432                 }\r
433 \r
434                 else\r
435                 {\r
436                         if ( bytes )\r
437                                 bytes = p_BusInterface->SetBusData(\r
438                                                         p_BusInterface->Context,\r
439                                                         PCI_WHICHSPACE_CONFIG,\r
440                                                         p_buffer,\r
441                                                         PCI_CONF_DATA,\r
442                                                         length);\r
443 \r
444                         if ( !bytes )\r
445                                 status = STATUS_NOT_SUPPORTED;\r
446                 }\r
447         }\r
448         return status;\r
449 }\r
450 \r
451 \r
452 static NTSTATUS\r
453 __map_crspace(\r
454         IN              struct ib_ucontext *                    p_context,\r
455         IN              mlnx_hob_t                      *       p_hob,\r
456         IN              PVOID                                           p_buf,\r
457         IN              ULONG                                           buf_size\r
458         )\r
459 {\r
460         NTSTATUS status;\r
461         PMDL p_mdl;\r
462         PVOID ua, ka;\r
463         ULONG sz;\r
464         hca_dev_ext_t *p_ext = EXT_FROM_HOB(p_hob);\r
465         map_crspace *p_res = (map_crspace *)p_buf;\r
466 \r
467         HCA_ENTER( HCA_DBG_PNP );\r
468 \r
469         // sanity checks\r
470         if ( buf_size < sizeof *p_res || !p_buf ) {\r
471                 status = STATUS_INVALID_PARAMETER;\r
472                 goto err_invalid_params;\r
473         }\r
474 \r
475         // map memory\r
476         sz =(ULONG)p_ext->bar[HCA_BAR_TYPE_HCR].size;\r
477         if (!p_ext->bar[HCA_BAR_TYPE_HCR].virt) {\r
478                 PHYSICAL_ADDRESS pa;\r
479                 pa.QuadPart = p_ext->bar[HCA_BAR_TYPE_HCR].phys;\r
480                 ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
481                 if ( ka == NULL) {\r
482                         HCA_PRINT(TRACE_LEVEL_ERROR  , HCA_DBG_SHIM,\r
483                                 ("No kernel mapping of CR space.\n") );\r
484                         status = STATUS_INSUFFICIENT_RESOURCES;\r
485                         goto err_map_to_kernel;\r
486                 }\r
487                 p_ext->bar[HCA_BAR_TYPE_HCR].virt = ka;\r
488         }\r
489         ka = p_ext->bar[HCA_BAR_TYPE_HCR].virt;\r
490 \r
491         // prepare for mapping to user space \r
492         p_mdl = IoAllocateMdl( ka, sz, FALSE,FALSE,NULL);\r
493         if (p_mdl == NULL) {\r
494                 HCA_PRINT(TRACE_LEVEL_ERROR  , HCA_DBG_SHIM, \r
495                         ("IoAllocateMdl failed.\n") );\r
496                 status = STATUS_INSUFFICIENT_RESOURCES;\r
497                 goto err_alloc_mdl;\r
498         }\r
499 \r
500         // fill MDL\r
501         MmBuildMdlForNonPagedPool(p_mdl);\r
502         \r
503         // map the buffer into user space \r
504         __try\r
505         {\r
506                 ua = MmMapLockedPagesSpecifyCache( p_mdl, UserMode, MmNonCached,\r
507                         NULL, FALSE, NormalPagePriority );\r
508         }\r
509         __except(EXCEPTION_EXECUTE_HANDLER)\r
510         {\r
511                 HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM,\r
512                         ("MmMapLockedPagesSpecifyCache failed.\n") );\r
513                 status = STATUS_INSUFFICIENT_RESOURCES;\r
514                 goto err_map_to_user;\r
515         }\r
516         \r
517         // fill the results\r
518         p_res->va = (uint64_t)(ULONG_PTR)ua;\r
519         p_res->size = sz;\r
520 \r
521         // resource tracking\r
522         p_context->p_mdl = p_mdl;\r
523         p_context->va = ua;\r
524         \r
525         status = STATUS_SUCCESS;\r
526         goto out;\r
527 \r
528 err_map_to_user:\r
529         IoFreeMdl( p_mdl );\r
530 err_alloc_mdl:\r
531 err_map_to_kernel:\r
532 err_invalid_params:     \r
533 out:    \r
534         HCA_EXIT( HCA_DBG_PNP );\r
535         return status;\r
536 }\r
537 \r
538 \r
539 static void\r
540 __unmap_crspace(\r
541         IN              struct ib_ucontext *                    p_context\r
542         )\r
543 {\r
544         HCA_ENTER( HCA_DBG_PNP );\r
545 \r
546         if (p_context->va && p_context->p_mdl) {\r
547                 MmUnmapLockedPages(p_context->va, p_context->p_mdl);\r
548                 IoFreeMdl( p_context->p_mdl );\r
549                 p_context->va = p_context->p_mdl = NULL;\r
550                 //NB: the unmap of IO space is being done in __UnmapHcaMemoryResources\r
551         }\r
552 \r
553         HCA_EXIT( HCA_DBG_PNP );\r
554 }\r
555 \r
556 \r
557 static void\r
558 __open_fw_access(\r
559         IN                              struct ib_ucontext*                     p_context,\r
560         IN                              PBUS_INTERFACE_STANDARD         p_bus_interface )\r
561 {\r
562         if( !p_context->fw_if_open )\r
563         {\r
564                 p_bus_interface->InterfaceReference( p_bus_interface->Context );\r
565                 p_context->fw_if_open = TRUE;\r
566         }\r
567 }\r
568 \r
569 \r
570 static void \r
571 __close_fw_access(\r
572         IN              struct ib_ucontext *    p_context,\r
573         IN              PBUS_INTERFACE_STANDARD p_bus_interface\r
574         )\r
575 {\r
576         if (p_context->fw_if_open ) {\r
577                 p_bus_interface->InterfaceDereference((PVOID)p_bus_interface->Context);\r
578                 p_context->fw_if_open = FALSE;\r
579         }\r
580 }\r
581 \r
582 \r
583 void\r
584 unmap_crspace_for_all( struct ib_ucontext *p_context )\r
585 {\r
586         mlnx_hob_t      *p_hob = HOB_FROM_IBDEV( p_context->device );\r
587         hca_dev_ext_t *p_ext = EXT_FROM_HOB(p_hob);\r
588         PBUS_INTERFACE_STANDARD    p_bus_interface = &p_ext->hcaBusIfc;\r
589 \r
590         HCA_ENTER( HCA_DBG_PNP );\r
591 \r
592         down( &p_context->mutex );\r
593         __unmap_crspace( p_context);\r
594         __close_fw_access(p_context, p_bus_interface);\r
595         up( &p_context->mutex );\r
596 \r
597         HCA_EXIT( HCA_DBG_PNP );\r
598 }\r
599 \r
600 ib_api_status_t\r
601 fw_access_ctrl(\r
602         IN              const   ib_ca_handle_t                          h_ca,\r
603         IN              const   void* __ptr64* const            handle_array    OPTIONAL,\r
604         IN                              uint32_t                                        num_handles,\r
605         IN                              ib_ci_op_t* const                       p_ci_op,\r
606         IN      OUT                     ci_umv_buf_t                            *p_umv_buf )\r
607 {\r
608         DEVICE_OBJECT                           *p_dev_obj;\r
609         PBUS_INTERFACE_STANDARD         p_bus_interface;\r
610         NTSTATUS                                        status = STATUS_SUCCESS;\r
611         PVOID                                           p_data;\r
612         ULONG                                           offset;\r
613         ULONG POINTER_ALIGNMENT         length;\r
614         struct ib_ucontext *                    p_context;\r
615         mlnx_hob_t                                      *p_hob;\r
616         hca_dev_ext_t *p_ext;\r
617 \r
618         UNREFERENCED_PARAMETER(handle_array);\r
619         UNREFERENCED_PARAMETER(num_handles);\r
620 \r
621         if( !p_umv_buf )\r
622                 return IB_UNSUPPORTED;\r
623 \r
624         p_context = (struct ib_ucontext *)h_ca;\r
625         p_hob = HOB_FROM_IBDEV( p_context->device );\r
626         p_ext = EXT_FROM_HOB(p_hob);\r
627         p_dev_obj = (DEVICE_OBJECT *)p_ext->cl_ext.p_self_do;\r
628         p_bus_interface = &p_ext->hcaBusIfc;\r
629 \r
630         if ( !p_ci_op )\r
631                 return IB_INVALID_PARAMETER;\r
632 \r
633         length = p_ci_op->buf_size;\r
634         offset = p_ci_op->buf_info;\r
635         p_data = p_ci_op->p_buf;\r
636 \r
637         down( &p_context->mutex );\r
638 \r
639         switch ( p_ci_op->command )\r
640         {\r
641         case FW_REREGISTER_HCA:\r
642                 reregister_hca(p_ext);\r
643                 break;\r
644                 \r
645         case FW_MAP_CRSPACE:\r
646                 status = __map_crspace(p_context, p_hob, p_data, length);\r
647                 break;\r
648                 \r
649         case FW_UNMAP_CRSPACE:\r
650                 __unmap_crspace(p_context);\r
651                 break;\r
652                                 \r
653         case FW_OPEN_IF: // open BusInterface\r
654                 __open_fw_access( p_context, p_bus_interface );\r
655                 break;\r
656 \r
657         case FW_READ: // read data from flash\r
658                 if ( p_context->fw_if_open )\r
659                         status = fw_flash_read_data(p_bus_interface, p_data, offset, length);\r
660                 break;\r
661 \r
662         case FW_WRITE: // write data to flash\r
663                 if ( p_context->fw_if_open )\r
664                         status = fw_flash_write_data(p_bus_interface, p_data, offset, length);\r
665                 break;\r
666 \r
667         case FW_READ_CMD:\r
668                 if ( p_context->fw_if_open )\r
669                         status = fw_access_pciconf(p_bus_interface, 0 , p_data, offset, 4);\r
670                 break;\r
671 \r
672         case FW_WRITE_CMD:\r
673                 if ( p_context->fw_if_open )\r
674                         status = fw_access_pciconf(p_bus_interface, 1 , p_data, offset, 4);\r
675                 break;\r
676 \r
677         case FW_CLOSE_IF: // close BusInterface\r
678                 __close_fw_access(p_context, p_bus_interface);\r
679                 break;\r
680 \r
681         default:\r
682                 status = STATUS_INVALID_DEVICE_REQUEST;\r
683         }\r
684 \r
685         if ( status != STATUS_SUCCESS ) {\r
686                 __close_fw_access(p_context, p_bus_interface);\r
687                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, \r
688                         ("fw_access_ctrl failed, ntstatus: %08x.\n", status));\r
689         }\r
690 \r
691         up( &p_context->mutex );\r
692 \r
693         switch( status ) {\r
694                 case STATUS_SUCCESS:                                    return IB_SUCCESS;\r
695                 case STATUS_INVALID_DEVICE_REQUEST:     return IB_UNSUPPORTED;\r
696                 case STATUS_INSUFFICIENT_RESOURCES:     return IB_INSUFFICIENT_RESOURCES;\r
697                 default:                                                                        return IB_ERROR;\r
698         }\r
699 }\r
700 \r
701 static NTSTATUS\r
702 fw_flash_write_data (\r
703                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
704                 IN              PVOID                                                   p_buffer,\r
705                 IN              ULONG                                                   offset,\r
706                 IN              ULONG POINTER_ALIGNMENT                 length )\r
707 {\r
708         NTSTATUS                status;\r
709         uint32_t                cnt = 0;\r
710         uint32_t                lcl_data;\r
711 \r
712         if (!length)\r
713                 return IB_INVALID_PARAMETER;\r
714         \r
715         lcl_data = (*((uint32_t*)p_buffer) << 24);\r
716 \r
717         status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET+4, length );\r
718         if ( status != STATUS_SUCCESS )\r
719                 return status;\r
720         lcl_data = ( WRITE_BIT | (offset & ADDR_MSK));\r
721                 \r
722         status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET, 4 );\r
723         if ( status != STATUS_SUCCESS )\r
724         return status;\r
725 \r
726         lcl_data = 0;\r
727         \r
728         do\r
729         {\r
730                 if (++cnt > 5000)\r
731                 {\r
732                         return STATUS_DEVICE_NOT_READY;\r
733                 }\r
734 \r
735                 status = fw_access_pciconf(p_BusInterface, FW_READ , &lcl_data, FLASH_OFFSET, 4 );\r
736                 if ( status != STATUS_SUCCESS )\r
737                 return status;\r
738 \r
739         } while(lcl_data & CMD_MASK);\r
740 \r
741         return status;\r
742 }\r
743 \r
744 static NTSTATUS\r
745 fw_flash_read_data (\r
746                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
747                 IN              PVOID                                                   p_buffer,\r
748                 IN              ULONG                                                   offset,\r
749                 IN              ULONG POINTER_ALIGNMENT                 length )\r
750 {\r
751         NTSTATUS        status = STATUS_SUCCESS;\r
752         uint32_t        cnt = 0;\r
753         uint32_t        lcl_data = ( READ_BIT | (offset & ADDR_MSK));\r
754 \r
755         if (!length)\r
756                 return IB_INVALID_PARAMETER;\r
757         \r
758         status = fw_access_pciconf(p_BusInterface, FW_WRITE, &lcl_data, FLASH_OFFSET, 4 );\r
759         if ( status != STATUS_SUCCESS )\r
760                 return status;\r
761 \r
762         lcl_data = 0;\r
763         do\r
764         {\r
765                 // Timeout checks\r
766                 if (++cnt > 5000 )\r
767                 {\r
768                         return STATUS_DEVICE_NOT_READY;\r
769         }\r
770 \r
771                 status = fw_access_pciconf(p_BusInterface, FW_READ, &lcl_data, FLASH_OFFSET, 4 );\r
772         \r
773                 if ( status != STATUS_SUCCESS )\r
774                         return status;\r
775 \r
776         } while(lcl_data & CMD_MASK);\r
777 \r
778         status = fw_access_pciconf(p_BusInterface, FW_READ, p_buffer, FLASH_OFFSET+4, length );\r
779         return status;\r
780 }\r
781 \r
782 static NTSTATUS\r
783 fw_flash_read4( \r
784         IN                      BUS_INTERFACE_STANDARD  *p_BusInterface,\r
785         IN                      uint32_t                                addr, \r
786         IN      OUT             uint32_t                                *p_data)\r
787 {\r
788         NTSTATUS        status = STATUS_SUCCESS;\r
789         uint32_t lcl_data = 0;\r
790         uint32_t bank;\r
791         static uint32_t curr_bank =     0xffffffff;\r
792 \r
793         if (addr & 0x3)\r
794         {\r
795                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT,\r
796                         ("Invalid address %08x\n", addr) );\r
797                 return STATUS_INVALID_PARAMETER;\r
798         }\r
799 \r
800         bank = addr & BANK_MASK;\r
801         if (bank !=  curr_bank)\r
802         {\r
803                 curr_bank = bank;\r
804                 if ((status = fw_set_bank(p_BusInterface, bank)) != STATUS_SUCCESS )\r
805                 {\r
806                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT,\r
807                                 ("fw_set_bank returned %08x\n", status) );\r
808                         return STATUS_INVALID_PARAMETER;\r
809                 }\r
810         }\r
811         status = fw_flash_read_data(p_BusInterface, &lcl_data, addr, 4);\r
812         *p_data = cl_ntoh32(lcl_data);\r
813         return STATUS_SUCCESS;\r
814 }\r
815 \r
816 static NTSTATUS\r
817 fw_flash_readbuf(\r
818                 IN              BUS_INTERFACE_STANDARD  *p_BusInterface,\r
819                 IN              uint32_t                                offset,\r
820                 IN OUT  void                                    *p_data,\r
821                 IN              uint32_t                                len)\r
822 {\r
823         NTSTATUS        status = STATUS_SUCCESS;\r
824         uint32_t *p_lcl_data;\r
825         uint32_t        i;\r
826 \r
827     if (offset & 0x3)\r
828     {\r
829         //Address should be 4-bytes aligned\r
830                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT,\r
831                         ("Invalid address %08x\n", offset) );\r
832         return STATUS_INVALID_PARAMETER;\r
833     }\r
834     if (len & 0x3)\r
835     {\r
836         //Length should be 4-bytes aligned\r
837                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT,\r
838                         ("Invalid length %d\n", len) );\r
839         return STATUS_INVALID_PARAMETER;\r
840     }\r
841     p_lcl_data = (uint32_t *)p_data;\r
842     \r
843         for ( i=0; i < (len >> 2); i++)\r
844     {                                   \r
845         if ( (status = fw_flash_read_data( p_BusInterface, p_lcl_data, offset, sizeof(uint32_t) )) != STATUS_SUCCESS )\r
846             return status;\r
847         offset += 4;\r
848                 p_lcl_data++;\r
849     }\r
850     return STATUS_SUCCESS;\r
851 } // Flash::flash_read\r
852 \r
853 static NTSTATUS\r
854 fw_flash_writebuf(\r
855                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
856                 IN              PVOID                                                   p_buffer,\r
857                 IN              ULONG                                                   offset,\r
858                 IN              ULONG POINTER_ALIGNMENT                 length )\r
859 {\r
860         NTSTATUS status = STATUS_SUCCESS;\r
861         uint32_t        i;\r
862         uint8_t *p_data = (uint8_t *)p_buffer;\r
863 \r
864         for ( i = 0; i < length;  i++ )\r
865         {\r
866                 status = fw_flash_write_data (p_BusInterface, p_data, offset, 1 );\r
867                 if (status != STATUS_SUCCESS )\r
868                         return status;\r
869                 p_data++;\r
870                 offset++;\r
871         }\r
872         return status;\r
873 }\r
874 static NTSTATUS\r
875 fw_flash_init(\r
876                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface  )\r
877 {\r
878         uint32_t dir;\r
879     uint32_t pol;\r
880     uint32_t mod;\r
881 \r
882     uint32_t cnt=0;\r
883     uint32_t data;\r
884         NTSTATUS status = STATUS_SUCCESS;\r
885         uint32_t        semaphore = 0;\r
886     \r
887         while ( !semaphore )\r
888         {\r
889                 status = fw_access_pciconf(p_BusInterface, FW_READ , &data, SEMAP63, 4);\r
890                 if ( status != STATUS_SUCCESS )\r
891                         break;\r
892                 if( !data )\r
893                 {\r
894                         semaphore = 1;\r
895                         break;\r
896                 }\r
897         if (++cnt > 5000 )\r
898         {\r
899             break;\r
900         }\r
901     } \r
902 \r
903         if ( !semaphore )\r
904         {\r
905                 return STATUS_NOT_SUPPORTED;\r
906         }\r
907 \r
908     // Save old values\r
909     \r
910         status = fw_access_pciconf(p_BusInterface, FW_READ , &old_dir,GPIO_DIR_L , 4);\r
911         if ( status == STATUS_SUCCESS )\r
912                 status = fw_access_pciconf(p_BusInterface, FW_READ , &old_pol,GPIO_POL_L , 4);\r
913         if ( status == STATUS_SUCCESS )\r
914                 status = fw_access_pciconf(p_BusInterface, FW_READ , &old_mod,GPIO_MOD_L , 4);\r
915         if ( status == STATUS_SUCCESS )\r
916                 status = fw_access_pciconf(p_BusInterface, FW_READ , &old_dat,GPIO_DAT_L , 4);\r
917 \r
918    // Set Direction=1, Polarity=0, Mode=0 for 3 GPIO lower bits\r
919     dir = old_dir | 0x70;\r
920     pol = old_pol & ~0x70;\r
921     mod = old_mod & ~0x70;\r
922 \r
923         status = fw_access_pciconf(p_BusInterface, FW_WRITE , &dir,GPIO_DIR_L , 4);\r
924         if ( status == STATUS_SUCCESS )\r
925                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &pol,GPIO_POL_L , 4);\r
926         if ( status == STATUS_SUCCESS )\r
927                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &mod,GPIO_MOD_L , 4);\r
928         if ( status == STATUS_SUCCESS )\r
929                 // Set CPUMODE\r
930                 status = fw_access_pciconf(p_BusInterface, FW_READ , &data, CPUMODE, 4);\r
931     if ( status == STATUS_SUCCESS )\r
932         {\r
933                 data &= ~CPUMODE_MSK;\r
934                 data |= 1 << CPUMODE_SHIFT;\r
935                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, CPUMODE, 4);\r
936         }\r
937         if ( status == STATUS_SUCCESS )\r
938         {\r
939                 // Reset flash\r
940                 data = 0xf0;\r
941                 status = fw_flash_write_data(p_BusInterface, &data, 0x0, 4);\r
942         }\r
943         return status;\r
944 }\r
945 \r
946 static NTSTATUS\r
947 fw_flash_deinit(\r
948         IN              BUS_INTERFACE_STANDARD  *p_BusInterface )\r
949 {\r
950         uint32_t data = 0;\r
951         NTSTATUS status = STATUS_SUCCESS;\r
952     \r
953         status = fw_set_bank(p_BusInterface, 0);\r
954         if ( status == STATUS_SUCCESS )\r
955                 // Restore origin values\r
956                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_dir,GPIO_DIR_L , 4);\r
957         if ( status == STATUS_SUCCESS )\r
958                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_pol,GPIO_POL_L , 4);\r
959         if ( status == STATUS_SUCCESS )\r
960                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_mod,GPIO_MOD_L , 4);\r
961         if ( status == STATUS_SUCCESS )\r
962                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_dat,GPIO_DAT_L , 4);\r
963         if ( status == STATUS_SUCCESS )\r
964                 // Free GPIO Semaphore\r
965                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, SEMAP63, 4);\r
966         return status;\r
967 }\r
968 \r
969 static NTSTATUS\r
970 fw_set_bank(\r
971         IN              BUS_INTERFACE_STANDARD  *p_BusInterface,\r
972         IN               uint32_t bank )\r
973 {\r
974         NTSTATUS  status = STATUS_SUCCESS;\r
975         uint32_t        data = ( (uint32_t)0x70 << 24 );\r
976         uint32_t        mask = ((bank >> (BANK_SHIFT-4)) << 24 );\r
977 \r
978         status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, GPIO_DATACLEAR_L, 4);\r
979         if (status == STATUS_SUCCESS)\r
980         {\r
981         // A1\r
982                 data &= mask;\r
983                 //data |= mask; // for A0\r
984                 status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, GPIO_DATASET_L, 4);\r
985         }\r
986         return status;\r
987 }\r