[mlx4] Fix error path on create qp.
[mirror/winof/.git] / hw / mlx4 / kernel / bus / drv / pci.c
1 \r
2 #include "precomp.h"\r
3 \r
4 #if defined(EVENT_TRACING)\r
5 #ifdef offsetof\r
6 #undef offsetof\r
7 #endif\r
8 #include "pci.tmh"\r
9 #endif\r
10 \r
11 #include <complib/cl_thread.h>\r
12 #include <initguid.h>\r
13 #include <wdmguid.h>\r
14 \r
15 #define MLX4_RESET_BASE         0xf0000\r
16 #define MLX4_RESET_SIZE           0x400\r
17 #define MLX4_SEM_OFFSET           0x3fc\r
18 #define MLX4_RESET_OFFSET          0x10\r
19 #define MLX4_RESET_VALUE        swab32(1)\r
20 \r
21 #define MLX4_SEM_TIMEOUT_JIFFIES        (10 * HZ)\r
22 #define MLX4_RESET_TIMEOUT_JIFFIES      (2 * HZ)\r
23 \r
24 //#define PCI_CAPABILITY_ID_VPD                         0x03\r
25 //#define PCI_CAPABILITY_ID_PCIX                                0x07\r
26 //#define PCI_CAPABILITY_ID_PCI_EXPRESS                 0x10\r
27 //#define PCI_CAPABILITY_ID_MSIX                        0x11\r
28 \r
29 /*\r
30  * MSI-X Capability\r
31  */\r
32 typedef struct _PCI_MSIX_CAPABILITY {\r
33 \r
34         PCI_CAPABILITIES_HEADER Header;\r
35 \r
36         USHORT          Flags;\r
37         ULONG           Table_Offset;\r
38         ULONG           PBA_Offset;\r
39         \r
40 } PCI_MSIX_CAPABILITY, *PPCI_MSIX_CAPABILITY;\r
41 \r
42 #define MSIX_FLAGS_MSIX_ENABLE(flags)                   (((flags)>>15)&1)       /* MSI-X is enabled */\r
43 #define MSIX_FLAGS_MSIX_FUNCTION_MASK(flags)    (((flags)>>14)&1)       /* all interrupts masked */\r
44 #define MSIX_FLAGS_SUPPORTED(flags)                             ((flags)&0x07ff)        /* vector table size */\r
45 #define MSIX_OFFSET_BIR(offset)                                 ((offset)&7)            /* BAR index register */\r
46 #define MSIX_OFFSET_ADDR(offset)                                ((offset)&0xfffffff8)           /* offset */\r
47 \r
48 /* this structure describes one MSI-X vector from N */\r
49 typedef struct _PCI_MSIX_VECTOR {\r
50 \r
51         ULONGLONG       Addr;\r
52         ULONG           Data;\r
53         ULONG           Flags;\r
54         \r
55 } PCI_MSIX_VECTOR, *PPCI_MSIX_VECTOR;\r
56 \r
57 #define MSIX_VECTOR_MASKED(flags)                       ((flags)&1)     /* this vector is masked */\r
58 \r
59 /* this structure pending state of 64 MSI-X vectors from N */\r
60 typedef struct _PCI_MSIX_PENDING {\r
61 \r
62         ULONGLONG       Mask;\r
63         \r
64 } PCI_MSIX_PENDING, *PPCI_MSIX_PENDING;\r
65 \r
66 /*\r
67  * Vital Product Data Capability\r
68  */\r
69 typedef struct _PCI_VPD_CAPABILITY {\r
70 \r
71         PCI_CAPABILITIES_HEADER Header;\r
72 \r
73         USHORT          Flags;\r
74         ULONG                   Data;\r
75 \r
76 } PCI_VPD_CAPABILITY, *PPCI_VPD_CAPABILITY;\r
77 \r
78 \r
79 /*\r
80  * PCI-X Capability\r
81  */\r
82 typedef struct _PCI_PCIX_CAPABILITY {\r
83 \r
84         PCI_CAPABILITIES_HEADER Header;\r
85 \r
86         USHORT          Command;\r
87         ULONG                   Status;\r
88 \r
89 /* for Command: */\r
90 } PCI_PCIX_CAPABILITY, *PPCI_PCIX_CAPABILITY;\r
91 \r
92 #define  PCI_X_CMD_MAX_READ     0x000c  /* Max Memory Read Byte Count */\r
93 \r
94 /*\r
95  * PCI-Express Capability\r
96  */\r
97 typedef struct _PCI_PCIEXP_CAPABILITY {\r
98 \r
99         PCI_CAPABILITIES_HEADER Header;\r
100 \r
101         USHORT          Flags;\r
102         ULONG                   DevCapabilities;\r
103         USHORT          DevControl;\r
104         USHORT          DevStatus;\r
105         ULONG                   LinkCapabilities;\r
106         USHORT          LinkControl;\r
107         USHORT          LinkStatus;\r
108         ULONG                   SlotCapabilities;\r
109         USHORT          SlotControl;\r
110         USHORT          SlotStatus;\r
111         USHORT          RootControl;\r
112         USHORT          RootCapabilities;\r
113         USHORT          RootStatus;\r
114 } PCI_PCIEXP_CAPABILITY, *PPCI_PCIEXP_CAPABILITY;\r
115 \r
116 /* for DevControl: */\r
117 #define  PCI_EXP_DEVCTL_READRQ  0x7000  /* Max_Read_Request_Size */\r
118 \r
119 static NTSTATUS\r
120 __get_bus_ifc(\r
121         IN                              DEVICE_OBJECT* const            pDevObj,\r
122         IN              const   GUID* const                                     pGuid,\r
123                 OUT                     BUS_INTERFACE_STANDARD          *pBusIfc );\r
124 \r
125 static NTSTATUS\r
126 __restore_pci_config(\r
127         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
128         IN                              PCI_COMMON_CONFIG* const        pConfig );\r
129 \r
130 \r
131 #ifdef ALLOC_PRAGMA\r
132 #pragma alloc_text (PAGE, __get_bus_ifc)\r
133 #pragma alloc_text (PAGE, __restore_pci_config)\r
134 #endif\r
135 \r
136 /*\r
137  * Returns the offset in configuration space of the PCI-X capabilites.\r
138  */\r
139 static ULONG\r
140 __find_capability(\r
141         IN                              PCI_COMMON_CONFIG* const        pConfig,  \r
142         IN                              char cap_id\r
143         )\r
144 {\r
145         ULONG                                           offset = 0;\r
146         PCI_CAPABILITIES_HEADER         *pHdr = NULL;\r
147         UCHAR                                           *pBuf = (UCHAR*)pConfig;\r
148 \r
149         MLX4_ENTER( MLX4_DBG_PNP );\r
150 \r
151         if  ( pConfig->HeaderType == PCI_DEVICE_TYPE ) {\r
152                 if( pConfig->u.type0.CapabilitiesPtr )\r
153                 {\r
154                         pHdr = (PCI_CAPABILITIES_HEADER*)\r
155                                 (pBuf + pConfig->u.type0.CapabilitiesPtr);\r
156                 }\r
157         }\r
158 \r
159         if  ( pConfig->HeaderType == PCI_BRIDGE_TYPE ) {\r
160                 if( pConfig->u.type1.CapabilitiesPtr )\r
161                 {\r
162                         pHdr = (PCI_CAPABILITIES_HEADER*)\r
163                                 (pBuf + pConfig->u.type1.CapabilitiesPtr);\r
164                 }\r
165         }\r
166 \r
167         /*\r
168          * Fix up any fields that might cause changes to the\r
169          * device - like writing VPD data.\r
170          */\r
171         while( pHdr )\r
172         {\r
173                 if( pHdr->CapabilityID == cap_id )\r
174                 {\r
175                         offset = (UCHAR)(((ULONG_PTR)pHdr) - ((ULONG_PTR)pConfig));\r
176                         break;\r
177                 }\r
178 \r
179                 if( pHdr->Next )\r
180                         pHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next);\r
181                 else\r
182                         pHdr = NULL;\r
183         }\r
184 \r
185         MLX4_EXIT( MLX4_DBG_PNP );\r
186         return offset;\r
187 }\r
188 \r
189 \r
190 static NTSTATUS\r
191 __pci_restore_msix_info(\r
192         IN                              struct pci_dev *pdev,\r
193         struct msix_saved_info *                p_info\r
194         )\r
195 {\r
196         int i;\r
197         int offset;\r
198         NTSTATUS status = STATUS_SUCCESS;\r
199         PCI_MSIX_CAPABILITY     *pPciMsix;\r
200         PPCI_MSIX_VECTOR p_cvector, p_svector;\r
201         PBUS_INTERFACE_STANDARD p_ifc = &pdev->bus_pci_ifc;\r
202         PCI_COMMON_CONFIG* p_cfg = &pdev->pci_cfg_space;\r
203 \r
204         if ( p_info->valid ) {\r
205 \r
206                 /* restore PBA Table */\r
207                 p_info->valid = 0;\r
208                 memcpy( p_info->mca, p_info->msa, p_info->msz );\r
209                 kfree( p_info->msa );\r
210                 MmUnmapIoSpace( p_info->mca, p_info->msz );\r
211 \r
212                 /* restore Vector Table */\r
213                 p_svector = p_info->vsa;\r
214                 p_cvector = p_info->vca;\r
215                 for (i=0; i<p_info->num; i++) \r
216                         p_cvector[i].Flags = p_svector[i].Flags;\r
217                 kfree( p_info->vsa );\r
218                 MmUnmapIoSpace( p_info->vca, p_info->vsz );\r
219 \r
220                 /* restore MSI-X Capability */\r
221                 offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
222                 pPciMsix = (PCI_MSIX_CAPABILITY*)(((UCHAR*)p_cfg) + offset);\r
223                 if (offset) { \r
224                         /* restore MSI-X control register */\r
225                         if ( sizeof( pPciMsix->Flags) != p_ifc->SetBusData( \r
226                                 p_ifc->Context, PCI_WHICHSPACE_CONFIG,\r
227                                 &pPciMsix->Flags,       offset + \r
228                                 offsetof( PCI_MSIX_CAPABILITY, Flags),\r
229                                 sizeof( pPciMsix->Flags ) )) {\r
230                                 MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
231                                         ("Couldn't restore MSI-X Control register, aborting.\n"));\r
232                                 status = STATUS_UNSUCCESSFUL;\r
233                                 goto end;\r
234                         }\r
235                 }\r
236         }\r
237 end:    \r
238         return status;\r
239 }\r
240 \r
241 /*\r
242  * Restore saved PCI configuration, skipping registers 22 and 23, as well\r
243  * as any registers where writing will have side effects such as the flags\r
244  * field of the VPD and vendor specific capabilities.  The function also delays\r
245  * writing the command register, bridge control register (if applicable), and\r
246  * PCIX command register (if present).\r
247  */\r
248 static NTSTATUS\r
249 __restore_pci_config(\r
250         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
251         IN                              PCI_COMMON_CONFIG* const        pConfig )\r
252 {\r
253         NTSTATUS status = STATUS_SUCCESS;\r
254         int             i, *pci_hdr = (int*)pConfig;\r
255 \r
256         MLX4_ENTER( MLX4_DBG_PNP );\r
257 \r
258         /* restore capabilities*/\r
259         {\r
260                 int offset;\r
261                 PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
262 \r
263                 /* PCI-X */\r
264                 offset = __find_capability( pConfig, PCI_CAPABILITY_ID_PCIX );\r
265                 if (offset) {\r
266                         if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
267                                 &pci_hdr[offset/4], offset, 4) ) {\r
268                                 MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
269                                         ("Couldn't restore HCA PCI-X command register, aborting.\n"));\r
270                                 status = STATUS_UNSUCCESSFUL;\r
271                                 goto out;\r
272                         }\r
273                 }\r
274 \r
275                 /* PCI-Express */\r
276                 offset = __find_capability( pConfig, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
277                 pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)pConfig) + offset);\r
278                 if (offset) {\r
279                         /* restore HCA PCI Express Device Control register */\r
280                         if ( sizeof( pPciExpCap->DevControl ) != pBusIfc->SetBusData( \r
281                                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
282                                 &pPciExpCap->DevControl,        offset + \r
283                                 offsetof( PCI_PCIEXP_CAPABILITY, DevControl),\r
284                                 sizeof( pPciExpCap->DevControl ) )) {\r
285                                 MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
286                                         ("Couldn't restore HCA PCI Express Device Control register, aborting.\n"));\r
287                                 status = STATUS_UNSUCCESSFUL;\r
288                                 goto out;\r
289                         }\r
290                         /* restore HCA PCI Express Link Control register */\r
291                         if ( sizeof( pPciExpCap->LinkControl ) != pBusIfc->SetBusData( \r
292                                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
293                                 &pPciExpCap->LinkControl,       offset + \r
294                                 offsetof( PCI_PCIEXP_CAPABILITY, LinkControl),\r
295                                 sizeof( pPciExpCap->LinkControl ) )) {\r
296                                 MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
297                                         ("Couldn't restore HCA PCI Express Link Control register, aborting.\n"));\r
298                                 status = STATUS_UNSUCCESSFUL;\r
299                                 goto out;\r
300                         }\r
301                 }\r
302         }\r
303 \r
304         /* write basic part */\r
305         for (i = 0; i < 16; ++i) {\r
306                 if (i == 1)\r
307                         continue;\r
308         \r
309                 if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
310                         PCI_WHICHSPACE_CONFIG, &pci_hdr[i], i * 4, 4 )) {\r
311                         MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,\r
312                                 ("Couldn't restore PCI cfg reg %x,   aborting.\n", i));\r
313                         status =  STATUS_DEVICE_NOT_READY;\r
314                         goto out;\r
315                 }\r
316         }\r
317 \r
318         /* Write the command register. */\r
319         if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
320                 PCI_WHICHSPACE_CONFIG, &pci_hdr[1], 4, 4 )) {\r
321                 MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Couldn't restore COMMAND.\n"));\r
322                 status =  STATUS_DEVICE_NOT_READY;\r
323         }\r
324 \r
325 out:    \r
326         MLX4_EXIT( MLX4_DBG_PNP );\r
327         return status;\r
328 }\r
329 \r
330 \r
331 static int\r
332 __save_msix_info(\r
333         IN                              PCI_COMMON_CONFIG *             p_cfg,\r
334         OUT                             struct msix_saved_info *p_info )\r
335 {\r
336         u64 bar;\r
337         int n_supported;\r
338         PHYSICAL_ADDRESS pa;\r
339         ULONG capOffset, bir;\r
340         PPCI_MSIX_CAPABILITY pPciMsixCap;\r
341 \r
342         MLX4_ENTER( MLX4_DBG_PNP );\r
343 \r
344         /* find capability */\r
345         capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
346         if( !capOffset ) {\r
347                 p_info->valid = 0;\r
348                 return 0;\r
349         }       \r
350         pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset);\r
351         n_supported = MSIX_FLAGS_SUPPORTED(pPciMsixCap->Flags) + 1;\r
352         p_info->num = n_supported;\r
353 \r
354         /* map memory for vectors */\r
355         p_info->vsz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR));\r
356         bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset);\r
357         bar = *(u64*)&p_cfg->u.type1.BaseAddresses[bir] & ~0x0f;\r
358         pa.QuadPart = bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset);\r
359         p_info->vca = MmMapIoSpace( pa, p_info->vsz, MmNonCached ); \r
360         if ( p_info->vca == NULL) {\r
361                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
362                         ("Failed kernel mapping of MSI-X vector table.\n") );\r
363                 goto end;\r
364         }\r
365 \r
366         /* alloc memory for vector table */\r
367         p_info->vsa = kmalloc(p_info->vsz, GFP_KERNEL);\r
368         if ( !p_info->vsa ) {\r
369                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
370                         ("Failed allocate memory for MSI-X vector table \n") );\r
371                 goto err_alloc_vectors;\r
372         }\r
373         memcpy( p_info->vsa, p_info->vca, p_info->vsz );\r
374 \r
375         /* map memory for mask table */\r
376         bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset);\r
377         bar = *(u64*)&p_cfg->u.type1.BaseAddresses[bir] & ~0x0f;\r
378         p_info->msz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64);\r
379         pa.QuadPart = bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset);\r
380         p_info->mca = MmMapIoSpace( pa, p_info->msz, MmNonCached ); \r
381         if ( p_info->mca == NULL) {\r
382                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
383                         ("Failed kernel mapping of MSI-X mask table.\n") );\r
384                 goto err_map_masks;\r
385         }\r
386 \r
387         /* alloc memory for mask table */\r
388         p_info->msa = kmalloc(p_info->msz, GFP_KERNEL);\r
389         if ( !p_info->msa ) {\r
390                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
391                         ("Failed allocate memory for MSI-X vector table \n") );\r
392                 goto err_alloc_masks;\r
393         }\r
394         memcpy( p_info->msa, p_info->mca, p_info->msz );\r
395 \r
396         p_info->valid = 1;\r
397         return 0;\r
398 \r
399 err_alloc_masks:\r
400         MmUnmapIoSpace( p_info->mca, p_info->msz );\r
401     p_info->mca = NULL;\r
402 \r
403 err_map_masks:\r
404         kfree(p_info->vsa);\r
405     p_info->vsa = NULL;\r
406 \r
407 err_alloc_vectors:\r
408         MmUnmapIoSpace( p_info->vca, p_info->vsz );\r
409     p_info->vca = NULL;\r
410 \r
411 end:    \r
412         MLX4_EXIT( MLX4_DBG_PNP );\r
413         return -EFAULT;\r
414 }\r
415 \r
416 void\r
417 pci_free_msix_info_resources(\r
418         IN struct msix_saved_info *     pMsixInfo\r
419         )\r
420 {\r
421         if (pMsixInfo->vca && pMsixInfo->vsz)\r
422                 MmUnmapIoSpace( pMsixInfo->vca, pMsixInfo->vsz );\r
423 \r
424         if (pMsixInfo->mca && pMsixInfo->msz)\r
425                 MmUnmapIoSpace( pMsixInfo->mca, pMsixInfo->msz );\r
426 \r
427         if (pMsixInfo->msa)\r
428                 kfree(pMsixInfo->msa);\r
429 \r
430         if (pMsixInfo->vsa)\r
431                 kfree(pMsixInfo->vsa);\r
432 \r
433         memset(pMsixInfo,0,sizeof(struct msix_saved_info));\r
434 }\r
435 \r
436 /*\r
437  * Reads and saves the PCI configuration of the device accessible\r
438  * through the provided bus interface.  Does not read registers 22 or 23\r
439  * as directed in PRM , Appendix A. Software Reset.\r
440  */\r
441 NTSTATUS\r
442 pci_save_config(\r
443         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
444                 OUT                     PCI_COMMON_CONFIG* const        pConfig)\r
445 {\r
446         ULONG                                   len;\r
447         UINT32                                  *pBuf;\r
448 \r
449         MLX4_ENTER( MLX4_DBG_PNP );\r
450         \r
451         pBuf = (UINT32*)pConfig;\r
452 \r
453         /*\r
454          * Read the lower portion of the configuration, up to but excluding\r
455          * register 22.\r
456          */\r
457         len = pBusIfc->GetBusData(\r
458                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 );\r
459         if( len != 88 )\r
460         {\r
461                 MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,("Failed to read HCA config.\n"));\r
462                 return STATUS_DEVICE_NOT_READY;\r
463         }\r
464 \r
465         /* Read the upper portion of the configuration, from register 24. */\r
466         len = pBusIfc->GetBusData(\r
467                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 );\r
468         if( len != 160 )\r
469         {\r
470                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to read HCA config.\n"));\r
471                 return STATUS_DEVICE_NOT_READY;\r
472         }\r
473 \r
474         MLX4_EXIT( MLX4_DBG_PNP );\r
475         return STATUS_SUCCESS;\r
476 }\r
477 \r
478 \r
479 /*\r
480  * Store Card's PCI Config space and print current MSI-X capabilities\r
481  */\r
482 void\r
483 pci_get_msi_info(\r
484         IN                              struct pci_dev                  *pdev,\r
485                 OUT                     PCI_COMMON_CONFIG *             p_cfg,\r
486                 OUT                     uplink_info_t *                 p_uplink_info )\r
487 {\r
488         ULONG                                   capOffset;\r
489         NTSTATUS                                status;\r
490         BUS_INTERFACE_STANDARD  *pBusIfc = &pdev->bus_pci_ifc;\r
491 \r
492         MLX4_ENTER( MLX4_DBG_PNP );\r
493 \r
494         status = pci_save_config( pBusIfc, p_cfg );\r
495         if (!NT_SUCCESS(status)) {\r
496                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
497                         ("Failed to read PCI configuration of the card.\n") );\r
498                 goto end;\r
499         }\r
500 \r
501         // PCI MSI-X Capability\r
502         memset( &p_uplink_info->x, 0, sizeof(p_uplink_info->x) );\r
503         capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
504         if( capOffset ) {\r
505                 PVOID ka;\r
506                 ULONG sz;\r
507                 PHYSICAL_ADDRESS pa;\r
508                 PPCI_MSIX_VECTOR p_vector;\r
509                 PPCI_MSIX_PENDING p_pend;\r
510                 ULONG granted_mask = 0;\r
511                 PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset);\r
512                 USHORT flags = pPciMsixCap->Flags;\r
513                 ULONG table_bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset);\r
514                 ULONG pend_bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset);\r
515                 u64 table_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[table_bir] & ~0x0f;\r
516                 u64 pend_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[pend_bir] & ~0x0f;\r
517                 int i, n_supported = MSIX_FLAGS_SUPPORTED(flags) + 1;\r
518 \r
519                 /* print capabilities structure */\r
520                 MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
521                         ("MSI-X Capability: Enabled - %d, Function Masked %d, Vectors Supported %d, Addr_Offset(BIR) %#x(%d), Pend_Offset(BIR) %#x(%d)\n",\r
522                         MSIX_FLAGS_MSIX_ENABLE(flags),\r
523                         MSIX_FLAGS_MSIX_FUNCTION_MASK(flags),\r
524                         n_supported, \r
525                         MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset), MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset), \r
526                         MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset), MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset) ));\r
527 \r
528                 /* fill info */\r
529                 p_uplink_info->x.valid = 1;\r
530                 p_uplink_info->x.enabled= MSIX_FLAGS_MSIX_ENABLE(flags);\r
531                 p_uplink_info->x.masked = MSIX_FLAGS_MSIX_FUNCTION_MASK(flags);\r
532                 p_uplink_info->x.requested = n_supported;\r
533 \r
534                 if (pdev->n_msi_vectors_alloc) {\r
535 \r
536                         /* map memory */\r
537                         sz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR));\r
538                         pa.QuadPart = table_bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset);\r
539                         ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
540                         if ( ka == NULL) {\r
541                                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
542                                         ("Failed kernel mapping of MSI-X vector table.\n") );\r
543                                 goto end;\r
544                         }\r
545                         \r
546                         p_vector = ka;\r
547                         /* print (allocated+2) vectors */\r
548                         for (i=0; i<pdev->n_msi_vectors_alloc+2; i++) {\r
549                                 MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
550                                         ("MSI-X Vectors: Id %d, Masked %d, Addr %#I64x, Data %#x\n",\r
551                                         i, MSIX_VECTOR_MASKED(p_vector[i].Flags),\r
552                                         p_vector[i].Addr, p_vector[i].Data ));\r
553                         }\r
554 \r
555                         p_uplink_info->x.granted = pdev->n_msi_vectors_alloc;\r
556                         p_uplink_info->x.granted_mask = granted_mask;\r
557                         MmUnmapIoSpace( ka, sz );\r
558 \r
559                         /* map memory */\r
560                         sz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64);\r
561                         pa.QuadPart = pend_bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset);\r
562                         ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
563                         if ( ka == NULL) {\r
564                                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
565                                         ("Failed kernel mapping of MSI-X mask table.\n") );\r
566                                 goto end;\r
567                         }\r
568 \r
569                         /* print first pending register (64 vectors) */\r
570                         p_pend = ka;\r
571                         for (i=0; i<1; i++) {\r
572                                 MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
573                                         ("MSI-X Pending: Id %d, Pend %#I64x\n", i, p_pend[i].Mask ));\r
574                         }\r
575                         p_uplink_info->x.pending_mask = *(u32*)&p_pend[0].Mask;\r
576                         MmUnmapIoSpace( ka, sz );\r
577                 }\r
578                 else {\r
579                         MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
580                                 ("MSI-X Vectors: Allocated 0 vectors\n") );\r
581                 }\r
582 \r
583         }\r
584 \r
585 end:    \r
586         MLX4_EXIT( MLX4_DBG_PNP );\r
587 }\r
588 \r
589 NTSTATUS\r
590 pci_hca_reset( \r
591         IN              struct pci_dev *pdev\r
592 )\r
593 {\r
594         u32                                                     sem;\r
595         NTSTATUS                                        status = STATUS_SUCCESS;\r
596         PBUS_INTERFACE_STANDARD         p_ifc = &pdev->bus_pci_ifc;\r
597         PCI_COMMON_CONFIG*                      p_cfg = &pdev->pci_cfg_space;\r
598         struct msix_saved_info          msix_info;\r
599         ULONG                                           len;\r
600 \r
601         MLX4_ENTER( MLX4_DBG_PNP );\r
602 \r
603         ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
604 \r
605         /* save Card Config Space including MSI-X capabilities */\r
606         pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info );\r
607 \r
608         /* save MSI-X info, if any */\r
609         len = __save_msix_info( p_cfg, &msix_info );\r
610         if (len) {\r
611                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to save MSI-X config.\n"));\r
612                 return STATUS_DEVICE_NOT_READY;\r
613         }\r
614 \r
615         /* reset the card */    \r
616         MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("\nResetting HCA ... \n\n"));\r
617         {\r
618                 u64 end;\r
619                 PUCHAR  p_reset;\r
620                 PHYSICAL_ADDRESS  pa;\r
621                 int cnt = 0;\r
622 \r
623                 /* map reset register */\r
624                 pa.QuadPart = pdev->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)MLX4_RESET_BASE;\r
625                 p_reset = MmMapIoSpace( pa, MLX4_RESET_SIZE, MmNonCached );\r
626                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
627                         ("Reset area ia mapped from pa 0x%I64x to va %p, size %#x\n", \r
628                         pa.QuadPart, p_reset, MLX4_RESET_SIZE));\r
629                 if( !p_reset ) {\r
630                         MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart));\r
631                         status = STATUS_UNSUCCESSFUL;\r
632                         goto err;\r
633                 }\r
634 \r
635                 /* grab HW semaphore to lock out flash updates  f0014 - dev_id 00a00190 */\r
636                 end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;\r
637                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
638                         ("Obtaining HW semaphore at %p till %I64d\n", p_reset + MLX4_SEM_OFFSET, end));\r
639                 do {\r
640                         sem = READ_REGISTER_ULONG((void*)(p_reset + MLX4_SEM_OFFSET));\r
641                         if (!sem)\r
642                                 break;\r
643                 \r
644                         cl_thread_suspend(1);\r
645                 } while (time_before(jiffies, end) || ++cnt < 100);\r
646                 \r
647                 if (sem) {\r
648                         MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
649                                 ("Failed to obtain HW semaphore in %d attemps till %I64d, aborting\n",\r
650                                 cnt, jiffies));\r
651                         status = STATUS_UNSUCCESSFUL;\r
652                         MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE );\r
653                         goto err;\r
654                 }\r
655                 \r
656                 \r
657                 /* Issue the reset. */\r
658                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
659                         ("Resetting  the chip at %p with %#x...\n", p_reset + MLX4_RESET_OFFSET, MLX4_RESET_VALUE));\r
660                 WRITE_REGISTER_ULONG( (void*)(p_reset + MLX4_RESET_OFFSET), MLX4_RESET_VALUE );\r
661 \r
662                 /* unmap the reset register */\r
663                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,("Unmapping reset register \n"));\r
664                 MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE );\r
665 \r
666                 /* Wait a second. */\r
667                 cl_thread_suspend( 100 );\r
668         }\r
669 \r
670         /* Read the configuration register until it doesn't return 0xFFFFFFFF */\r
671         {\r
672                 ULONG                                   data, i, reset_failed = 1;\r
673                 MLX4_PRINT( TRACE_LEVEL_INFORMATION     ,MLX4_DBG_PNP  ,("Read the configuration register \n"));\r
674                 for( i = 0; i < 500; i++ ) {\r
675                         if (4 != p_ifc->GetBusData( p_ifc->Context,\r
676                                 PCI_WHICHSPACE_CONFIG, &data, 0, 4)) {\r
677                                 MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
678                                         ("Failed to read device configuration data. Card reset failed !\n"));\r
679                                 status = STATUS_UNSUCCESSFUL;\r
680                                 break;\r
681                         }\r
682                         /* See if we got valid data. */\r
683                         if( data != 0xFFFFFFFF ) {\r
684                                 reset_failed = 0;\r
685                                 break;\r
686                         }\r
687                 \r
688                         cl_thread_suspend( 10 );\r
689                 }       \r
690 \r
691                 if (reset_failed) {\r
692                         MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
693                                 ("Doh! PCI device did not come back after reset!\n"));\r
694                         status = STATUS_UNSUCCESSFUL;\r
695                         goto err;\r
696                 }\r
697         }\r
698 \r
699         /* restore the HCA's PCI configuration headers */\r
700         {\r
701                 /* Restore the HCA's configuration. */\r
702                 MLX4_PRINT( TRACE_LEVEL_INFORMATION  ,MLX4_DBG_PNP  ,("Restoring HCA PCI configuration \n"));\r
703                 status = __restore_pci_config( p_ifc, p_cfg );\r
704                 if( !NT_SUCCESS( status ) ) {\r
705                         MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
706                                 ("Failed to restore HCA config. Card reset failed !\n"));\r
707                         goto err;\r
708                 }\r
709         }\r
710 \r
711         /* restore MSI-X info after reset */\r
712         status = __pci_restore_msix_info( pdev, &msix_info );\r
713         if (!NT_SUCCESS(status))\r
714                 goto err;\r
715 \r
716         /* check, whether MSI-X capabilities were restore */\r
717         pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info );\r
718 \r
719         MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("HCA has been reset ! \n"));\r
720 \r
721         status = STATUS_SUCCESS;\r
722 \r
723 err:\r
724         if (pdev->msix_info.valid) \r
725                 pci_free_msix_info_resources(&pdev->msix_info);\r
726         MLX4_EXIT( MLX4_DBG_PNP );\r
727         ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
728         return status;\r
729 }\r
730 \r
731 \r
732 /*\r
733  * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM.\r
734  */\r
735 void\r
736 pci_get_uplink_info(\r
737         IN                              PCI_COMMON_CONFIG *             p_cfg,\r
738         OUT                             uplink_info_t *                 p_uplink_info )\r
739 {\r
740         ULONG                                   capOffset;\r
741         PCI_PCIX_CAPABILITY             *pPciXCap;\r
742         PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
743 \r
744         MLX4_ENTER( MLX4_DBG_PNP );\r
745 \r
746         // PCIX Capability\r
747         capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX );\r
748         if( capOffset ) {\r
749                 pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
750 \r
751                 p_uplink_info->bus_type = UPLINK_BUS_PCIX;\r
752                 if (pPciXCap->Status & (1 << 17))\r
753                         p_uplink_info->u.pci_x.capabilities = UPLINK_BUS_PCIX_133;\r
754                 \r
755         }\r
756 \r
757         // PCI Express Capability\r
758         capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
759         if( capOffset ) {\r
760                 pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
761 \r
762                 p_uplink_info->bus_type = UPLINK_BUS_PCIE;\r
763                 if ((pPciExpCap->LinkStatus & 15) == 1)\r
764                         p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_SDR;\r
765                 if ((pPciExpCap->LinkStatus & 15) == 2)\r
766                         p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_DDR;\r
767                 p_uplink_info->u.pci_e.link_width = (uint8_t)((pPciExpCap->LinkStatus >> 4) & 0x03f);\r
768                 p_uplink_info->u.pci_e.capabilities = (uint8_t)((pPciExpCap->LinkCapabilities >> 2) & 0xfc);\r
769                 p_uplink_info->u.pci_e.capabilities |= pPciExpCap->LinkCapabilities & 3;\r
770         }\r
771 \r
772         MLX4_EXIT( MLX4_DBG_PNP );\r
773 }\r
774 \r
775 \r
776 NTSTATUS\r
777 pci_hca_enable(\r
778         IN              PBUS_INTERFACE_STANDARD         p_ifc,\r
779         IN              PCI_COMMON_CONFIG*                      p_cfg\r
780         )\r
781 {\r
782                 NTSTATUS                        status = STATUS_SUCCESS;\r
783                 ULONG                           len;\r
784         \r
785                 MLX4_ENTER( MLX4_DBG_PNP );\r
786         \r
787                 /* fix command register (set PCI Master bit) */\r
788                 // NOTE: we change here the saved value of the command register\r
789                 if ( (p_cfg->Command & 7) != 7 ) {\r
790                         p_cfg->Command |= 7;\r
791                         len = p_ifc->SetBusData( p_ifc->Context, PCI_WHICHSPACE_CONFIG,\r
792                                 (PVOID)&p_cfg->Command , 4, sizeof(ULONG) );\r
793                         if( len != sizeof(ULONG) ) {\r
794                                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to write command register.\n"));\r
795                                 status = STATUS_DEVICE_NOT_READY;\r
796                         }\r
797                 }\r
798 \r
799                 MLX4_EXIT( MLX4_DBG_PNP );\r
800                 return status;\r
801 }\r
802 \r
803 \r