5e12d4f79c13f372cd9b0d71c85cb88bde0a04b3
[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 \r
100 \r
101 #ifdef ALLOC_PRAGMA\r
102 #pragma alloc_text (PAGE, __get_bus_ifc)\r
103 #pragma alloc_text (PAGE, __fixup_pci_capabilities)\r
104 #pragma alloc_text (PAGE, __save_pci_config)\r
105 #pragma alloc_text (PAGE, __restore_pci_config)\r
106 #endif\r
107 \r
108 /* Forwards the request to the HCA's PDO. */\r
109 static NTSTATUS\r
110 __get_bus_ifc(\r
111         IN                              DEVICE_OBJECT* const            pDevObj,\r
112         IN              const   GUID* const                                     pGuid,\r
113                 OUT                     BUS_INTERFACE_STANDARD          *pBusIfc )\r
114 {\r
115         NTSTATUS                        status;\r
116         IRP                                     *pIrp;\r
117         IO_STATUS_BLOCK         ioStatus;\r
118         IO_STACK_LOCATION       *pIoStack;\r
119         DEVICE_OBJECT           *pDev;\r
120         KEVENT                          event;\r
121 \r
122         HCA_ENTER( HCA_DBG_PNP );\r
123 \r
124         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
125 \r
126         pDev = IoGetAttachedDeviceReference( pDevObj );\r
127 \r
128         KeInitializeEvent( &event, NotificationEvent, FALSE );\r
129 \r
130         /* Build the IRP for the HCA. */\r
131         pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev,\r
132                 NULL, 0, NULL, &event, &ioStatus );\r
133         if( !pIrp )\r
134         {\r
135                 ObDereferenceObject( pDev );\r
136                 HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, \r
137                         ("IoBuildSynchronousFsdRequest failed.\n"));\r
138                 return STATUS_INSUFFICIENT_RESOURCES;\r
139         }\r
140 \r
141         /* Copy the request query parameters. */\r
142         pIoStack = IoGetNextIrpStackLocation( pIrp );\r
143         pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;\r
144         pIoStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);\r
145         pIoStack->Parameters.QueryInterface.Version = 1;\r
146         pIoStack->Parameters.QueryInterface.InterfaceType = pGuid;\r
147         pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pBusIfc;\r
148         pIoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;\r
149 \r
150         pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
151 \r
152         /* Send the IRP. */\r
153         status = IoCallDriver( pDev, pIrp );\r
154         if( status == STATUS_PENDING )\r
155         {\r
156                 KeWaitForSingleObject( &event, Executive, KernelMode,\r
157                         FALSE, NULL );\r
158 \r
159                 status = ioStatus.Status;\r
160         }\r
161         ObDereferenceObject( pDev );\r
162 \r
163         HCA_EXIT( HCA_DBG_PNP );\r
164         return status;\r
165 }\r
166 \r
167 \r
168 /*\r
169  * Reads and saves the PCI configuration of the device accessible\r
170  * through the provided bus interface.  Does not read registers 22 or 23\r
171  * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset.\r
172  */\r
173 static NTSTATUS\r
174 __save_pci_config(\r
175         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
176                 OUT                     PCI_COMMON_CONFIG* const        pConfig )\r
177 {\r
178         ULONG                                   len;\r
179         UINT32                                  *pBuf;\r
180 \r
181         HCA_ENTER( HCA_DBG_PNP );\r
182         \r
183         pBuf = (UINT32*)pConfig;\r
184 \r
185         /*\r
186          * Read the lower portion of the configuration, up to but excluding\r
187          * register 22.\r
188          */\r
189         len = pBusIfc->GetBusData(\r
190                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 );\r
191         if( len != 88 )\r
192         {\r
193                 HCA_PRINT( TRACE_LEVEL_ERROR  , HCA_DBG_PNP  ,("Failed to read HCA config.\n"));\r
194                 return STATUS_DEVICE_NOT_READY;\r
195         }\r
196 \r
197         /* Read the upper portion of the configuration, from register 24. */\r
198         len = pBusIfc->GetBusData(\r
199                 pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 );\r
200         if( len != 160 )\r
201         {\r
202                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to read HCA config.\n"));\r
203                 return STATUS_DEVICE_NOT_READY;\r
204         }\r
205 \r
206         HCA_EXIT( HCA_DBG_PNP );\r
207         return STATUS_SUCCESS;\r
208 }\r
209 \r
210 \r
211 static void\r
212 __fixup_pci_capabilities(\r
213         IN                              PCI_COMMON_CONFIG* const        pConfig )\r
214 {\r
215         UCHAR                                           *pBuf;\r
216         PCI_CAPABILITIES_HEADER         *pHdr, *pNextHdr;\r
217 \r
218         HCA_ENTER( HCA_DBG_PNP );\r
219 \r
220         pBuf = (UCHAR*)pConfig;\r
221 \r
222         if( pConfig->HeaderType == PCI_DEVICE_TYPE )\r
223         {\r
224                 if( pConfig->u.type0.CapabilitiesPtr )\r
225                 {\r
226                         pNextHdr = (PCI_CAPABILITIES_HEADER*)\r
227                                 (pBuf + pConfig->u.type0.CapabilitiesPtr);\r
228                 }\r
229                 else\r
230                 {\r
231                         pNextHdr = NULL;\r
232                 }\r
233         }\r
234         else\r
235         {\r
236                 ASSERT( pConfig->HeaderType == PCI_BRIDGE_TYPE );\r
237                 if( pConfig->u.type1.CapabilitiesPtr )\r
238                 {\r
239                         pNextHdr = (PCI_CAPABILITIES_HEADER*)\r
240                                 (pBuf + pConfig->u.type1.CapabilitiesPtr);\r
241                 }\r
242                 else\r
243                 {\r
244                         pNextHdr = NULL;\r
245                 }\r
246         }\r
247 \r
248         /*\r
249          * Fix up any fields that might cause changes to the\r
250          * device - like writing VPD data.\r
251          */\r
252         while( pNextHdr )\r
253         {\r
254                 pHdr = pNextHdr;\r
255                 if( pNextHdr->Next )\r
256                         pNextHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next);\r
257                 else\r
258                         pNextHdr = NULL;\r
259 \r
260                 switch( pHdr->CapabilityID )\r
261                 {\r
262                 case PCI_CAPABILITY_ID_VPD:\r
263                         /* Clear the flags field so we don't cause a write. */\r
264                         ((PCI_VPD_CAPABILITY*)pHdr)->Flags = 0;\r
265                         break;\r
266 \r
267                 default:\r
268                         break;\r
269                 }\r
270         }\r
271 \r
272         HCA_EXIT( HCA_DBG_PNP );\r
273 }\r
274 \r
275 \r
276 /*\r
277  * Restore saved PCI configuration, skipping registers 22 and 23, as well\r
278  * as any registers where writing will have side effects such as the flags\r
279  * field of the VPD and vendor specific capabilities.  The function also delays\r
280  * writing the command register, bridge control register (if applicable), and\r
281  * PCIX command register (if present).\r
282  */\r
283 static NTSTATUS\r
284 __restore_pci_config(\r
285         IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
286         IN                              PCI_COMMON_CONFIG* const        pConfig )\r
287 {\r
288         NTSTATUS status = STATUS_SUCCESS;\r
289         int             i, *pci_hdr = (int*)pConfig;\r
290 \r
291         HCA_ENTER( HCA_DBG_PNP );\r
292 \r
293         for (i = 0; i < 16; ++i) {\r
294                 if (i == 1)\r
295                         continue;\r
296         \r
297                 if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
298                         PCI_WHICHSPACE_CONFIG, &pci_hdr[i], i * 4, 4 )) {\r
299                         HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,\r
300                                 ("Couldn't restore PCI cfg reg %x,   aborting.\n", i));\r
301                         status =  STATUS_DEVICE_NOT_READY;\r
302                         goto out;\r
303                 }\r
304         }\r
305 \r
306         /* Write the command register. */\r
307         if (4 != pBusIfc->SetBusData( pBusIfc->Context,\r
308                 PCI_WHICHSPACE_CONFIG, &pci_hdr[1], 4, 4 )) {\r
309                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Couldn't restore COMMAND.\n"));\r
310                 status =  STATUS_DEVICE_NOT_READY;\r
311         }\r
312 \r
313 out:    \r
314         HCA_EXIT( HCA_DBG_PNP );\r
315         return status;\r
316 }\r
317 \r
318 NTSTATUS\r
319 hca_reset( DEVICE_OBJECT* const         pDevObj, int is_tavor )\r
320 {\r
321         NTSTATUS                                status = STATUS_SUCCESS;\r
322         PCI_COMMON_CONFIG               hcaConfig, brConfig;\r
323         BUS_INTERFACE_STANDARD  hcaBusIfc;\r
324         BUS_INTERFACE_STANDARD  brBusIfc = {0}; // to bypass C4701\r
325         hca_dev_ext_t                   *pExt = (hca_dev_ext_t*)pDevObj->DeviceExtension;\r
326 \r
327         HCA_ENTER( HCA_DBG_PNP );\r
328 \r
329         /* get the resources */\r
330         {\r
331                 /* Get the HCA's bus interface. */\r
332                 status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, &hcaBusIfc );\r
333                 if( !NT_SUCCESS( status ) ) {\r
334                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("Failed to get HCA bus interface.\n"));\r
335                         goto resetErr1;\r
336                 }\r
337 \r
338                 /* Get the HCA Bridge's bus interface, if any */\r
339                 if (is_tavor) {\r
340                         if (!FindBridgeIf( pExt, &brBusIfc ))\r
341                                 goto resetErr2;\r
342                 }\r
343         }\r
344 \r
345         /* Save the HCA's PCI configuration headers */\r
346         {\r
347                 status = __save_pci_config( &hcaBusIfc, &hcaConfig );\r
348                 if( !NT_SUCCESS( status ) ) {\r
349                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
350                                 ("Failed to save HCA config.\n"));\r
351                         goto resetErr3;\r
352                 }\r
353 \r
354                 /* Save the HCA bridge's configuration, if any */\r
355                 if (is_tavor) {\r
356                         status = __save_pci_config( &brBusIfc, &brConfig );\r
357                         if( !NT_SUCCESS( status ) ) {\r
358                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
359                                         ("Failed to save bridge config.\n"));\r
360                                 goto resetErr3;\r
361                         }\r
362                 }\r
363         }\r
364         \r
365         /* reset the card */\r
366         {\r
367                 PULONG  reset_p;\r
368                 PHYSICAL_ADDRESS  pa;\r
369                 /* map reset register */\r
370                 pa.QuadPart = pExt->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)HCA_RESET_HCR_OFFSET;\r
371                 HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP  ,("Mapping reset register with address 0x%I64x\n", pa.QuadPart));\r
372                 reset_p = MmMapIoSpace( pa,     4, MmNonCached );\r
373                 if( !reset_p ) {\r
374                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart));\r
375                         status = STATUS_UNSUCCESSFUL;\r
376                         goto resetErr3;\r
377                 }\r
378                 \r
379                 /* Issue the reset. */\r
380                 HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP  ,("Resetting  the chip ...\n"));\r
381                 WRITE_REGISTER_ULONG( reset_p, HCA_RESET_TOKEN );\r
382 \r
383                 /* unmap the reset register */\r
384                 HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP  ,("Unmapping reset register \n"));\r
385                 MmUnmapIoSpace( reset_p, 4 );\r
386 \r
387                 /* Wait a second. */\r
388                 cl_thread_suspend( 1000 );\r
389         }\r
390 \r
391         /* Read the configuration register until it doesn't return 0xFFFFFFFF */\r
392         {\r
393                 ULONG                                   data, i;\r
394                 BUS_INTERFACE_STANDARD *p_ifc = (is_tavor) ? &brBusIfc : &hcaBusIfc;\r
395                 HCA_PRINT( TRACE_LEVEL_INFORMATION      ,HCA_DBG_PNP  ,("Read the configuration register \n"));\r
396                 for( i = 0; i < 100; i++ ) {\r
397                         if (4 != p_ifc->GetBusData( p_ifc->Context,\r
398                                 PCI_WHICHSPACE_CONFIG, &data, 0, 4)) {\r
399                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
400                                         ("Failed to read device configuration data.\n"));\r
401                                 status = STATUS_UNSUCCESSFUL;\r
402                                 goto resetErr3;\r
403                         }\r
404                         /* See if we got valid data. */\r
405                         if( data != 0xFFFFFFFF )\r
406                                 goto good;\r
407                 \r
408                         cl_thread_suspend( 100 );\r
409                 }       \r
410 \r
411                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
412                         ("Doh! PCI device did not come back after reset!\n"));\r
413                 status = STATUS_UNSUCCESSFUL;\r
414                 goto resetErr3;\r
415         }\r
416 \r
417 good:   /* restore the HCA's PCI configuration headers */\r
418         {\r
419                 if (is_tavor) {\r
420                         /* Restore the HCA's bridge configuration. */\r
421                         HCA_PRINT( TRACE_LEVEL_INFORMATION  ,HCA_DBG_PNP  ,("Restoring bridge PCI configuration \n"));\r
422                         status = __restore_pci_config( &brBusIfc, &brConfig );\r
423                         if( !NT_SUCCESS( status ) ) {\r
424                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
425                                         ("Failed to restore bridge config.\n"));\r
426                                 goto resetErr3;\r
427                         }\r
428                 }\r
429                 \r
430                 /* Restore the HCA's configuration. */\r
431                 HCA_PRINT( TRACE_LEVEL_INFORMATION  ,HCA_DBG_PNP  ,("Restoring HCA PCI configuration \n"));\r
432                 status = __restore_pci_config( &hcaBusIfc, &hcaConfig );\r
433                 if( !NT_SUCCESS( status ) ) {\r
434                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
435                                 ("Failed to restore HCA config.\n"));\r
436                 }\r
437         }\r
438 \r
439 resetErr3:\r
440         if (is_tavor) \r
441                 brBusIfc.InterfaceDereference( brBusIfc.Context );\r
442 \r
443 resetErr2:\r
444         hcaBusIfc.InterfaceDereference( hcaBusIfc.Context );\r
445 \r
446 resetErr1:\r
447         HCA_EXIT( HCA_DBG_PNP );\r
448         return status;\r
449 }\r
450 \r
451 \r
452 /*\r
453  * Returns the offset in configuration space of the PCI-X capabilites.\r
454  */\r
455 static ULONG\r
456 __FindCapability(\r
457         IN                              PCI_COMMON_CONFIG* const        pConfig,  \r
458         IN                              char cap_id\r
459         )\r
460 {\r
461         ULONG                                           offset = 0;\r
462         UCHAR                                           *pBuf;\r
463         PCI_CAPABILITIES_HEADER         *pHdr;\r
464 \r
465         HCA_ENTER( HCA_DBG_PNP );\r
466 \r
467         pBuf = (UCHAR*)pConfig;\r
468 \r
469         ASSERT( pConfig->HeaderType == PCI_DEVICE_TYPE );\r
470 \r
471         if( pConfig->u.type0.CapabilitiesPtr )\r
472         {\r
473                 pHdr = (PCI_CAPABILITIES_HEADER*)\r
474                         (pBuf + pConfig->u.type0.CapabilitiesPtr);\r
475         }\r
476         else\r
477         {\r
478                 pHdr = NULL;\r
479         }\r
480 \r
481         /*\r
482          * Fix up any fields that might cause changes to the\r
483          * device - like writing VPD data.\r
484          */\r
485         while( pHdr )\r
486         {\r
487                 if( pHdr->CapabilityID == cap_id )\r
488                 {\r
489                         offset = (UCHAR)(((ULONG_PTR)pHdr) - ((ULONG_PTR)pConfig));\r
490                         break;\r
491                 }\r
492 \r
493                 if( pHdr->Next )\r
494                         pHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next);\r
495                 else\r
496                         pHdr = NULL;\r
497         }\r
498 \r
499         HCA_EXIT( HCA_DBG_PNP );\r
500         return offset;\r
501 }\r
502 \r
503 \r
504 /*\r
505  * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM.\r
506  */\r
507 NTSTATUS\r
508 hca_tune_pci(\r
509         IN                              DEVICE_OBJECT* const            pDevObj )\r
510 {\r
511         NTSTATUS                                status;\r
512         PCI_COMMON_CONFIG               hcaConfig;\r
513         BUS_INTERFACE_STANDARD  hcaBusIfc;\r
514         ULONG                                   len;\r
515         ULONG                                   capOffset;\r
516         PCI_PCIX_CAPABILITY             *pPciXCap;\r
517         PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
518 \r
519         HCA_ENTER( HCA_DBG_PNP );\r
520 \r
521         /* Get the HCA's bus interface. */\r
522         status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, &hcaBusIfc );\r
523         if( !NT_SUCCESS( status ) )\r
524         {\r
525                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to get HCA bus interface.\n"));\r
526                 return status;\r
527         }\r
528 \r
529         /* Save the HCA's configuration. */\r
530         status = __save_pci_config( &hcaBusIfc, &hcaConfig );\r
531         if( !NT_SUCCESS( status ) )\r
532         {\r
533                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
534                         ("Failed to save HCA config.\n"));\r
535                 status = STATUS_UNSUCCESSFUL;\r
536                 goto tweakErr;\r
537         }\r
538         status = 0;\r
539 \r
540         /*\r
541         *               PCIX Capability\r
542         */\r
543         capOffset = __FindCapability( &hcaConfig, PCI_CAPABILITY_ID_PCIX );\r
544         if( capOffset )\r
545         {\r
546                 pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)&hcaConfig) + capOffset);\r
547                 /* Update the command field to max the read byte count if needed. */\r
548                 if( (pPciXCap->Command & 0x000C) != 0x000C )\r
549                 {\r
550                         HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP,\r
551                                 ("Updating max recv byte count of PCI-X capability.\n"));\r
552                         pPciXCap->Command = (pPciXCap->Command & ~PCI_X_CMD_MAX_READ) | (3 << 2);\r
553                         len = hcaBusIfc.SetBusData( hcaBusIfc.Context, PCI_WHICHSPACE_CONFIG,\r
554                                 &pPciXCap->Command,\r
555                                 capOffset + offsetof( PCI_PCIX_CAPABILITY, Command),\r
556                                 sizeof( pPciXCap->Command ) );\r
557                         if( len != sizeof( pPciXCap->Command ) )\r
558                         {\r
559                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
560                                         ("Failed to update PCI-X maximum read byte count.\n"));\r
561                                 status = STATUS_UNSUCCESSFUL;\r
562                                 goto tweakErr;\r
563                         }\r
564                 }\r
565         }\r
566 \r
567 \r
568         /*\r
569         *       PCI Express Capability\r
570         */\r
571         capOffset = __FindCapability( &hcaConfig, PCI_CAPABILITY_ID_PCIEXP );\r
572         if( capOffset )\r
573         {\r
574                 pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)&hcaConfig) + capOffset);\r
575                 \r
576                 /* Update Max_Read_Request_Size. */\r
577                 HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP,\r
578                         ("Updating max recv byte count of PCI-Express capability.\n"));\r
579                 pPciExpCap->DevControl = (pPciExpCap->DevControl & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);\r
580                 len = hcaBusIfc.SetBusData( hcaBusIfc.Context, PCI_WHICHSPACE_CONFIG,\r
581                         &pPciExpCap->DevControl,\r
582                         capOffset + offsetof( PCI_PCIEXP_CAPABILITY, DevControl),\r
583                         sizeof( pPciExpCap->DevControl ) );\r
584                 if( len != sizeof( pPciExpCap->DevControl ) )\r
585                 {\r
586                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, \r
587                                 ("Failed to update PCI-Exp maximum read byte count.\n"));\r
588                         goto tweakErr;\r
589                 }\r
590         }\r
591 \r
592 \r
593 tweakErr:\r
594         hcaBusIfc.InterfaceDereference( hcaBusIfc.Context );\r
595 \r
596         HCA_EXIT( HCA_DBG_PNP );\r
597         return status;\r
598 }\r
599 \r
600 \r
601 /* leo */\r
602 \r
603 NTSTATUS\r
604 hca_enable_pci(\r
605         IN              DEVICE_OBJECT* const            pDevObj,\r
606         OUT             PBUS_INTERFACE_STANDARD phcaBusIfc,\r
607         OUT             PCI_COMMON_CONFIG*      pHcaConfig\r
608         )\r
609 {\r
610                 NTSTATUS                                status;\r
611                 ULONG                           len;\r
612         \r
613                 HCA_ENTER( HCA_DBG_PNP );\r
614         \r
615                 /* Get the HCA's bus interface. */\r
616                 status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, phcaBusIfc );\r
617                 if( !NT_SUCCESS( status ) )\r
618                 {\r
619                         HCA_PRINT( TRACE_LEVEL_ERROR  , HCA_DBG_PNP  ,("Failed to get HCA bus interface.\n"));\r
620                         return STATUS_DEVICE_NOT_READY;\r
621                 }\r
622         \r
623                 /* Save the HCA's configuration. */\r
624                 status = __save_pci_config( phcaBusIfc, pHcaConfig );\r
625                 if( !NT_SUCCESS( status ) )\r
626                 {\r
627                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP,\r
628                                 ("Failed to save HCA config.\n"));\r
629                         goto pciErr;\r
630                 }\r
631 \r
632                 /* fix command register (set PCI Master bit) */\r
633                 // NOTE: we change here the saved value of the command register\r
634                 pHcaConfig->Command |= 7;\r
635            len = phcaBusIfc->SetBusData( phcaBusIfc->Context, PCI_WHICHSPACE_CONFIG,\r
636         (PVOID)&pHcaConfig->Command , 4, sizeof(ULONG) ); \r
637                 if( len != sizeof(ULONG) )\r
638                 {\r
639                         HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_PNP  ,("Failed to write command register.\n"));\r
640                         status = STATUS_DEVICE_NOT_READY;\r
641                         goto pciErr;\r
642                 }\r
643                 status = STATUS_SUCCESS;\r
644                 goto out;\r
645 \r
646         pciErr:\r
647                 phcaBusIfc->InterfaceDereference( phcaBusIfc->Context );\r
648         out:\r
649                 HCA_EXIT( HCA_DBG_PNP );\r
650                 return status;\r
651 }\r
652 \r
653 void hca_disable_pci(PBUS_INTERFACE_STANDARD    phcaBusIfc)\r
654 {\r
655         // no need to disable the card, so just release the PCI bus i/f\r
656         if (phcaBusIfc) {\r
657                 phcaBusIfc->InterfaceDereference( phcaBusIfc->Context );\r
658                 phcaBusIfc = NULL;\r
659         }\r
660 }\r
661 \r