[MLX4] add VPD data to bus interface. [mlnx: 4456]
[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 cap_offset, bir;\r
335         PPCI_MSIX_CAPABILITY pPciMsixCap;\r
336 \r
337         MLX4_ENTER( MLX4_DBG_PNP );\r
338 \r
339         /* find capability */\r
340         cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
341         if( !cap_offset ) {\r
342                 p_info->valid = 0;\r
343                 return 0;\r
344         }       \r
345         pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset);\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 static NTSTATUS __read_vpd_dword(\r
432         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
433         IN                              ULONG                                           cap_offset,\r
434         IN                              ULONG                                           offset,\r
435                 OUT                     UCHAR                                           *p_data\r
436         )\r
437 {\r
438         ULONG len;\r
439         USHORT addr = (USHORT)offset;\r
440 \r
441         /* write offset inside VPD data */\r
442         len = pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2,2 );\r
443         if ( len != 2 ) \r
444                 goto err_write;\r
445 \r
446         /* wait for data to be put in the data register */\r
447         while ( !(addr & 0x8000) ) {\r
448                 len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2, 2 );\r
449                 if ( len != 2 )\r
450                         goto err_read;\r
451         } \r
452 \r
453         /* get the tag value */\r
454         len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, p_data, cap_offset+4, 4 );\r
455         if ( len != 4 )\r
456                 goto err_read;\r
457 \r
458         return STATUS_SUCCESS;\r
459         \r
460 err_write:\r
461         MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  , \r
462                 ("Failed to write HCA config. \n" )); \r
463         return STATUS_DEVICE_NOT_READY;\r
464 \r
465 err_read:       \r
466         MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  , \r
467                 ("Failed to read HCA config. \n" )); \r
468         return STATUS_DEVICE_NOT_READY;\r
469 }\r
470 \r
471 \r
472 #define MAX_VPD_SIZE    (1 << 16)\r
473 \r
474 NTSTATUS pci_get_vpd(\r
475         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
476         IN                              PCI_COMMON_CONFIG* const        pConfig,\r
477                 OUT                     UCHAR*                                          *p_vpd,\r
478         IN      OUT                     int*                                            p_vpd_size\r
479         )\r
480 {\r
481         PCI_VPD_CAPABILITY              *pPciVpdCap;\r
482         ULONG                                   cap_offset;\r
483         NTSTATUS                                status = STATUS_SUCCESS;\r
484         int                                             vpd_size = 0;\r
485         UCHAR                                   *vpd = NULL;\r
486 \r
487         *p_vpd = NULL;\r
488         *p_vpd_size = 0;\r
489 \r
490         cap_offset = __find_capability( pConfig, PCI_CAPABILITY_ID_VPD );\r
491         if( cap_offset ) {\r
492                 ULONG offset;\r
493                 pPciVpdCap = (PCI_VPD_CAPABILITY*)(((UCHAR*)pConfig) + cap_offset);\r
494 \r
495                 /* allocate temp buffer */\r
496                 vpd = kmalloc( MAX_VPD_SIZE, GFP_KERNEL);\r
497                 if ( !vpd ) {\r
498                         MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,\r
499                                 ("Failed to allocate VPD buffer of size %d.\n", MAX_VPD_SIZE));\r
500                         return STATUS_UNSUCCESSFUL;\r
501                 }\r
502                 \r
503                 /* read VPD */\r
504                 for ( offset = 0; offset < MAX_VPD_SIZE; offset += 0x4 ) {\r
505                         status = __read_vpd_dword( pBusIfc, cap_offset,\r
506                                 offset, vpd + offset);\r
507                         if( !NT_SUCCESS( status ) ) {\r
508                                 kfree( vpd );\r
509                                 return STATUS_UNSUCCESSFUL;\r
510                         }\r
511                 }\r
512                 /* find the size */\r
513                 for ( offset = 0; offset < MAX_VPD_SIZE; ) {\r
514                         ULONG size;\r
515                         if ( vpd[offset] == 0x78 ) {\r
516                                 vpd_size = offset + 1;\r
517                                 break;\r
518                         }\r
519                         if ( vpd[offset] & 0x80 ) { /* Large Resource Type */ \r
520                                 size = *(PUSHORT)(&vpd[offset+1]);\r
521                                 offset += size + 3;     \r
522                         }\r
523                         else {  /* Small Resource Type */\r
524                                 size = vpd[offset] & 7;\r
525                                 offset += size + 1;     \r
526                         }\r
527                 }\r
528                 /* shorten the VPD array */\r
529                 if ( offset >= MAX_VPD_SIZE ) {\r
530                         /* we didn't found VPD end. We'll keep it all */\r
531                         *p_vpd = vpd;\r
532                         *p_vpd_size = MAX_VPD_SIZE;\r
533                 }\r
534                 else {\r
535                         /* allocate VPD */\r
536                         if ( vpd_size ) {\r
537                                 *p_vpd = kmalloc( vpd_size, GFP_KERNEL);\r
538                                 if ( !*p_vpd ) {\r
539                                         *p_vpd = vpd;\r
540                                         *p_vpd_size = MAX_VPD_SIZE;\r
541                                 }\r
542                                 else {\r
543                                         memcpy( *p_vpd, vpd, vpd_size );\r
544                                         *p_vpd_size = vpd_size;\r
545                                         kfree( vpd );\r
546                                 }\r
547                         }\r
548                         else {\r
549                                 MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,\r
550                                         ("VPD starts from end tag.\n"));\r
551                                 kfree( vpd );\r
552                                 status = STATUS_UNSUCCESSFUL;\r
553                         }\r
554                 }\r
555                 MLX4_PRINT( TRACE_LEVEL_WARNING  , MLX4_DBG_PNP  ,\r
556                         ("Found VPD of size %d, beginning with '%s'\n", *p_vpd_size, &vpd[3]));\r
557         }\r
558         else {\r
559                 MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,("Failed to find VPD capability.\n"));\r
560                 status = STATUS_UNSUCCESSFUL;\r
561         }\r
562 \r
563         return status;\r
564 }\r
565 \r
566 /*\r
567  * Reads and saves the PCI configuration of the device accessible\r
568  * through the provided bus interface.  Does not read registers 22 or 23\r
569  * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset.\r
570  */\r
571 NTSTATUS\r
572 pci_save_config(\r
573         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
574                 OUT                     PCI_COMMON_CONFIG* const        pConfig )\r
575 {\r
576         ULONG                                   len;\r
577         UINT32                                  *pBuf;\r
578 \r
579         MLX4_ENTER( MLX4_DBG_PNP );\r
580         \r
581         pBuf = (UINT32*)pConfig;\r
582 \r
583         /*\r
584          * Read the lower portion of the configuration, up to but excluding\r
585          * register 22.\r
586          */\r
587         len = pBusIfc->GetBusData(\r
588                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 );\r
589         if( len != 88 )\r
590         {\r
591                 MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,("Failed to read HCA config.\n"));\r
592                 return STATUS_DEVICE_NOT_READY;\r
593         }\r
594 \r
595         /* Read the upper portion of the configuration, from register 24. */\r
596         len = pBusIfc->GetBusData(\r
597                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 );\r
598         if( len != 160 )\r
599         {\r
600                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to read HCA config.\n"));\r
601                 return STATUS_DEVICE_NOT_READY;\r
602         }\r
603 \r
604         MLX4_EXIT( MLX4_DBG_PNP );\r
605         return STATUS_SUCCESS;\r
606 }\r
607 \r
608 \r
609 /*\r
610  * Store Card's PCI Config space and print current MSI-X capabilities\r
611  */\r
612 void\r
613 pci_get_msi_info(\r
614         IN                              struct pci_dev                  *pdev,\r
615                 OUT                     PCI_COMMON_CONFIG *             p_cfg,\r
616                 OUT                     uplink_info_t *                 p_uplink_info )\r
617 {\r
618         ULONG                                   cap_offset;\r
619         NTSTATUS                                status;\r
620         BUS_INTERFACE_STANDARD  *pBusIfc = &pdev->bus_pci_ifc;\r
621 \r
622         MLX4_ENTER( MLX4_DBG_PNP );\r
623 \r
624         status = pci_save_config( pBusIfc, p_cfg );\r
625         if (!NT_SUCCESS(status)) {\r
626                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
627                         ("Failed to read PCI configuration of the card.\n") );\r
628                 goto end;\r
629         }\r
630 \r
631         // PCI MSI-X Capability\r
632         memset( &p_uplink_info->x, 0, sizeof(p_uplink_info->x) );\r
633         cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
634         if( cap_offset ) {\r
635                 PVOID ka;\r
636                 ULONG sz;\r
637                 PHYSICAL_ADDRESS pa;\r
638                 PPCI_MSIX_VECTOR p_vector;\r
639                 PPCI_MSIX_PENDING p_pend;\r
640                 ULONG granted_mask = 0;\r
641                 PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset);\r
642                 USHORT flags = pPciMsixCap->Flags;\r
643                 ULONG table_bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset);\r
644                 ULONG pend_bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset);\r
645                 u64 table_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[table_bir] & ~0x0f;\r
646                 u64 pend_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[pend_bir] & ~0x0f;\r
647                 int i, n_supported = MSIX_FLAGS_SUPPORTED(flags) + 1;\r
648 \r
649                 /* print capabilities structure */\r
650                 MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
651                         ("MSI-X Capability: Enabled - %d, Function Masked %d, Vectors Supported %d, Addr_Offset(BIR) %#x(%d), Pend_Offset(BIR) %#x(%d)\n",\r
652                         MSIX_FLAGS_MSIX_ENABLE(flags),\r
653                         MSIX_FLAGS_MSIX_FUNCTION_MASK(flags),\r
654                         n_supported, \r
655                         MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset), MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset), \r
656                         MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset), MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset) ));\r
657 \r
658                 /* fill info */\r
659                 p_uplink_info->x.valid = 1;\r
660                 p_uplink_info->x.enabled= MSIX_FLAGS_MSIX_ENABLE(flags);\r
661                 p_uplink_info->x.masked = MSIX_FLAGS_MSIX_FUNCTION_MASK(flags);\r
662                 p_uplink_info->x.requested = n_supported;\r
663 \r
664                 if (pdev->n_msi_vectors_alloc) {\r
665 \r
666                         /* map memory */\r
667                         sz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR));\r
668                         pa.QuadPart = table_bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset);\r
669                         ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
670                         if ( ka == NULL) {\r
671                                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
672                                         ("Failed kernel mapping of MSI-X vector table.\n") );\r
673                                 goto end;\r
674                         }\r
675                         \r
676                         p_vector = ka;\r
677                         /* print (allocated+2) vectors */\r
678                         for (i=0; i<pdev->n_msi_vectors_alloc+2; i++) {\r
679                                 MLX4_PRINT( TRACE_LEVEL_VERBOSE  ,MLX4_DBG_PNP  ,\r
680                                         ("MSI-X Vectors: Id %d, Masked %d, Addr %#I64x, Data %#x\n",\r
681                                         i, MSIX_VECTOR_MASKED(p_vector[i].Flags),\r
682                                         p_vector[i].Addr, p_vector[i].Data ));\r
683                         }\r
684 \r
685                         p_uplink_info->x.granted = pdev->n_msi_vectors_alloc;\r
686                         p_uplink_info->x.granted_mask = granted_mask;\r
687                         MmUnmapIoSpace( ka, sz );\r
688 \r
689                         /* map memory */\r
690                         sz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64);\r
691                         pa.QuadPart = pend_bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset);\r
692                         ka = MmMapIoSpace( pa, sz, MmNonCached ); \r
693                         if ( ka == NULL) {\r
694                                 MLX4_PRINT(TRACE_LEVEL_ERROR  , MLX4_DBG_PNP,\r
695                                         ("Failed kernel mapping of MSI-X mask table.\n") );\r
696                                 goto end;\r
697                         }\r
698 \r
699                         /* print first pending register (64 vectors) */\r
700                         p_pend = ka;\r
701                         for (i=0; i<1; i++) {\r
702                                 MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
703                                         ("MSI-X Pending: Id %d, Pend %#I64x\n", i, p_pend[i].Mask ));\r
704                         }\r
705                         p_uplink_info->x.pending_mask = *(u32*)&p_pend[0].Mask;\r
706                         MmUnmapIoSpace( ka, sz );\r
707                 }\r
708                 else {\r
709                         MLX4_PRINT( TRACE_LEVEL_WARNING  ,MLX4_DBG_PNP  ,\r
710                                 ("MSI-X Vectors: Allocated 0 vectors\n") );\r
711                 }\r
712 \r
713         }\r
714 \r
715 end:    \r
716         MLX4_EXIT( MLX4_DBG_PNP );\r
717 }\r
718 \r
719 NTSTATUS\r
720 pci_hca_reset( \r
721         IN              struct pci_dev *pdev\r
722 )\r
723 {\r
724         u32                                                     sem;\r
725         NTSTATUS                                        status = STATUS_SUCCESS, status1;\r
726         PBUS_INTERFACE_STANDARD         p_ifc = &pdev->bus_pci_ifc;\r
727         PCI_COMMON_CONFIG*                      p_cfg = &pdev->pci_cfg_space;\r
728         struct msix_saved_info          msix_info;\r
729         ULONG                                           len;\r
730 \r
731         MLX4_ENTER( MLX4_DBG_PNP );\r
732 \r
733         ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
734 \r
735         /* save Card Config Space including MSI-X capabilities */\r
736         pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info );\r
737 \r
738         /* save MSI-X info, if any */\r
739         len = __save_msix_info( p_cfg, &msix_info );\r
740         if (len) {\r
741                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to save MSI-X config.\n"));\r
742                 return STATUS_DEVICE_NOT_READY;\r
743         }\r
744 \r
745         /* reset the card */    \r
746         MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("\nResetting HCA ... \n\n"));\r
747         {\r
748                 u64 end;\r
749                 PUCHAR  p_reset;\r
750                 PHYSICAL_ADDRESS  pa;\r
751                 int cnt = 0;\r
752 \r
753                 /* map reset register */\r
754                 pa.QuadPart = pdev->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)MLX4_RESET_BASE;\r
755                 p_reset = MmMapIoSpace( pa, MLX4_RESET_SIZE, MmNonCached );\r
756                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
757                         ("Reset area ia mapped from pa 0x%I64x to va %p, size %#x\n", \r
758                         pa.QuadPart, p_reset, MLX4_RESET_SIZE));\r
759                 if( !p_reset ) {\r
760                         MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart));\r
761                         status = STATUS_UNSUCCESSFUL;\r
762                         goto err;\r
763                 }\r
764 \r
765                 /* grab HW semaphore to lock out flash updates  f0014 - dev_id 00a00190 */\r
766                 end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;\r
767                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
768                         ("Obtaining HW semaphore at %p till %I64d\n", p_reset + MLX4_SEM_OFFSET, end));\r
769                 do {\r
770                         sem = READ_REGISTER_ULONG((void*)(p_reset + MLX4_SEM_OFFSET));\r
771                         if (!sem)\r
772                                 break;\r
773                 \r
774                         cl_thread_suspend(1);\r
775                 } while (time_before(jiffies, end) || ++cnt < 100);\r
776                 \r
777                 if (sem) {\r
778                         MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
779                                 ("Failed to obtain HW semaphore in %d attemps till %I64d, aborting\n",\r
780                                 cnt, jiffies));\r
781                         status = STATUS_UNSUCCESSFUL;\r
782                         MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE );\r
783                         goto err;\r
784                 }\r
785                 \r
786                 \r
787                 /* Issue the reset. */\r
788                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,\r
789                         ("Resetting  the chip at %p with %#x...\n", p_reset + MLX4_RESET_OFFSET, MLX4_RESET_VALUE));\r
790                 WRITE_REGISTER_ULONG( (void*)(p_reset + MLX4_RESET_OFFSET), MLX4_RESET_VALUE );\r
791 \r
792                 /* unmap the reset register */\r
793                 MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP  ,("Unmapping reset register \n"));\r
794                 MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE );\r
795 \r
796                 /* Wait a second. */\r
797                 cl_thread_suspend( 100 );\r
798         }\r
799 \r
800         /* Read the configuration register until it doesn't return 0xFFFFFFFF */\r
801         {\r
802                 ULONG                                   data, i, reset_failed = 1;\r
803                 MLX4_PRINT( TRACE_LEVEL_INFORMATION     ,MLX4_DBG_PNP  ,("Read the configuration register \n"));\r
804                 for( i = 0; i < 500; i++ ) {\r
805                         if (4 != p_ifc->GetBusData( p_ifc->Context,\r
806                                 PCI_WHICHSPACE_CONFIG, &data, 0, 4)) {\r
807                                 MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
808                                         ("Failed to read device configuration data. Card reset failed !\n"));\r
809                                 status = STATUS_UNSUCCESSFUL;\r
810                                 break;\r
811                         }\r
812                         /* See if we got valid data. */\r
813                         if( data != 0xFFFFFFFF ) {\r
814                                 reset_failed = 0;\r
815                                 break;\r
816                         }\r
817                 \r
818                         cl_thread_suspend( 10 );\r
819                 }       \r
820 \r
821                 if (reset_failed) {\r
822                         MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
823                                 ("Doh! PCI device did not come back after reset!\n"));\r
824                         status = STATUS_UNSUCCESSFUL;\r
825                         goto err;\r
826                 }\r
827         }\r
828 \r
829         /* restore the HCA's PCI configuration headers */\r
830         {\r
831                 /* Restore the HCA's configuration. */\r
832                 MLX4_PRINT( TRACE_LEVEL_INFORMATION  ,MLX4_DBG_PNP  ,("Restoring HCA PCI configuration \n"));\r
833                 status = __restore_pci_config( p_ifc, p_cfg );\r
834                 if( !NT_SUCCESS( status ) ) {\r
835                         MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, \r
836                                 ("Failed to restore HCA config. Card reset failed !\n"));\r
837                         goto err;\r
838                 }\r
839         }\r
840 \r
841         status = STATUS_SUCCESS;\r
842 \r
843 err:\r
844         /* restore MSI-X info after reset */\r
845         status1 = __pci_restore_msix_info( pdev, &msix_info );\r
846         status = (!status) ? status1 : status;  /* return the only or the first error */\r
847         if( NT_SUCCESS( status ) ) {\r
848                 MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("HCA has been reset ! \n"));\r
849         }\r
850 \r
851         /* check, whether MSI-X capabilities have been restored */\r
852         pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info );\r
853 \r
854         if (pdev->msix_info.valid) \r
855                 pci_free_msix_info_resources(&pdev->msix_info);\r
856         MLX4_EXIT( MLX4_DBG_PNP );\r
857         ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
858         return status;\r
859 }\r
860 \r
861 \r
862 /*\r
863  * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM.\r
864  */\r
865 void\r
866 pci_get_uplink_info(\r
867         IN                              PCI_COMMON_CONFIG *             p_cfg,\r
868         OUT                             uplink_info_t *                 p_uplink_info )\r
869 {\r
870         ULONG                                   cap_offset;\r
871         PCI_PCIX_CAPABILITY             *pPciXCap;\r
872         PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
873 \r
874         MLX4_ENTER( MLX4_DBG_PNP );\r
875 \r
876         // PCIX Capability\r
877         cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX );\r
878         if( cap_offset ) {\r
879                 pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset);\r
880 \r
881                 p_uplink_info->bus_type = UPLINK_BUS_PCIX;\r
882                 if (pPciXCap->Status & (1 << 17))\r
883                         p_uplink_info->u.pci_x.capabilities = UPLINK_BUS_PCIX_133;\r
884                 \r
885         }\r
886 \r
887         // PCI Express Capability\r
888         cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
889         if( cap_offset ) {\r
890                 pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset);\r
891 \r
892                 p_uplink_info->bus_type = UPLINK_BUS_PCIE;\r
893                 if ((pPciExpCap->LinkStatus & 15) == 1)\r
894                         p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_SDR;\r
895                 if ((pPciExpCap->LinkStatus & 15) == 2)\r
896                         p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_DDR;\r
897                 p_uplink_info->u.pci_e.link_width = (uint8_t)((pPciExpCap->LinkStatus >> 4) & 0x03f);\r
898                 p_uplink_info->u.pci_e.capabilities = (uint8_t)((pPciExpCap->LinkCapabilities >> 2) & 0xfc);\r
899                 p_uplink_info->u.pci_e.capabilities |= pPciExpCap->LinkCapabilities & 3;\r
900         }\r
901 \r
902         MLX4_EXIT( MLX4_DBG_PNP );\r
903 }\r
904 \r
905 \r
906 NTSTATUS\r
907 pci_hca_enable(\r
908         IN              PBUS_INTERFACE_STANDARD         p_ifc,\r
909         IN              PCI_COMMON_CONFIG*                      p_cfg\r
910         )\r
911 {\r
912                 NTSTATUS                        status = STATUS_SUCCESS;\r
913                 ULONG                           len;\r
914         \r
915                 MLX4_ENTER( MLX4_DBG_PNP );\r
916         \r
917                 /* fix command register (set PCI Master bit) */\r
918                 // NOTE: we change here the saved value of the command register\r
919                 if ( (p_cfg->Command & 7) != 7 ) {\r
920                         p_cfg->Command |= 7;\r
921                         len = p_ifc->SetBusData( p_ifc->Context, PCI_WHICHSPACE_CONFIG,\r
922                                 (PVOID)&p_cfg->Command , 4, sizeof(ULONG) );\r
923                         if( len != sizeof(ULONG) ) {\r
924                                 MLX4_PRINT( TRACE_LEVEL_ERROR  ,MLX4_DBG_PNP  ,("Failed to write command register.\n"));\r
925                                 status = STATUS_DEVICE_NOT_READY;\r
926                         }\r
927                 }\r
928 \r
929                 MLX4_EXIT( MLX4_DBG_PNP );\r
930                 return status;\r
931 }\r
932 \r
933 \r