PCI Bus Driver Enhancement
[people/mcb30/edk2.git] / edk2 / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
1 /**@file\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 **/\r
13 \r
14 \r
15 #include "pcibus.h"\r
16 #include "PciEnumeratorSupport.h"\r
17 #include "PciCommand.h"\r
18 #include "PciIo.h"\r
19 \r
20 EFI_STATUS\r
21 PciDevicePresent (\r
22   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,\r
23   PCI_TYPE00                          *Pci,\r
24   UINT8                               Bus,\r
25   UINT8                               Device,\r
26   UINT8                               Func\r
27   )\r
28 /*++\r
29 \r
30 Routine Description:\r
31 \r
32   This routine is used to check whether the pci device is present\r
33 \r
34 Arguments:\r
35 \r
36 Returns:\r
37 \r
38   None\r
39 \r
40 --*/\r
41 // TODO:    PciRootBridgeIo - add argument and description to function comment\r
42 // TODO:    Pci - add argument and description to function comment\r
43 // TODO:    Bus - add argument and description to function comment\r
44 // TODO:    Device - add argument and description to function comment\r
45 // TODO:    Func - add argument and description to function comment\r
46 // TODO:    EFI_SUCCESS - add return value to function comment\r
47 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
48 {\r
49   UINT64      Address;\r
50   EFI_STATUS  Status;\r
51 \r
52   //\r
53   // Create PCI address map in terms of Bus, Device and Func\r
54   //\r
55   Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
56 \r
57   //\r
58   // Read the Vendor Id register\r
59   //\r
60   Status = PciRootBridgeIoRead (\r
61                                   PciRootBridgeIo,\r
62                                   NULL,\r
63                                   EfiPciWidthUint32,\r
64                                   Address,\r
65                                   1,\r
66                                   Pci\r
67                                   );\r
68 \r
69   if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {\r
70 \r
71     //\r
72     // Read the entire config header for the device\r
73     //\r
74 \r
75     Status = PciRootBridgeIoRead (\r
76                                     PciRootBridgeIo,\r
77                                     NULL,\r
78                                     EfiPciWidthUint32,\r
79                                     Address,\r
80                                     sizeof (PCI_TYPE00) / sizeof (UINT32),\r
81                                     Pci\r
82                                     );\r
83 \r
84     return EFI_SUCCESS;\r
85   }\r
86 \r
87   return EFI_NOT_FOUND;\r
88 }\r
89 \r
90 EFI_STATUS\r
91 PciPciDeviceInfoCollector (\r
92   IN PCI_IO_DEVICE                      *Bridge,\r
93   UINT8                                 StartBusNumber\r
94   )\r
95 /*++\r
96 \r
97 Routine Description:\r
98 \r
99 Arguments:\r
100 \r
101 Returns:\r
102 \r
103   None\r
104 \r
105 --*/\r
106 // TODO:    Bridge - add argument and description to function comment\r
107 // TODO:    StartBusNumber - add argument and description to function comment\r
108 // TODO:    EFI_SUCCESS - add return value to function comment\r
109 {\r
110   EFI_STATUS          Status;\r
111   PCI_TYPE00          Pci;\r
112   UINT8               Device;\r
113   UINT8               Func;\r
114   UINT8               SecBus;\r
115   PCI_IO_DEVICE       *PciIoDevice;\r
116   EFI_PCI_IO_PROTOCOL *PciIo;\r
117 \r
118   Status  = EFI_SUCCESS;\r
119   SecBus  = 0;\r
120 \r
121   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
122 \r
123     for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
124 \r
125       //\r
126       // Check to see whether PCI device is present\r
127       //\r
128 \r
129       Status = PciDevicePresent (\r
130                 Bridge->PciRootBridgeIo,\r
131                 &Pci,\r
132                 (UINT8) StartBusNumber,\r
133                 (UINT8) Device,\r
134                 (UINT8) Func\r
135                 );\r
136 \r
137       if (!EFI_ERROR (Status)) {\r
138 \r
139         //\r
140         // Call back to host bridge function\r
141         //\r
142         PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);\r
143 \r
144         //\r
145         // Collect all the information about the PCI device discovered\r
146         //\r
147         Status = PciSearchDevice (\r
148                   Bridge,\r
149                   &Pci,\r
150                   (UINT8) StartBusNumber,\r
151                   Device,\r
152                   Func,\r
153                   &PciIoDevice\r
154                   );\r
155 \r
156         //\r
157         // Recursively scan PCI busses on the other side of PCI-PCI bridges\r
158         //\r
159         //\r
160 \r
161         if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {\r
162 \r
163           //\r
164           // If it is PPB, we need to get the secondary bus to continue the enumeration\r
165           //\r
166           PciIo   = &(PciIoDevice->PciIo);\r
167 \r
168           Status  = PciIoRead (PciIo, EfiPciIoWidthUint8, 0x19, 1, &SecBus);\r
169 \r
170           if (EFI_ERROR (Status)) {\r
171             return Status;\r
172           }\r
173 \r
174           //\r
175           // Get resource padding for PPB\r
176           //\r
177           GetResourcePaddingPpb (PciIoDevice);\r
178 \r
179           //\r
180           // Deep enumerate the next level bus\r
181           //\r
182           Status = PciPciDeviceInfoCollector (\r
183                     PciIoDevice,\r
184                     (UINT8) (SecBus)\r
185                     );\r
186 \r
187         }\r
188 \r
189         if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
190 \r
191           //\r
192           // Skip sub functions, this is not a multi function device\r
193           //\r
194           Func = PCI_MAX_FUNC;\r
195         }\r
196       }\r
197 \r
198     }\r
199   }\r
200 \r
201   return EFI_SUCCESS;\r
202 }\r
203 \r
204 EFI_STATUS\r
205 PciSearchDevice (\r
206   IN  PCI_IO_DEVICE                         *Bridge,\r
207   IN  PCI_TYPE00                            *Pci,\r
208   IN  UINT8                                 Bus,\r
209   IN  UINT8                                 Device,\r
210   IN  UINT8                                 Func,\r
211   OUT PCI_IO_DEVICE                         **PciDevice\r
212   )\r
213 /*++\r
214 \r
215 Routine Description:\r
216 \r
217   Search required device.\r
218 \r
219 Arguments:\r
220 \r
221   Bridge     - A pointer to the PCI_IO_DEVICE.\r
222   Pci        - A pointer to the PCI_TYPE00.\r
223   Bus        - Bus number.\r
224   Device     - Device number.\r
225   Func       - Function number.\r
226   PciDevice  - The Required pci device.\r
227 \r
228 Returns:\r
229 \r
230   Status code.\r
231 \r
232 --*/\r
233 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
234 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
235 // TODO:    EFI_SUCCESS - add return value to function comment\r
236 {\r
237   PCI_IO_DEVICE *PciIoDevice;\r
238 \r
239   PciIoDevice = NULL;\r
240 \r
241   if (!IS_PCI_BRIDGE (Pci)) {\r
242 \r
243     if (IS_CARDBUS_BRIDGE (Pci)) {\r
244       PciIoDevice = GatherP2CInfo (\r
245                       Bridge,\r
246                       Pci,\r
247                       Bus,\r
248                       Device,\r
249                       Func\r
250                       );\r
251       if ((PciIoDevice != NULL) && gFullEnumeration) {\r
252         InitializeP2C (PciIoDevice);\r
253       }\r
254     } else {\r
255 \r
256       //\r
257       // Create private data for Pci Device\r
258       //\r
259       PciIoDevice = GatherDeviceInfo (\r
260                       Bridge,\r
261                       Pci,\r
262                       Bus,\r
263                       Device,\r
264                       Func\r
265                       );\r
266 \r
267     }\r
268 \r
269   } else {\r
270 \r
271     //\r
272     // Create private data for PPB\r
273     //\r
274     PciIoDevice = GatherPpbInfo (\r
275                     Bridge,\r
276                     Pci,\r
277                     Bus,\r
278                     Device,\r
279                     Func\r
280                     );\r
281 \r
282     //\r
283     // Special initialization for PPB including making the PPB quiet\r
284     //\r
285     if ((PciIoDevice != NULL) && gFullEnumeration) {\r
286       InitializePpb (PciIoDevice);\r
287     }\r
288   }\r
289 \r
290   if (!PciIoDevice) {\r
291     return EFI_OUT_OF_RESOURCES;\r
292   }\r
293 \r
294   //\r
295   // Update the bar information for this PCI device so as to support some specific device\r
296   //\r
297   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACPI_RESOURCE_SUPPORT) {\r
298     UpdatePciInfo (PciIoDevice);\r
299   }\r
300 \r
301   if (PciIoDevice->DevicePath == NULL) {\r
302     return EFI_OUT_OF_RESOURCES;\r
303   }\r
304 \r
305   //\r
306   // Detect this function has option rom\r
307   //\r
308   if (gFullEnumeration) {\r
309 \r
310     if (!IS_CARDBUS_BRIDGE (Pci)) {\r
311 \r
312       GetOpRomInfo (PciIoDevice);\r
313 \r
314     }\r
315 \r
316     ResetPowerManagementFeature (PciIoDevice);\r
317 \r
318   }\r
319 \r
320   //\r
321   // Insert it into a global tree for future reference\r
322   //\r
323   InsertPciDevice (Bridge, PciIoDevice);\r
324 \r
325   //\r
326   // Determine PCI device attributes\r
327   //\r
328 \r
329   if (PciDevice != NULL) {\r
330     *PciDevice = PciIoDevice;\r
331   }\r
332 \r
333   return EFI_SUCCESS;\r
334 }\r
335 \r
336 PCI_IO_DEVICE *\r
337 GatherDeviceInfo (\r
338   IN PCI_IO_DEVICE                    *Bridge,\r
339   IN PCI_TYPE00                       *Pci,\r
340   UINT8                               Bus,\r
341   UINT8                               Device,\r
342   UINT8                               Func\r
343   )\r
344 /*++\r
345 \r
346 Routine Description:\r
347 \r
348 Arguments:\r
349 \r
350 Returns:\r
351 \r
352   None\r
353 \r
354 --*/\r
355 // TODO:    Bridge - add argument and description to function comment\r
356 // TODO:    Pci - add argument and description to function comment\r
357 // TODO:    Bus - add argument and description to function comment\r
358 // TODO:    Device - add argument and description to function comment\r
359 // TODO:    Func - add argument and description to function comment\r
360 {\r
361   UINTN                           Offset;\r
362   UINTN                           BarIndex;\r
363   PCI_IO_DEVICE                   *PciIoDevice;\r
364   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
365 \r
366   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
367   PciIoDevice = CreatePciIoDevice (\r
368                   PciRootBridgeIo,\r
369                   Pci,\r
370                   Bus,\r
371                   Device,\r
372                   Func\r
373                   );\r
374 \r
375   if (!PciIoDevice) {\r
376     return NULL;\r
377   }\r
378 \r
379   //\r
380   // Create a device path for this PCI device and store it into its private data\r
381   //\r
382   CreatePciDevicePath (\r
383     Bridge->DevicePath,\r
384     PciIoDevice\r
385     );\r
386 \r
387   //\r
388   // If it is a full enumeration, disconnect the device in advance\r
389   //\r
390   if (gFullEnumeration) {\r
391 \r
392     PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
393 \r
394   }\r
395 \r
396   //\r
397   // Start to parse the bars\r
398   //\r
399   for (Offset = 0x10, BarIndex = 0; Offset <= 0x24; BarIndex++) {\r
400     Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
401   }\r
402 \r
403   return PciIoDevice;\r
404 }\r
405 \r
406 PCI_IO_DEVICE *\r
407 GatherPpbInfo (\r
408   IN PCI_IO_DEVICE                    *Bridge,\r
409   IN PCI_TYPE00                       *Pci,\r
410   UINT8                               Bus,\r
411   UINT8                               Device,\r
412   UINT8                               Func\r
413   )\r
414 /*++\r
415 \r
416 Routine Description:\r
417 \r
418 Arguments:\r
419 \r
420 Returns:\r
421 \r
422   None\r
423 \r
424 --*/\r
425 // TODO:    Bridge - add argument and description to function comment\r
426 // TODO:    Pci - add argument and description to function comment\r
427 // TODO:    Bus - add argument and description to function comment\r
428 // TODO:    Device - add argument and description to function comment\r
429 // TODO:    Func - add argument and description to function comment\r
430 {\r
431   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
432   PCI_IO_DEVICE                   *PciIoDevice;\r
433   EFI_STATUS                      Status;\r
434   UINT32                          Value;\r
435   EFI_PCI_IO_PROTOCOL             *PciIo;\r
436   UINT8                           Temp;\r
437 \r
438   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
439   PciIoDevice = CreatePciIoDevice (\r
440                   PciRootBridgeIo,\r
441                   Pci,\r
442                   Bus,\r
443                   Device,\r
444                   Func\r
445                   );\r
446 \r
447   if (!PciIoDevice) {\r
448     return NULL;\r
449   }\r
450 \r
451   //\r
452   // Create a device path for this PCI device and store it into its private data\r
453   //\r
454   CreatePciDevicePath (\r
455     Bridge->DevicePath,\r
456     PciIoDevice\r
457     );\r
458 \r
459   if (gFullEnumeration) {\r
460     PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
461 \r
462     //\r
463     // Initalize the bridge control register\r
464     //\r
465     PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
466 \r
467   }\r
468 \r
469   //\r
470   // PPB can have two BARs\r
471   //\r
472   if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {\r
473     //\r
474     // Not 64-bit bar\r
475     //\r
476     PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);\r
477   }\r
478 \r
479   PciIo = &PciIoDevice->PciIo;\r
480 \r
481   //\r
482   // Test whether it support 32 decode or not\r
483   //\r
484   PciIoRead (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
485   PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
486   PciIoRead (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
487   PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
488 \r
489   if (Value) {\r
490     if (Value & 0x01) {\r
491       PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
492     } else {\r
493       PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
494     }\r
495   }\r
496 \r
497   Status = BarExisted (\r
498             PciIoDevice,\r
499             0x24,\r
500             NULL,\r
501             NULL\r
502             );\r
503 \r
504   //\r
505   // test if it supports 64 memory or not\r
506   //\r
507   if (!EFI_ERROR (Status)) {\r
508 \r
509     Status = BarExisted (\r
510               PciIoDevice,\r
511               0x28,\r
512               NULL,\r
513               NULL\r
514               );\r
515 \r
516     if (!EFI_ERROR (Status)) {\r
517       PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
518       PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
519     } else {\r
520       PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
521     }\r
522   }\r
523 \r
524   //\r
525   // Memory 32 code is required for ppb\r
526   //\r
527   PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
528 \r
529   GetResourcePaddingPpb (PciIoDevice);\r
530 \r
531   return PciIoDevice;\r
532 }\r
533 \r
534 PCI_IO_DEVICE *\r
535 GatherP2CInfo (\r
536   IN PCI_IO_DEVICE                    *Bridge,\r
537   IN PCI_TYPE00                       *Pci,\r
538   UINT8                               Bus,\r
539   UINT8                               Device,\r
540   UINT8                               Func\r
541   )\r
542 /*++\r
543 \r
544 Routine Description:\r
545 \r
546 Arguments:\r
547 \r
548 Returns:\r
549 \r
550   None\r
551 \r
552 --*/\r
553 // TODO:    Bridge - add argument and description to function comment\r
554 // TODO:    Pci - add argument and description to function comment\r
555 // TODO:    Bus - add argument and description to function comment\r
556 // TODO:    Device - add argument and description to function comment\r
557 // TODO:    Func - add argument and description to function comment\r
558 {\r
559   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
560   PCI_IO_DEVICE                   *PciIoDevice;\r
561 \r
562   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
563   PciIoDevice = CreatePciIoDevice (\r
564                   PciRootBridgeIo,\r
565                   Pci,\r
566                   Bus,\r
567                   Device,\r
568                   Func\r
569                   );\r
570 \r
571   if (!PciIoDevice) {\r
572     return NULL;\r
573   }\r
574 \r
575   //\r
576   // Create a device path for this PCI device and store it into its private data\r
577   //\r
578   CreatePciDevicePath (\r
579     Bridge->DevicePath,\r
580     PciIoDevice\r
581     );\r
582 \r
583   if (gFullEnumeration) {\r
584     PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
585 \r
586     //\r
587     // Initalize the bridge control register\r
588     //\r
589     PciDisableBridgeControlRegister (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
590 \r
591   }\r
592   //\r
593   // P2C only has one bar that is in 0x10\r
594   //\r
595   PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);\r
596 \r
597   //\r
598   // Read PciBar information from the bar register\r
599   //\r
600   GetBackPcCardBar (PciIoDevice);\r
601   PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED  |\r
602                          EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |\r
603                          EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
604 \r
605   return PciIoDevice;\r
606 }\r
607 \r
608 EFI_DEVICE_PATH_PROTOCOL *\r
609 CreatePciDevicePath (\r
610   IN  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
611   IN  PCI_IO_DEVICE            *PciIoDevice\r
612   )\r
613 /*++\r
614 \r
615 Routine Description:\r
616 \r
617 Arguments:\r
618 \r
619 Returns:\r
620 \r
621   None\r
622 \r
623 --*/\r
624 // TODO:    ParentDevicePath - add argument and description to function comment\r
625 // TODO:    PciIoDevice - add argument and description to function comment\r
626 {\r
627 \r
628   PCI_DEVICE_PATH PciNode;\r
629 \r
630   //\r
631   // Create PCI device path\r
632   //\r
633   PciNode.Header.Type     = HARDWARE_DEVICE_PATH;\r
634   PciNode.Header.SubType  = HW_PCI_DP;\r
635   SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
636 \r
637   PciNode.Device          = PciIoDevice->DeviceNumber;\r
638   PciNode.Function        = PciIoDevice->FunctionNumber;\r
639   PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);\r
640 \r
641   return PciIoDevice->DevicePath;\r
642 }\r
643 \r
644 EFI_STATUS\r
645 BarExisted (\r
646   IN PCI_IO_DEVICE *PciIoDevice,\r
647   IN UINTN         Offset,\r
648   OUT UINT32       *BarLengthValue,\r
649   OUT UINT32       *OriginalBarValue\r
650   )\r
651 /*++\r
652 \r
653 Routine Description:\r
654 \r
655   Check the bar is existed or not.\r
656 \r
657 Arguments:\r
658 \r
659   PciIoDevice       - A pointer to the PCI_IO_DEVICE.\r
660   Offset            - The offset.\r
661   BarLengthValue    - The bar length value.\r
662   OriginalBarValue  - The original bar value.\r
663 \r
664 Returns:\r
665 \r
666   EFI_NOT_FOUND     - The bar don't exist.\r
667   EFI_SUCCESS       - The bar exist.\r
668 \r
669 --*/\r
670 {\r
671   EFI_PCI_IO_PROTOCOL *PciIo;\r
672   UINT32              OriginalValue;\r
673   UINT32              Value;\r
674   EFI_TPL             OldTpl;\r
675 \r
676   PciIo = &PciIoDevice->PciIo;\r
677 \r
678   //\r
679   // Preserve the original value\r
680   //\r
681 \r
682   PciIoRead (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
683 \r
684   //\r
685   // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
686   //\r
687   OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
688 \r
689   PciIoWrite (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);\r
690   PciIoRead (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);\r
691 \r
692   //\r
693   // Write back the original value\r
694   //\r
695   PciIoWrite (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
696 \r
697   //\r
698   // Restore TPL to its original level\r
699   //\r
700   gBS->RestoreTPL (OldTpl);\r
701 \r
702   if (BarLengthValue != NULL) {\r
703     *BarLengthValue = Value;\r
704   }\r
705 \r
706   if (OriginalBarValue != NULL) {\r
707     *OriginalBarValue = OriginalValue;\r
708   }\r
709 \r
710   if (Value == 0) {\r
711     return EFI_NOT_FOUND;\r
712   } else {\r
713     return EFI_SUCCESS;\r
714   }\r
715 }\r
716 \r
717 EFI_STATUS\r
718 PciTestSupportedAttribute (\r
719   IN PCI_IO_DEVICE                      *PciIoDevice,\r
720   IN UINT16                             *Command,\r
721   IN UINT16                             *BridgeControl,\r
722   IN UINT16                             *OldCommand,\r
723   IN UINT16                             *OldBridgeControl\r
724   )\r
725 /*++\r
726 \r
727 Routine Description:\r
728 \r
729 Arguments:\r
730 \r
731 Returns:\r
732 \r
733   None\r
734 \r
735 --*/\r
736 // TODO:    PciIoDevice - add argument and description to function comment\r
737 // TODO:    Command - add argument and description to function comment\r
738 // TODO:    BridgeControl - add argument and description to function comment\r
739 // TODO:    OldCommand - add argument and description to function comment\r
740 // TODO:    OldBridgeControl - add argument and description to function comment\r
741 // TODO:    EFI_SUCCESS - add return value to function comment\r
742 {\r
743   EFI_TPL OldTpl;\r
744 \r
745   //\r
746   // Preserve the original value\r
747   //\r
748   PciReadCommandRegister (PciIoDevice, OldCommand);\r
749 \r
750   //\r
751   // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
752   //\r
753   OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
754 \r
755   PciSetCommandRegister (PciIoDevice, *Command);\r
756   PciReadCommandRegister (PciIoDevice, Command);\r
757 \r
758   //\r
759   // Write back the original value\r
760   //\r
761   PciSetCommandRegister (PciIoDevice, *OldCommand);\r
762 \r
763   //\r
764   // Restore TPL to its original level\r
765   //\r
766   gBS->RestoreTPL (OldTpl);\r
767 \r
768   if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
769 \r
770     //\r
771     // Preserve the original value\r
772     //\r
773     PciReadBridgeControlRegister (PciIoDevice, OldBridgeControl);\r
774 \r
775     //\r
776     // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
777     //\r
778     OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
779 \r
780     PciSetBridgeControlRegister (PciIoDevice, *BridgeControl);\r
781     PciReadBridgeControlRegister (PciIoDevice, BridgeControl);\r
782 \r
783     //\r
784     // Write back the original value\r
785     //\r
786     PciSetBridgeControlRegister (PciIoDevice, *OldBridgeControl);\r
787 \r
788     //\r
789     // Restore TPL to its original level\r
790     //\r
791     gBS->RestoreTPL (OldTpl);\r
792 \r
793   } else {\r
794     *OldBridgeControl = 0;\r
795     *BridgeControl    = 0;\r
796   }\r
797 \r
798   return EFI_SUCCESS;\r
799 }\r
800 \r
801 EFI_STATUS\r
802 PciSetDeviceAttribute (\r
803   IN PCI_IO_DEVICE                      *PciIoDevice,\r
804   IN UINT16                             Command,\r
805   IN UINT16                             BridgeControl,\r
806   IN UINTN                              Option\r
807   )\r
808 /*++\r
809 \r
810   Routine Description:\r
811     Set the supported or current attributes of a PCI device\r
812 \r
813   Arguments:\r
814     PciIoDevice   - Structure pointer for PCI device.\r
815     Command       - Command register value.\r
816     BridgeControl - Bridge control value for PPB or P2C.\r
817     Option        - Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
818 \r
819   Returns:\r
820 \r
821 --*/\r
822 \r
823 /*++\r
824 \r
825 Routine Description:\r
826 \r
827 \r
828 \r
829 Arguments:\r
830 \r
831 \r
832 Returns:\r
833 \r
834   EFI_SUCCESS   Always success\r
835 \r
836 \r
837 --*/\r
838 {\r
839   UINT64  Attributes;\r
840 \r
841   Attributes = 0;\r
842 \r
843   if (Command & EFI_PCI_COMMAND_IO_SPACE) {\r
844     Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
845   }\r
846 \r
847   if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {\r
848     Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
849   }\r
850 \r
851   if (Command & EFI_PCI_COMMAND_BUS_MASTER) {\r
852     Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
853   }\r
854 \r
855   if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {\r
856     Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
857   }\r
858 \r
859   if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) {\r
860     Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
861   }\r
862 \r
863   if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) {\r
864     Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
865     Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
866     Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
867   }\r
868 \r
869   if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) {\r
870     Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
871     Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
872   }\r
873 \r
874   if (Option == EFI_SET_SUPPORTS) {\r
875 \r
876     Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
877                   EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED        |\r
878                   EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE       |\r
879                   EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE      |\r
880                   EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM         |\r
881                   EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
882 \r
883     if (Attributes & EFI_PCI_IO_ATTRIBUTE_IO) {\r
884       Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
885       Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
886     }\r
887 \r
888     if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
889       //\r
890       // For bridge, it should support IDE attributes\r
891       //\r
892       Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
893       Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
894     } else {\r
895 \r
896       if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
897         Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
898         Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
899       }\r
900 \r
901       if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
902         Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
903         Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
904       }\r
905     }\r
906 \r
907     PciIoDevice->Supports = Attributes;\r
908     PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \\r
909                                EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
910                                EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );\r
911 \r
912   } else {\r
913     PciIoDevice->Attributes = Attributes;\r
914   }\r
915 \r
916   return EFI_SUCCESS;\r
917 }\r
918 \r
919 EFI_STATUS\r
920 GetFastBackToBackSupport (\r
921   IN PCI_IO_DEVICE                      *PciIoDevice,\r
922   IN UINT8                              StatusIndex\r
923   )\r
924 /*++\r
925 \r
926 Routine Description:\r
927 \r
928   Determine if the device can support Fast Back to Back attribute\r
929 \r
930 Arguments:\r
931 \r
932 Returns:\r
933 \r
934   None\r
935 \r
936 --*/\r
937 // TODO:    PciIoDevice - add argument and description to function comment\r
938 // TODO:    StatusIndex - add argument and description to function comment\r
939 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
940 // TODO:    EFI_SUCCESS - add return value to function comment\r
941 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
942 {\r
943   EFI_PCI_IO_PROTOCOL *PciIo;\r
944   EFI_STATUS          Status;\r
945   UINT32              StatusRegister;\r
946 \r
947   //\r
948   // Read the status register\r
949   //\r
950   PciIo   = &PciIoDevice->PciIo;\r
951   Status  = PciIoRead (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
952   if (EFI_ERROR (Status)) {\r
953     return EFI_UNSUPPORTED;\r
954   }\r
955 \r
956   //\r
957   // Check the Fast B2B bit\r
958   //\r
959   if (StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) {\r
960     return EFI_SUCCESS;\r
961   } else {\r
962     return EFI_UNSUPPORTED;\r
963   }\r
964 \r
965 }\r
966 \r
967 STATIC\r
968 EFI_STATUS\r
969 ProcessOptionRomLight (\r
970   IN PCI_IO_DEVICE                      *PciIoDevice\r
971   )\r
972 /*++\r
973 \r
974 Routine Description:\r
975 \r
976   Process the option ROM for all the children of the specified parent PCI device.\r
977   It can only be used after the first full Option ROM process.\r
978 \r
979 Arguments:\r
980 \r
981 Returns:\r
982 \r
983   None\r
984 \r
985 --*/\r
986 // TODO:    PciIoDevice - add argument and description to function comment\r
987 // TODO:    EFI_SUCCESS - add return value to function comment\r
988 {\r
989   PCI_IO_DEVICE   *Temp;\r
990   LIST_ENTRY      *CurrentLink;\r
991 \r
992   //\r
993   // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
994   //\r
995   CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
996   while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
997 \r
998     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
999 \r
1000     if (!IsListEmpty (&Temp->ChildList)) {\r
1001       ProcessOptionRomLight (Temp);\r
1002     }\r
1003 \r
1004     PciRomGetImageMapping (Temp);\r
1005     CurrentLink = CurrentLink->ForwardLink;\r
1006   }\r
1007 \r
1008   return EFI_SUCCESS;\r
1009 }\r
1010 \r
1011 EFI_STATUS\r
1012 DetermineDeviceAttribute (\r
1013   IN PCI_IO_DEVICE                      *PciIoDevice\r
1014   )\r
1015 /*++\r
1016 \r
1017 Routine Description:\r
1018 \r
1019   Determine the related attributes of all devices under a Root Bridge\r
1020 \r
1021 Arguments:\r
1022 \r
1023 Returns:\r
1024 \r
1025   None\r
1026 \r
1027 --*/\r
1028 // TODO:    PciIoDevice - add argument and description to function comment\r
1029 // TODO:    EFI_SUCCESS - add return value to function comment\r
1030 {\r
1031   UINT16          Command;\r
1032   UINT16          BridgeControl;\r
1033   UINT16          OldCommand;\r
1034   UINT16          OldBridgeControl;\r
1035   BOOLEAN         FastB2BSupport;\r
1036 \r
1037   /*\r
1038   UINT8  IdePI;\r
1039   EFI_PCI_IO_PROTOCOL   *PciIo;\r
1040   */\r
1041   PCI_IO_DEVICE   *Temp;\r
1042   LIST_ENTRY      *CurrentLink;\r
1043   EFI_STATUS      Status;\r
1044 \r
1045   //\r
1046   // For Root Bridge, just copy it by RootBridgeIo proctocol\r
1047   // so as to keep consistent with the actual attribute\r
1048   //\r
1049   if (!PciIoDevice->Parent) {\r
1050     Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1051                                             PciIoDevice->PciRootBridgeIo,\r
1052                                             &PciIoDevice->Supports,\r
1053                                             &PciIoDevice->Attributes\r
1054                                             );\r
1055     if (EFI_ERROR (Status)) {\r
1056       return Status;\r
1057     }\r
1058   } else {\r
1059 \r
1060     //\r
1061     // Set the attributes to be checked for common PCI devices and PPB or P2C\r
1062     // Since some devices only support part of them, it is better to set the\r
1063     // attribute according to its command or bridge control register\r
1064     //\r
1065     Command = EFI_PCI_COMMAND_IO_SPACE     |\r
1066               EFI_PCI_COMMAND_MEMORY_SPACE |\r
1067               EFI_PCI_COMMAND_BUS_MASTER   |\r
1068               EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1069 \r
1070     BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1071 \r
1072     //\r
1073     // Test whether the device can support attributes above\r
1074     //\r
1075     PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
1076 \r
1077     //\r
1078     // Set the supported attributes for specified PCI device\r
1079     //\r
1080     PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
1081 \r
1082     //\r
1083     // Set the current attributes for specified PCI device\r
1084     //\r
1085     PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
1086 \r
1087     //\r
1088     // Enable other supported attributes but not defined in PCI_IO_PROTOCOL\r
1089     //\r
1090     PciEnableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
1091 \r
1092     //\r
1093     // Enable IDE native mode\r
1094     //\r
1095     /*\r
1096     if (IS_PCI_IDE(&PciIoDevice->Pci)) {\r
1097 \r
1098       PciIo = &PciIoDevice->PciIo;\r
1099 \r
1100       PciIoRead (\r
1101                               PciIo,\r
1102                               EfiPciIoWidthUint8,\r
1103                               0x09,\r
1104                               1,\r
1105                               &IdePI\r
1106                               );\r
1107 \r
1108       //\r
1109       // Set native mode if it can be supported\r
1110       //\r
1111       IdePI |= (((IdePI & 0x0F) >> 1) & 0x05);\r
1112 \r
1113       PciIoWrite (\r
1114                               PciIo,\r
1115                               EfiPciIoWidthUint8,\r
1116                               0x09,\r
1117                               1,\r
1118                               &IdePI\r
1119                               );\r
1120 \r
1121     }\r
1122     */\r
1123   }\r
1124 \r
1125   FastB2BSupport = TRUE;\r
1126 \r
1127   //\r
1128   // P2C can not support FB2B on the secondary side\r
1129   //\r
1130   if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1131     FastB2BSupport = FALSE;\r
1132   }\r
1133 \r
1134   //\r
1135   // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1136   //\r
1137   CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1138   while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
1139 \r
1140     Temp    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1141     Status  = DetermineDeviceAttribute (Temp);\r
1142     if (EFI_ERROR (Status)) {\r
1143       return Status;\r
1144     }\r
1145     //\r
1146     // Detect Fast Bact to Bact support for the device under the bridge\r
1147     //\r
1148     Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1149     if (FastB2BSupport && EFI_ERROR (Status)) {\r
1150       FastB2BSupport = FALSE;\r
1151     }\r
1152 \r
1153     CurrentLink = CurrentLink->ForwardLink;\r
1154   }\r
1155   //\r
1156   // Set or clear Fast Back to Back bit for the whole bridge\r
1157   //\r
1158   if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
1159 \r
1160     if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1161 \r
1162       Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1163 \r
1164       if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1165         FastB2BSupport = FALSE;\r
1166         PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1167       } else {\r
1168         PciEnableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1169       }\r
1170     }\r
1171 \r
1172     CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1173     while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
1174       Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1175       if (FastB2BSupport) {\r
1176         PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1177       } else {\r
1178         PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1179       }\r
1180 \r
1181       CurrentLink = CurrentLink->ForwardLink;\r
1182     }\r
1183   }\r
1184   //\r
1185   // End for IsListEmpty\r
1186   //\r
1187   return EFI_SUCCESS;\r
1188 }\r
1189 \r
1190 EFI_STATUS\r
1191 UpdatePciInfo (\r
1192   IN PCI_IO_DEVICE  *PciIoDevice\r
1193   )\r
1194 /*++\r
1195 \r
1196 Routine Description:\r
1197 \r
1198   This routine is used to update the bar information for those incompatible PCI device\r
1199 \r
1200 Arguments:\r
1201 \r
1202 Returns:\r
1203 \r
1204   None\r
1205 \r
1206 --*/\r
1207 // TODO:    PciIoDevice - add argument and description to function comment\r
1208 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
1209 {\r
1210   EFI_STATUS                        Status;\r
1211   UINTN                             BarIndex;\r
1212   UINTN                             BarEndIndex;\r
1213   BOOLEAN                           SetFlag;\r
1214   EFI_PCI_DEVICE_INFO               PciDeviceInfo;\r
1215   VOID                              *Configuration;\r
1216   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1217 \r
1218   Configuration = NULL;\r
1219 \r
1220   //\r
1221   // Check whether the device belongs to incompatible devices or not\r
1222   // If it is , then get its special requirement in the ACPI table\r
1223   //\r
1224   PciDeviceInfo.VendorID          = PciIoDevice->Pci.Hdr.VendorId;\r
1225   PciDeviceInfo.DeviceID          = PciIoDevice->Pci.Hdr.DeviceId;\r
1226   PciDeviceInfo.RevisionID        = PciIoDevice->Pci.Hdr.RevisionID;\r
1227   PciDeviceInfo.SubsystemVendorID = PciIoDevice->Pci.Device.SubsystemVendorID;\r
1228   PciDeviceInfo.SubsystemID       = PciIoDevice->Pci.Device.SubsystemID;\r
1229 \r
1230   Status = PciResourceUpdateCheck (&PciDeviceInfo, &Configuration);\r
1231 \r
1232   if (EFI_ERROR (Status)) {\r
1233     return Status;\r
1234   }\r
1235 \r
1236   //\r
1237   // Update PCI device information from the ACPI table\r
1238   //\r
1239   Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1240 \r
1241   while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1242 \r
1243     if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1244       //\r
1245       // The format is not support\r
1246       //\r
1247       break;\r
1248     }\r
1249 \r
1250     BarIndex    = (UINTN) Ptr->AddrTranslationOffset;\r
1251     BarEndIndex = BarIndex;\r
1252 \r
1253     //\r
1254     // Update all the bars in the device\r
1255     //\r
1256     if (BarIndex == PCI_BAR_ALL) {\r
1257       BarIndex    = 0;\r
1258       BarEndIndex = PCI_MAX_BAR - 1;\r
1259     }\r
1260 \r
1261     if (BarIndex >= PCI_MAX_BAR) {\r
1262       Ptr++;\r
1263       continue;\r
1264     }\r
1265 \r
1266     for (; BarIndex <= BarEndIndex; BarIndex++) {\r
1267       SetFlag = FALSE;\r
1268       switch (Ptr->ResType) {\r
1269       case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1270 \r
1271         //\r
1272         // Make sure the bar is memory type\r
1273         //\r
1274         if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
1275           SetFlag = TRUE;\r
1276         }\r
1277         break;\r
1278 \r
1279       case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1280 \r
1281         //\r
1282         // Make sure the bar is IO type\r
1283         //\r
1284         if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1285           SetFlag = TRUE;\r
1286         }\r
1287         break;\r
1288       }\r
1289 \r
1290       if (SetFlag) {\r
1291 \r
1292         //\r
1293         // Update the new alignment for the device\r
1294         //\r
1295         SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1296 \r
1297         //\r
1298         // Update the new length for the device\r
1299         //\r
1300         if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
1301           PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1302         }\r
1303       }\r
1304     }\r
1305 \r
1306     Ptr++;\r
1307   }\r
1308 \r
1309   gBS->FreePool (Configuration);\r
1310   return Status;\r
1311 \r
1312 }\r
1313 \r
1314 VOID\r
1315 SetNewAlign (\r
1316   IN UINT64 *Alignment,\r
1317   IN UINT64 NewAlignment\r
1318   )\r
1319 /*++\r
1320 \r
1321 Routine Description:\r
1322 \r
1323   This routine will update the alignment with the new alignment\r
1324 \r
1325 Arguments:\r
1326 \r
1327 Returns:\r
1328 \r
1329   None\r
1330 \r
1331 --*/\r
1332 // TODO:    Alignment - add argument and description to function comment\r
1333 // TODO:    NewAlignment - add argument and description to function comment\r
1334 {\r
1335   UINT64  OldAlignment;\r
1336   UINTN   ShiftBit;\r
1337 \r
1338   //\r
1339   // The new alignment is the same as the original,\r
1340   // so skip it\r
1341   //\r
1342   if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1343     return ;\r
1344   }\r
1345   //\r
1346   // Check the validity of the parameter\r
1347   //\r
1348    if (NewAlignment != PCI_BAR_EVEN_ALIGN  &&\r
1349        NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1350        NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1351     *Alignment = NewAlignment;\r
1352     return ;\r
1353   }\r
1354 \r
1355   OldAlignment  = (*Alignment) + 1;\r
1356   ShiftBit      = 0;\r
1357 \r
1358   //\r
1359   // Get the first non-zero hex value of the length\r
1360   //\r
1361   while ((OldAlignment & 0x0F) == 0x00) {\r
1362     OldAlignment = RShiftU64 (OldAlignment, 4);\r
1363     ShiftBit += 4;\r
1364   }\r
1365 \r
1366   //\r
1367   // Adjust the alignment to even, quad or double quad boundary\r
1368   //\r
1369   if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
1370     if (OldAlignment & 0x01) {\r
1371       OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1372     }\r
1373   } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
1374     if (OldAlignment & 0x03) {\r
1375       OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1376     }\r
1377   } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
1378     if (OldAlignment & 0x07) {\r
1379       OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1380     }\r
1381   }\r
1382 \r
1383   //\r
1384   // Update the old value\r
1385   //\r
1386   NewAlignment  = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1387   *Alignment    = NewAlignment;\r
1388 \r
1389   return ;\r
1390 }\r
1391 \r
1392 UINTN\r
1393 PciParseBar (\r
1394   IN PCI_IO_DEVICE  *PciIoDevice,\r
1395   IN UINTN          Offset,\r
1396   IN UINTN          BarIndex\r
1397   )\r
1398 /*++\r
1399 \r
1400 Routine Description:\r
1401 \r
1402 Arguments:\r
1403 \r
1404 Returns:\r
1405 \r
1406   None\r
1407 \r
1408 --*/\r
1409 // TODO:    PciIoDevice - add argument and description to function comment\r
1410 // TODO:    Offset - add argument and description to function comment\r
1411 // TODO:    BarIndex - add argument and description to function comment\r
1412 {\r
1413   UINT32      Value;\r
1414   UINT32      OriginalValue;\r
1415   UINT32      Mask;\r
1416   UINT32      Data;\r
1417   UINT8       Index;\r
1418   EFI_STATUS  Status;\r
1419 \r
1420   OriginalValue = 0;\r
1421   Value         = 0;\r
1422 \r
1423   Status = BarExisted (\r
1424             PciIoDevice,\r
1425             Offset,\r
1426             &Value,\r
1427             &OriginalValue\r
1428             );\r
1429 \r
1430   if (EFI_ERROR (Status)) {\r
1431     PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1432     PciIoDevice->PciBar[BarIndex].Length      = 0;\r
1433     PciIoDevice->PciBar[BarIndex].Alignment   = 0;\r
1434 \r
1435     //\r
1436     // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1437     //\r
1438     PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1439     return Offset + 4;\r
1440   }\r
1441 \r
1442   PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1443   if (Value & 0x01) {\r
1444     //\r
1445     // Device I/Os\r
1446     //\r
1447     Mask = 0xfffffffc;\r
1448 \r
1449     if (Value & 0xFFFF0000) {\r
1450       //\r
1451       // It is a IO32 bar\r
1452       //\r
1453       PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo32;\r
1454       PciIoDevice->PciBar[BarIndex].Length    = ((~(Value & Mask)) + 1);\r
1455       PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1456 \r
1457     } else {\r
1458       //\r
1459       // It is a IO16 bar\r
1460       //\r
1461       PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo16;\r
1462       PciIoDevice->PciBar[BarIndex].Length    = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1463       PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1464 \r
1465     }\r
1466     //\r
1467     // Workaround. Some platforms inplement IO bar with 0 length\r
1468     // Need to treat it as no-bar\r
1469     //\r
1470     if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1471       PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1472     }\r
1473 \r
1474     PciIoDevice->PciBar[BarIndex].Prefetchable  = FALSE;\r
1475     PciIoDevice->PciBar[BarIndex].BaseAddress   = OriginalValue & Mask;\r
1476 \r
1477   } else {\r
1478 \r
1479     Mask  = 0xfffffff0;\r
1480 \r
1481     PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1482 \r
1483     switch (Value & 0x07) {\r
1484 \r
1485     //\r
1486     //memory space; anywhere in 32 bit address space\r
1487     //\r
1488     case 0x00:\r
1489       if (Value & 0x08) {\r
1490         PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1491       } else {\r
1492         PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1493       }\r
1494 \r
1495       PciIoDevice->PciBar[BarIndex].Length    = (~(Value & Mask)) + 1;\r
1496       PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1497 \r
1498       break;\r
1499 \r
1500     //\r
1501     // memory space; anywhere in 64 bit address space\r
1502     //\r
1503     case 0x04:\r
1504       if (Value & 0x08) {\r
1505         PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1506       } else {\r
1507         PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1508       }\r
1509 \r
1510       //\r
1511       // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1512       // is regarded as an extension for the first bar. As a result\r
1513       // the sizing will be conducted on combined 64 bit value\r
1514       // Here just store the masked first 32bit value for future size\r
1515       // calculation\r
1516       //\r
1517       PciIoDevice->PciBar[BarIndex].Length    = Value & Mask;\r
1518       PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1519 \r
1520       //\r
1521       // Increment the offset to point to next DWORD\r
1522       //\r
1523       Offset += 4;\r
1524 \r
1525       Status = BarExisted (\r
1526                 PciIoDevice,\r
1527                 Offset,\r
1528                 &Value,\r
1529                 &OriginalValue\r
1530                 );\r
1531 \r
1532       if (EFI_ERROR (Status)) {\r
1533         return Offset + 4;\r
1534       }\r
1535 \r
1536       //\r
1537       // Fix the length to support some spefic 64 bit BAR\r
1538       //\r
1539       Data  = Value;\r
1540       Index = 0;\r
1541       for (Data = Value; Data != 0; Data >>= 1) {\r
1542         Index ++;\r
1543       }\r
1544       Value |= ((UINT32)(-1) << Index);\r
1545 \r
1546       //\r
1547       // Calculate the size of 64bit bar\r
1548       //\r
1549       PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1550 \r
1551       PciIoDevice->PciBar[BarIndex].Length    = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1552       PciIoDevice->PciBar[BarIndex].Length    = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1553       PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1554 \r
1555       break;\r
1556 \r
1557     //\r
1558     // reserved\r
1559     //\r
1560     default:\r
1561       PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeUnknown;\r
1562       PciIoDevice->PciBar[BarIndex].Length    = (~(Value & Mask)) + 1;\r
1563       PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1564 \r
1565       break;\r
1566     }\r
1567   }\r
1568 \r
1569   //\r
1570   // Check the length again so as to keep compatible with some special bars\r
1571   //\r
1572   if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1573     PciIoDevice->PciBar[BarIndex].BarType     = PciBarTypeUnknown;\r
1574     PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1575     PciIoDevice->PciBar[BarIndex].Alignment   = 0;\r
1576   }\r
1577 \r
1578   //\r
1579   // Increment number of bar\r
1580   //\r
1581   return Offset + 4;\r
1582 }\r
1583 \r
1584 EFI_STATUS\r
1585 InitializePciDevice (\r
1586   IN PCI_IO_DEVICE *PciIoDevice\r
1587   )\r
1588 /*++\r
1589 \r
1590 Routine Description:\r
1591 \r
1592   This routine is used to initialize the bar of a PCI device\r
1593   It can be called typically when a device is going to be rejected\r
1594 \r
1595 Arguments:\r
1596 \r
1597 Returns:\r
1598 \r
1599   None\r
1600 \r
1601 --*/\r
1602 // TODO:    PciIoDevice - add argument and description to function comment\r
1603 // TODO:    EFI_SUCCESS - add return value to function comment\r
1604 {\r
1605   EFI_PCI_IO_PROTOCOL *PciIo;\r
1606   UINT8               Offset;\r
1607 \r
1608   PciIo = &(PciIoDevice->PciIo);\r
1609 \r
1610   //\r
1611   // Put all the resource apertures\r
1612   // Resource base is set to all ones so as to indicate its resource\r
1613   // has not been alloacted\r
1614   //\r
1615   for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1616     PciIoWrite (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1617   }\r
1618 \r
1619   return EFI_SUCCESS;\r
1620 }\r
1621 \r
1622 EFI_STATUS\r
1623 InitializePpb (\r
1624   IN PCI_IO_DEVICE *PciIoDevice\r
1625   )\r
1626 /*++\r
1627 \r
1628 Routine Description:\r
1629 \r
1630 Arguments:\r
1631 \r
1632 Returns:\r
1633 \r
1634   None\r
1635 \r
1636 --*/\r
1637 // TODO:    PciIoDevice - add argument and description to function comment\r
1638 // TODO:    EFI_SUCCESS - add return value to function comment\r
1639 {\r
1640   EFI_PCI_IO_PROTOCOL *PciIo;\r
1641 \r
1642   PciIo = &(PciIoDevice->PciIo);\r
1643 \r
1644   //\r
1645   // Put all the resource apertures including IO16\r
1646   // Io32, pMem32, pMem64 to quiescent state\r
1647   // Resource base all ones, Resource limit all zeros\r
1648   //\r
1649   PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1650   PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1651 \r
1652   PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1653   PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1654 \r
1655   PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1656   PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1657 \r
1658   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1659   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1660 \r
1661   //\r
1662   // don't support use io32 as for now\r
1663   //\r
1664   PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1665   PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1666 \r
1667   //\r
1668   // Force Interrupt line to zero for cards that come up randomly\r
1669   //\r
1670   PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1671 \r
1672   return EFI_SUCCESS;\r
1673 }\r
1674 \r
1675 EFI_STATUS\r
1676 InitializeP2C (\r
1677   IN PCI_IO_DEVICE *PciIoDevice\r
1678   )\r
1679 /*++\r
1680 \r
1681 Routine Description:\r
1682 \r
1683 Arguments:\r
1684 \r
1685 Returns:\r
1686 \r
1687   None\r
1688 \r
1689 --*/\r
1690 // TODO:    PciIoDevice - add argument and description to function comment\r
1691 // TODO:    EFI_SUCCESS - add return value to function comment\r
1692 {\r
1693   EFI_PCI_IO_PROTOCOL *PciIo;\r
1694 \r
1695   PciIo = &(PciIoDevice->PciIo);\r
1696 \r
1697   //\r
1698   // Put all the resource apertures including IO16\r
1699   // Io32, pMem32, pMem64 to quiescent state(\r
1700   // Resource base all ones, Resource limit all zeros\r
1701   //\r
1702   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1703   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
1704 \r
1705   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1706   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
1707 \r
1708   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1709   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
1710 \r
1711   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1712   PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
1713 \r
1714   //\r
1715   // Force Interrupt line to zero for cards that come up randomly\r
1716   //\r
1717   PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1718   return EFI_SUCCESS;\r
1719 }\r
1720 \r
1721 PCI_IO_DEVICE *\r
1722 CreatePciIoDevice (\r
1723   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,\r
1724   IN PCI_TYPE00                       *Pci,\r
1725   UINT8                               Bus,\r
1726   UINT8                               Device,\r
1727   UINT8                               Func\r
1728   )\r
1729 /*++\r
1730 \r
1731 Routine Description:\r
1732 \r
1733 Arguments:\r
1734 \r
1735 Returns:\r
1736 \r
1737   None\r
1738 \r
1739 --*/\r
1740 // TODO:    PciRootBridgeIo - add argument and description to function comment\r
1741 // TODO:    Pci - add argument and description to function comment\r
1742 // TODO:    Bus - add argument and description to function comment\r
1743 // TODO:    Device - add argument and description to function comment\r
1744 // TODO:    Func - add argument and description to function comment\r
1745 {\r
1746 \r
1747   EFI_STATUS    Status;\r
1748   PCI_IO_DEVICE *PciIoDevice;\r
1749 \r
1750   PciIoDevice = NULL;\r
1751 \r
1752   Status = gBS->AllocatePool (\r
1753                   EfiBootServicesData,\r
1754                   sizeof (PCI_IO_DEVICE),\r
1755                   (VOID **) &PciIoDevice\r
1756                   );\r
1757 \r
1758   if (EFI_ERROR (Status)) {\r
1759     return NULL;\r
1760   }\r
1761 \r
1762   ZeroMem (PciIoDevice, sizeof (PCI_IO_DEVICE));\r
1763 \r
1764   PciIoDevice->Signature        = PCI_IO_DEVICE_SIGNATURE;\r
1765   PciIoDevice->Handle           = NULL;\r
1766   PciIoDevice->PciRootBridgeIo  = PciRootBridgeIo;\r
1767   PciIoDevice->DevicePath       = NULL;\r
1768   PciIoDevice->BusNumber        = Bus;\r
1769   PciIoDevice->DeviceNumber     = Device;\r
1770   PciIoDevice->FunctionNumber   = Func;\r
1771   PciIoDevice->Decodes          = 0;\r
1772   if (gFullEnumeration) {\r
1773     PciIoDevice->Allocated = FALSE;\r
1774   } else {\r
1775     PciIoDevice->Allocated = TRUE;\r
1776   }\r
1777 \r
1778   PciIoDevice->Registered         = FALSE;\r
1779   PciIoDevice->Attributes         = 0;\r
1780   PciIoDevice->Supports           = 0;\r
1781   PciIoDevice->BusOverride        = FALSE;\r
1782   PciIoDevice->AllOpRomProcessed  = FALSE;\r
1783 \r
1784   PciIoDevice->IsPciExp           = FALSE;\r
1785 \r
1786   CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
1787 \r
1788   //\r
1789   // Initialize the PCI I/O instance structure\r
1790   //\r
1791 \r
1792   Status  = InitializePciIoInstance (PciIoDevice);\r
1793   Status  = InitializePciDriverOverrideInstance (PciIoDevice);\r
1794 \r
1795   if (EFI_ERROR (Status)) {\r
1796     gBS->FreePool (PciIoDevice);\r
1797     return NULL;\r
1798   }\r
1799 \r
1800   //\r
1801   // Initialize the reserved resource list\r
1802   //\r
1803   InitializeListHead (&PciIoDevice->ReservedResourceList);\r
1804 \r
1805   //\r
1806   // Initialize the driver list\r
1807   //\r
1808   InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
1809 \r
1810   //\r
1811   // Initialize the child list\r
1812   //\r
1813   InitializeListHead (&PciIoDevice->ChildList);\r
1814 \r
1815   return PciIoDevice;\r
1816 }\r
1817 \r
1818 EFI_STATUS\r
1819 PciEnumeratorLight (\r
1820   IN EFI_HANDLE                    Controller\r
1821   )\r
1822 /*++\r
1823 \r
1824 Routine Description:\r
1825 \r
1826   This routine is used to enumerate entire pci bus system\r
1827   in a given platform\r
1828 \r
1829 Arguments:\r
1830 \r
1831 Returns:\r
1832 \r
1833   None\r
1834 \r
1835 --*/\r
1836 // TODO:    Controller - add argument and description to function comment\r
1837 // TODO:    EFI_SUCCESS - add return value to function comment\r
1838 // TODO:    EFI_SUCCESS - add return value to function comment\r
1839 {\r
1840 \r
1841   EFI_STATUS                        Status;\r
1842   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;\r
1843   PCI_IO_DEVICE                     *RootBridgeDev;\r
1844   UINT16                            MinBus;\r
1845   UINT16                            MaxBus;\r
1846   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1847 \r
1848   MinBus      = 0;\r
1849   MaxBus      = PCI_MAX_BUS;\r
1850   Descriptors = NULL;\r
1851 \r
1852   //\r
1853   // If this host bridge has been already enumerated, then return successfully\r
1854   //\r
1855   if (RootBridgeExisted (Controller)) {\r
1856     return EFI_SUCCESS;\r
1857   }\r
1858 \r
1859   //\r
1860   // Open pci root bridge io protocol\r
1861   //\r
1862   Status = gBS->OpenProtocol (\r
1863                   Controller,\r
1864                   &gEfiPciRootBridgeIoProtocolGuid,\r
1865                   (VOID **) &PciRootBridgeIo,\r
1866                   gPciBusDriverBinding.DriverBindingHandle,\r
1867                   Controller,\r
1868                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1869                   );\r
1870   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1871     return Status;\r
1872   }\r
1873 \r
1874   Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1875 \r
1876   if (EFI_ERROR (Status)) {\r
1877     return Status;\r
1878   }\r
1879 \r
1880   while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
1881 \r
1882     //\r
1883     // Create a device node for root bridge device with a NULL host bridge controller handle\r
1884     //\r
1885     RootBridgeDev = CreateRootBridge (Controller);\r
1886 \r
1887     if (!RootBridgeDev) {\r
1888       Descriptors++;\r
1889       continue;\r
1890     }\r
1891 \r
1892     //\r
1893     // Record the root bridge io protocol\r
1894     //\r
1895     RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1896 \r
1897     Status = PciPciDeviceInfoCollector (\r
1898               RootBridgeDev,\r
1899               (UINT8) MinBus\r
1900               );\r
1901 \r
1902     if (!EFI_ERROR (Status)) {\r
1903 \r
1904       //\r
1905       // Remove those PCI devices which are rejected when full enumeration\r
1906       //\r
1907       RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
1908 \r
1909       //\r
1910       // Process option rom light\r
1911       //\r
1912       ProcessOptionRomLight (RootBridgeDev);\r
1913 \r
1914       //\r
1915       // Determine attributes for all devices under this root bridge\r
1916       //\r
1917       DetermineDeviceAttribute (RootBridgeDev);\r
1918 \r
1919       //\r
1920       // If successfully, insert the node into device pool\r
1921       //\r
1922       InsertRootBridge (RootBridgeDev);\r
1923     } else {\r
1924 \r
1925       //\r
1926       // If unsuccessly, destroy the entire node\r
1927       //\r
1928       DestroyRootBridge (RootBridgeDev);\r
1929     }\r
1930 \r
1931     Descriptors++;\r
1932   }\r
1933 \r
1934   return EFI_SUCCESS;\r
1935 }\r
1936 \r
1937 EFI_STATUS\r
1938 PciGetBusRange (\r
1939   IN     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  **Descriptors,\r
1940   OUT    UINT16                             *MinBus,\r
1941   OUT    UINT16                             *MaxBus,\r
1942   OUT    UINT16                             *BusRange\r
1943   )\r
1944 /*++\r
1945 \r
1946 Routine Description:\r
1947 \r
1948   Get the bus range.\r
1949 \r
1950 Arguments:\r
1951 \r
1952   Descriptors     - A pointer to the address space descriptor.\r
1953   MinBus          - The min bus.\r
1954   MaxBus          - The max bus.\r
1955   BusRange        - The bus range.\r
1956 \r
1957 Returns:\r
1958 \r
1959   Status Code.\r
1960 \r
1961 --*/\r
1962 // TODO:    EFI_SUCCESS - add return value to function comment\r
1963 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1964 {\r
1965 \r
1966   while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1967     if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1968       if (MinBus != NULL) {\r
1969         *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
1970       }\r
1971 \r
1972       if (MaxBus != NULL) {\r
1973         *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
1974       }\r
1975 \r
1976       if (BusRange != NULL) {\r
1977         *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
1978       }\r
1979 \r
1980       return EFI_SUCCESS;\r
1981     }\r
1982 \r
1983     (*Descriptors)++;\r
1984   }\r
1985 \r
1986   return EFI_NOT_FOUND;\r
1987 }\r
1988 \r
1989 EFI_STATUS\r
1990 StartManagingRootBridge (\r
1991   IN PCI_IO_DEVICE *RootBridgeDev\r
1992   )\r
1993 /*++\r
1994 \r
1995 Routine Description:\r
1996 \r
1997 \r
1998 Arguments:\r
1999 \r
2000 Returns:\r
2001 \r
2002   None\r
2003 \r
2004 --*/\r
2005 // TODO:    RootBridgeDev - add argument and description to function comment\r
2006 // TODO:    EFI_SUCCESS - add return value to function comment\r
2007 {\r
2008   EFI_HANDLE                      RootBridgeHandle;\r
2009   EFI_STATUS                      Status;\r
2010   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2011 \r
2012   //\r
2013   // Get the root bridge handle\r
2014   //\r
2015   RootBridgeHandle  = RootBridgeDev->Handle;\r
2016   PciRootBridgeIo   = NULL;\r
2017 \r
2018   //\r
2019   // Get the pci root bridge io protocol\r
2020   //\r
2021   Status = gBS->OpenProtocol (\r
2022                   RootBridgeHandle,\r
2023                   &gEfiPciRootBridgeIoProtocolGuid,\r
2024                   (VOID **) &PciRootBridgeIo,\r
2025                   gPciBusDriverBinding.DriverBindingHandle,\r
2026                   RootBridgeHandle,\r
2027                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
2028                   );\r
2029 \r
2030   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2031     return Status;\r
2032   }\r
2033 \r
2034   //\r
2035   // Store the PciRootBridgeIo protocol into root bridge private data\r
2036   //\r
2037   RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2038 \r
2039   return EFI_SUCCESS;\r
2040 \r
2041 }\r
2042 \r
2043 BOOLEAN\r
2044 IsPciDeviceRejected (\r
2045   IN PCI_IO_DEVICE *PciIoDevice\r
2046   )\r
2047 /*++\r
2048 \r
2049 Routine Description:\r
2050 \r
2051   This routine can be used to check whether a PCI device should be rejected when light enumeration\r
2052 \r
2053 Arguments:\r
2054 \r
2055 Returns:\r
2056 \r
2057   TRUE      This device should be rejected\r
2058   FALSE     This device shouldn't be rejected\r
2059 \r
2060 --*/\r
2061 // TODO:    PciIoDevice - add argument and description to function comment\r
2062 {\r
2063   EFI_STATUS  Status;\r
2064   UINT32      TestValue;\r
2065   UINT32      OldValue;\r
2066   UINT32      Mask;\r
2067   UINT8       BarOffset;\r
2068 \r
2069   //\r
2070   // PPB should be skip!\r
2071   //\r
2072   if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2073     return FALSE;\r
2074   }\r
2075 \r
2076   if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2077     //\r
2078     // Only test base registers for P2C\r
2079     //\r
2080     for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2081 \r
2082       Mask    = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2083       Status  = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2084       if (EFI_ERROR (Status)) {\r
2085         continue;\r
2086       }\r
2087 \r
2088       TestValue = TestValue & Mask;\r
2089       if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2090         //\r
2091         // The bar isn't programed, so it should be rejected\r
2092         //\r
2093         return TRUE;\r
2094       }\r
2095     }\r
2096 \r
2097     return FALSE;\r
2098   }\r
2099 \r
2100   for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2101     //\r
2102     // Test PCI devices\r
2103     //\r
2104     Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2105     if (EFI_ERROR (Status)) {\r
2106       continue;\r
2107     }\r
2108 \r
2109     if (TestValue & 0x01) {\r
2110 \r
2111       //\r
2112       // IO Bar\r
2113       //\r
2114 \r
2115       Mask      = 0xFFFFFFFC;\r
2116       TestValue = TestValue & Mask;\r
2117       if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2118         return TRUE;\r
2119       }\r
2120 \r
2121     } else {\r
2122 \r
2123       //\r
2124       // Mem Bar\r
2125       //\r
2126 \r
2127       Mask      = 0xFFFFFFF0;\r
2128       TestValue = TestValue & Mask;\r
2129 \r
2130       if ((TestValue & 0x07) == 0x04) {\r
2131 \r
2132         //\r
2133         // Mem64 or PMem64\r
2134         //\r
2135         BarOffset += sizeof (UINT32);\r
2136         if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2137 \r
2138           //\r
2139           // Test its high 32-Bit BAR\r
2140           //\r
2141 \r
2142           Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2143           if (TestValue == OldValue) {\r
2144             return TRUE;\r
2145           }\r
2146         }\r
2147 \r
2148       } else {\r
2149 \r
2150         //\r
2151         // Mem32 or PMem32\r
2152         //\r
2153         if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2154           return TRUE;\r
2155         }\r
2156       }\r
2157     }\r
2158   }\r
2159 \r
2160   return FALSE;\r
2161 }\r
2162 \r
2163 EFI_STATUS\r
2164 ResetAllPpbBusNumber (\r
2165   IN PCI_IO_DEVICE                      *Bridge,\r
2166   IN UINT8                              StartBusNumber\r
2167   )\r
2168 /*++\r
2169 \r
2170 Routine Description:\r
2171 \r
2172   TODO: Add function description\r
2173 \r
2174 Arguments:\r
2175 \r
2176   Bridge          - TODO: add argument description\r
2177   StartBusNumber  - TODO: add argument description\r
2178 \r
2179 Returns:\r
2180 \r
2181   EFI_SUCCESS - TODO: Add description for return value\r
2182 \r
2183 --*/\r
2184 {\r
2185   EFI_STATUS                      Status;\r
2186   PCI_TYPE00                      Pci;\r
2187   UINT8                           Device;\r
2188   UINT32                          Register;\r
2189   UINT8                           Func;\r
2190   UINT64                          Address;\r
2191   UINT8                           SecondaryBus;\r
2192   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2193 \r
2194   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2195 \r
2196   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2197     for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2198 \r
2199       //\r
2200       // Check to see whether a pci device is present\r
2201       //\r
2202       Status = PciDevicePresent (\r
2203                 PciRootBridgeIo,\r
2204                 &Pci,\r
2205                 StartBusNumber,\r
2206                 Device,\r
2207                 Func\r
2208                 );\r
2209 \r
2210       if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2211 \r
2212         Register  = 0;\r
2213         Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2214         Status   = PciRootBridgeIoRead (\r
2215                                         PciRootBridgeIo,\r
2216                                         &Pci,\r
2217                                         EfiPciWidthUint32,\r
2218                                         Address,\r
2219                                         1,\r
2220                                         &Register\r
2221                                         );\r
2222         SecondaryBus = (UINT8)(Register >> 8);\r
2223 \r
2224         if (SecondaryBus != 0) {\r
2225           ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2226         }\r
2227 \r
2228         //\r
2229         // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2230         //\r
2231         Register &= 0xFF000000;\r
2232         Status = PciRootBridgeIoWrite (\r
2233                                         PciRootBridgeIo,\r
2234                                         &Pci,\r
2235                                         EfiPciWidthUint32,\r
2236                                         Address,\r
2237                                         1,\r
2238                                         &Register\r
2239                                         );\r
2240       }\r
2241 \r
2242       if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2243         //\r
2244         // Skip sub functions, this is not a multi function device\r
2245         //\r
2246         Func = PCI_MAX_FUNC;\r
2247       }\r
2248     }\r
2249   }\r
2250 \r
2251   return EFI_SUCCESS;\r
2252 }\r
2253 \r