[MLTHCA] added polling mode support.
[mirror/winof/.git] / hw / mlx4 / kernel / hca / fw.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $\r
32  */\r
33 \r
34 #include "precomp.h"\r
35 \r
36 #if defined(EVENT_TRACING)\r
37 #ifdef offsetof\r
38 #undef offsetof\r
39 #endif\r
40 #include "fw.tmh"\r
41 #endif\r
42 \r
43 \r
44 /***********************************\r
45 Firmware Update definitions\r
46 ***********************************/\r
47 #define PCI_CONF_ADDR   (0x00000058)\r
48 #define PCI_CONF_DATA   (0x0000005c)\r
49 #define FLASH_OFFSET    (0x000f01a4)\r
50 #define READ_BIT                (1<<29)\r
51 #define WRITE_BIT               (2<<29)\r
52 #define ADDR_MSK                (0x0007ffff)\r
53 #define CMD_MASK                (0xe0000000)\r
54 #define BANK_SHIFT              (19)\r
55 #define BANK_MASK               (0xfff80000)\r
56 #define MAX_FLASH_SIZE  (0x80000) // 512K\r
57 \r
58 #define SEMAP63                         (0xf03fc)\r
59 #define GPIO_DIR_L                      (0xf008c)\r
60 #define GPIO_POL_L                      (0xf0094)\r
61 #define GPIO_MOD_L                      (0xf009c)\r
62 #define GPIO_DAT_L                      (0xf0084)\r
63 #define GPIO_DATACLEAR_L        (0xf00d4)\r
64 #define GPIO_DATASET_L          (0xf00dc)\r
65 \r
66 #define CPUMODE                         (0xf0150)\r
67 #define CPUMODE_MSK                     (0xc0000000UL)\r
68 #define CPUMODE_SHIFT           (30)\r
69 \r
70 /* Definitions intended to become shared with UM. Later... */\r
71 #define FW_READ                 0x00\r
72 #define FW_WRITE                0x01\r
73 #define FW_READ_CMD             0x08\r
74 #define FW_WRITE_CMD    0x09\r
75 #define FW_OPEN_IF              0xe7\r
76 #define FW_CLOSE_IF             0x7e\r
77 \r
78 #define FW_SIGNATURE            (0x5a445a44)\r
79 #define FW_SECT_SIZE            (0x10000)\r
80 \r
81 typedef struct Primary_Sector{\r
82         uint32_t fi_addr;\r
83         uint32_t fi_size;\r
84         uint32_t signature;\r
85         uint32_t fw_reserved[5];\r
86         uint32_t vsd[56];\r
87         uint32_t branch_to;\r
88         uint32_t crc016;\r
89 } primary_sector_t;\r
90 \r
91 static uint32_t old_dir;\r
92 static uint32_t old_pol;\r
93 static uint32_t old_mod;\r
94 static uint32_t old_dat;\r
95 \r
96 \r
97 static NTSTATUS\r
98 fw_access_pciconf (\r
99                 IN              BUS_INTERFACE_STANDARD          *p_BusInterface,\r
100                 IN              ULONG                                           op_flag,\r
101                 IN              PVOID                                           p_buffer,\r
102                 IN              ULONG                                           offset,\r
103                 IN              ULONG POINTER_ALIGNMENT         length )\r
104 {\r
105 \r
106         ULONG                           bytes;  \r
107         NTSTATUS                        status = STATUS_SUCCESS;\r
108 \r
109         PAGED_CODE();\r
110 \r
111         if( !p_buffer )\r
112                 return STATUS_INVALID_PARAMETER;\r
113 \r
114         if (p_BusInterface)\r
115         {\r
116 \r
117                 bytes = p_BusInterface->SetBusData(\r
118                                                 p_BusInterface->Context,\r
119                                                 PCI_WHICHSPACE_CONFIG,\r
120                                                 (PVOID)&offset,\r
121                                                 PCI_CONF_ADDR,\r
122                                                 sizeof(ULONG) );\r
123 \r
124                 if( op_flag == 0 )\r
125                 {\r
126                         if ( bytes )\r
127                                 bytes = p_BusInterface->GetBusData(\r
128                                                         p_BusInterface->Context,\r
129                                                         PCI_WHICHSPACE_CONFIG,\r
130                                                         p_buffer,\r
131                                                         PCI_CONF_DATA,\r
132                                                         length );\r
133                         if ( !bytes )\r
134                                 status = STATUS_NOT_SUPPORTED;\r
135                 }\r
136 \r
137                 else\r
138                 {\r
139                         if ( bytes )\r
140                                 bytes = p_BusInterface->SetBusData(\r
141                                                         p_BusInterface->Context,\r
142                                                         PCI_WHICHSPACE_CONFIG,\r
143                                                         p_buffer,\r
144                                                         PCI_CONF_DATA,\r
145                                                         length);\r
146 \r
147                         if ( !bytes )\r
148                                 status = STATUS_NOT_SUPPORTED;\r
149                 }\r
150         }\r
151         return status;\r
152 }\r
153 \r
154 \r
155 static NTSTATUS\r
156 __map_crspace(\r
157         IN              struct ib_ucontext *            p_uctx,\r
158         IN              PVOID                                           p_buf,\r
159         IN              ULONG                                           buf_size\r
160         )\r
161 {\r
162         NTSTATUS status;\r
163         PMDL p_mdl;\r
164         PVOID ua, ka;\r
165         ULONG sz;\r
166         PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo;\r
167         map_crspace *p_res = (map_crspace *)p_buf;\r
168         struct pci_dev *p_pdev = p_fdo->bus_ib_ifc.pdev;\r
169 \r
170         HCA_ENTER( HCA_DBG_PNP );\r
171 \r
172         // sanity checks\r
173         if ( buf_size < sizeof *p_res || !p_buf ) {\r
174                 status = STATUS_INVALID_PARAMETER;\r
175                 goto err_invalid_params;\r
176         }\r
177 \r
178         // map memory\r
179         sz =(ULONG)p_pdev->bar[HCA_BAR_TYPE_HCR].size;\r
180         if (!p_pdev->bar[HCA_BAR_TYPE_HCR].virt) {\r
181                 PHYSICAL_ADDRESS pa;\r
182                 pa.QuadPart = p_pdev->bar[HCA_BAR_TYPE_HCR].phys;\r
183                 ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
184                 if ( ka == NULL) {\r
185                         HCA_PRINT(TRACE_LEVEL_ERROR  , HCA_DBG_SHIM,\r
186                                 ("No kernel mapping of CR space.\n") );\r
187                         status = STATUS_INSUFFICIENT_RESOURCES;\r
188                         goto err_map_to_kernel;\r
189                 }\r
190                 p_pdev->bar[HCA_BAR_TYPE_HCR].virt = ka;\r
191         }\r
192         ka = p_pdev->bar[HCA_BAR_TYPE_HCR].virt;\r
193 \r
194         // prepare for mapping to user space \r
195         p_mdl = IoAllocateMdl( ka, sz, FALSE,FALSE,NULL);\r
196         if (p_mdl == NULL) {\r
197                 HCA_PRINT(TRACE_LEVEL_ERROR  , HCA_DBG_SHIM, \r
198                         ("IoAllocateMdl failed.\n") );\r
199                 status = STATUS_INSUFFICIENT_RESOURCES;\r
200                 goto err_alloc_mdl;\r
201         }\r
202 \r
203         // fill MDL\r
204         MmBuildMdlForNonPagedPool(p_mdl);\r
205         \r
206         // map the buffer into user space \r
207         __try\r
208         {\r
209                 ua = MmMapLockedPagesSpecifyCache( p_mdl, UserMode, MmNonCached,\r
210                         NULL, FALSE, NormalPagePriority );\r
211         }\r
212         __except(EXCEPTION_EXECUTE_HANDLER)\r
213         {\r
214                 HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM,\r
215                         ("MmMapLockedPagesSpecifyCache failed.\n") );\r
216                 status = STATUS_INSUFFICIENT_RESOURCES;\r
217                 goto err_map_to_user;\r
218         }\r
219         \r
220         // fill the results\r
221         p_res->va = (uint64_t)(ULONG_PTR)ua;\r
222         p_res->size = sz;\r
223 \r
224         // resource tracking\r
225         p_uctx->x.p_mdl = p_mdl;\r
226         p_uctx->x.va = ua;\r
227 \r
228 #if 0   \r
229         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SHIM,\r
230                 ("MTHCA: __map_crspace succeeded with .ka %I64x, size %I64x va %I64x, size %x, pa %I64x \n",\r
231                 p_pdev->bar[HCA_BAR_TYPE_HCR].virt, p_pdev->bar[HCA_BAR_TYPE_HCR].size, \r
232                 p_res->va, p_res->size, p_pdev->bar[HCA_BAR_TYPE_HCR].phys ));\r
233 #endif\r
234         status = STATUS_SUCCESS;\r
235         goto out;\r
236 \r
237 err_map_to_user:\r
238         IoFreeMdl( p_mdl );\r
239 err_alloc_mdl:\r
240 err_map_to_kernel:\r
241 err_invalid_params:     \r
242 out:    \r
243         HCA_EXIT( HCA_DBG_PNP );\r
244         return status;\r
245 }\r
246 \r
247 \r
248 static void\r
249 __unmap_crspace(\r
250         IN              struct ib_ucontext *                    p_uctx\r
251         )\r
252 {\r
253         HCA_ENTER( HCA_DBG_PNP );\r
254 \r
255         if (p_uctx->x.va && p_uctx->x.p_mdl) {\r
256                 MmUnmapLockedPages(p_uctx->x.va, p_uctx->x.p_mdl);\r
257                 IoFreeMdl( p_uctx->x.p_mdl );\r
258                 p_uctx->x.va = p_uctx->x.p_mdl = NULL;\r
259                 //NB: the unmap of IO space is being done in __UnmapHcaMemoryResources\r
260         }\r
261 \r
262         HCA_EXIT( HCA_DBG_PNP );\r
263 }\r
264 \r
265 static void\r
266 __open_fw_access(\r
267         IN                              struct ib_ucontext*                     p_uctx,\r
268         IN                              PBUS_INTERFACE_STANDARD         p_bus_interface )\r
269 {\r
270         if( !p_uctx->x.fw_if_open )\r
271         {\r
272                 p_bus_interface->InterfaceReference( p_bus_interface->Context );\r
273                 p_uctx->x.fw_if_open = TRUE;\r
274         }\r
275 }\r
276 \r
277 static void \r
278 __close_fw_access(\r
279         IN              struct ib_ucontext *    p_uctx,\r
280         IN              PBUS_INTERFACE_STANDARD p_bus_interface\r
281         )\r
282 {\r
283         if (p_uctx->x.fw_if_open ) {\r
284                 p_bus_interface->InterfaceDereference((PVOID)p_bus_interface->Context);\r
285                 p_uctx->x.fw_if_open = FALSE;\r
286         }\r
287 }\r
288 \r
289 \r
290 void\r
291 unmap_crspace_for_all( struct ib_ucontext *p_uctx )\r
292 {\r
293         PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo;\r
294         PBUS_INTERFACE_STANDARD    p_bus_interface = &p_fdo->bus_pci_ifc;\r
295 \r
296         HCA_ENTER( HCA_DBG_PNP );\r
297 \r
298         mutex_lock( &p_uctx->x.mutex );\r
299         __unmap_crspace( p_uctx);\r
300         __close_fw_access(p_uctx, p_bus_interface);\r
301         mutex_unlock( &p_uctx->x.mutex );\r
302 \r
303         HCA_EXIT( HCA_DBG_PNP );\r
304 }\r
305 \r
306 static NTSTATUS\r
307 fw_flash_write_data (\r
308                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
309                 IN              PVOID                                                   p_buffer,\r
310                 IN              ULONG                                                   offset,\r
311                 IN              ULONG POINTER_ALIGNMENT                 length )\r
312 {\r
313         NTSTATUS                status;\r
314         uint32_t                cnt = 0;\r
315         uint32_t                lcl_data;\r
316 \r
317         if (!length)\r
318                 return IB_INVALID_PARAMETER;\r
319         \r
320         lcl_data = (*((uint32_t*)p_buffer) << 24);\r
321 \r
322         status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET+4, length );\r
323         if ( status != STATUS_SUCCESS )\r
324                 return status;\r
325         lcl_data = ( WRITE_BIT | (offset & ADDR_MSK));\r
326                 \r
327         status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET, 4 );\r
328         if ( status != STATUS_SUCCESS )\r
329         return status;\r
330 \r
331         lcl_data = 0;\r
332         \r
333         do\r
334         {\r
335                 if (++cnt > 5000)\r
336                 {\r
337                         return STATUS_DEVICE_NOT_READY;\r
338                 }\r
339 \r
340                 status = fw_access_pciconf(p_BusInterface, FW_READ , &lcl_data, FLASH_OFFSET, 4 );\r
341                 if ( status != STATUS_SUCCESS )\r
342                 return status;\r
343 \r
344         } while(lcl_data & CMD_MASK);\r
345 \r
346         return status;\r
347 }\r
348 \r
349 \r
350 static NTSTATUS\r
351 fw_flash_read_data (\r
352                 IN              BUS_INTERFACE_STANDARD                  *p_BusInterface,\r
353                 IN              PVOID                                                   p_buffer,\r
354                 IN              ULONG                                                   offset,\r
355                 IN              ULONG POINTER_ALIGNMENT                 length )\r
356 {\r
357         NTSTATUS        status = STATUS_SUCCESS;\r
358         uint32_t        cnt = 0;\r
359         uint32_t        lcl_data = ( READ_BIT | (offset & ADDR_MSK));\r
360 \r
361         if (!length)\r
362                 return IB_INVALID_PARAMETER;\r
363         \r
364         status = fw_access_pciconf(p_BusInterface, FW_WRITE, &lcl_data, FLASH_OFFSET, 4 );\r
365         if ( status != STATUS_SUCCESS )\r
366                 return status;\r
367 \r
368         lcl_data = 0;\r
369         do\r
370         {\r
371                 // Timeout checks\r
372                 if (++cnt > 5000 )\r
373                 {\r
374                         return STATUS_DEVICE_NOT_READY;\r
375         }\r
376 \r
377                 status = fw_access_pciconf(p_BusInterface, FW_READ, &lcl_data, FLASH_OFFSET, 4 );\r
378         \r
379                 if ( status != STATUS_SUCCESS )\r
380                         return status;\r
381 \r
382         } while(lcl_data & CMD_MASK);\r
383 \r
384         status = fw_access_pciconf(p_BusInterface, FW_READ, p_buffer, FLASH_OFFSET+4, length );\r
385         return status;\r
386 }\r
387 \r
388 ib_api_status_t\r
389 fw_access_ctrl(\r
390         IN              const   ib_ca_handle_t                          h_ca,\r
391         IN              const   void** const                            handle_array    OPTIONAL,\r
392         IN                              uint32_t                                        num_handles,\r
393         IN                              ib_ci_op_t* const                       p_ci_op,\r
394         IN      OUT                     ci_umv_buf_t                            *p_umv_buf )\r
395 {\r
396         NTSTATUS                                        status = STATUS_SUCCESS;\r
397         PVOID                                           p_data;\r
398         ULONG                                           offset;\r
399         ULONG POINTER_ALIGNMENT         length;\r
400         struct ib_ucontext *p_uctx = (struct ib_ucontext *)h_ca;\r
401         PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo;\r
402         PBUS_INTERFACE_STANDARD         p_bus_interface = &p_fdo->bus_pci_ifc;\r
403 \r
404         UNREFERENCED_PARAMETER(handle_array);\r
405         UNREFERENCED_PARAMETER(num_handles);\r
406 \r
407     if(!p_umv_buf ) {\r
408 #if 1//WORKAROUND_POLL_EQ\r
409                 if ((p_ci_op->command == FW_POLL_EQ_START) || (p_ci_op->command == FW_POLL_EQ_STOP)){ // poll EQ (in case of missed interrupt) \r
410                         mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca;\r
411                         struct ib_device *p_ibdev = hca2ibdev(p_hca);\r
412                         if(p_ci_op->command == FW_POLL_EQ_START)\r
413                         {\r
414                                 p_ibdev->x.poll_eq(p_ibdev,1);\r
415                         }else\r
416                         {\r
417                                 p_ibdev->x.poll_eq(p_ibdev,0);\r
418                         }\r
419                         return IB_SUCCESS;\r
420                 }\r
421                 else\r
422 #endif\r
423                 return IB_UNSUPPORTED;\r
424         }\r
425 \r
426         if ( !p_ci_op )\r
427                 return IB_INVALID_PARAMETER;\r
428 \r
429         length = p_ci_op->buf_size;\r
430         offset = p_ci_op->buf_info;\r
431         p_data = p_ci_op->p_buf;\r
432 \r
433         mutex_lock( &p_uctx->x.mutex );\r
434 \r
435         switch ( p_ci_op->command )\r
436         {\r
437         case FW_MAP_CRSPACE:\r
438                 status = __map_crspace(p_uctx, p_data, length);\r
439                 break;\r
440                 \r
441         case FW_UNMAP_CRSPACE:\r
442                 __unmap_crspace(p_uctx);\r
443                 break;\r
444                                 \r
445         case FW_OPEN_IF: // open BusInterface\r
446                 if (p_fdo->bus_pci_ifc_taken)\r
447                         __open_fw_access( p_uctx, p_bus_interface );\r
448                 break;\r
449 \r
450         case FW_READ: // read data from flash\r
451                 if ( p_uctx->x.fw_if_open )\r
452                         status = fw_flash_read_data(p_bus_interface, p_data, offset, length);\r
453                 break;\r
454 \r
455         case FW_WRITE: // write data to flash\r
456                 if ( p_uctx->x.fw_if_open )\r
457                         status = fw_flash_write_data(p_bus_interface, p_data, offset, length);\r
458                 break;\r
459 \r
460         case FW_READ_CMD:\r
461                 if ( p_uctx->x.fw_if_open )\r
462                         status = fw_access_pciconf(p_bus_interface, 0 , p_data, offset, 4);\r
463                 break;\r
464 \r
465         case FW_WRITE_CMD:\r
466                 if ( p_uctx->x.fw_if_open )\r
467                         status = fw_access_pciconf(p_bus_interface, 1 , p_data, offset, 4);\r
468                 break;\r
469 \r
470         case FW_CLOSE_IF: // close BusInterface\r
471                 __close_fw_access(p_uctx, p_bus_interface);\r
472                 break;\r
473 \r
474         default:\r
475                 status = STATUS_INVALID_DEVICE_REQUEST;\r
476         }\r
477 \r
478         if ( status != STATUS_SUCCESS ) {\r
479                 __close_fw_access(p_uctx, p_bus_interface);\r
480                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, \r
481                         ("fw_access_ctrl failed, ntstatus: %08x.\n", status));\r
482         }\r
483 \r
484         mutex_unlock( &p_uctx->x.mutex );\r
485 \r
486         switch( status ) {\r
487                 case STATUS_SUCCESS:                                    return IB_SUCCESS;\r
488                 case STATUS_INVALID_DEVICE_REQUEST:     return IB_UNSUPPORTED;\r
489                 case STATUS_INSUFFICIENT_RESOURCES:     return IB_INSUFFICIENT_RESOURCES;\r
490                 default:                                                                        return IB_ERROR;\r
491         }\r
492 }\r
493 \r
494 \r