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