[Description]:
[people/mcb30/edk2.git] / edk2 / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciLib.c
1 /**@file\r
2 \r
3   PCI Bus Driver Lib file\r
4   It abstracts some functions that can be different\r
5   between light PCI bus driver and full PCI bus driver\r
6 \r
7 Copyright (c) 2006 - 2008, Intel Corporation\r
8 All rights reserved. This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution.  The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12 \r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15 \r
16 **/\r
17 \r
18 #include "pcibus.h"\r
19 \r
20 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest = {\r
21   PciHotPlugRequestNotify\r
22 };\r
23 \r
24 \r
25 VOID\r
26 InstallHotPlugRequestProtocol (\r
27   IN EFI_STATUS *Status\r
28   )\r
29 /*++\r
30 \r
31 Routine Description:\r
32 \r
33 Arguments:\r
34   Status   - A pointer to the status.\r
35 \r
36 Returns:\r
37 \r
38   None\r
39 \r
40 --*/\r
41 {\r
42   EFI_HANDLE  Handle;\r
43 \r
44   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
45     return;\r
46   }\r
47 \r
48   Handle = NULL;\r
49   *Status = gBS->InstallProtocolInterface (\r
50                   &Handle,\r
51                   &gEfiPciHotPlugRequestProtocolGuid,\r
52                   EFI_NATIVE_INTERFACE,\r
53                   &gPciHotPlugRequest\r
54                   );\r
55 }\r
56 \r
57 VOID\r
58 InstallPciHotplugGuid (\r
59   IN  PCI_IO_DEVICE                  *PciIoDevice\r
60   )\r
61 /*++\r
62 \r
63 Routine Description:\r
64 \r
65 Arguments:\r
66 \r
67   PciIoDevice    -  A pointer to the PCI_IO_DEVICE.\r
68 \r
69 Returns:\r
70 \r
71   None\r
72 \r
73 --*/\r
74 {\r
75   EFI_STATUS  Status;\r
76 \r
77   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
78     return;\r
79   }\r
80 \r
81   if (IS_CARDBUS_BRIDGE (&PciIoDevice->Parent->Pci)) {\r
82 \r
83     Status = gBS->InstallProtocolInterface (\r
84                     &PciIoDevice->Handle,\r
85                     &gEfiPciHotplugDeviceGuid,\r
86                     EFI_NATIVE_INTERFACE,\r
87                     NULL\r
88                     );\r
89     ASSERT_EFI_ERROR (Status);\r
90   }\r
91 }\r
92 \r
93 VOID\r
94 UninstallPciHotplugGuid (\r
95   IN  PCI_IO_DEVICE                  *PciIoDevice\r
96   )\r
97 /*++\r
98 \r
99 Routine Description:\r
100 \r
101 Arguments:\r
102 \r
103   PciIoDevice    - A pointer to the PCI_IO_DEVICE.\r
104 \r
105 Returns:\r
106 \r
107   None\r
108 \r
109 --*/\r
110 {\r
111   EFI_STATUS  Status;\r
112 \r
113   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
114     return;\r
115   }\r
116 \r
117   Status = gBS->OpenProtocol (\r
118                   PciIoDevice->Handle,\r
119                   &gEfiPciHotplugDeviceGuid,\r
120                   NULL,\r
121                   NULL,\r
122                   NULL,\r
123                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
124                   );\r
125 \r
126   if (Status == EFI_SUCCESS) {\r
127     //\r
128     // This may triger CardBus driver to stop for\r
129     // Pccard devices opened the GUID via BY_DRIVER\r
130     //\r
131     Status = gBS->UninstallProtocolInterface (\r
132                     PciIoDevice->Handle,\r
133                     &gEfiPciHotplugDeviceGuid,\r
134                     NULL\r
135                     );\r
136   }\r
137 }\r
138 \r
139 VOID\r
140 GetBackPcCardBar (\r
141   IN  PCI_IO_DEVICE                  *PciIoDevice\r
142   )\r
143 /*++\r
144 \r
145 Routine Description:\r
146 \r
147 \r
148 Arguments:\r
149 \r
150   PciIoDevice      - A pointer to the PCI_IO_DEVICE.\r
151 \r
152 Returns:\r
153 \r
154   None\r
155 \r
156 --*/\r
157 {\r
158   UINT32  Address;\r
159 \r
160   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
161     return;\r
162   }\r
163 \r
164   //\r
165   // Read PciBar information from the bar register\r
166   //\r
167   if (!gFullEnumeration) {\r
168 \r
169     Address = 0;\r
170     PciIoRead (\r
171                             &(PciIoDevice->PciIo),\r
172                             EfiPciIoWidthUint32,\r
173                             0x1c,\r
174                             1,\r
175                             &Address\r
176                             );\r
177 \r
178     (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress  = (UINT64) (Address);\r
179     (PciIoDevice->PciBar)[P2C_MEM_1].Length       = 0x2000000;\r
180     (PciIoDevice->PciBar)[P2C_MEM_1].BarType      = PciBarTypeMem32;\r
181 \r
182     Address = 0;\r
183     PciIoRead (\r
184                             &(PciIoDevice->PciIo),\r
185                             EfiPciIoWidthUint32,\r
186                             0x20,\r
187                             1,\r
188                             &Address\r
189                             );\r
190     (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress  = (UINT64) (Address);\r
191     (PciIoDevice->PciBar)[P2C_MEM_2].Length       = 0x2000000;\r
192     (PciIoDevice->PciBar)[P2C_MEM_2].BarType      = PciBarTypePMem32;\r
193 \r
194     Address = 0;\r
195     PciIoRead (\r
196                             &(PciIoDevice->PciIo),\r
197                             EfiPciIoWidthUint32,\r
198                             0x2c,\r
199                             1,\r
200                             &Address\r
201                             );\r
202     (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);\r
203     (PciIoDevice->PciBar)[P2C_IO_1].Length      = 0x100;\r
204     (PciIoDevice->PciBar)[P2C_IO_1].BarType     = PciBarTypeIo16;\r
205 \r
206     Address = 0;\r
207     PciIoRead (\r
208                             &(PciIoDevice->PciIo),\r
209                             EfiPciIoWidthUint32,\r
210                             0x34,\r
211                             1,\r
212                             &Address\r
213                             );\r
214     (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);\r
215     (PciIoDevice->PciBar)[P2C_IO_2].Length      = 0x100;\r
216     (PciIoDevice->PciBar)[P2C_IO_2].BarType     = PciBarTypeIo16;\r
217 \r
218   }\r
219 \r
220   if (gPciHotPlugInit != NULL) {\r
221     GetResourcePaddingForHpb (PciIoDevice);\r
222   }\r
223 }\r
224 \r
225 EFI_STATUS\r
226 RemoveRejectedPciDevices (\r
227   EFI_HANDLE        RootBridgeHandle,\r
228   IN PCI_IO_DEVICE  *Bridge\r
229   )\r
230 /*++\r
231 \r
232 Routine Description:\r
233 \r
234 \r
235 Arguments:\r
236 \r
237   RootBridgeHandle   - An efi handle.\r
238   Bridge             - An pointer to the PCI_IO_DEVICE.\r
239 \r
240 Returns:\r
241 \r
242   None\r
243 \r
244 --*/\r
245 // TODO:    EFI_SUCCESS - add return value to function comment\r
246 {\r
247   PCI_IO_DEVICE   *Temp;\r
248   LIST_ENTRY      *CurrentLink;\r
249   LIST_ENTRY      *LastLink;\r
250 \r
251   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
252     return EFI_SUCCESS;\r
253   }\r
254 \r
255   CurrentLink = Bridge->ChildList.ForwardLink;\r
256 \r
257   while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
258 \r
259     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
260 \r
261     if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
262       //\r
263       // Remove rejected devices recusively\r
264       //\r
265       RemoveRejectedPciDevices (RootBridgeHandle, Temp);\r
266     } else {\r
267       //\r
268       // Skip rejection for all PPBs, while detect rejection for others\r
269       //\r
270       if (IsPciDeviceRejected (Temp)) {\r
271 \r
272         //\r
273         // For P2C, remove all devices on it\r
274         //\r
275 \r
276         if (!IsListEmpty (&Temp->ChildList)) {\r
277           RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
278         }\r
279 \r
280         //\r
281         // Finally remove itself\r
282         //\r
283 \r
284         LastLink = CurrentLink->BackLink;\r
285         RemoveEntryList (CurrentLink);\r
286         FreePciDevice (Temp);\r
287 \r
288         CurrentLink = LastLink;\r
289       }\r
290     }\r
291 \r
292     CurrentLink = CurrentLink->ForwardLink;\r
293   }\r
294 \r
295   return EFI_SUCCESS;\r
296 }\r
297 \r
298 EFI_STATUS\r
299 PciHostBridgeResourceAllocator (\r
300   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
301   )\r
302 {\r
303   if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
304     return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (\r
305              PciResAlloc\r
306              );\r
307   } else {\r
308     return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (\r
309              PciResAlloc\r
310              );\r
311   }\r
312 }\r
313 \r
314 \r
315 EFI_STATUS\r
316 PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (\r
317   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
318   )\r
319 /*++\r
320 \r
321 Routine Description:\r
322 \r
323 Arguments:\r
324 \r
325 Returns:\r
326 \r
327   None\r
328 \r
329 --*/\r
330 // TODO:    PciResAlloc - add argument and description to function comment\r
331 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
332 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
333 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
334 // TODO:    EFI_SUCCESS - add return value to function comment\r
335 {\r
336   PCI_IO_DEVICE                   *RootBridgeDev;\r
337   EFI_HANDLE                      RootBridgeHandle;\r
338   VOID                            *AcpiConfig;\r
339   EFI_STATUS                      Status;\r
340   UINT64                          IoBase;\r
341   UINT64                          Mem32Base;\r
342   UINT64                          PMem32Base;\r
343   UINT64                          Mem64Base;\r
344   UINT64                          PMem64Base;\r
345   UINT64                          MaxOptionRomSize;\r
346   PCI_RESOURCE_NODE               *IoBridge;\r
347   PCI_RESOURCE_NODE               *Mem32Bridge;\r
348   PCI_RESOURCE_NODE               *PMem32Bridge;\r
349   PCI_RESOURCE_NODE               *Mem64Bridge;\r
350   PCI_RESOURCE_NODE               *PMem64Bridge;\r
351   PCI_RESOURCE_NODE               IoPool;\r
352   PCI_RESOURCE_NODE               Mem32Pool;\r
353   PCI_RESOURCE_NODE               PMem32Pool;\r
354   PCI_RESOURCE_NODE               Mem64Pool;\r
355   PCI_RESOURCE_NODE               PMem64Pool;\r
356   EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD  ExtendedData;\r
357 \r
358   //\r
359   // Initialize resource pool\r
360   //\r
361 \r
362   InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
363   InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
364   InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
365   InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);\r
366   InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);\r
367 \r
368   RootBridgeDev     = NULL;\r
369   RootBridgeHandle  = 0;\r
370 \r
371   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
372     //\r
373     // Get RootBridg Device by handle\r
374     //\r
375     RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
376 \r
377     if (RootBridgeDev == NULL) {\r
378       return EFI_NOT_FOUND;\r
379     }\r
380 \r
381     //\r
382     // Get host bridge handle for status report\r
383     //\r
384     ExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;\r
385 \r
386     //\r
387     // Create the entire system resource map from the information collected by\r
388     // enumerator. Several resource tree was created\r
389     //\r
390 \r
391     IoBridge = CreateResourceNode (\r
392                 RootBridgeDev,\r
393                 0,\r
394                 0xFFF,\r
395                 0,\r
396                 PciBarTypeIo16,\r
397                 PciResUsageTypical\r
398                 );\r
399 \r
400     Mem32Bridge = CreateResourceNode (\r
401                     RootBridgeDev,\r
402                     0,\r
403                     0xFFFFF,\r
404                     0,\r
405                     PciBarTypeMem32,\r
406                     PciResUsageTypical\r
407                     );\r
408 \r
409     PMem32Bridge = CreateResourceNode (\r
410                     RootBridgeDev,\r
411                     0,\r
412                     0xFFFFF,\r
413                     0,\r
414                     PciBarTypePMem32,\r
415                     PciResUsageTypical\r
416                     );\r
417 \r
418     Mem64Bridge = CreateResourceNode (\r
419                     RootBridgeDev,\r
420                     0,\r
421                     0xFFFFF,\r
422                     0,\r
423                     PciBarTypeMem64,\r
424                     PciResUsageTypical\r
425                     );\r
426 \r
427     PMem64Bridge = CreateResourceNode (\r
428                     RootBridgeDev,\r
429                     0,\r
430                     0xFFFFF,\r
431                     0,\r
432                     PciBarTypePMem64,\r
433                     PciResUsageTypical\r
434                     );\r
435 \r
436     //\r
437     // Create resourcemap by going through all the devices subject to this root bridge\r
438     //\r
439     Status = CreateResourceMap (\r
440               RootBridgeDev,\r
441               IoBridge,\r
442               Mem32Bridge,\r
443               PMem32Bridge,\r
444               Mem64Bridge,\r
445               PMem64Bridge\r
446               );\r
447 \r
448     //\r
449     // Get the max ROM size that the root bridge can process\r
450     //\r
451     RootBridgeDev->RomSize = Mem32Bridge->Length;\r
452 \r
453     //\r
454     // Get Max Option Rom size for current root bridge\r
455     //\r
456     MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
457 \r
458     //\r
459     // Enlarger the mem32 resource to accomdate the option rom\r
460     // if the mem32 resource is not enough to hold the rom\r
461     //\r
462     if (MaxOptionRomSize > Mem32Bridge->Length) {\r
463 \r
464       Mem32Bridge->Length     = MaxOptionRomSize;\r
465       RootBridgeDev->RomSize  = MaxOptionRomSize;\r
466 \r
467       //\r
468       // Alignment should be adjusted as well\r
469       //\r
470       if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {\r
471         Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
472       }\r
473     }\r
474 \r
475     //\r
476     // Based on the all the resource tree, contruct ACPI resource node to\r
477     // submit the resource aperture to pci host bridge protocol\r
478     //\r
479     Status = ConstructAcpiResourceRequestor (\r
480               RootBridgeDev,\r
481               IoBridge,\r
482               Mem32Bridge,\r
483               PMem32Bridge,\r
484               Mem64Bridge,\r
485               PMem64Bridge,\r
486               &AcpiConfig\r
487               );\r
488 \r
489     //\r
490     // Insert these resource nodes into the database\r
491     //\r
492     InsertResourceNode (&IoPool, IoBridge);\r
493     InsertResourceNode (&Mem32Pool, Mem32Bridge);\r
494     InsertResourceNode (&PMem32Pool, PMem32Bridge);\r
495     InsertResourceNode (&Mem64Pool, Mem64Bridge);\r
496     InsertResourceNode (&PMem64Pool, PMem64Bridge);\r
497 \r
498     if (Status == EFI_SUCCESS) {\r
499       //\r
500       // Submit the resource requirement\r
501       //\r
502       Status = PciResAlloc->SubmitResources (\r
503                               PciResAlloc,\r
504                               RootBridgeDev->Handle,\r
505                               AcpiConfig\r
506                               );\r
507     }\r
508     //\r
509     // Free acpi resource node\r
510     //\r
511     if (AcpiConfig != NULL) {\r
512       FreePool (AcpiConfig);\r
513     }\r
514 \r
515     if (EFI_ERROR (Status)) {\r
516       //\r
517       // Destroy all the resource tree\r
518       //\r
519       DestroyResourceTree (&IoPool);\r
520       DestroyResourceTree (&Mem32Pool);\r
521       DestroyResourceTree (&PMem32Pool);\r
522       DestroyResourceTree (&Mem64Pool);\r
523       DestroyResourceTree (&PMem64Pool);\r
524       return Status;\r
525     }\r
526   }\r
527   //\r
528   // End while\r
529   //\r
530 \r
531   //\r
532   // Notify pci bus driver starts to program the resource\r
533   //\r
534   Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);\r
535 \r
536   if (EFI_ERROR (Status)) {\r
537     //\r
538     // Allocation failed, then return\r
539     //\r
540     return EFI_OUT_OF_RESOURCES;\r
541   }\r
542   //\r
543   // Raise the EFI_IOB_PCI_RES_ALLOC status code\r
544   //\r
545   REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
546         EFI_PROGRESS_CODE,\r
547         EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,\r
548         (VOID *) &ExtendedData,\r
549         sizeof (ExtendedData)\r
550         );\r
551 \r
552   //\r
553   // Notify pci bus driver starts to program the resource\r
554   //\r
555   NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);\r
556 \r
557   RootBridgeDev     = NULL;\r
558 \r
559   RootBridgeHandle  = 0;\r
560 \r
561   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
562     //\r
563     // Get RootBridg Device by handle\r
564     //\r
565     RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
566 \r
567     if (RootBridgeDev == NULL) {\r
568       return EFI_NOT_FOUND;\r
569     }\r
570 \r
571     //\r
572     // Get acpi resource node for all the resource types\r
573     //\r
574     AcpiConfig = NULL;\r
575     Status = PciResAlloc->GetProposedResources (\r
576                             PciResAlloc,\r
577                             RootBridgeDev->Handle,\r
578                             &AcpiConfig\r
579                             );\r
580 \r
581     if (EFI_ERROR (Status)) {\r
582       return Status;\r
583     }\r
584 \r
585     //\r
586     // Get the resource base by interpreting acpi resource node\r
587     //\r
588     //\r
589     GetResourceBase (\r
590       AcpiConfig,\r
591       &IoBase,\r
592       &Mem32Base,\r
593       &PMem32Base,\r
594       &Mem64Base,\r
595       &PMem64Base\r
596       );\r
597 \r
598     //\r
599     // Process option rom for this root bridge\r
600     //\r
601     Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);\r
602 \r
603     //\r
604     // Create the entire system resource map from the information collected by\r
605     // enumerator. Several resource tree was created\r
606     //\r
607     Status = GetResourceMap (\r
608               RootBridgeDev,\r
609               &IoBridge,\r
610               &Mem32Bridge,\r
611               &PMem32Bridge,\r
612               &Mem64Bridge,\r
613               &PMem64Bridge,\r
614               &IoPool,\r
615               &Mem32Pool,\r
616               &PMem32Pool,\r
617               &Mem64Pool,\r
618               &PMem64Pool\r
619               );\r
620 \r
621     if (EFI_ERROR (Status)) {\r
622       return Status;\r
623     }\r
624 \r
625     //\r
626     // Program IO resources\r
627     //\r
628     ProgramResource (\r
629       IoBase,\r
630       IoBridge\r
631       );\r
632 \r
633     //\r
634     // Program Mem32 resources\r
635     //\r
636     ProgramResource (\r
637       Mem32Base,\r
638       Mem32Bridge\r
639       );\r
640 \r
641     //\r
642     // Program PMem32 resources\r
643     //\r
644     ProgramResource (\r
645       PMem32Base,\r
646       PMem32Bridge\r
647       );\r
648 \r
649     //\r
650     // Program Mem64 resources\r
651     //\r
652     ProgramResource (\r
653       Mem64Base,\r
654       Mem64Bridge\r
655       );\r
656 \r
657     //\r
658     // Program PMem64 resources\r
659     //\r
660     ProgramResource (\r
661       PMem64Base,\r
662       PMem64Bridge\r
663       );\r
664 \r
665     if (AcpiConfig != NULL) {\r
666       FreePool (AcpiConfig);\r
667     }\r
668   }\r
669 \r
670   //\r
671   // Destroy all the resource tree\r
672   //\r
673   DestroyResourceTree (&IoPool);\r
674   DestroyResourceTree (&Mem32Pool);\r
675   DestroyResourceTree (&PMem32Pool);\r
676   DestroyResourceTree (&Mem64Pool);\r
677   DestroyResourceTree (&PMem64Pool);\r
678 \r
679   //\r
680   // Notify the resource allocation phase is to end\r
681   //\r
682   NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);\r
683 \r
684   return EFI_SUCCESS;\r
685 }\r
686 \r
687 \r
688 EFI_STATUS\r
689 PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (\r
690   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
691   )\r
692 /*++\r
693 \r
694 Routine Description:\r
695 \r
696   Host brige resource allocator.\r
697 \r
698 Arguments:\r
699 \r
700   PciResAlloc  - A pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.\r
701 \r
702 Returns:\r
703 \r
704   EFI Status.\r
705 \r
706 --*/\r
707 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
708 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
709 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
710 // TODO:    EFI_SUCCESS - add return value to function comment\r
711 {\r
712   PCI_IO_DEVICE                         *RootBridgeDev;\r
713   EFI_HANDLE                            RootBridgeHandle;\r
714   VOID                                  *AcpiConfig;\r
715   EFI_STATUS                            Status;\r
716   UINT64                                IoBase;\r
717   UINT64                                Mem32Base;\r
718   UINT64                                PMem32Base;\r
719   UINT64                                Mem64Base;\r
720   UINT64                                PMem64Base;\r
721   UINT64                                IoResStatus;\r
722   UINT64                                Mem32ResStatus;\r
723   UINT64                                PMem32ResStatus;\r
724   UINT64                                Mem64ResStatus;\r
725   UINT64                                PMem64ResStatus;\r
726   UINT64                                MaxOptionRomSize;\r
727   PCI_RESOURCE_NODE                     *IoBridge;\r
728   PCI_RESOURCE_NODE                     *Mem32Bridge;\r
729   PCI_RESOURCE_NODE                     *PMem32Bridge;\r
730   PCI_RESOURCE_NODE                     *Mem64Bridge;\r
731   PCI_RESOURCE_NODE                     *PMem64Bridge;\r
732   PCI_RESOURCE_NODE                     IoPool;\r
733   PCI_RESOURCE_NODE                     Mem32Pool;\r
734   PCI_RESOURCE_NODE                     PMem32Pool;\r
735   PCI_RESOURCE_NODE                     Mem64Pool;\r
736   PCI_RESOURCE_NODE                     PMem64Pool;\r
737   BOOLEAN                               ReAllocate;\r
738   EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD        HandleExtendedData;\r
739   EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD  AllocFailExtendedData;\r
740 \r
741   //\r
742   // Reallocate flag\r
743   //\r
744   ReAllocate = FALSE;\r
745 \r
746   //\r
747   // It will try several times if the resource allocation fails\r
748   //\r
749   while (TRUE) {\r
750 \r
751     //\r
752     // Initialize resource pool\r
753     //\r
754     InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
755     InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
756     InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
757     InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);\r
758     InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);\r
759 \r
760     RootBridgeDev     = NULL;\r
761     RootBridgeHandle  = 0;\r
762 \r
763     while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
764 \r
765       //\r
766       // Get RootBridg Device by handle\r
767       //\r
768       RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
769 \r
770       if (RootBridgeDev == NULL) {\r
771         return EFI_NOT_FOUND;\r
772       }\r
773 \r
774       //\r
775       // Create the entire system resource map from the information collected by\r
776       // enumerator. Several resource tree was created\r
777       //\r
778 \r
779       IoBridge = CreateResourceNode (\r
780                   RootBridgeDev,\r
781                   0,\r
782                   0xFFF,\r
783                   0,\r
784                   PciBarTypeIo16,\r
785                   PciResUsageTypical\r
786                   );\r
787 \r
788       Mem32Bridge = CreateResourceNode (\r
789                       RootBridgeDev,\r
790                       0,\r
791                       0xFFFFF,\r
792                       0,\r
793                       PciBarTypeMem32,\r
794                       PciResUsageTypical\r
795                       );\r
796 \r
797       PMem32Bridge = CreateResourceNode (\r
798                       RootBridgeDev,\r
799                       0,\r
800                       0xFFFFF,\r
801                       0,\r
802                       PciBarTypePMem32,\r
803                       PciResUsageTypical\r
804                       );\r
805 \r
806       Mem64Bridge = CreateResourceNode (\r
807                       RootBridgeDev,\r
808                       0,\r
809                       0xFFFFF,\r
810                       0,\r
811                       PciBarTypeMem64,\r
812                       PciResUsageTypical\r
813                       );\r
814 \r
815       PMem64Bridge = CreateResourceNode (\r
816                       RootBridgeDev,\r
817                       0,\r
818                       0xFFFFF,\r
819                       0,\r
820                       PciBarTypePMem64,\r
821                       PciResUsageTypical\r
822                       );\r
823 \r
824       //\r
825       // Create resourcemap by going through all the devices subject to this root bridge\r
826       //\r
827       Status = CreateResourceMap (\r
828                 RootBridgeDev,\r
829                 IoBridge,\r
830                 Mem32Bridge,\r
831                 PMem32Bridge,\r
832                 Mem64Bridge,\r
833                 PMem64Bridge\r
834                 );\r
835 \r
836       //\r
837       // Get the max ROM size that the root bridge can process\r
838       //\r
839       RootBridgeDev->RomSize = Mem32Bridge->Length;\r
840 \r
841       //\r
842       // Skip to enlarge the resource request during realloction\r
843       //\r
844       if (!ReAllocate) {\r
845         //\r
846         // Get Max Option Rom size for current root bridge\r
847         //\r
848         MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
849 \r
850         //\r
851         // Enlarger the mem32 resource to accomdate the option rom\r
852         // if the mem32 resource is not enough to hold the rom\r
853         //\r
854         if (MaxOptionRomSize > Mem32Bridge->Length) {\r
855 \r
856           Mem32Bridge->Length     = MaxOptionRomSize;\r
857           RootBridgeDev->RomSize  = MaxOptionRomSize;\r
858 \r
859           //\r
860           // Alignment should be adjusted as well\r
861           //\r
862           if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {\r
863             Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
864           }\r
865         }\r
866       }\r
867 \r
868       //\r
869       // Based on the all the resource tree, contruct ACPI resource node to\r
870       // submit the resource aperture to pci host bridge protocol\r
871       //\r
872       Status = ConstructAcpiResourceRequestor (\r
873                 RootBridgeDev,\r
874                 IoBridge,\r
875                 Mem32Bridge,\r
876                 PMem32Bridge,\r
877                 Mem64Bridge,\r
878                 PMem64Bridge,\r
879                 &AcpiConfig\r
880                 );\r
881 \r
882       //\r
883       // Insert these resource nodes into the database\r
884       //\r
885       InsertResourceNode (&IoPool, IoBridge);\r
886       InsertResourceNode (&Mem32Pool, Mem32Bridge);\r
887       InsertResourceNode (&PMem32Pool, PMem32Bridge);\r
888       InsertResourceNode (&Mem64Pool, Mem64Bridge);\r
889       InsertResourceNode (&PMem64Pool, PMem64Bridge);\r
890 \r
891       if (Status == EFI_SUCCESS) {\r
892         //\r
893         // Submit the resource requirement\r
894         //\r
895         Status = PciResAlloc->SubmitResources (\r
896                                 PciResAlloc,\r
897                                 RootBridgeDev->Handle,\r
898                                 AcpiConfig\r
899                                 );\r
900       }\r
901 \r
902       //\r
903       // Free acpi resource node\r
904       //\r
905       if (AcpiConfig != NULL) {\r
906         FreePool (AcpiConfig);\r
907       }\r
908 \r
909       if (EFI_ERROR (Status)) {\r
910         //\r
911         // Destroy all the resource tree\r
912         //\r
913         DestroyResourceTree (&IoPool);\r
914         DestroyResourceTree (&Mem32Pool);\r
915         DestroyResourceTree (&PMem32Pool);\r
916         DestroyResourceTree (&Mem64Pool);\r
917         DestroyResourceTree (&PMem64Pool);\r
918         return Status;\r
919       }\r
920     }\r
921 \r
922     //\r
923     // Notify pci bus driver starts to program the resource\r
924     //\r
925 \r
926     Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);\r
927 \r
928     if (!EFI_ERROR (Status)) {\r
929       //\r
930       // Allocation succeed, then continue the following\r
931       //\r
932       break;\r
933     }\r
934 \r
935     //\r
936     // If the resource allocation is unsuccessful, free resources on bridge\r
937     //\r
938 \r
939     RootBridgeDev     = NULL;\r
940     RootBridgeHandle  = 0;\r
941 \r
942     IoResStatus       = EFI_RESOURCE_SATISFIED;\r
943     Mem32ResStatus    = EFI_RESOURCE_SATISFIED;\r
944     PMem32ResStatus   = EFI_RESOURCE_SATISFIED;\r
945     Mem64ResStatus    = EFI_RESOURCE_SATISFIED;\r
946     PMem64ResStatus   = EFI_RESOURCE_SATISFIED;\r
947 \r
948     while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
949       //\r
950       // Get RootBridg Device by handle\r
951       //\r
952       RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
953       if (RootBridgeDev == NULL) {\r
954         return EFI_NOT_FOUND;\r
955       }\r
956 \r
957       //\r
958       // Get host bridge handle for status report\r
959       //\r
960       HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;\r
961 \r
962       //\r
963       // Get acpi resource node for all the resource types\r
964       //\r
965       AcpiConfig = NULL;\r
966 \r
967       Status = PciResAlloc->GetProposedResources (\r
968                               PciResAlloc,\r
969                               RootBridgeDev->Handle,\r
970                               &AcpiConfig\r
971                               );\r
972 \r
973       if (EFI_ERROR (Status)) {\r
974         return Status;\r
975       }\r
976 \r
977       if (AcpiConfig != NULL) {\r
978         //\r
979         // Adjust resource allocation policy for each RB\r
980         //\r
981         GetResourceAllocationStatus (\r
982           AcpiConfig,\r
983           &IoResStatus,\r
984           &Mem32ResStatus,\r
985           &PMem32ResStatus,\r
986           &Mem64ResStatus,\r
987           &PMem64ResStatus\r
988           );\r
989         FreePool (AcpiConfig);\r
990       }\r
991     }\r
992     //\r
993     // End while\r
994     //\r
995 \r
996     //\r
997     // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code\r
998     //\r
999     //\r
1000     // It is very difficult to follow the spec here\r
1001     // Device path , Bar index can not be get here\r
1002     //\r
1003     ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));\r
1004 \r
1005     REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1006           EFI_PROGRESS_CODE,\r
1007           EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,\r
1008           (VOID *) &AllocFailExtendedData,\r
1009           sizeof (AllocFailExtendedData)\r
1010           );\r
1011 \r
1012     Status = PciHostBridgeAdjustAllocation (\r
1013               &IoPool,\r
1014               &Mem32Pool,\r
1015               &PMem32Pool,\r
1016               &Mem64Pool,\r
1017               &PMem64Pool,\r
1018               IoResStatus,\r
1019               Mem32ResStatus,\r
1020               PMem32ResStatus,\r
1021               Mem64ResStatus,\r
1022               PMem64ResStatus\r
1023               );\r
1024 \r
1025     //\r
1026     // Destroy all the resource tree\r
1027     //\r
1028     DestroyResourceTree (&IoPool);\r
1029     DestroyResourceTree (&Mem32Pool);\r
1030     DestroyResourceTree (&PMem32Pool);\r
1031     DestroyResourceTree (&Mem64Pool);\r
1032     DestroyResourceTree (&PMem64Pool);\r
1033 \r
1034     NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);\r
1035 \r
1036     if (EFI_ERROR (Status)) {\r
1037       return Status;\r
1038     }\r
1039 \r
1040     ReAllocate = TRUE;\r
1041 \r
1042   }\r
1043   //\r
1044   // End main while\r
1045   //\r
1046 \r
1047   //\r
1048   // Raise the EFI_IOB_PCI_RES_ALLOC status code\r
1049   //\r
1050   REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1051         EFI_PROGRESS_CODE,\r
1052         EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,\r
1053         (VOID *) &HandleExtendedData,\r
1054         sizeof (HandleExtendedData)\r
1055         );\r
1056 \r
1057   //\r
1058   // Notify pci bus driver starts to program the resource\r
1059   //\r
1060   NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);\r
1061 \r
1062   RootBridgeDev     = NULL;\r
1063 \r
1064   RootBridgeHandle  = 0;\r
1065 \r
1066   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1067 \r
1068     //\r
1069     // Get RootBridg Device by handle\r
1070     //\r
1071     RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
1072 \r
1073     if (RootBridgeDev == NULL) {\r
1074       return EFI_NOT_FOUND;\r
1075     }\r
1076 \r
1077     //\r
1078     // Get acpi resource node for all the resource types\r
1079     //\r
1080     AcpiConfig = NULL;\r
1081     Status = PciResAlloc->GetProposedResources (\r
1082                             PciResAlloc,\r
1083                             RootBridgeDev->Handle,\r
1084                             &AcpiConfig\r
1085                             );\r
1086 \r
1087     if (EFI_ERROR (Status)) {\r
1088       return Status;\r
1089     }\r
1090 \r
1091     //\r
1092     // Get the resource base by interpreting acpi resource node\r
1093     //\r
1094     //\r
1095     GetResourceBase (\r
1096       AcpiConfig,\r
1097       &IoBase,\r
1098       &Mem32Base,\r
1099       &PMem32Base,\r
1100       &Mem64Base,\r
1101       &PMem64Base\r
1102       );\r
1103 \r
1104     //\r
1105     // Process option rom for this root bridge\r
1106     //\r
1107     Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);\r
1108 \r
1109     //\r
1110     // Create the entire system resource map from the information collected by\r
1111     // enumerator. Several resource tree was created\r
1112     //\r
1113     Status = GetResourceMap (\r
1114               RootBridgeDev,\r
1115               &IoBridge,\r
1116               &Mem32Bridge,\r
1117               &PMem32Bridge,\r
1118               &Mem64Bridge,\r
1119               &PMem64Bridge,\r
1120               &IoPool,\r
1121               &Mem32Pool,\r
1122               &PMem32Pool,\r
1123               &Mem64Pool,\r
1124               &PMem64Pool\r
1125               );\r
1126 \r
1127     if (EFI_ERROR (Status)) {\r
1128       return Status;\r
1129     }\r
1130 \r
1131     //\r
1132     // Program IO resources\r
1133     //\r
1134     ProgramResource (\r
1135       IoBase,\r
1136       IoBridge\r
1137       );\r
1138 \r
1139     //\r
1140     // Program Mem32 resources\r
1141     //\r
1142     ProgramResource (\r
1143       Mem32Base,\r
1144       Mem32Bridge\r
1145       );\r
1146 \r
1147     //\r
1148     // Program PMem32 resources\r
1149     //\r
1150     ProgramResource (\r
1151       PMem32Base,\r
1152       PMem32Bridge\r
1153       );\r
1154 \r
1155     //\r
1156     // Program Mem64 resources\r
1157     //\r
1158     ProgramResource (\r
1159       Mem64Base,\r
1160       Mem64Bridge\r
1161       );\r
1162 \r
1163     //\r
1164     // Program PMem64 resources\r
1165     //\r
1166     ProgramResource (\r
1167       PMem64Base,\r
1168       PMem64Bridge\r
1169       );\r
1170 \r
1171     if (AcpiConfig != NULL) {\r
1172       gBS->FreePool (AcpiConfig);\r
1173     }\r
1174   }\r
1175 \r
1176   //\r
1177   // Destroy all the resource tree\r
1178   //\r
1179   DestroyResourceTree (&IoPool);\r
1180   DestroyResourceTree (&Mem32Pool);\r
1181   DestroyResourceTree (&PMem32Pool);\r
1182   DestroyResourceTree (&Mem64Pool);\r
1183   DestroyResourceTree (&PMem64Pool);\r
1184 \r
1185   //\r
1186   // Notify the resource allocation phase is to end\r
1187   //\r
1188   NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);\r
1189 \r
1190   return EFI_SUCCESS;\r
1191 }\r
1192 \r
1193 \r
1194 EFI_STATUS\r
1195 PciScanBus (\r
1196   IN PCI_IO_DEVICE                      *Bridge,\r
1197   IN UINT8                              StartBusNumber,\r
1198   OUT UINT8                             *SubBusNumber,\r
1199   OUT UINT8                             *PaddedBusRange\r
1200   )\r
1201 {\r
1202   if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1203     return PciScanBus_WithHotPlugDeviceSupport (\r
1204       Bridge,\r
1205       StartBusNumber,\r
1206       SubBusNumber,\r
1207       PaddedBusRange\r
1208       );\r
1209   } else {\r
1210     return PciScanBus_WithoutHotPlugDeviceSupport (\r
1211       Bridge,\r
1212       StartBusNumber,\r
1213       SubBusNumber,\r
1214       PaddedBusRange\r
1215       );\r
1216   }\r
1217 }\r
1218 \r
1219 \r
1220 EFI_STATUS\r
1221 PciScanBus_WithoutHotPlugDeviceSupport (\r
1222   IN PCI_IO_DEVICE                      *Bridge,\r
1223   IN UINT8                              StartBusNumber,\r
1224   OUT UINT8                             *SubBusNumber,\r
1225   OUT UINT8                             *PaddedBusRange\r
1226   )\r
1227 /*++\r
1228 \r
1229 Routine Description:\r
1230 \r
1231   This routine is used to assign bus number to the given PCI bus system\r
1232 \r
1233 Arguments:\r
1234 \r
1235 Returns:\r
1236 \r
1237   None\r
1238 \r
1239 --*/\r
1240 // TODO:    Bridge - add argument and description to function comment\r
1241 // TODO:    StartBusNumber - add argument and description to function comment\r
1242 // TODO:    SubBusNumber - add argument and description to function comment\r
1243 // TODO:    PaddedBusRange - add argument and description to function comment\r
1244 // TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
1245 // TODO:    EFI_SUCCESS - add return value to function comment\r
1246 {\r
1247   EFI_STATUS                      Status;\r
1248   PCI_TYPE00                      Pci;\r
1249   UINT8                           Device;\r
1250   UINT8                           Func;\r
1251   UINT64                          Address;\r
1252   UINTN                           SecondBus;\r
1253   UINT16                          Register;\r
1254   PCI_IO_DEVICE                   *PciDevice;\r
1255   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1256 \r
1257   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1258   SecondBus       = 0;\r
1259   Register        = 0;\r
1260 \r
1261   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1262     for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1263 \r
1264       //\r
1265       // Check to see whether a pci device is present\r
1266       //\r
1267       Status = PciDevicePresent (\r
1268                 PciRootBridgeIo,\r
1269                 &Pci,\r
1270                 StartBusNumber,\r
1271                 Device,\r
1272                 Func\r
1273                 );\r
1274 \r
1275       if (!EFI_ERROR (Status)   &&\r
1276           (IS_PCI_BRIDGE (&Pci) ||\r
1277           IS_CARDBUS_BRIDGE (&Pci))) {\r
1278 \r
1279         DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));\r
1280 \r
1281         //\r
1282         // Get the bridge information\r
1283         //\r
1284         Status = PciSearchDevice (\r
1285                   Bridge,\r
1286                   &Pci,\r
1287                   StartBusNumber,\r
1288                   Device,\r
1289                   Func,\r
1290                   &PciDevice\r
1291                   );\r
1292 \r
1293         if (EFI_ERROR (Status)) {\r
1294           return Status;\r
1295         }\r
1296 \r
1297         //\r
1298         // Add feature to support customized secondary bus number\r
1299         //\r
1300         if (*SubBusNumber == 0) {\r
1301           *SubBusNumber   = *PaddedBusRange;\r
1302           *PaddedBusRange = 0;\r
1303         }\r
1304 \r
1305         (*SubBusNumber)++;\r
1306 \r
1307         SecondBus = (*SubBusNumber);\r
1308 \r
1309         Register  = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1310 \r
1311         Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
1312 \r
1313         Status = PciRootBridgeIoWrite (\r
1314                                         PciRootBridgeIo,\r
1315                                         &Pci,\r
1316                                         EfiPciWidthUint16,\r
1317                                         Address,\r
1318                                         1,\r
1319                                         &Register\r
1320                                         );\r
1321 \r
1322         //\r
1323         // Initialize SubBusNumber to SecondBus\r
1324         //\r
1325         Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1326         Status = PciRootBridgeIoWrite (\r
1327                                         PciRootBridgeIo,\r
1328                                         &Pci,\r
1329                                         EfiPciWidthUint8,\r
1330                                         Address,\r
1331                                         1,\r
1332                                         SubBusNumber\r
1333                                         );\r
1334         //\r
1335         // If it is PPB, resursively search down this bridge\r
1336         //\r
1337         if (IS_PCI_BRIDGE (&Pci)) {\r
1338           //\r
1339           // Temporarily initialize SubBusNumber to maximum bus number to ensure the\r
1340           // PCI configuration transaction to go through any PPB\r
1341           //\r
1342           Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1343           Register  = 0xFF;\r
1344           Status = PciRootBridgeIoWrite (\r
1345                                           PciRootBridgeIo,\r
1346                                           &Pci,\r
1347                                           EfiPciWidthUint8,\r
1348                                           Address,\r
1349                                           1,\r
1350                                           &Register\r
1351                                           );\r
1352 \r
1353           PreprocessController (\r
1354             PciDevice,\r
1355             PciDevice->BusNumber,\r
1356             PciDevice->DeviceNumber,\r
1357             PciDevice->FunctionNumber,\r
1358             EfiPciBeforeChildBusEnumeration\r
1359             );\r
1360 \r
1361           DEBUG((EFI_D_ERROR, "Scan  PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber ));\r
1362           Status = PciScanBus (\r
1363                     PciDevice,\r
1364                     (UINT8) (SecondBus),\r
1365                     SubBusNumber,\r
1366                     PaddedBusRange\r
1367                     );\r
1368 \r
1369           if (EFI_ERROR (Status)) {\r
1370             return EFI_DEVICE_ERROR;\r
1371           }\r
1372         }\r
1373 \r
1374         //\r
1375         // Set the current maximum bus number under the PPB\r
1376         //\r
1377 \r
1378         Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1379 \r
1380         Status = PciRootBridgeIoWrite (\r
1381                                         PciRootBridgeIo,\r
1382                                         &Pci,\r
1383                                         EfiPciWidthUint8,\r
1384                                         Address,\r
1385                                         1,\r
1386                                         SubBusNumber\r
1387                                         );\r
1388 \r
1389       }\r
1390 \r
1391       if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1392 \r
1393         //\r
1394         // Skip sub functions, this is not a multi function device\r
1395         //\r
1396 \r
1397         Func = PCI_MAX_FUNC;\r
1398       }\r
1399     }\r
1400   }\r
1401 \r
1402   return EFI_SUCCESS;\r
1403 }\r
1404 \r
1405 EFI_STATUS\r
1406 PciScanBus_WithHotPlugDeviceSupport (\r
1407   IN PCI_IO_DEVICE                      *Bridge,\r
1408   IN UINT8                              StartBusNumber,\r
1409   OUT UINT8                             *SubBusNumber,\r
1410   OUT UINT8                             *PaddedBusRange\r
1411   )\r
1412 /*++\r
1413 \r
1414 Routine Description:\r
1415 \r
1416   This routine is used to assign bus number to the given PCI bus system\r
1417 \r
1418 Arguments:\r
1419 \r
1420   Bridge         - A pointer to the PCI_IO_DEVICE structure.\r
1421   StartBusNumber - The start bus number.\r
1422   SubBusNumber   - A pointer to the sub bus number.\r
1423   PaddedBusRange - A pointer to the padded bus range.\r
1424 \r
1425 Returns:\r
1426 \r
1427   None\r
1428 \r
1429 --*/\r
1430 // TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
1431 // TODO:    EFI_SUCCESS - add return value to function comment\r
1432 {\r
1433   EFI_STATUS                        Status;\r
1434   PCI_TYPE00                        Pci;\r
1435   UINT8                             Device;\r
1436   UINT8                             Func;\r
1437   UINT64                            Address;\r
1438   UINTN                             SecondBus;\r
1439   UINT16                            Register;\r
1440   UINTN                             HpIndex;\r
1441   PCI_IO_DEVICE                     *PciDevice;\r
1442   EFI_EVENT                         Event;\r
1443   EFI_HPC_STATE                     State;\r
1444   UINT64                            PciAddress;\r
1445   EFI_HPC_PADDING_ATTRIBUTES        Attributes;\r
1446   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1447   UINT16                            BusRange;\r
1448   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;\r
1449   BOOLEAN                           BusPadding;\r
1450 \r
1451   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1452   SecondBus       = 0;\r
1453   Register        = 0;\r
1454   State           = 0;\r
1455   Attributes      = (EFI_HPC_PADDING_ATTRIBUTES) 0;\r
1456   BusRange        = 0;\r
1457 \r
1458   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1459     for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1460 \r
1461       //\r
1462       // Check to see whether a pci device is present\r
1463       //\r
1464       Status = PciDevicePresent (\r
1465                 PciRootBridgeIo,\r
1466                 &Pci,\r
1467                 StartBusNumber,\r
1468                 Device,\r
1469                 Func\r
1470                 );\r
1471 \r
1472       if (EFI_ERROR (Status)) {\r
1473         if (Func == 0) {\r
1474           //\r
1475           // Skip sub functions, this is not a multi function device\r
1476           //\r
1477           Func = PCI_MAX_FUNC;\r
1478         }\r
1479 \r
1480         continue;\r
1481       }\r
1482 \r
1483       DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));\r
1484 \r
1485       //\r
1486       // Get the PCI device information\r
1487       //\r
1488       Status = PciSearchDevice (\r
1489                 Bridge,\r
1490                 &Pci,\r
1491                 StartBusNumber,\r
1492                 Device,\r
1493                 Func,\r
1494                 &PciDevice\r
1495                 );\r
1496 \r
1497       ASSERT (!EFI_ERROR (Status));\r
1498 \r
1499       PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);\r
1500 \r
1501       if (!IS_PCI_BRIDGE (&Pci)) {\r
1502         //\r
1503         // PCI bridges will be called later\r
1504         // Here just need for PCI device or PCI to cardbus controller\r
1505         // EfiPciBeforeChildBusEnumeration for PCI Device Node\r
1506         //\r
1507         PreprocessController (\r
1508             PciDevice,\r
1509             PciDevice->BusNumber,\r
1510             PciDevice->DeviceNumber,\r
1511             PciDevice->FunctionNumber,\r
1512             EfiPciBeforeChildBusEnumeration\r
1513             );\r
1514       }\r
1515 \r
1516       //\r
1517       // For Pci Hotplug controller devcie only\r
1518       //\r
1519       if (gPciHotPlugInit != NULL) {\r
1520         //\r
1521         // Check if it is a Hotplug PCI controller\r
1522         //\r
1523         if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {\r
1524 \r
1525           if (!gPciRootHpcData[HpIndex].Initialized) {\r
1526 \r
1527             Status = CreateEventForHpc (HpIndex, &Event);\r
1528 \r
1529             ASSERT (!EFI_ERROR (Status));\r
1530 \r
1531             Status = gPciHotPlugInit->InitializeRootHpc (\r
1532                                         gPciHotPlugInit,\r
1533                                         gPciRootHpcPool[HpIndex].HpcDevicePath,\r
1534                                         PciAddress,\r
1535                                         Event,\r
1536                                         &State\r
1537                                         );\r
1538 \r
1539             PreprocessController (\r
1540               PciDevice,\r
1541               PciDevice->BusNumber,\r
1542               PciDevice->DeviceNumber,\r
1543               PciDevice->FunctionNumber,\r
1544               EfiPciBeforeChildBusEnumeration\r
1545             );\r
1546           }\r
1547         }\r
1548       }\r
1549 \r
1550       if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {\r
1551         //\r
1552         // For PPB\r
1553         // Get the bridge information\r
1554         //\r
1555         BusPadding = FALSE;\r
1556         if (gPciHotPlugInit != NULL) {\r
1557 \r
1558           if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {\r
1559 \r
1560             //\r
1561             // If it is initialized, get the padded bus range\r
1562             //\r
1563             Status = gPciHotPlugInit->GetResourcePadding (\r
1564                                         gPciHotPlugInit,\r
1565                                         gPciRootHpcPool[HpIndex].HpbDevicePath,\r
1566                                         PciAddress,\r
1567                                         &State,\r
1568                                         (VOID **) &Descriptors,\r
1569                                         &Attributes\r
1570                                         );\r
1571 \r
1572             if (EFI_ERROR (Status)) {\r
1573               return Status;\r
1574             }\r
1575 \r
1576             BusRange = 0;\r
1577             Status = PciGetBusRange (\r
1578                       &Descriptors,\r
1579                       NULL,\r
1580                       NULL,\r
1581                       &BusRange\r
1582                       );\r
1583 \r
1584             gBS->FreePool (Descriptors);\r
1585 \r
1586             if (EFI_ERROR (Status)) {\r
1587               return Status;\r
1588             }\r
1589 \r
1590             BusPadding = TRUE;\r
1591           }\r
1592         }\r
1593 \r
1594         //\r
1595         // Add feature to support customized secondary bus number\r
1596         //\r
1597         if (*SubBusNumber == 0) {\r
1598           *SubBusNumber   = *PaddedBusRange;\r
1599           *PaddedBusRange = 0;\r
1600         }\r
1601 \r
1602         (*SubBusNumber)++;\r
1603         SecondBus = *SubBusNumber;\r
1604 \r
1605         Register  = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1606         Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
1607 \r
1608         Status = PciRootBridgeIoWrite (\r
1609                                         PciRootBridgeIo,\r
1610                                         &Pci,\r
1611                                         EfiPciWidthUint16,\r
1612                                         Address,\r
1613                                         1,\r
1614                                         &Register\r
1615                                         );\r
1616 \r
1617 \r
1618         //\r
1619         // If it is PPB, resursively search down this bridge\r
1620         //\r
1621         if (IS_PCI_BRIDGE (&Pci)) {\r
1622 \r
1623           //\r
1624           // Initialize SubBusNumber to Maximum bus number\r
1625           //\r
1626           Register  = 0xFF;\r
1627           Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1628           Status = PciRootBridgeIoWrite (\r
1629                                           PciRootBridgeIo,\r
1630                                           &Pci,\r
1631                                           EfiPciWidthUint8,\r
1632                                           Address,\r
1633                                           1,\r
1634                                           &Register\r
1635                                           );\r
1636 \r
1637           //\r
1638           // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige\r
1639           //\r
1640           PreprocessController (\r
1641             PciDevice,\r
1642             PciDevice->BusNumber,\r
1643             PciDevice->DeviceNumber,\r
1644             PciDevice->FunctionNumber,\r
1645             EfiPciBeforeChildBusEnumeration\r
1646             );\r
1647 \r
1648           DEBUG((EFI_D_ERROR, "Scan  PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber ));\r
1649           Status = PciScanBus (\r
1650                     PciDevice,\r
1651                     (UINT8) (SecondBus),\r
1652                     SubBusNumber,\r
1653                     PaddedBusRange\r
1654                     );\r
1655 \r
1656           if (EFI_ERROR (Status)) {\r
1657             return EFI_DEVICE_ERROR;\r
1658           }\r
1659         }\r
1660 \r
1661         if (BusPadding) {\r
1662           //\r
1663           // Ensure the device is enabled and initialized\r
1664           //\r
1665           if ((Attributes == EfiPaddingPciRootBridge) &&\r
1666               (State & EFI_HPC_STATE_ENABLED)         &&\r
1667               (State & EFI_HPC_STATE_INITIALIZED)     ) {\r
1668             *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);\r
1669           } else {\r
1670             *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);\r
1671           }\r
1672         }\r
1673 \r
1674         //\r
1675         // Set the current maximum bus number under the PPB\r
1676         //\r
1677         Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1678 \r
1679         Status = PciRootBridgeIoWrite (\r
1680                                         PciRootBridgeIo,\r
1681                                         &Pci,\r
1682                                         EfiPciWidthUint8,\r
1683                                         Address,\r
1684                                         1,\r
1685                                         SubBusNumber\r
1686                                         );\r
1687       }\r
1688 \r
1689       if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1690 \r
1691         //\r
1692         // Skip sub functions, this is not a multi function device\r
1693         //\r
1694         Func = PCI_MAX_FUNC;\r
1695       }\r
1696 \r
1697     }\r
1698   }\r
1699 \r
1700   return EFI_SUCCESS;\r
1701 }\r
1702 \r
1703 EFI_STATUS\r
1704 PciRootBridgeP2CProcess (\r
1705   IN PCI_IO_DEVICE *Bridge\r
1706   )\r
1707 /*++\r
1708 \r
1709 Routine Description:\r
1710 \r
1711     Process Option Rom on this host bridge\r
1712 \r
1713 Arguments:\r
1714 \r
1715 Returns:\r
1716 \r
1717   None\r
1718 \r
1719 --*/\r
1720 // TODO:    Bridge - add argument and description to function comment\r
1721 // TODO:    EFI_SUCCESS - add return value to function comment\r
1722 {\r
1723   LIST_ENTRY      *CurrentLink;\r
1724   PCI_IO_DEVICE   *Temp;\r
1725   EFI_HPC_STATE   State;\r
1726   UINT64          PciAddress;\r
1727   EFI_STATUS      Status;\r
1728 \r
1729   CurrentLink = Bridge->ChildList.ForwardLink;\r
1730 \r
1731   while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
1732 \r
1733     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1734 \r
1735     if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {\r
1736 \r
1737       if (gPciHotPlugInit && Temp->Allocated) {\r
1738 \r
1739         //\r
1740         // Raise the EFI_IOB_PCI_HPC_INIT status code\r
1741         //\r
1742         REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1743           EFI_PROGRESS_CODE,\r
1744           EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,\r
1745           Temp->DevicePath\r
1746           );\r
1747 \r
1748         PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1749         Status = gPciHotPlugInit->InitializeRootHpc (\r
1750                                     gPciHotPlugInit,\r
1751                                     Temp->DevicePath,\r
1752                                     PciAddress,\r
1753                                     NULL,\r
1754                                     &State\r
1755                                     );\r
1756 \r
1757         if (!EFI_ERROR (Status)) {\r
1758           Status = PciBridgeEnumerator (Temp);\r
1759 \r
1760           if (EFI_ERROR (Status)) {\r
1761             return Status;\r
1762           }\r
1763         }\r
1764 \r
1765         CurrentLink = CurrentLink->ForwardLink;\r
1766         continue;\r
1767 \r
1768       }\r
1769     }\r
1770 \r
1771     if (!IsListEmpty (&Temp->ChildList)) {\r
1772       Status = PciRootBridgeP2CProcess (Temp);\r
1773     }\r
1774 \r
1775     CurrentLink = CurrentLink->ForwardLink;\r
1776   }\r
1777 \r
1778   return EFI_SUCCESS;\r
1779 }\r
1780 \r
1781 EFI_STATUS\r
1782 PciHostBridgeP2CProcess (\r
1783   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
1784   )\r
1785 /*++\r
1786 \r
1787 Routine Description:\r
1788 \r
1789 Arguments:\r
1790 \r
1791 Returns:\r
1792 \r
1793   None\r
1794 \r
1795 --*/\r
1796 // TODO:    PciResAlloc - add argument and description to function comment\r
1797 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1798 // TODO:    EFI_SUCCESS - add return value to function comment\r
1799 {\r
1800   EFI_HANDLE    RootBridgeHandle;\r
1801   PCI_IO_DEVICE *RootBridgeDev;\r
1802   EFI_STATUS    Status;\r
1803 \r
1804   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1805     return EFI_SUCCESS;\r
1806   }\r
1807 \r
1808   RootBridgeHandle = NULL;\r
1809 \r
1810   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1811 \r
1812     //\r
1813     // Get RootBridg Device by handle\r
1814     //\r
1815     RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
1816 \r
1817     if (RootBridgeDev == NULL) {\r
1818       return EFI_NOT_FOUND;\r
1819     }\r
1820 \r
1821     Status = PciRootBridgeP2CProcess (RootBridgeDev);\r
1822 \r
1823     if (EFI_ERROR (Status)) {\r
1824       return Status;\r
1825     }\r
1826 \r
1827   }\r
1828 \r
1829   return EFI_SUCCESS;\r
1830 }\r
1831 \r
1832 EFI_STATUS\r
1833 PciHostBridgeEnumerator (\r
1834   EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL  *PciResAlloc\r
1835   )\r
1836 /*++\r
1837 \r
1838 Routine Description:\r
1839 \r
1840   This function is used to enumerate the entire host bridge\r
1841   in a given platform\r
1842 \r
1843 Arguments:\r
1844 \r
1845   PciResAlloc   - A pointer to the resource allocate protocol.\r
1846 \r
1847 Returns:\r
1848 \r
1849   None\r
1850 \r
1851 --*/\r
1852 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
1853 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
1854 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
1855 // TODO:    EFI_SUCCESS - add return value to function comment\r
1856 {\r
1857   EFI_HANDLE                        RootBridgeHandle;\r
1858   PCI_IO_DEVICE                     *RootBridgeDev;\r
1859   EFI_STATUS                        Status;\r
1860   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;\r
1861   UINT16                            MinBus;\r
1862   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1863   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *pConfiguration;\r
1864   UINT8                             StartBusNumber;\r
1865   LIST_ENTRY                        RootBridgeList;\r
1866   LIST_ENTRY                        *Link;\r
1867 \r
1868   InitializeHotPlugSupport ();\r
1869 \r
1870   InitializeListHead (&RootBridgeList);\r
1871 \r
1872   //\r
1873   // Notify the bus allocation phase is about to start\r
1874   //\r
1875   NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1876 \r
1877   DEBUG((EFI_D_ERROR, "PCI Bus First Scanning\n"));\r
1878   RootBridgeHandle = NULL;\r
1879   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1880 \r
1881     //\r
1882     // if a root bridge instance is found, create root bridge device for it\r
1883     //\r
1884 \r
1885     RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1886 \r
1887     if (RootBridgeDev == NULL) {\r
1888       return EFI_OUT_OF_RESOURCES;\r
1889     }\r
1890 \r
1891     //\r
1892     // Enumerate all the buses under this root bridge\r
1893     //\r
1894 \r
1895     Status = PciRootBridgeEnumerator (\r
1896               PciResAlloc,\r
1897               RootBridgeDev\r
1898               );\r
1899 \r
1900     if (gPciHotPlugInit != NULL) {\r
1901       InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));\r
1902     } else {\r
1903       DestroyRootBridge (RootBridgeDev);\r
1904     }\r
1905     if (EFI_ERROR (Status)) {\r
1906       return Status;\r
1907     }\r
1908   }\r
1909 \r
1910   //\r
1911   // Notify the bus allocation phase is finished for the first time\r
1912   //\r
1913   NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1914 \r
1915   if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1916 \r
1917     if (gPciHotPlugInit != NULL) {\r
1918       //\r
1919       // Reset all assigned PCI bus number in all PPB\r
1920       //\r
1921       RootBridgeHandle = NULL;\r
1922       Link = GetFirstNode (&RootBridgeList);\r
1923       while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&\r
1924         (!IsNull (&RootBridgeList, Link))) {\r
1925         RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);\r
1926         //\r
1927         // Get the Bus information\r
1928         //\r
1929         Status = PciResAlloc->StartBusEnumeration (\r
1930                                 PciResAlloc,\r
1931                                 RootBridgeHandle,\r
1932                                 (VOID **) &pConfiguration\r
1933                                 );\r
1934         if (EFI_ERROR (Status)) {\r
1935           return Status;\r
1936         }\r
1937 \r
1938         //\r
1939         // Get the bus number to start with\r
1940         //\r
1941         StartBusNumber  = (UINT8) (pConfiguration->AddrRangeMin);\r
1942 \r
1943         ResetAllPpbBusNumber (\r
1944           RootBridgeDev,\r
1945           StartBusNumber\r
1946         );\r
1947 \r
1948         gBS->FreePool (pConfiguration);\r
1949         Link = GetNextNode (&RootBridgeList, Link);\r
1950         DestroyRootBridge (RootBridgeDev);\r
1951       }\r
1952 \r
1953       //\r
1954       // Wait for all HPC initialized\r
1955      //\r
1956       Status = AllRootHPCInitialized (STALL_1_SECOND * 15);\r
1957 \r
1958       if (EFI_ERROR (Status)) {\r
1959         return Status;\r
1960       }\r
1961 \r
1962       //\r
1963       // Notify the bus allocation phase is about to start for the 2nd time\r
1964       //\r
1965       NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1966 \r
1967       DEBUG((EFI_D_ERROR, "PCI Bus Second Scanning\n"));\r
1968       RootBridgeHandle = NULL;\r
1969       while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1970 \r
1971         //\r
1972         // if a root bridge instance is found, create root bridge device for it\r
1973         //\r
1974 \r
1975         RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1976 \r
1977         if (RootBridgeDev == NULL) {\r
1978           return EFI_OUT_OF_RESOURCES;\r
1979         }\r
1980 \r
1981         //\r
1982         // Enumerate all the buses under this root bridge\r
1983         //\r
1984 \r
1985         Status = PciRootBridgeEnumerator (\r
1986                   PciResAlloc,\r
1987                   RootBridgeDev\r
1988                   );\r
1989 \r
1990         DestroyRootBridge (RootBridgeDev);\r
1991         if (EFI_ERROR (Status)) {\r
1992           return Status;\r
1993         }\r
1994       }\r
1995 \r
1996       //\r
1997       // Notify the bus allocation phase is to end for the 2nd time\r
1998       //\r
1999       NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
2000     }\r
2001   }\r
2002 \r
2003   //\r
2004   // Notify the resource allocation phase is to start\r
2005   //\r
2006   NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);\r
2007 \r
2008   RootBridgeHandle = NULL;\r
2009   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
2010 \r
2011     //\r
2012     // if a root bridge instance is found, create root bridge device for it\r
2013     //\r
2014 \r
2015     RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
2016 \r
2017     if (RootBridgeDev == NULL) {\r
2018       return EFI_OUT_OF_RESOURCES;\r
2019     }\r
2020 \r
2021     Status = StartManagingRootBridge (RootBridgeDev);\r
2022 \r
2023     if (EFI_ERROR (Status)) {\r
2024       return Status;\r
2025     }\r
2026 \r
2027     PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;\r
2028     Status          = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2029 \r
2030     if (EFI_ERROR (Status)) {\r
2031       return Status;\r
2032     }\r
2033 \r
2034     Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);\r
2035 \r
2036     if (EFI_ERROR (Status)) {\r
2037       return Status;\r
2038     }\r
2039 \r
2040     //\r
2041     // Determine root bridge attribute by calling interface of Pcihostbridge\r
2042     // protocol\r
2043     //\r
2044     DetermineRootBridgeAttributes (\r
2045       PciResAlloc,\r
2046       RootBridgeDev\r
2047       );\r
2048 \r
2049     //\r
2050     // Collect all the resource information under this root bridge\r
2051     // A database that records all the information about pci device subject to this\r
2052     // root bridge will then be created\r
2053     //\r
2054     Status = PciPciDeviceInfoCollector (\r
2055               RootBridgeDev,\r
2056               (UINT8) MinBus\r
2057               );\r
2058 \r
2059     if (EFI_ERROR (Status)) {\r
2060       return Status;\r
2061     }\r
2062 \r
2063     InsertRootBridge (RootBridgeDev);\r
2064 \r
2065     //\r
2066     // Record the hostbridge handle\r
2067     //\r
2068     AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);\r
2069   }\r
2070 \r
2071   return EFI_SUCCESS;\r
2072 }\r
2073 \r
2074 /**\r
2075   Read PCI device configuration register by specified address.\r
2076 \r
2077   This function check the incompatiblilites on PCI device. Return the register\r
2078   value.\r
2079 \r
2080   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2081   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2082   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2083   @param  Width               Signifies the width of the memory operations.\r
2084   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2085   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2086                               write operations, the source buffer to write data from.\r
2087 \r
2088    @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2089    @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2090    @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2091    @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2092 \r
2093 **/\r
2094 STATIC\r
2095 EFI_STATUS\r
2096 ReadConfigData (\r
2097   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2098   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2099   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2100   IN       UINT64                                 Width,\r
2101   IN       UINT64                                 Address,\r
2102   IN OUT   VOID                                   *Buffer\r
2103   )\r
2104 {\r
2105   EFI_STATUS                    Status;\r
2106   UINT64                        AccessWidth;\r
2107   EFI_PCI_REGISTER_ACCESS_DATA  *PciRegisterAccessData;\r
2108   UINT64                        AccessAddress;\r
2109   UINTN                         Stride;\r
2110   UINT64                        TempBuffer;\r
2111   UINT8                         *Pointer;\r
2112 \r
2113   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2114 \r
2115   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2116     //\r
2117     // check access compatibility at first time\r
2118     //\r
2119     Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData);\r
2120 \r
2121     if (Status == EFI_SUCCESS) {\r
2122       //\r
2123       // there exist incompatibility on this operation\r
2124       //\r
2125       AccessWidth = Width;\r
2126 \r
2127       if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2128         AccessWidth = PciRegisterAccessData->Width;\r
2129       }\r
2130 \r
2131       AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2132 \r
2133       TempBuffer    = 0;\r
2134       Stride        = 0;\r
2135       Pointer       = (UINT8 *) &TempBuffer;\r
2136 \r
2137       while (1) {\r
2138 \r
2139         if (PciRootBridgeIo != NULL) {\r
2140           Status = PciRootBridgeIo->Pci.Read (\r
2141                          PciRootBridgeIo,\r
2142                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2143                          AccessAddress,\r
2144                          1,\r
2145                          Pointer\r
2146                          );\r
2147         } else if (PciIo != NULL) {\r
2148           Status = PciIo->Pci.Read (\r
2149                          PciIo,\r
2150                          (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2151                          (UINT32) AccessAddress,\r
2152                          1,\r
2153                          Pointer\r
2154                          );\r
2155         }\r
2156 \r
2157         if (Status != EFI_SUCCESS) {\r
2158           return Status;\r
2159         }\r
2160 \r
2161        Stride = (UINTN)1 << AccessWidth;\r
2162         AccessAddress += Stride;\r
2163         if (AccessAddress >= (Address + LShiftU64 (1ULL, (UINTN)Width))) {\r
2164           //\r
2165           // if all datas have been read, exist\r
2166           //\r
2167           break;\r
2168         }\r
2169 \r
2170         Pointer += Stride;\r
2171 \r
2172         if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2173           //\r
2174           // if current offset doesn't reach the end\r
2175           //\r
2176           continue;\r
2177         }\r
2178 \r
2179         FreePool (PciRegisterAccessData);\r
2180 \r
2181         //\r
2182         // continue checking access incompatibility\r
2183         //\r
2184         Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2185         if (Status == EFI_SUCCESS) {\r
2186           if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2187             AccessWidth = PciRegisterAccessData->Width;\r
2188           }\r
2189         }\r
2190       }\r
2191 \r
2192       FreePool (PciRegisterAccessData);\r
2193 \r
2194       switch (Width) {\r
2195       case EfiPciWidthUint8:\r
2196         * (UINT8 *) Buffer = (UINT8) TempBuffer;\r
2197         break;\r
2198       case EfiPciWidthUint16:\r
2199         * (UINT16 *) Buffer = (UINT16) TempBuffer;\r
2200         break;\r
2201       case EfiPciWidthUint32:\r
2202         * (UINT32 *) Buffer = (UINT32) TempBuffer;\r
2203         break;\r
2204       default:\r
2205         return EFI_UNSUPPORTED;\r
2206       }\r
2207 \r
2208       return Status;\r
2209     }\r
2210   }\r
2211   //\r
2212   // AccessWidth incompatible check not supportted\r
2213   // or, there doesn't exist incompatibility on this operation\r
2214   //\r
2215   if (PciRootBridgeIo != NULL) {\r
2216     Status = PciRootBridgeIo->Pci.Read (\r
2217                      PciRootBridgeIo,\r
2218                      (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2219                      Address,\r
2220                      1,\r
2221                      Buffer\r
2222                      );\r
2223 \r
2224   } else {\r
2225     Status = PciIo->Pci.Read (\r
2226                      PciIo,\r
2227                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2228                      (UINT32) Address,\r
2229                      1,\r
2230                      Buffer\r
2231                      );\r
2232   }\r
2233 \r
2234   return Status;\r
2235 }\r
2236 \r
2237 /**\r
2238   Update register value by checking PCI device incompatibility.\r
2239 \r
2240   This function check register value incompatibilites on PCI device. Return the register\r
2241   value.\r
2242 \r
2243   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2244   @param  AccessType          Access type, READ or WRITE.\r
2245   @Param  Address             The address within the PCI configuration space.\r
2246   @param  Buffer              Store the register data.\r
2247 \r
2248   @retval EFI_SUCCESS         The data has been updated.\r
2249 \r
2250 **/\r
2251 STATIC\r
2252 EFI_STATUS\r
2253 UpdateConfigData (\r
2254   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2255   IN       UINT64                                 AccessType,\r
2256   IN       UINT64                                 Width,\r
2257   IN       UINT64                                 Address,\r
2258   IN OUT   VOID                                   *Buffer\r
2259 )\r
2260 {\r
2261   EFI_STATUS                    Status;\r
2262   EFI_PCI_REGISTER_VALUE_DATA   *PciRegisterData;\r
2263   UINT32                        AndValue;\r
2264   UINT32                        OrValue;\r
2265   UINT32                        TempValue;\r
2266 \r
2267   //\r
2268   // check register value incompatibility\r
2269   //\r
2270   Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData);\r
2271 \r
2272   if (Status == EFI_SUCCESS) {\r
2273 \r
2274     AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Address & 0x3) * 8);\r
2275     OrValue  = ((UINT32) PciRegisterData->OrValue)  >> (((UINT8) Address & 0x3) * 8);\r
2276 \r
2277     TempValue = * (UINT32 *) Buffer;\r
2278     if (PciRegisterData->AndValue != VALUE_NOCARE) {\r
2279       TempValue &= AndValue;\r
2280     }\r
2281     if (PciRegisterData->OrValue != VALUE_NOCARE) {\r
2282       TempValue |= OrValue;\r
2283     }\r
2284 \r
2285     switch (Width) {\r
2286     case EfiPciWidthUint8:\r
2287       *(UINT8 *)Buffer = (UINT8) TempValue;\r
2288       break;\r
2289 \r
2290     case EfiPciWidthUint16:\r
2291       *(UINT16 *)Buffer = (UINT16) TempValue;\r
2292       break;\r
2293     case EfiPciWidthUint32:\r
2294       *(UINT32 *)Buffer = TempValue;\r
2295       break;\r
2296 \r
2297     default:\r
2298       return EFI_UNSUPPORTED;\r
2299     }\r
2300 \r
2301     FreePool (PciRegisterData);\r
2302   }\r
2303 \r
2304   return Status;\r
2305 }\r
2306 \r
2307 /**\r
2308   Write PCI device configuration register by specified address.\r
2309 \r
2310   This function check the incompatiblilites on PCI device, and write date\r
2311   into register.\r
2312 \r
2313   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2314   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2315   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2316   @param  Width               Signifies the width of the memory operations.\r
2317   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2318   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2319                               write operations, the source buffer to write data from.\r
2320 \r
2321    @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2322    @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2323    @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2324    @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2325 \r
2326 **/\r
2327 STATIC\r
2328 EFI_STATUS\r
2329 WriteConfigData (\r
2330   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2331   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2332   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2333   IN       UINT64                                 Width,\r
2334   IN       UINT64                                 Address,\r
2335   IN       VOID                                   *Buffer\r
2336   )\r
2337 {\r
2338   EFI_STATUS                    Status;\r
2339   UINT64                        AccessWidth;\r
2340   EFI_PCI_REGISTER_ACCESS_DATA  *PciRegisterAccessData;\r
2341   UINT64                        AccessAddress;\r
2342   UINTN                         Stride;\r
2343   UINT8                         *Pointer;\r
2344   UINT64                        Data;\r
2345   UINTN                         Shift;\r
2346 \r
2347   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2348 \r
2349   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2350     //\r
2351     // check access compatibility at first time\r
2352     //\r
2353     Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData);\r
2354 \r
2355     if (Status == EFI_SUCCESS) {\r
2356       //\r
2357       // there exist incompatibility on this operation\r
2358       //\r
2359       AccessWidth = Width;\r
2360 \r
2361       if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2362         AccessWidth = PciRegisterAccessData->Width;\r
2363       }\r
2364 \r
2365       AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2366 \r
2367       Stride        = 0;\r
2368       Pointer       = (UINT8 *) &Buffer;\r
2369       Data          = * (UINT64 *) Buffer;\r
2370 \r
2371       while (1) {\r
2372 \r
2373         if (AccessWidth > Width) {\r
2374           //\r
2375           // if actual access width is larger than orignal one, additional data need to be read back firstly\r
2376           //\r
2377           Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);\r
2378           if (Status != EFI_SUCCESS) {\r
2379             return Status;\r
2380           }\r
2381 \r
2382           //\r
2383           // check data read incompatibility\r
2384           //\r
2385           UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);\r
2386 \r
2387           Shift = (UINTN)(Address - AccessAddress) * 8;\r
2388           switch (Width) {\r
2389           case EfiPciWidthUint8:\r
2390             Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));\r
2391             break;\r
2392 \r
2393           case EfiPciWidthUint16:\r
2394             Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));\r
2395             break;\r
2396           }\r
2397 \r
2398           //\r
2399           // check data write incompatibility\r
2400           //\r
2401           UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, MultU64x32 (AccessAddress, 0xff), &Data);\r
2402         }\r
2403 \r
2404         if (PciRootBridgeIo != NULL) {\r
2405           Status = PciRootBridgeIo->Pci.Write (\r
2406                          PciRootBridgeIo,\r
2407                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2408                          AccessAddress,\r
2409                          1,\r
2410                          &Data\r
2411                          );\r
2412         } else {\r
2413           Status = PciIo->Pci.Write (\r
2414                          PciIo,\r
2415                          (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2416                          (UINT32) AccessAddress,\r
2417                          1,\r
2418                          &Data\r
2419                          );\r
2420         }\r
2421 \r
2422         if (Status != EFI_SUCCESS) {\r
2423           return Status;\r
2424         }\r
2425 \r
2426         Data = RShiftU64 (Data, ((1 << AccessWidth) * 8));\r
2427 \r
2428         Stride = (UINTN)1 << AccessWidth;\r
2429         AccessAddress += Stride;\r
2430         if (AccessAddress >= (Address + LShiftU64 (1ULL, (UINTN)Width))) {\r
2431           //\r
2432           // if all datas have been written, exist\r
2433           //\r
2434           break;\r
2435         }\r
2436 \r
2437         Pointer += Stride;\r
2438 \r
2439         if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2440           //\r
2441           // if current offset doesn't reach the end\r
2442           //\r
2443           continue;\r
2444         }\r
2445 \r
2446         FreePool (PciRegisterAccessData);\r
2447 \r
2448         //\r
2449         // continue checking access incompatibility\r
2450         //\r
2451         Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2452         if (Status == EFI_SUCCESS) {\r
2453           if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2454             AccessWidth = PciRegisterAccessData->Width;\r
2455           }\r
2456         }\r
2457       };\r
2458 \r
2459       FreePool (PciRegisterAccessData);\r
2460 \r
2461       return Status;\r
2462     }\r
2463 \r
2464   }\r
2465   //\r
2466   // AccessWidth incompatible check not supportted\r
2467   // or, there doesn't exist incompatibility on this operation\r
2468   //\r
2469   if (PciRootBridgeIo != NULL) {\r
2470     Status = PciRootBridgeIo->Pci.Write (\r
2471                      PciRootBridgeIo,\r
2472                      (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2473                      Address,\r
2474                      1,\r
2475                      Buffer\r
2476                      );\r
2477   } else {\r
2478     Status = PciIo->Pci.Write (\r
2479                    PciIo,\r
2480                    (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2481                    (UINT32) Address,\r
2482                    1,\r
2483                    Buffer\r
2484                    );\r
2485   }\r
2486 \r
2487   return Status;\r
2488 }\r
2489 \r
2490 /**\r
2491   Abstract PCI device device information.\r
2492 \r
2493   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2494   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2495   @param  Pci                 A pointer to PCI_TYPE00.\r
2496   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2497   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2498 \r
2499   @retval EFI_SUCCESS         Pci device device information has been abstracted.\r
2500 \r
2501 **/\r
2502 STATIC\r
2503 EFI_STATUS\r
2504 GetPciDeviceDeviceInfo (\r
2505   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2506   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2507   IN       PCI_TYPE00                             *Pci,              OPTIONAL\r
2508   IN       UINT64                                 Address,           OPTIONAL\r
2509   OUT      EFI_PCI_DEVICE_INFO                    *PciDeviceInfo\r
2510 )\r
2511 {\r
2512   EFI_STATUS                    Status;\r
2513   UINT64                        PciAddress;\r
2514   UINT32                        PciConfigData;\r
2515   PCI_IO_DEVICE                 *PciIoDevice;\r
2516 \r
2517   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2518 \r
2519   if (PciIo != NULL) {\r
2520     PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
2521 \r
2522     //\r
2523     // get pointer to PCI_TYPE00 from PciIoDevice\r
2524     //\r
2525     Pci = &PciIoDevice->Pci;\r
2526   }\r
2527 \r
2528   if (Pci == NULL) {\r
2529     //\r
2530     // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly\r
2531     //\r
2532     PciAddress = Address & 0xffffffffffffff00ULL;\r
2533     Status = PciRootBridgeIo->Pci.Read (\r
2534                                     PciRootBridgeIo,\r
2535                                     EfiPciWidthUint32,\r
2536                                     PciAddress,\r
2537                                     1,\r
2538                                     &PciConfigData\r
2539                                     );\r
2540 \r
2541     if (EFI_ERROR (Status)) {\r
2542       return Status;\r
2543     }\r
2544 \r
2545     if ((PciConfigData & 0xffff) == 0xffff) {\r
2546       return EFI_NOT_FOUND;\r
2547     }\r
2548 \r
2549     PciDeviceInfo->VendorID = PciConfigData & 0xffff;\r
2550     PciDeviceInfo->DeviceID = PciConfigData >> 16;\r
2551 \r
2552     Status = PciRootBridgeIo->Pci.Read (\r
2553                                     PciRootBridgeIo,\r
2554                                     EfiPciWidthUint32,\r
2555                                     PciAddress + 8,\r
2556                                     1,\r
2557                                     &PciConfigData\r
2558                                     );\r
2559     if (EFI_ERROR (Status)) {\r
2560       return Status;\r
2561     }\r
2562 \r
2563     PciDeviceInfo->RevisionID = PciConfigData & 0xf;\r
2564 \r
2565     Status = PciRootBridgeIo->Pci.Read (\r
2566                                     PciRootBridgeIo,\r
2567                                     EfiPciWidthUint32,\r
2568                                     PciAddress + 0x2c,\r
2569                                     1,\r
2570                                     &PciConfigData\r
2571                                     );\r
2572 \r
2573     if (EFI_ERROR (Status)) {\r
2574       return Status;\r
2575     }\r
2576 \r
2577     PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;\r
2578     PciDeviceInfo->SubsystemID = PciConfigData >> 16;\r
2579 \r
2580   } else {\r
2581     PciDeviceInfo->VendorID          = Pci->Hdr.VendorId;\r
2582     PciDeviceInfo->DeviceID          = Pci->Hdr.DeviceId;\r
2583     PciDeviceInfo->RevisionID        = Pci->Hdr.RevisionID;\r
2584     PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;\r
2585     PciDeviceInfo->SubsystemID       = Pci->Device.SubsystemID;\r
2586   }\r
2587 \r
2588   return EFI_SUCCESS;\r
2589 }\r
2590 \r
2591 /**\r
2592   Read PCI configuration space with incompatibility check.\r
2593 \r
2594   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2595   @param  PciIo               A pointer to the EFI_PCI_IO_PROTOCOL.\r
2596   @param  Pci                 A pointer to PCI_TYPE00.\r
2597   @param  Width               Signifies the width of the memory operations.\r
2598   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2599   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2600                               write operations, the source buffer to write data from.\r
2601 \r
2602   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2603   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2604   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2605   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2606 \r
2607 **/\r
2608 STATIC\r
2609 EFI_STATUS\r
2610 PciIncompatibilityCheckRead (\r
2611   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,   OPTIONAL\r
2612   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,             OPTIONAL\r
2613   IN       PCI_TYPE00                             *Pci,               OPTIONAL\r
2614   IN       UINTN                                  Width,\r
2615   IN       UINT64                                 Address,\r
2616   IN       UINTN                                  Count,\r
2617   IN OUT   VOID                                   *Buffer\r
2618 )\r
2619 {\r
2620   EFI_STATUS                    Status;\r
2621   EFI_PCI_DEVICE_INFO           PciDeviceInfo;\r
2622   UINT32                        Stride;\r
2623 \r
2624   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2625 \r
2626   //\r
2627   // get PCI device device information\r
2628   //\r
2629   Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2630   if (Status != EFI_SUCCESS) {\r
2631     return Status;\r
2632   }\r
2633 \r
2634   Stride = 1 << Width;\r
2635 \r
2636   for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) {\r
2637 \r
2638     //\r
2639     // read configuration register\r
2640     //\r
2641     Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer);\r
2642 \r
2643     if (Status != EFI_SUCCESS) {\r
2644       return Status;\r
2645     }\r
2646 \r
2647     //\r
2648     // update the data read from configuration register\r
2649     //\r
2650     if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2651       UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer);\r
2652     }\r
2653   }\r
2654 \r
2655   return EFI_SUCCESS;\r
2656 }\r
2657 \r
2658 /**\r
2659   Write PCI configuration space with incompatibility check.\r
2660 \r
2661   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2662   @param  PciIo               A pointer to the EFI_PCI_IO_PROTOCOL.\r
2663   @param  Pci                 A pointer to PCI_TYPE00.\r
2664   @param  Width               Signifies the width of the memory operations.\r
2665   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2666   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2667                               write operations, the source buffer to write data from.\r
2668 \r
2669   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2670   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2671   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2672   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2673 \r
2674 **/\r
2675 STATIC\r
2676 EFI_STATUS\r
2677 PciIncompatibilityCheckWrite (\r
2678   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,   OPTIONAL\r
2679   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,             OPTIONAL\r
2680   IN       PCI_TYPE00                             *Pci,               OPTIONAL\r
2681   IN       UINTN                                  Width,\r
2682   IN       UINT64                                 Address,\r
2683   IN       UINTN                                  Count,\r
2684   IN OUT   VOID                                   *Buffer\r
2685 )\r
2686 {\r
2687   EFI_STATUS                    Status;\r
2688   EFI_PCI_DEVICE_INFO           PciDeviceInfo;\r
2689   UINT32                        Stride;\r
2690   UINT64                        Data;\r
2691 \r
2692   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2693 \r
2694   //\r
2695   // get PCI device device information\r
2696   //\r
2697   Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2698   if (Status != EFI_SUCCESS) {\r
2699     return Status;\r
2700   }\r
2701 \r
2702   Stride = 1 << Width;\r
2703 \r
2704   for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) {\r
2705 \r
2706     Data = 0;\r
2707 \r
2708     switch (Width) {\r
2709     case EfiPciWidthUint8:\r
2710       Data = * (UINT8 *) Buffer;\r
2711       break;\r
2712     case EfiPciWidthUint16:\r
2713       Data = * (UINT16 *) Buffer;\r
2714       break;\r
2715 \r
2716     case EfiPciWidthUint32:\r
2717       Data = * (UINT32 *) Buffer;\r
2718       break;\r
2719 \r
2720     default:\r
2721       return EFI_UNSUPPORTED;\r
2722     }\r
2723 \r
2724     //\r
2725     // update the data writen into configuration register\r
2726     //\r
2727     if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2728       UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data);\r
2729     }\r
2730 \r
2731     //\r
2732     // write configuration register\r
2733     //\r
2734     Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data);\r
2735 \r
2736     if (Status != EFI_SUCCESS) {\r
2737       return Status;\r
2738     }\r
2739   }\r
2740 \r
2741   return EFI_SUCCESS;\r
2742 }\r
2743 \r
2744 /**\r
2745   Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2746 \r
2747   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2748   @param  Pci                 A pointer to PCI_TYPE00.\r
2749   @param  Width               Signifies the width of the memory operations.\r
2750   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2751   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2752                               write operations, the source buffer to write data from.\r
2753 \r
2754   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2755   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2756   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2757   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2758 \r
2759 **/\r
2760 EFI_STATUS\r
2761 PciRootBridgeIoRead (\r
2762   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,\r
2763   IN       PCI_TYPE00                             *Pci,            OPTIONAL\r
2764   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
2765   IN       UINT64                                 Address,\r
2766   IN       UINTN                                  Count,\r
2767   IN OUT   VOID                                   *Buffer\r
2768   )\r
2769 {\r
2770   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2771     //\r
2772     // if PCI incompatibility check enabled\r
2773     //\r
2774     return PciIncompatibilityCheckRead (\r
2775                    PciRootBridgeIo,\r
2776                    NULL,\r
2777                    Pci,\r
2778                    (UINTN) Width,\r
2779                    Address,\r
2780                    Count,\r
2781                    Buffer\r
2782                    );\r
2783   } else {\r
2784     return PciRootBridgeIo->Pci.Read (\r
2785                    PciRootBridgeIo,\r
2786                    Width,\r
2787                    Address,\r
2788                    Count,\r
2789                    Buffer\r
2790                    );\r
2791   }\r
2792 }\r
2793 \r
2794 /**\r
2795   Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2796 \r
2797   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2798   @param  Pci                 A pointer to PCI_TYPE00.\r
2799   @param  Width               Signifies the width of the memory operations.\r
2800   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2801   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2802                               write operations, the source buffer to write data from.\r
2803 \r
2804   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2805   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2806   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2807   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2808 \r
2809 **/\r
2810 EFI_STATUS\r
2811 PciRootBridgeIoWrite (\r
2812   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,\r
2813   IN       PCI_TYPE00                             *Pci,\r
2814   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
2815   IN       UINT64                                 Address,\r
2816   IN       UINTN                                  Count,\r
2817   IN OUT   VOID                                   *Buffer\r
2818   )\r
2819 {\r
2820   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2821     //\r
2822     // if PCI incompatibility check enabled\r
2823     //\r
2824     return  PciIncompatibilityCheckWrite (\r
2825                    PciRootBridgeIo,\r
2826                    NULL,\r
2827                    Pci,\r
2828                    Width,\r
2829                    Address,\r
2830                    Count,\r
2831                    Buffer\r
2832                    );\r
2833 \r
2834   } else {\r
2835     return  PciRootBridgeIo->Pci.Write (\r
2836                    PciRootBridgeIo,\r
2837                    Width,\r
2838                    Address,\r
2839                    Count,\r
2840                    Buffer\r
2841                    );\r
2842   }\r
2843 }\r
2844 \r
2845 /**\r
2846   Read PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2847 \r
2848   @param  PciIo               A pointer to the EFI_PCI_O_PROTOCOL.\r
2849   @param  Width               Signifies the width of the memory operations.\r
2850   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2851   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2852                               write operations, the source buffer to write data from.\r
2853 \r
2854   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2855   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2856   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2857   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2858 \r
2859 **/\r
2860 EFI_STATUS\r
2861 PciIoRead (\r
2862   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,\r
2863   IN       EFI_PCI_IO_PROTOCOL_WIDTH              Width,\r
2864   IN       UINT32                                 Address,\r
2865   IN       UINTN                                  Count,\r
2866   IN OUT   VOID                                   *Buffer\r
2867   )\r
2868 {\r
2869   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2870     //\r
2871     // if PCI incompatibility check enabled\r
2872     //\r
2873     return PciIncompatibilityCheckRead (\r
2874                    NULL,\r
2875                    PciIo,\r
2876                    NULL,\r
2877                    (UINTN) Width,\r
2878                    Address,\r
2879                    Count,\r
2880                    Buffer\r
2881                    );\r
2882   } else {\r
2883     return PciIo->Pci.Read (\r
2884                    PciIo,\r
2885                    Width,\r
2886                    Address,\r
2887                    Count,\r
2888                    Buffer\r
2889                    );\r
2890   }\r
2891 }\r
2892 \r
2893 /**\r
2894   Write PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2895 \r
2896   @param  PciIo               A pointer to the EFI_PCI_O_PROTOCOL.\r
2897   @param  Width               Signifies the width of the memory operations.\r
2898   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2899   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2900                               write operations, the source buffer to write data from.\r
2901 \r
2902   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2903   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2904   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2905   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2906 \r
2907 **/\r
2908 EFI_STATUS\r
2909 PciIoWrite (\r
2910   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,\r
2911   IN       EFI_PCI_IO_PROTOCOL_WIDTH              Width,\r
2912   IN       UINT32                                 Address,\r
2913   IN       UINTN                                  Count,\r
2914   IN OUT   VOID                                   *Buffer\r
2915   )\r
2916 {\r
2917   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2918 \r
2919     //\r
2920     // if PCI incompatibility check enabled\r
2921     //\r
2922     return  PciIncompatibilityCheckWrite (\r
2923                    NULL,\r
2924                    PciIo,\r
2925                    NULL,\r
2926                    Width,\r
2927                    Address,\r
2928                    Count,\r
2929                    Buffer\r
2930                    );\r
2931 \r
2932   } else {\r
2933     return PciIo->Pci.Write (\r
2934                    PciIo,\r
2935                    Width,\r
2936                    Address,\r
2937                    Count,\r
2938                    Buffer\r
2939                    );\r
2940   }\r
2941 }\r