[MTHCA] feature: added new Registry parameter - TunePci - which is set by default...
[mirror/winof/.git] / hw / mthca / kernel / hca_pci.c
1 \r
2 #include "hca_driver.h"\r
3 #if defined(EVENT_TRACING)\r
4 #ifdef offsetof\r
5 #undef offsetof\r
6 #endif\r
7 #include "hca_pci.tmh"\r
8 #endif\r
9 #include <complib/cl_thread.h>\r
10 #include <initguid.h>\r
11 #include <wdmguid.h>\r
12 \r
13 #define HCA_RESET_HCR_OFFSET                            0x000F0010\r
14 #define HCA_RESET_TOKEN                                         CL_HTON32(0x00000001)\r
15 \r
16 #define PCI_CAPABILITY_ID_VPD                           0x03\r
17 #define PCI_CAPABILITY_ID_PCIX                          0x07\r
18 #define PCI_CAPABILITY_ID_PCIEXP                        0x10\r
19 \r
20 boolean_t\r
21 FindBridgeIf(\r
22         IN hca_dev_ext_t                *pi_ext,\r
23         IN      PBUS_INTERFACE_STANDARD pi_pInterface\r
24         );\r
25 \r
26 \r
27 /*\r
28  * Vital Product Data Capability\r
29  */\r
30 typedef struct _PCI_VPD_CAPABILITY {\r
31 \r
32         PCI_CAPABILITIES_HEADER Header;\r
33 \r
34         USHORT          Flags;\r
35         ULONG                   Data;\r
36 \r
37 } PCI_VPD_CAPABILITY, *PPCI_VPD_CAPABILITY;\r
38 \r
39 \r
40 /*\r
41  * PCI-X Capability\r
42  */\r
43 typedef struct _PCI_PCIX_CAPABILITY {\r
44 \r
45         PCI_CAPABILITIES_HEADER Header;\r
46 \r
47         USHORT          Command;\r
48         ULONG                   Status;\r
49 \r
50 /* for Command: */\r
51 } PCI_PCIX_CAPABILITY, *PPCI_PCIX_CAPABILITY;\r
52 \r
53 #define  PCI_X_CMD_MAX_READ     0x000c  /* Max Memory Read Byte Count */\r
54 \r
55 /*\r
56  * PCI-Express Capability\r
57  */\r
58 typedef struct _PCI_PCIEXP_CAPABILITY {\r
59 \r
60         PCI_CAPABILITIES_HEADER Header;\r
61 \r
62         USHORT          Flags;\r
63         ULONG                   DevCapabilities;\r
64         USHORT          DevControl;\r
65         USHORT          DevStatus;\r
66         ULONG                   LinkCapabilities;\r
67         USHORT          LinkControl;\r
68         USHORT          LinkStatus;\r
69         ULONG                   SlotCapabilities;\r
70         USHORT          SlotControl;\r
71         USHORT          SlotStatus;\r
72         USHORT          RootControl;\r
73         USHORT          RootCapabilities;\r
74         USHORT          RootStatus;\r
75 } PCI_PCIEXP_CAPABILITY, *PPCI_PCIEXP_CAPABILITY;\r
76 \r
77 /* for DevControl: */\r
78 #define  PCI_EXP_DEVCTL_READRQ  0x7000  /* Max_Read_Request_Size */\r
79 \r
80 static NTSTATUS\r
81 __get_bus_ifc(\r
82         IN                              DEVICE_OBJECT* const            pDevObj,\r
83         IN              const   GUID* const                                     pGuid,\r
84                 OUT                     BUS_INTERFACE_STANDARD          *pBusIfc );\r
85 \r
86 static void\r
87 __fixup_pci_capabilities(\r
88         IN                              PCI_COMMON_CONFIG* const        pConfig );\r
89 \r
90 static NTSTATUS\r
91 __save_pci_config(\r
92         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
93                 OUT                     PCI_COMMON_CONFIG* const        pConfig );\r
94 \r
95 static NTSTATUS\r
96 __restore_pci_config(\r
97         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
98         IN                              PCI_COMMON_CONFIG* const        pConfig,\r
99         IN                              const int                                               is_bridge );\r
100 \r
101 \r
102 #ifdef ALLOC_PRAGMA\r
103 #pragma alloc_text (PAGE, __get_bus_ifc)\r
104 #pragma alloc_text (PAGE, __fixup_pci_capabilities)\r
105 #pragma alloc_text (PAGE, __save_pci_config)\r
106 #pragma alloc_text (PAGE, __restore_pci_config)\r
107 #endif\r
108 \r
109 /*\r
110  * Returns the offset in configuration space of the PCI-X capabilites.\r
111  */\r
112 static ULONG\r
113 __FindCapability(\r
114         IN                              PCI_COMMON_CONFIG* const        pConfig,  \r
115         IN                              char cap_id\r
116         )\r
117 {\r
118         ULONG                                           offset = 0;\r
119         PCI_CAPABILITIES_HEADER         *pHdr = NULL;\r
120         UCHAR                                           *pBuf = (UCHAR*)pConfig;\r
121 \r
122         HCA_ENTER( HCA_DBG_PNP );\r
123 \r
124         if  ( pConfig->HeaderType == PCI_DEVICE_TYPE ) {\r
125                 if( pConfig->u.type0.CapabilitiesPtr )\r
126                 {\r
127                         pHdr = (PCI_CAPABILITIES_HEADER*)\r
128                                 (pBuf + pConfig->u.type0.CapabilitiesPtr);\r
129                 }\r
130         }\r
131 \r
132         if  ( pConfig->HeaderType == PCI_BRIDGE_TYPE ) {\r
133                 if( pConfig->u.type1.CapabilitiesPtr )\r
134                 {\r
135                         pHdr = (PCI_CAPABILITIES_HEADER*)\r
136                                 (pBuf + pConfig->u.type1.CapabilitiesPtr);\r
137                 }\r
138         }\r
139 \r
140         /*\r
141          * Fix up any fields that might cause changes to the\r
142          * device - like writing VPD data.\r
143          */\r
144         while( pHdr )\r
145         {\r
146                 if( pHdr->CapabilityID == cap_id )\r
147                 {\r
148                         offset = (UCHAR)(((ULONG_PTR)pHdr) - ((ULONG_PTR)pConfig));\r
149                         break;\r
150                 }\r
151 \r
152                 if( pHdr->Next )\r
153                         pHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next);\r
154                 else\r
155                         pHdr = NULL;\r
156         }\r
157 \r
158         HCA_EXIT( HCA_DBG_PNP );\r
159         return offset;\r
160 }\r
161 \r
162 /* Forwards the request to the HCA's PDO. */\r
163 static NTSTATUS\r
164 __get_bus_ifc(\r
165         IN                              DEVICE_OBJECT* const            pDevObj,\r
166         IN              const   GUID* const                                     pGuid,\r
167                 OUT                     BUS_INTERFACE_STANDARD          *pBusIfc )\r
168 {\r
169         NTSTATUS                        status;\r
170         IRP                                     *pIrp;\r
171         IO_STATUS_BLOCK         ioStatus;\r
172         IO_STACK_LOCATION       *pIoStack;\r
173         DEVICE_OBJECT           *pDev;\r
174         KEVENT                          event;\r
175 \r
176         HCA_ENTER( HCA_DBG_PNP );\r
177 \r
178         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
179 \r
180         pDev = IoGetAttachedDeviceReference( pDevObj );\r
181 \r
182         KeInitializeEvent( &event, NotificationEvent, FALSE );\r
183 \r
184         /* Build the IRP for the HCA. */\r
185         pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev,\r
186                 NULL, 0, NULL, &event, &ioStatus );\r
187         if( !pIrp )\r
188         {\r
189                 ObDereferenceObject( pDev );\r
190                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
191                         ("IoBuildSynchronousFsdRequest failed.\n"));\r
192                 return STATUS_INSUFFICIENT_RESOURCES;\r
193         }\r
194 \r
195         /* Copy the request query parameters. */\r
196         pIoStack = IoGetNextIrpStackLocation( pIrp );\r
197         pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;\r
198         pIoStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);\r
199         pIoStack->Parameters.QueryInterface.Version = 1;\r
200         pIoStack->Parameters.QueryInterface.InterfaceType = pGuid;\r
201         pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pBusIfc;\r
202         pIoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;\r
203 \r
204         pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
205 \r
206         /* Send the IRP. */\r
207         status = IoCallDriver( pDev, pIrp );\r
208         if( status == STATUS_PENDING )\r
209         {\r
210                 KeWaitForSingleObject( &event, Executive, KernelMode,\r
211                         FALSE, NULL );\r
212 \r
213                 status = ioStatus.Status;\r
214         }\r
215         ObDereferenceObject( pDev );\r
216 \r
217         HCA_EXIT( HCA_DBG_PNP );\r
218         return status;\r
219 }\r
220 \r
221 \r
222 /*\r
223  * Reads and saves the PCI configuration of the device accessible\r
224  * through the provided bus interface.  Does not read registers 22 or 23\r
225  * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset.\r
226  */\r
227 static NTSTATUS\r
228 __save_pci_config(\r
229         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
230                 OUT                     PCI_COMMON_CONFIG* const        pConfig )\r
231 {\r
232         ULONG                                   len;\r
233         UINT32                                  *pBuf;\r
234 \r
235         HCA_ENTER( HCA_DBG_PNP );\r
236         \r
237         pBuf = (UINT32*)pConfig;\r
238 \r
239         /*\r
240          * Read the lower portion of the configuration, up to but excluding\r
241          * register 22.\r
242          */\r
243         len = pBusIfc->GetBusData(\r
244                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 );\r
245         if( len != 88 )\r
246         {\r
247                 HCA_PRINT( TRACE_LEVEL_ERROR  , HCA_DBG_PNP  ,("Failed to read HCA config.\n"));\r
248                 return STATUS_DEVICE_NOT_READY;\r
249         }\r
250 \r
251         /* Read the upper portion of the configuration, from register 24. */\r
252         len = pBusIfc->GetBusData(\r
253                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 );\r
254         if( len != 160 )\r
255         {\r
256                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to read HCA config.\n"));\r
257                 return STATUS_DEVICE_NOT_READY;\r
258         }\r
259 \r
260         HCA_EXIT( HCA_DBG_PNP );\r
261         return STATUS_SUCCESS;\r
262 }\r
263 \r
264 \r
265 static void\r
266 __fixup_pci_capabilities(\r
267         IN                              PCI_COMMON_CONFIG* const        pConfig )\r
268 {\r
269         UCHAR                                           *pBuf;\r
270         PCI_CAPABILITIES_HEADER         *pHdr, *pNextHdr;\r
271 \r
272         HCA_ENTER( HCA_DBG_PNP );\r
273 \r
274         pBuf = (UCHAR*)pConfig;\r
275 \r
276         if( pConfig->HeaderType == PCI_DEVICE_TYPE )\r
277         {\r
278                 if( pConfig->u.type0.CapabilitiesPtr )\r
279                 {\r
280                         pNextHdr = (PCI_CAPABILITIES_HEADER*)\r
281                                 (pBuf + pConfig->u.type0.CapabilitiesPtr);\r
282                 }\r
283                 else\r
284                 {\r
285                         pNextHdr = NULL;\r
286                 }\r
287         }\r
288         else\r
289         {\r
290                 ASSERT( pConfig->HeaderType == PCI_BRIDGE_TYPE );\r
291                 if( pConfig->u.type1.CapabilitiesPtr )\r
292                 {\r
293                         pNextHdr = (PCI_CAPABILITIES_HEADER*)\r
294                                 (pBuf + pConfig->u.type1.CapabilitiesPtr);\r
295                 }\r
296                 else\r
297                 {\r
298                         pNextHdr = NULL;\r
299                 }\r
300         }\r
301 \r
302         /*\r
303          * Fix up any fields that might cause changes to the\r
304          * device - like writing VPD data.\r
305          */\r
306         while( pNextHdr )\r
307         {\r
308                 pHdr = pNextHdr;\r
309                 if( pNextHdr->Next )\r
310                         pNextHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next);\r
311                 else\r
312                         pNextHdr = NULL;\r
313 \r
314                 switch( pHdr->CapabilityID )\r
315                 {\r
316                 case PCI_CAPABILITY_ID_VPD:\r
317                         /* Clear the flags field so we don't cause a write. */\r
318                         ((PCI_VPD_CAPABILITY*)pHdr)->Flags = 0;\r
319                         break;\r
320 \r
321                 default:\r
322                         break;\r
323                 }\r
324         }\r
325 \r
326         HCA_EXIT( HCA_DBG_PNP );\r
327 }\r
328 \r
329 \r
330 /*\r
331  * Restore saved PCI configuration, skipping registers 22 and 23, as well\r
332  * as any registers where writing will have side effects such as the flags\r
333  * field of the VPD and vendor specific capabilities.  The function also delays\r
334  * writing the command register, bridge control register (if applicable), and\r
335  * PCIX command register (if present).\r
336  */\r
337 static NTSTATUS\r
338 __restore_pci_config(\r
339         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
340         IN                              PCI_COMMON_CONFIG* const        pConfig,\r
341         IN                              const int                                               is_bridge )\r
342 {\r
343         NTSTATUS status = STATUS_SUCCESS;\r
344         int             i, *pci_hdr = (int*)pConfig;\r
345         int hca_pcix_cap = 0;\r
346 \r
347         HCA_ENTER( HCA_DBG_PNP );\r
348 \r
349         /* get capabilities */\r
350         hca_pcix_cap = __FindCapability( pConfig, PCI_CAPABILITY_ID_PCIX );\r
351 \r
352         /* restore capabilities*/\r
353         if (is_bridge) {\r
354                 if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
355                         &pci_hdr[(hca_pcix_cap + 0x8) / 4], hca_pcix_cap + 0x8, 4) ) {\r
356                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
357                                 ("Couldn't restore HCA bridge Upstream split transaction control, aborting.\n"));\r
358                         status = STATUS_UNSUCCESSFUL;\r
359                         goto out;\r
360                 }\r
361                 if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
362                         &pci_hdr[(hca_pcix_cap + 0xc) / 4], hca_pcix_cap + 0xc, 4) ) {\r
363                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
364                                 ("Couldn't restore HCA bridge Downstream split transaction control, aborting.\n"));\r
365                         status = STATUS_UNSUCCESSFUL;\r
366                         goto out;\r
367                 }\r
368         }\r
369         else {\r
370                 int hca_pcie_cap = __FindCapability( pConfig, PCI_CAPABILITY_ID_PCIEXP );\r
371                 PCI_PCIEXP_CAPABILITY   *pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)pConfig) + hca_pcie_cap);\r
372 \r
373                 if (hca_pcix_cap) {\r
374                         if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
375                                 &pci_hdr[hca_pcix_cap/4], hca_pcix_cap, 4) ) {\r
376                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
377                                         ("Couldn't restore HCA PCI-X command register, aborting.\n"));\r
378                                 status = STATUS_UNSUCCESSFUL;\r
379                                 goto out;\r
380                         }\r
381                 }\r
382 \r
383                 if (hca_pcie_cap) {\r
384                         /* restore HCA PCI Express Device Control register */\r
385                         if ( sizeof( pPciExpCap->DevControl ) != pBusIfc->SetBusData( \r
386                                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
387                                 &pPciExpCap->DevControl,        hca_pcie_cap + \r
388                                 offsetof( PCI_PCIEXP_CAPABILITY, DevControl),\r
389                                 sizeof( pPciExpCap->DevControl ) )) {\r
390                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
391                                         ("Couldn't restore HCA PCI Express Device Control register, aborting.\n"));\r
392                                 status = STATUS_UNSUCCESSFUL;\r
393                                 goto out;\r
394                         }\r
395                         /* restore HCA PCI Express Link Control register */\r
396                         if ( sizeof( pPciExpCap->LinkControl ) != pBusIfc->SetBusData( \r
397                                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
398                                 &pPciExpCap->LinkControl,       hca_pcie_cap + \r
399                                 offsetof( PCI_PCIEXP_CAPABILITY, LinkControl),\r
400                                 sizeof( pPciExpCap->LinkControl ) )) {\r
401                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
402                                         ("Couldn't restore HCA PCI Express Link Control register, aborting.\n"));\r
403                                 status = STATUS_UNSUCCESSFUL;\r
404                                 goto out;\r
405                         }\r
406                 }\r
407         }\r
408 \r
409         /* write basic part */\r
410         for (i = 0; i < 16; ++i) {\r
411                 if (i == 1)\r
412                         continue;\r
413         \r
414                 if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
415                         PCI_WHICHSPACE_CONFIG, &pci_hdr[i], i * 4, 4 )) {\r
416                         HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,\r
417                                 ("Couldn't restore PCI cfg reg %x,   aborting.\n", i));\r
418                         status =  STATUS_DEVICE_NOT_READY;\r
419                         goto out;\r
420                 }\r
421         }\r
422 \r
423         /* Write the command register. */\r
424         if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
425                 PCI_WHICHSPACE_CONFIG, &pci_hdr[1], 4, 4 )) {\r
426                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Couldn't restore COMMAND.\n"));\r
427                 status =  STATUS_DEVICE_NOT_READY;\r
428         }\r
429 \r
430 out:    \r
431         HCA_EXIT( HCA_DBG_PNP );\r
432         return status;\r
433 }\r
434 \r
435 NTSTATUS\r
436 hca_reset( DEVICE_OBJECT* const         pDevObj, int is_tavor )\r
437 {\r
438         NTSTATUS                                status = STATUS_SUCCESS;\r
439         PCI_COMMON_CONFIG               hcaConfig, brConfig;\r
440         BUS_INTERFACE_STANDARD  hcaBusIfc;\r
441         BUS_INTERFACE_STANDARD  brBusIfc = {0}; // to bypass C4701\r
442         hca_dev_ext_t                   *pExt = (hca_dev_ext_t*)pDevObj->DeviceExtension;\r
443 \r
444         HCA_ENTER( HCA_DBG_PNP );\r
445 \r
446         /* sanity check */\r
447         if (is_tavor && g_skip_tavor_reset) {\r
448                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_PNP  ,("Card reset is skipped, trying to proceed.\n"));\r
449                 goto resetExit;\r
450         }\r
451 \r
452         /* get the resources */\r
453         {\r
454                 /* Get the HCA's bus interface. */\r
455                 status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, &hcaBusIfc );\r
456                 if( !NT_SUCCESS( status ) ) {\r
457                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to get HCA bus interface.\n"));\r
458                         goto resetErr1;\r
459                 }\r
460 \r
461                 /* Get the HCA Bridge's bus interface, if any */\r
462                 if (is_tavor) {\r
463                         if (!FindBridgeIf( pExt, &brBusIfc ))\r
464                                 goto resetErr2;\r
465                 }\r
466         }\r
467 \r
468         /* Save the HCA's PCI configuration headers */\r
469         {\r
470                 status = __save_pci_config( &hcaBusIfc, &hcaConfig );\r
471                 if( !NT_SUCCESS( status ) ) {\r
472                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
473                                 ("Failed to save HCA config.\n"));\r
474                         goto resetErr3;\r
475                 }\r
476 \r
477                 /* Save the HCA bridge's configuration, if any */\r
478                 if (is_tavor) {\r
479                         int hca_pcix_cap;\r
480                         status = __save_pci_config( &brBusIfc, &brConfig );\r
481                         if( !NT_SUCCESS( status ) ) {\r
482                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
483                                         ("Failed to save bridge config.\n"));\r
484                                 goto resetErr3;\r
485                         }\r
486                         hca_pcix_cap = __FindCapability( &brConfig, PCI_CAPABILITY_ID_PCIX );\r
487                         if (!hca_pcix_cap) {\r
488                                 status = STATUS_UNSUCCESSFUL;\r
489                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
490                                         ("Couldn't locate HCA bridge PCI-X capability, aborting.\n"));\r
491                                 goto resetErr3;\r
492                         }\r
493                 }\r
494         }\r
495         \r
496         /* reset the card */\r
497         {\r
498                 PULONG  reset_p;\r
499                 PHYSICAL_ADDRESS  pa;\r
500                 /* map reset register */\r
501                 pa.QuadPart = pExt->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)HCA_RESET_HCR_OFFSET;\r
502                 HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP  ,("Mapping reset register with address 0x%I64x\n", pa.QuadPart));\r
503                 reset_p = MmMapIoSpace( pa,     4, MmNonCached );\r
504                 if( !reset_p ) {\r
505                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart));\r
506                         status = STATUS_UNSUCCESSFUL;\r
507                         goto resetErr3;\r
508                 }\r
509                 \r
510                 /* Issue the reset. */\r
511                 HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP  ,("Resetting  the chip ...\n"));\r
512                 WRITE_REGISTER_ULONG( reset_p, HCA_RESET_TOKEN );\r
513 \r
514                 /* unmap the reset register */\r
515                 HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP  ,("Unmapping reset register \n"));\r
516                 MmUnmapIoSpace( reset_p, 4 );\r
517 \r
518                 /* Wait a second. */\r
519                 cl_thread_suspend( 1000 );\r
520         }\r
521 \r
522         /* Read the configuration register until it doesn't return 0xFFFFFFFF */\r
523         {\r
524                 ULONG                                   data, i, reset_failed = 1;\r
525                 BUS_INTERFACE_STANDARD *p_ifc = (is_tavor) ? &brBusIfc : &hcaBusIfc;\r
526                 HCA_PRINT( TRACE_LEVEL_INFORMATION      ,HCA_DBG_PNP  ,("Read the configuration register \n"));\r
527                 for( i = 0; i < 100; i++ ) {\r
528                         if (4 != p_ifc->GetBusData( p_ifc->Context,\r
529                                 PCI_WHICHSPACE_CONFIG, &data, 0, 4)) {\r
530                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
531                                         ("Failed to read device configuration data. Card reset failed !\n"));\r
532                                 status = STATUS_UNSUCCESSFUL;\r
533                                 break;\r
534                         }\r
535                         /* See if we got valid data. */\r
536                         if( data != 0xFFFFFFFF ) {\r
537                                 reset_failed = 0;\r
538                                 break;\r
539                         }\r
540                 \r
541                         cl_thread_suspend( 100 );\r
542                 }       \r
543 \r
544                 if (reset_failed) {\r
545                         /* on Tavor reset failure, if configured so, we disable the reset for next time */\r
546                         if (is_tavor && g_disable_tavor_reset)\r
547                                 set_skip_tavor_reset();\r
548 \r
549                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
550                                 ("Doh! PCI device did not come back after reset!\n"));\r
551                         status = STATUS_UNSUCCESSFUL;\r
552                         goto resetErr3;\r
553                 }\r
554         }\r
555 \r
556         /* restore the HCA's PCI configuration headers */\r
557         {\r
558                 if (is_tavor) {\r
559                         /* Restore the HCA's bridge configuration. */\r
560                         HCA_PRINT( TRACE_LEVEL_INFORMATION  ,HCA_DBG_PNP  ,("Restoring bridge PCI configuration \n"));\r
561                         status = __restore_pci_config( &brBusIfc, &brConfig, TRUE );\r
562                         if( !NT_SUCCESS( status ) ) {\r
563                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
564                                         ("Failed to restore bridge config. Card reset failed !\n"));\r
565                                 goto resetErr3;\r
566                         }\r
567                 }\r
568                 \r
569                 /* Restore the HCA's configuration. */\r
570                 HCA_PRINT( TRACE_LEVEL_INFORMATION  ,HCA_DBG_PNP  ,("Restoring HCA PCI configuration \n"));\r
571                 status = __restore_pci_config( &hcaBusIfc, &hcaConfig, FALSE );\r
572                 if( !NT_SUCCESS( status ) ) {\r
573                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
574                                 ("Failed to restore HCA config. Card reset failed !\n"));\r
575                 }\r
576         }\r
577 \r
578 resetErr3:\r
579         if (is_tavor) \r
580                 brBusIfc.InterfaceDereference( brBusIfc.Context );\r
581 \r
582 resetErr2:\r
583         hcaBusIfc.InterfaceDereference( hcaBusIfc.Context );\r
584 \r
585 resetErr1:\r
586 resetExit:\r
587         HCA_EXIT( HCA_DBG_PNP );\r
588         return status;\r
589 }\r
590 \r
591 \r
592 /*\r
593  * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM.\r
594  */\r
595 NTSTATUS\r
596 hca_tune_pci(\r
597         IN                              DEVICE_OBJECT* const            pDevObj,\r
598         OUT                             uplink_info_t *p_uplink_info )\r
599 {\r
600         NTSTATUS                                status;\r
601         PCI_COMMON_CONFIG               hcaConfig;\r
602         BUS_INTERFACE_STANDARD  hcaBusIfc;\r
603         ULONG                                   len;\r
604         ULONG                                   capOffset;\r
605         PCI_PCIX_CAPABILITY             *pPciXCap;\r
606         PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
607 \r
608         HCA_ENTER( HCA_DBG_PNP );\r
609 \r
610         /* Get the HCA's bus interface. */\r
611         status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, &hcaBusIfc );\r
612         if( !NT_SUCCESS( status ) )\r
613         {\r
614                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to get HCA bus interface.\n"));\r
615                 return status;\r
616         }\r
617 \r
618         /* Save the HCA's configuration. */\r
619         status = __save_pci_config( &hcaBusIfc, &hcaConfig );\r
620         if( !NT_SUCCESS( status ) )\r
621         {\r
622                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
623                         ("Failed to save HCA config.\n"));\r
624                 status = STATUS_UNSUCCESSFUL;\r
625                 goto tweakErr;\r
626         }\r
627         status = 0;\r
628 \r
629         /*\r
630         *               PCIX Capability\r
631         */\r
632         capOffset = __FindCapability( &hcaConfig, PCI_CAPABILITY_ID_PCIX );\r
633         if( capOffset )\r
634         {\r
635                 pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)&hcaConfig) + capOffset);\r
636 \r
637                 /* fill uplink features */\r
638                 p_uplink_info->bus_type = UPLINK_BUS_PCIX;\r
639                 if (pPciXCap->Status & (1 << 17))\r
640                         p_uplink_info->u.pci_x.capabilities = UPLINK_BUS_PCIX_133;\r
641                 \r
642                 /* Update the command field to max the read byte count if needed. */\r
643                 if ( g_tune_pci && (pPciXCap->Command & 0x000C) != 0x000C )\r
644                 {\r
645                         HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
646                                 ("Updating max recv byte count of PCI-X capability.\n"));\r
647                         pPciXCap->Command = (pPciXCap->Command & ~PCI_X_CMD_MAX_READ) | (3 << 2);\r
648                         len = hcaBusIfc.SetBusData( hcaBusIfc.Context, PCI_WHICHSPACE_CONFIG,\r
649                                 &pPciXCap->Command,\r
650                                 capOffset + offsetof( PCI_PCIX_CAPABILITY, Command),\r
651                                 sizeof( pPciXCap->Command ) );\r
652                         if( len != sizeof( pPciXCap->Command ) )\r
653                         {\r
654                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
655                                         ("Failed to update PCI-X maximum read byte count.\n"));\r
656                                 status = STATUS_UNSUCCESSFUL;\r
657                                 goto tweakErr;\r
658                         }\r
659                 }\r
660         }\r
661 \r
662 \r
663         /*\r
664         *       PCI Express Capability\r
665         */\r
666         capOffset = __FindCapability( &hcaConfig, PCI_CAPABILITY_ID_PCIEXP );\r
667         if( capOffset )\r
668         {\r
669                 pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)&hcaConfig) + capOffset);\r
670 \r
671                 /* fill uplink features */\r
672                 p_uplink_info->bus_type = UPLINK_BUS_PCIE;\r
673                 if ((pPciExpCap->LinkStatus & 15) == 1)\r
674                         p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_SDR;\r
675                 p_uplink_info->u.pci_e.link_width = (uint8_t)((pPciExpCap->LinkStatus >> 4) & 0x03f);\r
676 \r
677                 if (g_tune_pci) {\r
678                         /* Update Max_Read_Request_Size. */\r
679                         HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
680                                 ("Updating max recv byte count of PCI-Express capability.\n"));\r
681                         pPciExpCap->DevControl = (pPciExpCap->DevControl & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);\r
682                         len = hcaBusIfc.SetBusData( hcaBusIfc.Context, PCI_WHICHSPACE_CONFIG,\r
683                                 &pPciExpCap->DevControl,\r
684                                 capOffset + offsetof( PCI_PCIEXP_CAPABILITY, DevControl),\r
685                                 sizeof( pPciExpCap->DevControl ) );\r
686                         if( len != sizeof( pPciExpCap->DevControl ) )\r
687                         {\r
688                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
689                                         ("Failed to update PCI-Exp maximum read byte count.\n"));\r
690                                 goto tweakErr;\r
691                         }\r
692                 }\r
693         }\r
694 \r
695 \r
696 tweakErr:\r
697         hcaBusIfc.InterfaceDereference( hcaBusIfc.Context );\r
698 \r
699         HCA_EXIT( HCA_DBG_PNP );\r
700         return status;\r
701 }\r
702 \r
703 \r
704 /* leo */\r
705 \r
706 NTSTATUS\r
707 hca_enable_pci(\r
708         IN              DEVICE_OBJECT* const            pDevObj,\r
709         OUT             PBUS_INTERFACE_STANDARD phcaBusIfc,\r
710         OUT             PCI_COMMON_CONFIG*      pHcaConfig\r
711         )\r
712 {\r
713                 NTSTATUS                                status;\r
714                 ULONG                           len;\r
715         \r
716                 HCA_ENTER( HCA_DBG_PNP );\r
717         \r
718                 /* Get the HCA's bus interface. */\r
719                 status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, phcaBusIfc );\r
720                 if( !NT_SUCCESS( status ) )\r
721                 {\r
722                         HCA_PRINT( TRACE_LEVEL_ERROR  , HCA_DBG_PNP  ,("Failed to get HCA bus interface.\n"));\r
723                         return STATUS_DEVICE_NOT_READY;\r
724                 }\r
725         \r
726                 /* Save the HCA's configuration. */\r
727                 status = __save_pci_config( phcaBusIfc, pHcaConfig );\r
728                 if( !NT_SUCCESS( status ) )\r
729                 {\r
730                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
731                                 ("Failed to save HCA config.\n"));\r
732                         goto pciErr;\r
733                 }\r
734 \r
735                 /* fix command register (set PCI Master bit) */\r
736                 // NOTE: we change here the saved value of the command register\r
737                 pHcaConfig->Command |= 7;\r
738                 len = phcaBusIfc->SetBusData( phcaBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
739                         (PVOID)&pHcaConfig->Command , 4, sizeof(ULONG) );\r
740                 if( len != sizeof(ULONG) )\r
741                 {\r
742                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to write command register.\n"));\r
743                         status = STATUS_DEVICE_NOT_READY;\r
744                         goto pciErr;\r
745                 }\r
746                 status = STATUS_SUCCESS;\r
747                 goto out;\r
748 \r
749         pciErr:\r
750                 phcaBusIfc->InterfaceDereference( phcaBusIfc->Context );\r
751                 phcaBusIfc->InterfaceDereference = NULL;\r
752         out:\r
753                 HCA_EXIT( HCA_DBG_PNP );\r
754                 return status;\r
755 }\r
756 \r
757 void hca_disable_pci(PBUS_INTERFACE_STANDARD    phcaBusIfc)\r
758 {\r
759         // no need to disable the card, so just release the PCI bus i/f\r
760         if (phcaBusIfc->InterfaceDereference) {\r
761                 phcaBusIfc->InterfaceDereference( phcaBusIfc->Context );\r
762                 phcaBusIfc->InterfaceDereference = NULL;\r
763         }\r
764 }\r
765 \r