PCI Bus Driver Enhancement
[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, 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 \r
1864   InitializeHotPlugSupport ();\r
1865 \r
1866   //\r
1867   // Notify the bus allocation phase is about to start\r
1868   //\r
1869   NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1870 \r
1871   DEBUG((EFI_D_ERROR, "PCI Bus First Scanning\n"));\r
1872   RootBridgeHandle = NULL;\r
1873   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1874 \r
1875     //\r
1876     // if a root bridge instance is found, create root bridge device for it\r
1877     //\r
1878 \r
1879     RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1880 \r
1881     if (RootBridgeDev == NULL) {\r
1882       return EFI_OUT_OF_RESOURCES;\r
1883     }\r
1884 \r
1885     //\r
1886     // Enumerate all the buses under this root bridge\r
1887     //\r
1888 \r
1889     Status = PciRootBridgeEnumerator (\r
1890               PciResAlloc,\r
1891               RootBridgeDev\r
1892               );\r
1893 \r
1894     DestroyRootBridge (RootBridgeDev);\r
1895     if (EFI_ERROR (Status)) {\r
1896       return Status;\r
1897     }\r
1898   }\r
1899 \r
1900   //\r
1901   // Notify the bus allocation phase is finished for the first time\r
1902   //\r
1903   NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1904 \r
1905   if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1906 \r
1907     if (gPciHotPlugInit != NULL) {\r
1908       //\r
1909       // Wait for all HPC initialized\r
1910       //\r
1911       Status = AllRootHPCInitialized (STALL_1_SECOND * 15);\r
1912 \r
1913       if (EFI_ERROR (Status)) {\r
1914         return Status;\r
1915       }\r
1916 \r
1917       //\r
1918       // Notify the bus allocation phase is about to start for the 2nd time\r
1919       //\r
1920       NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1921 \r
1922       DEBUG((EFI_D_ERROR, "PCI Bus Second Scanning\n"));  \r
1923       RootBridgeHandle = NULL;\r
1924       while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1925 \r
1926         //\r
1927         // if a root bridge instance is found, create root bridge device for it\r
1928         //\r
1929 \r
1930         RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1931 \r
1932         if (RootBridgeDev == NULL) {\r
1933           return EFI_OUT_OF_RESOURCES;\r
1934         }\r
1935 \r
1936         //\r
1937         // Enumerate all the buses under this root bridge\r
1938         //\r
1939 \r
1940         Status = PciRootBridgeEnumerator (\r
1941                   PciResAlloc,\r
1942                   RootBridgeDev\r
1943                   );\r
1944 \r
1945         DestroyRootBridge (RootBridgeDev);\r
1946         if (EFI_ERROR (Status)) {\r
1947           return Status;\r
1948         }\r
1949       }\r
1950 \r
1951       //\r
1952       // Notify the bus allocation phase is to end for the 2nd time\r
1953       //\r
1954       NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1955     }\r
1956   }\r
1957 \r
1958   //\r
1959   // Notify the resource allocation phase is to start\r
1960   //\r
1961   NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);\r
1962 \r
1963   RootBridgeHandle = NULL;\r
1964   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1965 \r
1966     //\r
1967     // if a root bridge instance is found, create root bridge device for it\r
1968     //\r
1969 \r
1970     RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1971 \r
1972     if (RootBridgeDev == NULL) {\r
1973       return EFI_OUT_OF_RESOURCES;\r
1974     }\r
1975 \r
1976     Status = StartManagingRootBridge (RootBridgeDev);\r
1977 \r
1978     if (EFI_ERROR (Status)) {\r
1979       return Status;\r
1980     }\r
1981 \r
1982     PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;\r
1983     Status          = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1984 \r
1985     if (EFI_ERROR (Status)) {\r
1986       return Status;\r
1987     }\r
1988 \r
1989     Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);\r
1990 \r
1991     if (EFI_ERROR (Status)) {\r
1992       return Status;\r
1993     }\r
1994 \r
1995     //\r
1996     // Determine root bridge attribute by calling interface of Pcihostbridge\r
1997     // protocol\r
1998     //\r
1999     DetermineRootBridgeAttributes (\r
2000       PciResAlloc,\r
2001       RootBridgeDev\r
2002       );\r
2003 \r
2004     //\r
2005     // Collect all the resource information under this root bridge\r
2006     // A database that records all the information about pci device subject to this\r
2007     // root bridge will then be created\r
2008     //\r
2009     Status = PciPciDeviceInfoCollector (\r
2010               RootBridgeDev,\r
2011               (UINT8) MinBus\r
2012               );\r
2013 \r
2014     if (EFI_ERROR (Status)) {\r
2015       return Status;\r
2016     }\r
2017 \r
2018     InsertRootBridge (RootBridgeDev);\r
2019 \r
2020     //\r
2021     // Record the hostbridge handle\r
2022     //\r
2023     AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);\r
2024   }\r
2025 \r
2026   return EFI_SUCCESS;\r
2027 }\r
2028 \r
2029 /**\r
2030   Read PCI device configuration register by specified address.\r
2031 \r
2032   This function check the incompatiblilites on PCI device. Return the register\r
2033   value.\r
2034 \r
2035   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2036   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2037   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2038   @param  Width               Signifies the width of the memory operations.\r
2039   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2040   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2041                               write operations, the source buffer to write data from.\r
2042 \r
2043    @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2044    @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2045    @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2046    @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2047 \r
2048 **/\r
2049 STATIC\r
2050 EFI_STATUS\r
2051 ReadConfigData (\r
2052   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2053   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2054   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2055   IN       UINT64                                 Width,\r
2056   IN       UINT64                                 Address,\r
2057   IN OUT   VOID                                   *Buffer\r
2058   )\r
2059 {\r
2060   EFI_STATUS                    Status;\r
2061   UINT64                        AccessWidth;\r
2062   EFI_PCI_REGISTER_ACCESS_DATA  *PciRegisterAccessData;\r
2063   UINT64                        AccessAddress;\r
2064   UINTN                         Stride;\r
2065   UINT64                        TempBuffer;\r
2066   UINT8                         *Pointer;\r
2067 \r
2068   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2069 \r
2070   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2071     //\r
2072     // check access compatibility at first time\r
2073     //\r
2074     Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData);\r
2075 \r
2076     if (Status == EFI_SUCCESS) {\r
2077       //\r
2078       // there exist incompatibility on this operation\r
2079       //\r
2080       AccessWidth = Width;\r
2081 \r
2082       if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2083         AccessWidth = PciRegisterAccessData->Width;\r
2084       }\r
2085 \r
2086       AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2087 \r
2088       TempBuffer    = 0;\r
2089       Stride        = 0;\r
2090       Pointer       = (UINT8 *) &TempBuffer;\r
2091 \r
2092       while (1) {\r
2093 \r
2094         if (PciRootBridgeIo != NULL) {\r
2095           Status = PciRootBridgeIo->Pci.Read (\r
2096                          PciRootBridgeIo,\r
2097                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2098                          AccessAddress,\r
2099                          1,\r
2100                          Pointer\r
2101                          );\r
2102         } else if (PciIo != NULL) {\r
2103           Status = PciIo->Pci.Read (\r
2104                          PciIo,\r
2105                          (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2106                          (UINT32) AccessAddress,\r
2107                          1,\r
2108                          Pointer\r
2109                          );\r
2110         }\r
2111 \r
2112         if (Status != EFI_SUCCESS) {\r
2113           return Status;\r
2114         }\r
2115 \r
2116        Stride = 1 << AccessWidth;\r
2117         AccessAddress += Stride;\r
2118         if (AccessAddress >= (Address + (1 << Width))) {\r
2119           //\r
2120           // if all datas have been read, exist\r
2121           //\r
2122           break;\r
2123         }\r
2124 \r
2125         Pointer += Stride;\r
2126 \r
2127         if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2128           //\r
2129           // if current offset doesn't reach the end\r
2130           //\r
2131           continue;\r
2132         }\r
2133 \r
2134         FreePool (PciRegisterAccessData);\r
2135 \r
2136         //\r
2137         // continue checking access incompatibility\r
2138         //\r
2139         Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2140         if (Status == EFI_SUCCESS) {\r
2141           if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2142             AccessWidth = PciRegisterAccessData->Width;\r
2143           }\r
2144         }\r
2145       }\r
2146 \r
2147       FreePool (PciRegisterAccessData);\r
2148 \r
2149       switch (Width) {\r
2150       case EfiPciWidthUint8:\r
2151         * (UINT8 *) Buffer = (UINT8) TempBuffer;\r
2152         break;\r
2153       case EfiPciWidthUint16:\r
2154         * (UINT16 *) Buffer = (UINT16) TempBuffer;\r
2155         break;\r
2156       case EfiPciWidthUint32:\r
2157         * (UINT32 *) Buffer = (UINT32) TempBuffer;\r
2158         break;\r
2159       default:\r
2160         return EFI_UNSUPPORTED;\r
2161       }\r
2162 \r
2163       return Status;\r
2164     }\r
2165   }\r
2166   //\r
2167   // AccessWidth incompatible check not supportted\r
2168   // or, there doesn't exist incompatibility on this operation\r
2169   //\r
2170   if (PciRootBridgeIo != NULL) {\r
2171     Status = PciRootBridgeIo->Pci.Read (\r
2172                      PciRootBridgeIo,\r
2173                      (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2174                      Address,\r
2175                      1,\r
2176                      Buffer\r
2177                      );\r
2178 \r
2179   } else {\r
2180     Status = PciIo->Pci.Read (\r
2181                      PciIo,\r
2182                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2183                      (UINT32) Address,\r
2184                      1,\r
2185                      Buffer\r
2186                      );\r
2187   }\r
2188 \r
2189   return Status;\r
2190 }\r
2191 \r
2192 /**\r
2193   Update register value by checking PCI device incompatibility.\r
2194 \r
2195   This function check register value incompatibilites on PCI device. Return the register\r
2196   value.\r
2197 \r
2198   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2199   @param  AccessType          Access type, READ or WRITE.\r
2200   @Param  Address             The address within the PCI configuration space.\r
2201   @param  Buffer              Store the register data.\r
2202 \r
2203   @retval EFI_SUCCESS         The data has been updated.\r
2204 \r
2205 **/\r
2206 STATIC\r
2207 EFI_STATUS\r
2208 UpdateConfigData (\r
2209   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2210   IN       UINT64                                 AccessType,\r
2211   IN       UINT64                                 Width,\r
2212   IN       UINT64                                 Address,\r
2213   IN OUT   VOID                                   *Buffer\r
2214 )\r
2215 {\r
2216   EFI_STATUS                    Status;\r
2217   EFI_PCI_REGISTER_VALUE_DATA   *PciRegisterData;\r
2218   UINT32                        AndValue;\r
2219   UINT32                        OrValue;\r
2220   UINT32                        TempValue;\r
2221 \r
2222   //\r
2223   // check register value incompatibility\r
2224   //\r
2225   Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData);\r
2226 \r
2227   if (Status == EFI_SUCCESS) {\r
2228 \r
2229     AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Address & 0x3) * 8);\r
2230     OrValue  = ((UINT32) PciRegisterData->OrValue)  >> (((UINT8) Address & 0x3) * 8);\r
2231 \r
2232     TempValue = * (UINT32 *) Buffer;\r
2233     if (PciRegisterData->AndValue != VALUE_NOCARE) {\r
2234       TempValue &= AndValue;\r
2235     }\r
2236     if (PciRegisterData->OrValue != VALUE_NOCARE) {\r
2237       TempValue |= OrValue;\r
2238     }\r
2239 \r
2240     switch (Width) {\r
2241     case EfiPciWidthUint8:\r
2242       *(UINT8 *)Buffer = (UINT8) TempValue;\r
2243       break;\r
2244 \r
2245     case EfiPciWidthUint16:\r
2246       *(UINT16 *)Buffer = (UINT16) TempValue;\r
2247       break;\r
2248     case EfiPciWidthUint32:\r
2249       *(UINT32 *)Buffer = TempValue;\r
2250       break;\r
2251 \r
2252     default:\r
2253       return EFI_UNSUPPORTED;\r
2254     }\r
2255 \r
2256     FreePool (PciRegisterData);\r
2257   }\r
2258 \r
2259   return Status;\r
2260 }\r
2261 \r
2262 /**\r
2263   Write PCI device configuration register by specified address.\r
2264 \r
2265   This function check the incompatiblilites on PCI device, and write date\r
2266   into register.\r
2267 \r
2268   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2269   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2270   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2271   @param  Width               Signifies the width of the memory operations.\r
2272   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2273   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2274                               write operations, the source buffer to write data from.\r
2275 \r
2276    @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2277    @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2278    @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2279    @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2280 \r
2281 **/\r
2282 STATIC\r
2283 EFI_STATUS\r
2284 WriteConfigData (\r
2285   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2286   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2287   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2288   IN       UINT64                                 Width,\r
2289   IN       UINT64                                 Address,\r
2290   IN       VOID                                   *Buffer\r
2291   )\r
2292 {\r
2293   EFI_STATUS                    Status;\r
2294   UINT64                        AccessWidth;\r
2295   EFI_PCI_REGISTER_ACCESS_DATA  *PciRegisterAccessData;\r
2296   UINT64                        AccessAddress;\r
2297   UINTN                         Stride;\r
2298   UINT8                         *Pointer;\r
2299   UINT64                        Data;\r
2300   UINTN                         Shift;\r
2301 \r
2302   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2303 \r
2304   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2305     //\r
2306     // check access compatibility at first time\r
2307     //\r
2308     Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData);\r
2309 \r
2310     if (Status == EFI_SUCCESS) {\r
2311       //\r
2312       // there exist incompatibility on this operation\r
2313       //\r
2314       AccessWidth = Width;\r
2315 \r
2316       if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2317         AccessWidth = PciRegisterAccessData->Width;\r
2318       }\r
2319 \r
2320       AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2321 \r
2322       Stride        = 0;\r
2323       Pointer       = (UINT8 *) &Buffer;\r
2324       Data          = * (UINT64 *) Buffer;\r
2325 \r
2326       while (1) {\r
2327 \r
2328         if (AccessWidth > Width) {\r
2329           //\r
2330           // if actual access width is larger than orignal one, additional data need to be read back firstly\r
2331           //\r
2332           Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);\r
2333           if (Status != EFI_SUCCESS) {\r
2334             return Status;\r
2335           }\r
2336 \r
2337           //\r
2338           // check data read incompatibility\r
2339           //\r
2340           UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);\r
2341 \r
2342           Shift = (UINTN)(Address - AccessAddress) * 8;\r
2343           switch (Width) {\r
2344           case EfiPciWidthUint8:\r
2345             Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));\r
2346             break;\r
2347 \r
2348           case EfiPciWidthUint16:\r
2349             Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));\r
2350             break;\r
2351           }\r
2352 \r
2353           //\r
2354           // check data write incompatibility\r
2355           //\r
2356           UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, MultU64x32 (AccessAddress, 0xff), &Data);\r
2357         }\r
2358 \r
2359         if (PciRootBridgeIo != NULL) {\r
2360           Status = PciRootBridgeIo->Pci.Write (\r
2361                          PciRootBridgeIo,\r
2362                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2363                          AccessAddress,\r
2364                          1,\r
2365                          &Data\r
2366                          );\r
2367         } else {\r
2368           Status = PciIo->Pci.Write (\r
2369                          PciIo,\r
2370                          (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2371                          (UINT32) AccessAddress,\r
2372                          1,\r
2373                          &Data\r
2374                          );\r
2375         }\r
2376 \r
2377         if (Status != EFI_SUCCESS) {\r
2378           return Status;\r
2379         }\r
2380 \r
2381         Data = RShiftU64 (Data, ((1 << AccessWidth) * 8));\r
2382 \r
2383         Stride = 1 << AccessWidth;\r
2384         AccessAddress += Stride;\r
2385         if (AccessAddress >= (Address + (1 << Width))) {\r
2386           //\r
2387           // if all datas have been written, exist\r
2388           //\r
2389           break;\r
2390         }\r
2391 \r
2392         Pointer += Stride;\r
2393 \r
2394         if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2395           //\r
2396           // if current offset doesn't reach the end\r
2397           //\r
2398           continue;\r
2399         }\r
2400 \r
2401         FreePool (PciRegisterAccessData);\r
2402 \r
2403         //\r
2404         // continue checking access incompatibility\r
2405         //\r
2406         Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2407         if (Status == EFI_SUCCESS) {\r
2408           if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2409             AccessWidth = PciRegisterAccessData->Width;\r
2410           }\r
2411         }\r
2412       };\r
2413 \r
2414       FreePool (PciRegisterAccessData);\r
2415 \r
2416       return Status;\r
2417     }\r
2418 \r
2419   }\r
2420   //\r
2421   // AccessWidth incompatible check not supportted\r
2422   // or, there doesn't exist incompatibility on this operation\r
2423   //\r
2424   if (PciRootBridgeIo != NULL) {\r
2425     Status = PciRootBridgeIo->Pci.Write (\r
2426                      PciRootBridgeIo,\r
2427                      (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2428                      Address,\r
2429                      1,\r
2430                      Buffer\r
2431                      );\r
2432   } else {\r
2433     Status = PciIo->Pci.Write (\r
2434                    PciIo,\r
2435                    (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2436                    (UINT32) Address,\r
2437                    1,\r
2438                    Buffer\r
2439                    );\r
2440   }\r
2441 \r
2442   return Status;\r
2443 }\r
2444 \r
2445 /**\r
2446   Abstract PCI device device information.\r
2447 \r
2448   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2449   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2450   @param  Pci                 A pointer to PCI_TYPE00.\r
2451   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2452   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2453 \r
2454   @retval EFI_SUCCESS         Pci device device information has been abstracted.\r
2455 \r
2456 **/\r
2457 STATIC\r
2458 EFI_STATUS\r
2459 GetPciDeviceDeviceInfo (\r
2460   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2461   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2462   IN       PCI_TYPE00                             *Pci,              OPTIONAL\r
2463   IN       UINT64                                 Address,           OPTIONAL\r
2464   OUT      EFI_PCI_DEVICE_INFO                    *PciDeviceInfo\r
2465 )\r
2466 {\r
2467   EFI_STATUS                    Status;\r
2468   UINT64                        PciAddress;\r
2469   UINT32                        PciConfigData;\r
2470   PCI_IO_DEVICE                 *PciIoDevice;\r
2471 \r
2472   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2473 \r
2474   if (PciIo != NULL) {\r
2475     PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
2476 \r
2477     //\r
2478     // get pointer to PCI_TYPE00 from PciIoDevice\r
2479     //\r
2480     Pci = &PciIoDevice->Pci;\r
2481   }\r
2482 \r
2483   if (Pci == NULL) {\r
2484     //\r
2485     // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly\r
2486     //\r
2487     PciAddress = Address & 0xffffffffffffff00ULL;\r
2488     Status = PciRootBridgeIo->Pci.Read (\r
2489                                     PciRootBridgeIo,\r
2490                                     EfiPciWidthUint32,\r
2491                                     PciAddress,\r
2492                                     1,\r
2493                                     &PciConfigData\r
2494                                     );\r
2495 \r
2496     if (EFI_ERROR (Status)) {\r
2497       return Status;\r
2498     }\r
2499 \r
2500     if ((PciConfigData & 0xffff) == 0xffff) {\r
2501       return EFI_NOT_FOUND;\r
2502     }\r
2503 \r
2504     PciDeviceInfo->VendorID = PciConfigData & 0xffff;\r
2505     PciDeviceInfo->DeviceID = PciConfigData >> 16;\r
2506 \r
2507     Status = PciRootBridgeIo->Pci.Read (\r
2508                                     PciRootBridgeIo,\r
2509                                     EfiPciWidthUint32,\r
2510                                     PciAddress + 8,\r
2511                                     1,\r
2512                                     &PciConfigData\r
2513                                     );\r
2514     if (EFI_ERROR (Status)) {\r
2515       return Status;\r
2516     }\r
2517 \r
2518     PciDeviceInfo->RevisionID = PciConfigData & 0xf;\r
2519 \r
2520     Status = PciRootBridgeIo->Pci.Read (\r
2521                                     PciRootBridgeIo,\r
2522                                     EfiPciWidthUint32,\r
2523                                     PciAddress + 0x2c,\r
2524                                     1,\r
2525                                     &PciConfigData\r
2526                                     );\r
2527 \r
2528     if (EFI_ERROR (Status)) {\r
2529       return Status;\r
2530     }\r
2531 \r
2532     PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;\r
2533     PciDeviceInfo->SubsystemID = PciConfigData >> 16;\r
2534 \r
2535   } else {\r
2536     PciDeviceInfo->VendorID          = Pci->Hdr.VendorId;\r
2537     PciDeviceInfo->DeviceID          = Pci->Hdr.DeviceId;\r
2538     PciDeviceInfo->RevisionID        = Pci->Hdr.RevisionID;\r
2539     PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;\r
2540     PciDeviceInfo->SubsystemID       = Pci->Device.SubsystemID;\r
2541   }\r
2542 \r
2543   return EFI_SUCCESS;\r
2544 }\r
2545 \r
2546 /**\r
2547   Read PCI configuration space with incompatibility check.\r
2548 \r
2549   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2550   @param  PciIo               A pointer to the EFI_PCI_IO_PROTOCOL.\r
2551   @param  Pci                 A pointer to PCI_TYPE00.\r
2552   @param  Width               Signifies the width of the memory operations.\r
2553   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2554   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2555                               write operations, the source buffer to write data from.\r
2556 \r
2557   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2558   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2559   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2560   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2561 \r
2562 **/\r
2563 STATIC\r
2564 EFI_STATUS\r
2565 PciIncompatibilityCheckRead (\r
2566   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,   OPTIONAL\r
2567   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,             OPTIONAL\r
2568   IN       PCI_TYPE00                             *Pci,               OPTIONAL\r
2569   IN       UINTN                                  Width,\r
2570   IN       UINT64                                 Address,\r
2571   IN       UINTN                                  Count,\r
2572   IN OUT   VOID                                   *Buffer\r
2573 )\r
2574 {\r
2575   EFI_STATUS                    Status;\r
2576   EFI_PCI_DEVICE_INFO           PciDeviceInfo;\r
2577   UINT32                        Stride;\r
2578 \r
2579   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2580 \r
2581   //\r
2582   // get PCI device device information\r
2583   //\r
2584   Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2585   if (Status != EFI_SUCCESS) {\r
2586     return Status;\r
2587   }\r
2588 \r
2589   Stride = 1 << Width;\r
2590 \r
2591   for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) {\r
2592 \r
2593     //\r
2594     // read configuration register\r
2595     //\r
2596     Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer);\r
2597 \r
2598     if (Status != EFI_SUCCESS) {\r
2599       return Status;\r
2600     }\r
2601 \r
2602     //\r
2603     // update the data read from configuration register\r
2604     //\r
2605     if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2606       UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer);\r
2607     }\r
2608   }\r
2609 \r
2610   return EFI_SUCCESS;\r
2611 }\r
2612 \r
2613 /**\r
2614   Write PCI configuration space with incompatibility check.\r
2615 \r
2616   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2617   @param  PciIo               A pointer to the EFI_PCI_IO_PROTOCOL.\r
2618   @param  Pci                 A pointer to PCI_TYPE00.\r
2619   @param  Width               Signifies the width of the memory operations.\r
2620   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2621   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2622                               write operations, the source buffer to write data from.\r
2623 \r
2624   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2625   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2626   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2627   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2628 \r
2629 **/\r
2630 STATIC\r
2631 EFI_STATUS\r
2632 PciIncompatibilityCheckWrite (\r
2633   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,   OPTIONAL\r
2634   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,             OPTIONAL\r
2635   IN       PCI_TYPE00                             *Pci,               OPTIONAL\r
2636   IN       UINTN                                  Width,\r
2637   IN       UINT64                                 Address,\r
2638   IN       UINTN                                  Count,\r
2639   IN OUT   VOID                                   *Buffer\r
2640 )\r
2641 {\r
2642   EFI_STATUS                    Status;\r
2643   EFI_PCI_DEVICE_INFO           PciDeviceInfo;\r
2644   UINT32                        Stride;\r
2645   UINT64                        Data;\r
2646 \r
2647   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2648 \r
2649   //\r
2650   // get PCI device device information\r
2651   //\r
2652   Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2653   if (Status != EFI_SUCCESS) {\r
2654     return Status;\r
2655   }\r
2656 \r
2657   Stride = 1 << Width;\r
2658 \r
2659   for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) {\r
2660 \r
2661     Data = 0;\r
2662 \r
2663     switch (Width) {\r
2664     case EfiPciWidthUint8:\r
2665       Data = * (UINT8 *) Buffer;\r
2666       break;\r
2667     case EfiPciWidthUint16:\r
2668       Data = * (UINT16 *) Buffer;\r
2669       break;\r
2670 \r
2671     case EfiPciWidthUint32:\r
2672       Data = * (UINT32 *) Buffer;\r
2673       break;\r
2674 \r
2675     default:\r
2676       return EFI_UNSUPPORTED;\r
2677     }\r
2678 \r
2679     //\r
2680     // update the data writen into configuration register\r
2681     //\r
2682     if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2683       UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data);\r
2684     }\r
2685 \r
2686     //\r
2687     // write configuration register\r
2688     //\r
2689     Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data);\r
2690 \r
2691     if (Status != EFI_SUCCESS) {\r
2692       return Status;\r
2693     }\r
2694   }\r
2695 \r
2696   return EFI_SUCCESS;\r
2697 }\r
2698 \r
2699 /**\r
2700   Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2701 \r
2702   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2703   @param  Pci                 A pointer to PCI_TYPE00.\r
2704   @param  Width               Signifies the width of the memory operations.\r
2705   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2706   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2707                               write operations, the source buffer to write data from.\r
2708 \r
2709   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2710   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2711   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2712   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2713 \r
2714 **/\r
2715 EFI_STATUS\r
2716 PciRootBridgeIoRead (\r
2717   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,\r
2718   IN       PCI_TYPE00                             *Pci,            OPTIONAL\r
2719   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
2720   IN       UINT64                                 Address,\r
2721   IN       UINTN                                  Count,\r
2722   IN OUT   VOID                                   *Buffer\r
2723   )\r
2724 {\r
2725   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2726     //\r
2727     // if PCI incompatibility check enabled\r
2728     //\r
2729     return PciIncompatibilityCheckRead (\r
2730                    PciRootBridgeIo,\r
2731                    NULL,\r
2732                    Pci,\r
2733                    (UINTN) Width,\r
2734                    Address,\r
2735                    Count,\r
2736                    Buffer\r
2737                    );\r
2738   } else {\r
2739     return PciRootBridgeIo->Pci.Read (\r
2740                    PciRootBridgeIo,\r
2741                    Width,\r
2742                    Address,\r
2743                    Count,\r
2744                    Buffer\r
2745                    );\r
2746   }\r
2747 }\r
2748 \r
2749 /**\r
2750   Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2751 \r
2752   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2753   @param  Pci                 A pointer to PCI_TYPE00.\r
2754   @param  Width               Signifies the width of the memory operations.\r
2755   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2756   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2757                               write operations, the source buffer to write data from.\r
2758 \r
2759   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2760   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2761   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2762   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2763 \r
2764 **/\r
2765 EFI_STATUS\r
2766 PciRootBridgeIoWrite (\r
2767   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,\r
2768   IN       PCI_TYPE00                             *Pci,\r
2769   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
2770   IN       UINT64                                 Address,\r
2771   IN       UINTN                                  Count,\r
2772   IN OUT   VOID                                   *Buffer\r
2773   )\r
2774 {\r
2775   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2776     //\r
2777     // if PCI incompatibility check enabled\r
2778     //\r
2779     return  PciIncompatibilityCheckWrite (\r
2780                    PciRootBridgeIo,\r
2781                    NULL,\r
2782                    Pci,\r
2783                    Width,\r
2784                    Address,\r
2785                    Count,\r
2786                    Buffer\r
2787                    );\r
2788 \r
2789   } else {\r
2790     return  PciRootBridgeIo->Pci.Write (\r
2791                    PciRootBridgeIo,\r
2792                    Width,\r
2793                    Address,\r
2794                    Count,\r
2795                    Buffer\r
2796                    );\r
2797   }\r
2798 }\r
2799 \r
2800 /**\r
2801   Read PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2802 \r
2803   @param  PciIo               A pointer to the EFI_PCI_O_PROTOCOL.\r
2804   @param  Width               Signifies the width of the memory operations.\r
2805   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2806   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2807                               write operations, the source buffer to write data from.\r
2808 \r
2809   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2810   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2811   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2812   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2813 \r
2814 **/\r
2815 EFI_STATUS\r
2816 PciIoRead (\r
2817   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,\r
2818   IN       EFI_PCI_IO_PROTOCOL_WIDTH              Width,\r
2819   IN       UINT32                                 Address,\r
2820   IN       UINTN                                  Count,\r
2821   IN OUT   VOID                                   *Buffer\r
2822   )\r
2823 {\r
2824   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2825     //\r
2826     // if PCI incompatibility check enabled\r
2827     //\r
2828     return PciIncompatibilityCheckRead (\r
2829                    NULL,\r
2830                    PciIo,\r
2831                    NULL,\r
2832                    (UINTN) Width,\r
2833                    Address,\r
2834                    Count,\r
2835                    Buffer\r
2836                    );\r
2837   } else {\r
2838     return PciIo->Pci.Read (\r
2839                    PciIo,\r
2840                    Width,\r
2841                    Address,\r
2842                    Count,\r
2843                    Buffer\r
2844                    );\r
2845   }\r
2846 }\r
2847 \r
2848 /**\r
2849   Write PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2850 \r
2851   @param  PciIo               A pointer to the EFI_PCI_O_PROTOCOL.\r
2852   @param  Width               Signifies the width of the memory operations.\r
2853   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2854   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2855                               write operations, the source buffer to write data from.\r
2856 \r
2857   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2858   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2859   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2860   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2861 \r
2862 **/\r
2863 EFI_STATUS\r
2864 PciIoWrite (\r
2865   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,\r
2866   IN       EFI_PCI_IO_PROTOCOL_WIDTH              Width,\r
2867   IN       UINT32                                 Address,\r
2868   IN       UINTN                                  Count,\r
2869   IN OUT   VOID                                   *Buffer\r
2870   )\r
2871 {\r
2872   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2873 \r
2874     //\r
2875     // if PCI incompatibility check enabled\r
2876     //\r
2877     return  PciIncompatibilityCheckWrite (\r
2878                    NULL,\r
2879                    PciIo,\r
2880                    NULL,\r
2881                    Width,\r
2882                    Address,\r
2883                    Count,\r
2884                    Buffer\r
2885                    );\r
2886 \r
2887   } else {\r
2888     return PciIo->Pci.Write (\r
2889                    PciIo,\r
2890                    Width,\r
2891                    Address,\r
2892                    Count,\r
2893                    Buffer\r
2894                    );\r
2895   }\r
2896 }\r