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