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