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