7a4684d96d3331b86e8639a6251f1d27cf97a21b
[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   ResetAllPpbBusReg (Bridge, StartBusNumber);\r
1262 \r
1263   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1264     for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1265 \r
1266       //\r
1267       // Check to see whether a pci device is present\r
1268       //\r
1269       Status = PciDevicePresent (\r
1270                 PciRootBridgeIo,\r
1271                 &Pci,\r
1272                 StartBusNumber,\r
1273                 Device,\r
1274                 Func\r
1275                 );\r
1276 \r
1277       if (!EFI_ERROR (Status)   &&\r
1278           (IS_PCI_BRIDGE (&Pci) ||\r
1279           IS_CARDBUS_BRIDGE (&Pci))) {\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         (*SubBusNumber)++;\r
1298 \r
1299         SecondBus = (*SubBusNumber);\r
1300 \r
1301         Register  = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1302 \r
1303         Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
1304 \r
1305         Status = PciRootBridgeIoWrite (\r
1306                                         PciRootBridgeIo,\r
1307                                         &Pci,\r
1308                                         EfiPciWidthUint16,\r
1309                                         Address,\r
1310                                         1,\r
1311                                         &Register\r
1312                                         );\r
1313 \r
1314         //\r
1315         // Initialize SubBusNumber to SecondBus\r
1316         //\r
1317         Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1318         Status = PciRootBridgeIoWrite (\r
1319                                         PciRootBridgeIo,\r
1320                                         &Pci,\r
1321                                         EfiPciWidthUint8,\r
1322                                         Address,\r
1323                                         1,\r
1324                                         SubBusNumber\r
1325                                         );\r
1326         //\r
1327         // If it is PPB, resursively search down this bridge\r
1328         //\r
1329         if (IS_PCI_BRIDGE (&Pci)) {\r
1330           //\r
1331           // Temporarily initialize SubBusNumber to maximum bus number to ensure the\r
1332           // PCI configuration transaction to go through any PPB\r
1333           //\r
1334           Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1335           Register  = 0xFF;\r
1336           Status = PciRootBridgeIoWrite (\r
1337                                           PciRootBridgeIo,\r
1338                                           &Pci,\r
1339                                           EfiPciWidthUint8,\r
1340                                           Address,\r
1341                                           1,\r
1342                                           &Register\r
1343                                           );\r
1344 \r
1345           PreprocessController (\r
1346             PciDevice,\r
1347             PciDevice->BusNumber,\r
1348             PciDevice->DeviceNumber,\r
1349             PciDevice->FunctionNumber,\r
1350             EfiPciBeforeChildBusEnumeration\r
1351             );\r
1352 \r
1353           Status = PciScanBus (\r
1354                     PciDevice,\r
1355                     (UINT8) (SecondBus),\r
1356                     SubBusNumber,\r
1357                     PaddedBusRange\r
1358                     );\r
1359 \r
1360           if (EFI_ERROR (Status)) {\r
1361             return EFI_DEVICE_ERROR;\r
1362           }\r
1363         }\r
1364 \r
1365         //\r
1366         // Set the current maximum bus number under the PPB\r
1367         //\r
1368 \r
1369         Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1370 \r
1371         Status = PciRootBridgeIoWrite (\r
1372                                         PciRootBridgeIo,\r
1373                                         &Pci,\r
1374                                         EfiPciWidthUint8,\r
1375                                         Address,\r
1376                                         1,\r
1377                                         SubBusNumber\r
1378                                         );\r
1379 \r
1380       }\r
1381 \r
1382       if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1383 \r
1384         //\r
1385         // Skip sub functions, this is not a multi function device\r
1386         //\r
1387 \r
1388         Func = PCI_MAX_FUNC;\r
1389       }\r
1390     }\r
1391   }\r
1392 \r
1393   return EFI_SUCCESS;\r
1394 }\r
1395 \r
1396 EFI_STATUS\r
1397 PciScanBus_WithHotPlugDeviceSupport (\r
1398   IN PCI_IO_DEVICE                      *Bridge,\r
1399   IN UINT8                              StartBusNumber,\r
1400   OUT UINT8                             *SubBusNumber,\r
1401   OUT UINT8                             *PaddedBusRange\r
1402   )\r
1403 /*++\r
1404 \r
1405 Routine Description:\r
1406 \r
1407   This routine is used to assign bus number to the given PCI bus system\r
1408 \r
1409 Arguments:\r
1410 \r
1411   Bridge         - A pointer to the PCI_IO_DEVICE structure.\r
1412   StartBusNumber - The start bus number.\r
1413   SubBusNumber   - A pointer to the sub bus number.\r
1414   PaddedBusRange - A pointer to the padded bus range.\r
1415 \r
1416 Returns:\r
1417 \r
1418   None\r
1419 \r
1420 --*/\r
1421 // TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
1422 // TODO:    EFI_SUCCESS - add return value to function comment\r
1423 {\r
1424   EFI_STATUS                        Status;\r
1425   PCI_TYPE00                        Pci;\r
1426   UINT8                             Device;\r
1427   UINT8                             Func;\r
1428   UINT64                            Address;\r
1429   UINTN                             SecondBus;\r
1430   UINT16                            Register;\r
1431   UINTN                             HpIndex;\r
1432   PCI_IO_DEVICE                     *PciDevice;\r
1433   EFI_EVENT                         Event;\r
1434   EFI_HPC_STATE                     State;\r
1435   UINT64                            PciAddress;\r
1436   EFI_HPC_PADDING_ATTRIBUTES        Attributes;\r
1437   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1438   UINT16                            BusRange;\r
1439   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;\r
1440   BOOLEAN                           BusPadding;\r
1441 \r
1442   PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1443   SecondBus       = 0;\r
1444   Register        = 0;\r
1445   State           = 0;\r
1446   Attributes      = (EFI_HPC_PADDING_ATTRIBUTES) 0;\r
1447   BusRange        = 0;\r
1448 \r
1449   ResetAllPpbBusReg (Bridge, StartBusNumber);\r
1450 \r
1451   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1452     for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1453 \r
1454       //\r
1455       // Check to see whether a pci device is present\r
1456       //\r
1457       Status = PciDevicePresent (\r
1458                 PciRootBridgeIo,\r
1459                 &Pci,\r
1460                 StartBusNumber,\r
1461                 Device,\r
1462                 Func\r
1463                 );\r
1464 \r
1465       if (EFI_ERROR (Status)) {\r
1466         if (Func == 0) {\r
1467           //\r
1468           // Skip sub functions, this is not a multi function device\r
1469           //\r
1470           Func = PCI_MAX_FUNC;\r
1471         }\r
1472 \r
1473         continue;\r
1474       }\r
1475 \r
1476       //\r
1477       // Get the PCI device information\r
1478       //\r
1479       Status = PciSearchDevice (\r
1480                 Bridge,\r
1481                 &Pci,\r
1482                 StartBusNumber,\r
1483                 Device,\r
1484                 Func,\r
1485                 &PciDevice\r
1486                 );\r
1487 \r
1488       ASSERT (!EFI_ERROR (Status));\r
1489 \r
1490       PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);\r
1491 \r
1492       if (!IS_PCI_BRIDGE (&Pci)) {\r
1493         //\r
1494         // PCI bridges will be called later\r
1495         // Here just need for PCI device or PCI to cardbus controller\r
1496         // EfiPciBeforeChildBusEnumeration for PCI Device Node\r
1497         //\r
1498         PreprocessController (\r
1499             PciDevice,\r
1500             PciDevice->BusNumber,\r
1501             PciDevice->DeviceNumber,\r
1502             PciDevice->FunctionNumber,\r
1503             EfiPciBeforeChildBusEnumeration\r
1504             );\r
1505       }\r
1506 \r
1507       //\r
1508       // For Pci Hotplug controller devcie only\r
1509       //\r
1510       if (gPciHotPlugInit != NULL) {\r
1511         //\r
1512         // Check if it is a Hotplug PCI controller\r
1513         //\r
1514         if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {\r
1515 \r
1516           if (!gPciRootHpcData[HpIndex].Initialized) {\r
1517 \r
1518             Status = CreateEventForHpc (HpIndex, &Event);\r
1519 \r
1520             ASSERT (!EFI_ERROR (Status));\r
1521 \r
1522             Status = gPciHotPlugInit->InitializeRootHpc (\r
1523                                         gPciHotPlugInit,\r
1524                                         gPciRootHpcPool[HpIndex].HpcDevicePath,\r
1525                                         PciAddress,\r
1526                                         Event,\r
1527                                         &State\r
1528                                         );\r
1529 \r
1530             PreprocessController (\r
1531               PciDevice,\r
1532               PciDevice->BusNumber,\r
1533               PciDevice->DeviceNumber,\r
1534               PciDevice->FunctionNumber,\r
1535               EfiPciBeforeChildBusEnumeration\r
1536             );\r
1537             continue;\r
1538           }\r
1539         }\r
1540       }\r
1541 \r
1542       if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {\r
1543         //\r
1544         // For PPB\r
1545         // Get the bridge information\r
1546         //\r
1547         BusPadding = FALSE;\r
1548         if (gPciHotPlugInit != NULL) {\r
1549 \r
1550           if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {\r
1551 \r
1552             //\r
1553             // If it is initialized, get the padded bus range\r
1554             //\r
1555             Status = gPciHotPlugInit->GetResourcePadding (\r
1556                                         gPciHotPlugInit,\r
1557                                         gPciRootHpcPool[HpIndex].HpbDevicePath,\r
1558                                         PciAddress,\r
1559                                         &State,\r
1560                                         (VOID **) &Descriptors,\r
1561                                         &Attributes\r
1562                                         );\r
1563 \r
1564             if (EFI_ERROR (Status)) {\r
1565               return Status;\r
1566             }\r
1567 \r
1568             BusRange = 0;\r
1569             Status = PciGetBusRange (\r
1570                       &Descriptors,\r
1571                       NULL,\r
1572                       NULL,\r
1573                       &BusRange\r
1574                       );\r
1575 \r
1576             gBS->FreePool (Descriptors);\r
1577 \r
1578             if (EFI_ERROR (Status)) {\r
1579               return Status;\r
1580             }\r
1581 \r
1582             BusPadding = TRUE;\r
1583           }\r
1584         }\r
1585 \r
1586         (*SubBusNumber)++;\r
1587         SecondBus = *SubBusNumber;\r
1588 \r
1589         Register  = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1590         Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
1591 \r
1592         Status = PciRootBridgeIoWrite (\r
1593                                         PciRootBridgeIo,\r
1594                                         &Pci,\r
1595                                         EfiPciWidthUint16,\r
1596                                         Address,\r
1597                                         1,\r
1598                                         &Register\r
1599                                         );\r
1600 \r
1601 \r
1602         //\r
1603         // If it is PPB, resursively search down this bridge\r
1604         //\r
1605         if (IS_PCI_BRIDGE (&Pci)) {\r
1606 \r
1607           //\r
1608           // Initialize SubBusNumber to Maximum bus number\r
1609           //\r
1610           Register  = 0xFF;\r
1611           Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1612           Status = PciRootBridgeIoWrite (\r
1613                                           PciRootBridgeIo,\r
1614                                           &Pci,\r
1615                                           EfiPciWidthUint8,\r
1616                                           Address,\r
1617                                           1,\r
1618                                           &Register\r
1619                                           );\r
1620 \r
1621           //\r
1622           // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige\r
1623           //\r
1624           PreprocessController (\r
1625             PciDevice,\r
1626             PciDevice->BusNumber,\r
1627             PciDevice->DeviceNumber,\r
1628             PciDevice->FunctionNumber,\r
1629             EfiPciBeforeChildBusEnumeration\r
1630             );\r
1631 \r
1632           Status = PciScanBus (\r
1633                     PciDevice,\r
1634                     (UINT8) (SecondBus),\r
1635                     SubBusNumber,\r
1636                     PaddedBusRange\r
1637                     );\r
1638 \r
1639           if (EFI_ERROR (Status)) {\r
1640             return EFI_DEVICE_ERROR;\r
1641           }\r
1642         }\r
1643 \r
1644         if (BusPadding) {\r
1645           //\r
1646           // Ensure the device is enabled and initialized\r
1647           //\r
1648           if ((Attributes == EfiPaddingPciRootBridge) &&\r
1649               (State & EFI_HPC_STATE_ENABLED)         &&\r
1650               (State & EFI_HPC_STATE_INITIALIZED)     ) {\r
1651             *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);\r
1652           } else {\r
1653             *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);\r
1654           }\r
1655         }\r
1656 \r
1657         //\r
1658         // Set the current maximum bus number under the PPB\r
1659         //\r
1660         Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1661 \r
1662         Status = PciRootBridgeIoWrite (\r
1663                                         PciRootBridgeIo,\r
1664                                         &Pci,\r
1665                                         EfiPciWidthUint8,\r
1666                                         Address,\r
1667                                         1,\r
1668                                         SubBusNumber\r
1669                                         );\r
1670       }\r
1671 \r
1672       if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1673 \r
1674         //\r
1675         // Skip sub functions, this is not a multi function device\r
1676         //\r
1677         Func = PCI_MAX_FUNC;\r
1678       }\r
1679 \r
1680     }\r
1681   }\r
1682 \r
1683   return EFI_SUCCESS;\r
1684 }\r
1685 \r
1686 EFI_STATUS\r
1687 PciRootBridgeP2CProcess (\r
1688   IN PCI_IO_DEVICE *Bridge\r
1689   )\r
1690 /*++\r
1691 \r
1692 Routine Description:\r
1693 \r
1694     Process Option Rom on this host bridge\r
1695 \r
1696 Arguments:\r
1697 \r
1698 Returns:\r
1699 \r
1700   None\r
1701 \r
1702 --*/\r
1703 // TODO:    Bridge - add argument and description to function comment\r
1704 // TODO:    EFI_SUCCESS - add return value to function comment\r
1705 {\r
1706   LIST_ENTRY      *CurrentLink;\r
1707   PCI_IO_DEVICE   *Temp;\r
1708   EFI_HPC_STATE   State;\r
1709   UINT64          PciAddress;\r
1710   EFI_STATUS      Status;\r
1711 \r
1712   CurrentLink = Bridge->ChildList.ForwardLink;\r
1713 \r
1714   while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
1715 \r
1716     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1717 \r
1718     if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {\r
1719 \r
1720       if (gPciHotPlugInit && Temp->Allocated) {\r
1721 \r
1722         //\r
1723         // Raise the EFI_IOB_PCI_HPC_INIT status code\r
1724         //\r
1725         REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1726           EFI_PROGRESS_CODE,\r
1727           EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,\r
1728           Temp->DevicePath\r
1729           );\r
1730 \r
1731         PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1732         Status = gPciHotPlugInit->InitializeRootHpc (\r
1733                                     gPciHotPlugInit,\r
1734                                     Temp->DevicePath,\r
1735                                     PciAddress,\r
1736                                     NULL,\r
1737                                     &State\r
1738                                     );\r
1739 \r
1740         if (!EFI_ERROR (Status)) {\r
1741           Status = PciBridgeEnumerator (Temp);\r
1742 \r
1743           if (EFI_ERROR (Status)) {\r
1744             return Status;\r
1745           }\r
1746         }\r
1747 \r
1748         CurrentLink = CurrentLink->ForwardLink;\r
1749         continue;\r
1750 \r
1751       }\r
1752     }\r
1753 \r
1754     if (!IsListEmpty (&Temp->ChildList)) {\r
1755       Status = PciRootBridgeP2CProcess (Temp);\r
1756     }\r
1757 \r
1758     CurrentLink = CurrentLink->ForwardLink;\r
1759   }\r
1760 \r
1761   return EFI_SUCCESS;\r
1762 }\r
1763 \r
1764 EFI_STATUS\r
1765 PciHostBridgeP2CProcess (\r
1766   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
1767   )\r
1768 /*++\r
1769 \r
1770 Routine Description:\r
1771 \r
1772 Arguments:\r
1773 \r
1774 Returns:\r
1775 \r
1776   None\r
1777 \r
1778 --*/\r
1779 // TODO:    PciResAlloc - add argument and description to function comment\r
1780 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1781 // TODO:    EFI_SUCCESS - add return value to function comment\r
1782 {\r
1783   EFI_HANDLE    RootBridgeHandle;\r
1784   PCI_IO_DEVICE *RootBridgeDev;\r
1785   EFI_STATUS    Status;\r
1786 \r
1787   if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1788     return EFI_SUCCESS;\r
1789   }\r
1790 \r
1791   RootBridgeHandle = NULL;\r
1792 \r
1793   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1794 \r
1795     //\r
1796     // Get RootBridg Device by handle\r
1797     //\r
1798     RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
1799 \r
1800     if (RootBridgeDev == NULL) {\r
1801       return EFI_NOT_FOUND;\r
1802     }\r
1803 \r
1804     Status = PciRootBridgeP2CProcess (RootBridgeDev);\r
1805 \r
1806     if (EFI_ERROR (Status)) {\r
1807       return Status;\r
1808     }\r
1809 \r
1810   }\r
1811 \r
1812   return EFI_SUCCESS;\r
1813 }\r
1814 \r
1815 EFI_STATUS\r
1816 PciHostBridgeEnumerator (\r
1817   EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL  *PciResAlloc\r
1818   )\r
1819 /*++\r
1820 \r
1821 Routine Description:\r
1822 \r
1823   This function is used to enumerate the entire host bridge\r
1824   in a given platform\r
1825 \r
1826 Arguments:\r
1827 \r
1828   PciResAlloc   - A pointer to the resource allocate protocol.\r
1829 \r
1830 Returns:\r
1831 \r
1832   None\r
1833 \r
1834 --*/\r
1835 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
1836 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
1837 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment\r
1838 // TODO:    EFI_SUCCESS - add return value to function comment\r
1839 {\r
1840   EFI_HANDLE                        RootBridgeHandle;\r
1841   PCI_IO_DEVICE                     *RootBridgeDev;\r
1842   EFI_STATUS                        Status;\r
1843   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;\r
1844   UINT16                            MinBus;\r
1845   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1846 \r
1847   InitializeHotPlugSupport ();\r
1848 \r
1849   //\r
1850   // Notify the bus allocation phase is about to start\r
1851   //\r
1852   NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1853 \r
1854   RootBridgeHandle = NULL;\r
1855   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1856 \r
1857     //\r
1858     // if a root bridge instance is found, create root bridge device for it\r
1859     //\r
1860 \r
1861     RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1862 \r
1863     if (RootBridgeDev == NULL) {\r
1864       return EFI_OUT_OF_RESOURCES;\r
1865     }\r
1866 \r
1867     //\r
1868     // Enumerate all the buses under this root bridge\r
1869     //\r
1870 \r
1871     Status = PciRootBridgeEnumerator (\r
1872               PciResAlloc,\r
1873               RootBridgeDev\r
1874               );\r
1875 \r
1876     DestroyRootBridge (RootBridgeDev);\r
1877     if (EFI_ERROR (Status)) {\r
1878       return Status;\r
1879     }\r
1880   }\r
1881 \r
1882   //\r
1883   // Notify the bus allocation phase is finished for the first time\r
1884   //\r
1885   NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1886 \r
1887   if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1888 \r
1889     if (gPciHotPlugInit != NULL) {\r
1890       //\r
1891       // Wait for all HPC initialized\r
1892       //\r
1893       Status = AllRootHPCInitialized (STALL_1_SECOND * 15);\r
1894 \r
1895       if (EFI_ERROR (Status)) {\r
1896         return Status;\r
1897       }\r
1898 \r
1899       //\r
1900       // Notify the bus allocation phase is about to start for the 2nd time\r
1901       //\r
1902       NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1903 \r
1904       RootBridgeHandle = NULL;\r
1905       while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1906 \r
1907         //\r
1908         // if a root bridge instance is found, create root bridge device for it\r
1909         //\r
1910 \r
1911         RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1912 \r
1913         if (RootBridgeDev == NULL) {\r
1914           return EFI_OUT_OF_RESOURCES;\r
1915         }\r
1916 \r
1917         //\r
1918         // Enumerate all the buses under this root bridge\r
1919         //\r
1920 \r
1921         Status = PciRootBridgeEnumerator (\r
1922                   PciResAlloc,\r
1923                   RootBridgeDev\r
1924                   );\r
1925 \r
1926         DestroyRootBridge (RootBridgeDev);\r
1927         if (EFI_ERROR (Status)) {\r
1928           return Status;\r
1929         }\r
1930       }\r
1931 \r
1932       //\r
1933       // Notify the bus allocation phase is to end for the 2nd time\r
1934       //\r
1935       NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1936     }\r
1937   }\r
1938 \r
1939   //\r
1940   // Notify the resource allocation phase is to start\r
1941   //\r
1942   NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);\r
1943 \r
1944   RootBridgeHandle = NULL;\r
1945   while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1946 \r
1947     //\r
1948     // if a root bridge instance is found, create root bridge device for it\r
1949     //\r
1950 \r
1951     RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1952 \r
1953     if (RootBridgeDev == NULL) {\r
1954       return EFI_OUT_OF_RESOURCES;\r
1955     }\r
1956 \r
1957     Status = StartManagingRootBridge (RootBridgeDev);\r
1958 \r
1959     if (EFI_ERROR (Status)) {\r
1960       return Status;\r
1961     }\r
1962 \r
1963     PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;\r
1964     Status          = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1965 \r
1966     if (EFI_ERROR (Status)) {\r
1967       return Status;\r
1968     }\r
1969 \r
1970     Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);\r
1971 \r
1972     if (EFI_ERROR (Status)) {\r
1973       return Status;\r
1974     }\r
1975 \r
1976     //\r
1977     // Determine root bridge attribute by calling interface of Pcihostbridge\r
1978     // protocol\r
1979     //\r
1980     DetermineRootBridgeAttributes (\r
1981       PciResAlloc,\r
1982       RootBridgeDev\r
1983       );\r
1984 \r
1985     //\r
1986     // Collect all the resource information under this root bridge\r
1987     // A database that records all the information about pci device subject to this\r
1988     // root bridge will then be created\r
1989     //\r
1990     Status = PciPciDeviceInfoCollector (\r
1991               RootBridgeDev,\r
1992               (UINT8) MinBus\r
1993               );\r
1994 \r
1995     if (EFI_ERROR (Status)) {\r
1996       return Status;\r
1997     }\r
1998 \r
1999     InsertRootBridge (RootBridgeDev);\r
2000 \r
2001     //\r
2002     // Record the hostbridge handle\r
2003     //\r
2004     AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);\r
2005   }\r
2006 \r
2007   return EFI_SUCCESS;\r
2008 }\r
2009 \r
2010 /**\r
2011   Read PCI device configuration register by specified address.\r
2012 \r
2013   This function check the incompatiblilites on PCI device. Return the register\r
2014   value.\r
2015 \r
2016   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2017   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2018   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2019   @param  Width               Signifies the width of the memory operations.\r
2020   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2021   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2022                               write operations, the source buffer to write data from.\r
2023 \r
2024    @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2025    @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2026    @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2027    @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2028 \r
2029 **/\r
2030 STATIC\r
2031 EFI_STATUS\r
2032 ReadConfigData (\r
2033   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2034   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2035   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2036   IN       UINT64                                 Width,\r
2037   IN       UINT64                                 Address,\r
2038   IN OUT   VOID                                   *Buffer\r
2039   )\r
2040 {\r
2041   EFI_STATUS                    Status;\r
2042   UINT64                        AccessWidth;\r
2043   EFI_PCI_REGISTER_ACCESS_DATA  *PciRegisterAccessData;\r
2044   UINT64                        AccessAddress;\r
2045   UINTN                         Stride;\r
2046   UINT64                        TempBuffer;\r
2047   UINT8                         *Pointer;\r
2048 \r
2049   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2050 \r
2051   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2052     //\r
2053     // check access compatibility at first time\r
2054     //\r
2055     Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData);\r
2056 \r
2057     if (Status == EFI_SUCCESS) {\r
2058       //\r
2059       // there exist incompatibility on this operation\r
2060       //\r
2061       AccessWidth = Width;\r
2062 \r
2063       if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2064         AccessWidth = PciRegisterAccessData->Width;\r
2065       }\r
2066 \r
2067       AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2068 \r
2069       TempBuffer    = 0;\r
2070       Stride        = 0;\r
2071       Pointer       = (UINT8 *) &TempBuffer;\r
2072 \r
2073       while (1) {\r
2074 \r
2075         if (PciRootBridgeIo != NULL) {\r
2076           Status = PciRootBridgeIo->Pci.Read (\r
2077                          PciRootBridgeIo,\r
2078                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2079                          AccessAddress,\r
2080                          1,\r
2081                          Pointer\r
2082                          );\r
2083         } else if (PciIo != NULL) {\r
2084           Status = PciIo->Pci.Read (\r
2085                          PciIo,\r
2086                          (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2087                          (UINT32) AccessAddress,\r
2088                          1,\r
2089                          Pointer\r
2090                          );\r
2091         }\r
2092 \r
2093         if (Status != EFI_SUCCESS) {\r
2094           return Status;\r
2095         }\r
2096 \r
2097        Stride = 1 << AccessWidth;\r
2098         AccessAddress += Stride;\r
2099         if (AccessAddress >= (Address + (1 << Width))) {\r
2100           //\r
2101           // if all datas have been read, exist\r
2102           //\r
2103           break;\r
2104         }\r
2105 \r
2106         Pointer += Stride;\r
2107 \r
2108         if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2109           //\r
2110           // if current offset doesn't reach the end\r
2111           //\r
2112           continue;\r
2113         }\r
2114 \r
2115         FreePool (PciRegisterAccessData);\r
2116 \r
2117         //\r
2118         // continue checking access incompatibility\r
2119         //\r
2120         Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2121         if (Status == EFI_SUCCESS) {\r
2122           if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2123             AccessWidth = PciRegisterAccessData->Width;\r
2124           }\r
2125         }\r
2126       }\r
2127 \r
2128       FreePool (PciRegisterAccessData);\r
2129 \r
2130       switch (Width) {\r
2131       case EfiPciWidthUint8:\r
2132         * (UINT8 *) Buffer = (UINT8) TempBuffer;\r
2133         break;\r
2134       case EfiPciWidthUint16:\r
2135         * (UINT16 *) Buffer = (UINT16) TempBuffer;\r
2136         break;\r
2137       case EfiPciWidthUint32:\r
2138         * (UINT32 *) Buffer = (UINT32) TempBuffer;\r
2139         break;\r
2140       default:\r
2141         return EFI_UNSUPPORTED;\r
2142       }\r
2143 \r
2144       return Status;\r
2145     }\r
2146   }\r
2147   //\r
2148   // AccessWidth incompatible check not supportted\r
2149   // or, there doesn't exist incompatibility on this operation\r
2150   //\r
2151   if (PciRootBridgeIo != NULL) {\r
2152     Status = PciRootBridgeIo->Pci.Read (\r
2153                      PciRootBridgeIo,\r
2154                      (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2155                      Address,\r
2156                      1,\r
2157                      Buffer\r
2158                      );\r
2159 \r
2160   } else {\r
2161     Status = PciIo->Pci.Read (\r
2162                      PciIo,\r
2163                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2164                      (UINT32) Address,\r
2165                      1,\r
2166                      Buffer\r
2167                      );\r
2168   }\r
2169 \r
2170   return Status;\r
2171 }\r
2172 \r
2173 /**\r
2174   Update register value by checking PCI device incompatibility.\r
2175 \r
2176   This function check register value incompatibilites on PCI device. Return the register\r
2177   value.\r
2178 \r
2179   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2180   @param  AccessType          Access type, READ or WRITE.\r
2181   @Param  Address             The address within the PCI configuration space.\r
2182   @param  Buffer              Store the register data.\r
2183 \r
2184   @retval EFI_SUCCESS         The data has been updated.\r
2185 \r
2186 **/\r
2187 STATIC\r
2188 EFI_STATUS\r
2189 UpdateConfigData (\r
2190   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2191   IN       UINT64                                 AccessType,\r
2192   IN       UINT64                                 Width,\r
2193   IN       UINT64                                 Address,\r
2194   IN OUT   VOID                                   *Buffer\r
2195 )\r
2196 {\r
2197   EFI_STATUS                    Status;\r
2198   EFI_PCI_REGISTER_VALUE_DATA   *PciRegisterData;\r
2199   UINT32                        AndValue;\r
2200   UINT32                        OrValue;\r
2201   UINT32                        TempValue;\r
2202 \r
2203   //\r
2204   // check register value incompatibility\r
2205   //\r
2206   Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData);\r
2207 \r
2208   if (Status == EFI_SUCCESS) {\r
2209 \r
2210     AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Address & 0x3) * 8);\r
2211     OrValue  = ((UINT32) PciRegisterData->OrValue)  >> (((UINT8) Address & 0x3) * 8);\r
2212 \r
2213     TempValue = * (UINT32 *) Buffer;\r
2214     if (PciRegisterData->AndValue != VALUE_NOCARE) {\r
2215       TempValue &= AndValue;\r
2216     }\r
2217     if (PciRegisterData->OrValue != VALUE_NOCARE) {\r
2218       TempValue |= OrValue;\r
2219     }\r
2220 \r
2221     switch (Width) {\r
2222     case EfiPciWidthUint8:\r
2223       *(UINT8 *)Buffer = (UINT8) TempValue;\r
2224       break;\r
2225 \r
2226     case EfiPciWidthUint16:\r
2227       *(UINT16 *)Buffer = (UINT16) TempValue;\r
2228       break;\r
2229     case EfiPciWidthUint32:\r
2230       *(UINT32 *)Buffer = TempValue;\r
2231       break;\r
2232 \r
2233     default:\r
2234       return EFI_UNSUPPORTED;\r
2235     }\r
2236 \r
2237     FreePool (PciRegisterData);\r
2238   }\r
2239 \r
2240   return Status;\r
2241 }\r
2242 \r
2243 /**\r
2244   Write PCI device configuration register by specified address.\r
2245 \r
2246   This function check the incompatiblilites on PCI device, and write date\r
2247   into register.\r
2248 \r
2249   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2250   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2251   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2252   @param  Width               Signifies the width of the memory operations.\r
2253   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2254   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2255                               write operations, the source buffer to write data from.\r
2256 \r
2257    @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2258    @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2259    @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2260    @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2261 \r
2262 **/\r
2263 STATIC\r
2264 EFI_STATUS\r
2265 WriteConfigData (\r
2266   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2267   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2268   IN       EFI_PCI_DEVICE_INFO                    *PciDeviceInfo,\r
2269   IN       UINT64                                 Width,\r
2270   IN       UINT64                                 Address,\r
2271   IN       VOID                                   *Buffer\r
2272   )\r
2273 {\r
2274   EFI_STATUS                    Status;\r
2275   UINT64                        AccessWidth;\r
2276   EFI_PCI_REGISTER_ACCESS_DATA  *PciRegisterAccessData;\r
2277   UINT64                        AccessAddress;\r
2278   UINTN                         Stride;\r
2279   UINT8                         *Pointer;\r
2280   UINT64                        Data;\r
2281   UINTN                         Shift;\r
2282 \r
2283   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2284 \r
2285   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2286     //\r
2287     // check access compatibility at first time\r
2288     //\r
2289     Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData);\r
2290 \r
2291     if (Status == EFI_SUCCESS) {\r
2292       //\r
2293       // there exist incompatibility on this operation\r
2294       //\r
2295       AccessWidth = Width;\r
2296 \r
2297       if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2298         AccessWidth = PciRegisterAccessData->Width;\r
2299       }\r
2300 \r
2301       AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2302 \r
2303       Stride        = 0;\r
2304       Pointer       = (UINT8 *) &Buffer;\r
2305       Data          = * (UINT64 *) Buffer;\r
2306 \r
2307       while (1) {\r
2308 \r
2309         if (AccessWidth > Width) {\r
2310           //\r
2311           // if actual access width is larger than orignal one, additional data need to be read back firstly\r
2312           //\r
2313           Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);\r
2314           if (Status != EFI_SUCCESS) {\r
2315             return Status;\r
2316           }\r
2317 \r
2318           //\r
2319           // check data read incompatibility\r
2320           //\r
2321           UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);\r
2322 \r
2323           Shift = (UINTN)(Address - AccessAddress) * 8;\r
2324           switch (Width) {\r
2325           case EfiPciWidthUint8:\r
2326             Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));\r
2327             break;\r
2328 \r
2329           case EfiPciWidthUint16:\r
2330             Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));\r
2331             break;\r
2332           }\r
2333 \r
2334           //\r
2335           // check data write incompatibility\r
2336           //\r
2337           UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, MultU64x32 (AccessAddress, 0xff), &Data);\r
2338         }\r
2339 \r
2340         if (PciRootBridgeIo != NULL) {\r
2341           Status = PciRootBridgeIo->Pci.Write (\r
2342                          PciRootBridgeIo,\r
2343                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2344                          AccessAddress,\r
2345                          1,\r
2346                          &Data\r
2347                          );\r
2348         } else {\r
2349           Status = PciIo->Pci.Write (\r
2350                          PciIo,\r
2351                          (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2352                          (UINT32) AccessAddress,\r
2353                          1,\r
2354                          &Data\r
2355                          );\r
2356         }\r
2357 \r
2358         if (Status != EFI_SUCCESS) {\r
2359           return Status;\r
2360         }\r
2361 \r
2362         Data = RShiftU64 (Data, ((1 << AccessWidth) * 8));\r
2363 \r
2364         Stride = 1 << AccessWidth;\r
2365         AccessAddress += Stride;\r
2366         if (AccessAddress >= (Address + (1 << Width))) {\r
2367           //\r
2368           // if all datas have been written, exist\r
2369           //\r
2370           break;\r
2371         }\r
2372 \r
2373         Pointer += Stride;\r
2374 \r
2375         if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2376           //\r
2377           // if current offset doesn't reach the end\r
2378           //\r
2379           continue;\r
2380         }\r
2381 \r
2382         FreePool (PciRegisterAccessData);\r
2383 \r
2384         //\r
2385         // continue checking access incompatibility\r
2386         //\r
2387         Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2388         if (Status == EFI_SUCCESS) {\r
2389           if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2390             AccessWidth = PciRegisterAccessData->Width;\r
2391           }\r
2392         }\r
2393       };\r
2394 \r
2395       FreePool (PciRegisterAccessData);\r
2396 \r
2397       return Status;\r
2398     }\r
2399 \r
2400   }\r
2401   //\r
2402   // AccessWidth incompatible check not supportted\r
2403   // or, there doesn't exist incompatibility on this operation\r
2404   //\r
2405   if (PciRootBridgeIo != NULL) {\r
2406     Status = PciRootBridgeIo->Pci.Write (\r
2407                      PciRootBridgeIo,\r
2408                      (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2409                      Address,\r
2410                      1,\r
2411                      Buffer\r
2412                      );\r
2413   } else {\r
2414     Status = PciIo->Pci.Write (\r
2415                    PciIo,\r
2416                    (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2417                    (UINT32) Address,\r
2418                    1,\r
2419                    Buffer\r
2420                    );\r
2421   }\r
2422 \r
2423   return Status;\r
2424 }\r
2425 \r
2426 /**\r
2427   Abstract PCI device device information.\r
2428 \r
2429   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2430   @param  PciIo               A pointer to EFI_PCI_PROTOCOL.\r
2431   @param  Pci                 A pointer to PCI_TYPE00.\r
2432   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2433   @param  PciDeviceInfo       A pointer to EFI_PCI_DEVICE_INFO.\r
2434 \r
2435   @retval EFI_SUCCESS         Pci device device information has been abstracted.\r
2436 \r
2437 **/\r
2438 STATIC\r
2439 EFI_STATUS\r
2440 GetPciDeviceDeviceInfo (\r
2441   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,  OPTIONAL\r
2442   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,            OPTIONAL\r
2443   IN       PCI_TYPE00                             *Pci,              OPTIONAL\r
2444   IN       UINT64                                 Address,           OPTIONAL\r
2445   OUT      EFI_PCI_DEVICE_INFO                    *PciDeviceInfo\r
2446 )\r
2447 {\r
2448   EFI_STATUS                    Status;\r
2449   UINT64                        PciAddress;\r
2450   UINT32                        PciConfigData;\r
2451   PCI_IO_DEVICE                 *PciIoDevice;\r
2452 \r
2453   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2454 \r
2455   if (PciIo != NULL) {\r
2456     PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
2457 \r
2458     //\r
2459     // get pointer to PCI_TYPE00 from PciIoDevice\r
2460     //\r
2461     Pci = &PciIoDevice->Pci;\r
2462   }\r
2463 \r
2464   if (Pci == NULL) {\r
2465     //\r
2466     // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly\r
2467     //\r
2468     PciAddress = Address & 0xffffffffffffff00ULL;\r
2469     Status = PciRootBridgeIo->Pci.Read (\r
2470                                     PciRootBridgeIo,\r
2471                                     EfiPciWidthUint32,\r
2472                                     PciAddress,\r
2473                                     1,\r
2474                                     &PciConfigData\r
2475                                     );\r
2476 \r
2477     if (EFI_ERROR (Status)) {\r
2478       return Status;\r
2479     }\r
2480 \r
2481     if ((PciConfigData & 0xffff) == 0xffff) {\r
2482       return EFI_NOT_FOUND;\r
2483     }\r
2484 \r
2485     PciDeviceInfo->VendorID = PciConfigData & 0xffff;\r
2486     PciDeviceInfo->DeviceID = PciConfigData >> 16;\r
2487 \r
2488     Status = PciRootBridgeIo->Pci.Read (\r
2489                                     PciRootBridgeIo,\r
2490                                     EfiPciWidthUint32,\r
2491                                     PciAddress + 8,\r
2492                                     1,\r
2493                                     &PciConfigData\r
2494                                     );\r
2495     if (EFI_ERROR (Status)) {\r
2496       return Status;\r
2497     }\r
2498 \r
2499     PciDeviceInfo->RevisionID = PciConfigData & 0xf;\r
2500 \r
2501     Status = PciRootBridgeIo->Pci.Read (\r
2502                                     PciRootBridgeIo,\r
2503                                     EfiPciWidthUint32,\r
2504                                     PciAddress + 0x2c,\r
2505                                     1,\r
2506                                     &PciConfigData\r
2507                                     );\r
2508 \r
2509     if (EFI_ERROR (Status)) {\r
2510       return Status;\r
2511     }\r
2512 \r
2513     PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;\r
2514     PciDeviceInfo->SubsystemID = PciConfigData >> 16;\r
2515 \r
2516   } else {\r
2517     PciDeviceInfo->VendorID          = Pci->Hdr.VendorId;\r
2518     PciDeviceInfo->DeviceID          = Pci->Hdr.DeviceId;\r
2519     PciDeviceInfo->RevisionID        = Pci->Hdr.RevisionID;\r
2520     PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;\r
2521     PciDeviceInfo->SubsystemID       = Pci->Device.SubsystemID;\r
2522   }\r
2523 \r
2524   return EFI_SUCCESS;\r
2525 }\r
2526 \r
2527 /**\r
2528   Read PCI configuration space with incompatibility check.\r
2529 \r
2530   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2531   @param  PciIo               A pointer to the EFI_PCI_IO_PROTOCOL.\r
2532   @param  Pci                 A pointer to PCI_TYPE00.\r
2533   @param  Width               Signifies the width of the memory operations.\r
2534   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2535   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2536                               write operations, the source buffer to write data from.\r
2537 \r
2538   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2539   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2540   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2541   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2542 \r
2543 **/\r
2544 STATIC\r
2545 EFI_STATUS\r
2546 PciIncompatibilityCheckRead (\r
2547   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,   OPTIONAL\r
2548   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,             OPTIONAL\r
2549   IN       PCI_TYPE00                             *Pci,               OPTIONAL\r
2550   IN       UINTN                                  Width,\r
2551   IN       UINT64                                 Address,\r
2552   IN       UINTN                                  Count,\r
2553   IN OUT   VOID                                   *Buffer\r
2554 )\r
2555 {\r
2556   EFI_STATUS                    Status;\r
2557   EFI_PCI_DEVICE_INFO           PciDeviceInfo;\r
2558   UINT32                        Stride;\r
2559 \r
2560   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2561 \r
2562   //\r
2563   // get PCI device device information\r
2564   //\r
2565   Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2566   if (Status != EFI_SUCCESS) {\r
2567     return Status;\r
2568   }\r
2569 \r
2570   Stride = 1 << Width;\r
2571 \r
2572   for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) {\r
2573 \r
2574     //\r
2575     // read configuration register\r
2576     //\r
2577     Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer);\r
2578 \r
2579     if (Status != EFI_SUCCESS) {\r
2580       return Status;\r
2581     }\r
2582 \r
2583     //\r
2584     // update the data read from configuration register\r
2585     //\r
2586     if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2587       UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer);\r
2588     }\r
2589   }\r
2590 \r
2591   return EFI_SUCCESS;\r
2592 }\r
2593 \r
2594 /**\r
2595   Write PCI configuration space with incompatibility check.\r
2596 \r
2597   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2598   @param  PciIo               A pointer to the EFI_PCI_IO_PROTOCOL.\r
2599   @param  Pci                 A pointer to PCI_TYPE00.\r
2600   @param  Width               Signifies the width of the memory operations.\r
2601   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2602   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2603                               write operations, the source buffer to write data from.\r
2604 \r
2605   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2606   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2607   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2608   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2609 \r
2610 **/\r
2611 STATIC\r
2612 EFI_STATUS\r
2613 PciIncompatibilityCheckWrite (\r
2614   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,   OPTIONAL\r
2615   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,             OPTIONAL\r
2616   IN       PCI_TYPE00                             *Pci,               OPTIONAL\r
2617   IN       UINTN                                  Width,\r
2618   IN       UINT64                                 Address,\r
2619   IN       UINTN                                  Count,\r
2620   IN OUT   VOID                                   *Buffer\r
2621 )\r
2622 {\r
2623   EFI_STATUS                    Status;\r
2624   EFI_PCI_DEVICE_INFO           PciDeviceInfo;\r
2625   UINT32                        Stride;\r
2626   UINT64                        Data;\r
2627 \r
2628   ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2629 \r
2630   //\r
2631   // get PCI device device information\r
2632   //\r
2633   Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2634   if (Status != EFI_SUCCESS) {\r
2635     return Status;\r
2636   }\r
2637 \r
2638   Stride = 1 << Width;\r
2639 \r
2640   for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) {\r
2641 \r
2642     Data = 0;\r
2643 \r
2644     switch (Width) {\r
2645     case EfiPciWidthUint8:\r
2646       Data = * (UINT8 *) Buffer;\r
2647       break;\r
2648     case EfiPciWidthUint16:\r
2649       Data = * (UINT16 *) Buffer;\r
2650       break;\r
2651 \r
2652     case EfiPciWidthUint32:\r
2653       Data = * (UINT32 *) Buffer;\r
2654       break;\r
2655 \r
2656     default:\r
2657       return EFI_UNSUPPORTED;\r
2658     }\r
2659 \r
2660     //\r
2661     // update the data writen into configuration register\r
2662     //\r
2663     if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2664       UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data);\r
2665     }\r
2666 \r
2667     //\r
2668     // write configuration register\r
2669     //\r
2670     Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data);\r
2671 \r
2672     if (Status != EFI_SUCCESS) {\r
2673       return Status;\r
2674     }\r
2675   }\r
2676 \r
2677   return EFI_SUCCESS;\r
2678 }\r
2679 \r
2680 /**\r
2681   Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2682 \r
2683   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2684   @param  Pci                 A pointer to PCI_TYPE00.\r
2685   @param  Width               Signifies the width of the memory operations.\r
2686   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2687   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2688                               write operations, the source buffer to write data from.\r
2689 \r
2690   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2691   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2692   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2693   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2694 \r
2695 **/\r
2696 EFI_STATUS\r
2697 PciRootBridgeIoRead (\r
2698   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,\r
2699   IN       PCI_TYPE00                             *Pci,            OPTIONAL\r
2700   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
2701   IN       UINT64                                 Address,\r
2702   IN       UINTN                                  Count,\r
2703   IN OUT   VOID                                   *Buffer\r
2704   )\r
2705 {\r
2706   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2707     //\r
2708     // if PCI incompatibility check enabled\r
2709     //\r
2710     return PciIncompatibilityCheckRead (\r
2711                    PciRootBridgeIo,\r
2712                    NULL,\r
2713                    Pci,\r
2714                    (UINTN) Width,\r
2715                    Address,\r
2716                    Count,\r
2717                    Buffer\r
2718                    );\r
2719   } else {\r
2720     return PciRootBridgeIo->Pci.Read (\r
2721                    PciRootBridgeIo,\r
2722                    Width,\r
2723                    Address,\r
2724                    Count,\r
2725                    Buffer\r
2726                    );\r
2727   }\r
2728 }\r
2729 \r
2730 /**\r
2731   Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2732 \r
2733   @param  PciRootBridgeIo     A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2734   @param  Pci                 A pointer to PCI_TYPE00.\r
2735   @param  Width               Signifies the width of the memory operations.\r
2736   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2737   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2738                               write operations, the source buffer to write data from.\r
2739 \r
2740   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2741   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2742   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2743   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2744 \r
2745 **/\r
2746 EFI_STATUS\r
2747 PciRootBridgeIoWrite (\r
2748   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo,\r
2749   IN       PCI_TYPE00                             *Pci,\r
2750   IN       EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
2751   IN       UINT64                                 Address,\r
2752   IN       UINTN                                  Count,\r
2753   IN OUT   VOID                                   *Buffer\r
2754   )\r
2755 {\r
2756   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2757     //\r
2758     // if PCI incompatibility check enabled\r
2759     //\r
2760     return  PciIncompatibilityCheckWrite (\r
2761                    PciRootBridgeIo,\r
2762                    NULL,\r
2763                    Pci,\r
2764                    Width,\r
2765                    Address,\r
2766                    Count,\r
2767                    Buffer\r
2768                    );\r
2769 \r
2770   } else {\r
2771     return  PciRootBridgeIo->Pci.Write (\r
2772                    PciRootBridgeIo,\r
2773                    Width,\r
2774                    Address,\r
2775                    Count,\r
2776                    Buffer\r
2777                    );\r
2778   }\r
2779 }\r
2780 \r
2781 /**\r
2782   Read PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2783 \r
2784   @param  PciIo               A pointer to the EFI_PCI_O_PROTOCOL.\r
2785   @param  Width               Signifies the width of the memory operations.\r
2786   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2787   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2788                               write operations, the source buffer to write data from.\r
2789 \r
2790   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2791   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2792   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2793   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2794 \r
2795 **/\r
2796 EFI_STATUS\r
2797 PciIoRead (\r
2798   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,\r
2799   IN       EFI_PCI_IO_PROTOCOL_WIDTH              Width,\r
2800   IN       UINT32                                 Address,\r
2801   IN       UINTN                                  Count,\r
2802   IN OUT   VOID                                   *Buffer\r
2803   )\r
2804 {\r
2805   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2806     //\r
2807     // if PCI incompatibility check enabled\r
2808     //\r
2809     return PciIncompatibilityCheckRead (\r
2810                    NULL,\r
2811                    PciIo,\r
2812                    NULL,\r
2813                    (UINTN) Width,\r
2814                    Address,\r
2815                    Count,\r
2816                    Buffer\r
2817                    );\r
2818   } else {\r
2819     return PciIo->Pci.Read (\r
2820                    PciIo,\r
2821                    Width,\r
2822                    Address,\r
2823                    Count,\r
2824                    Buffer\r
2825                    );\r
2826   }\r
2827 }\r
2828 \r
2829 /**\r
2830   Write PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2831 \r
2832   @param  PciIo               A pointer to the EFI_PCI_O_PROTOCOL.\r
2833   @param  Width               Signifies the width of the memory operations.\r
2834   @Param  Address             The address within the PCI configuration space for the PCI controller.\r
2835   @param  Buffer              For read operations, the destination buffer to store the results. For\r
2836                               write operations, the source buffer to write data from.\r
2837 \r
2838   @retval EFI_SUCCESS            The data was read from or written to the PCI root bridge.\r
2839   @retval EFI_INVALID_PARAMETER  Width is invalid for this PCI root bridge.\r
2840   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
2841   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.\r
2842 \r
2843 **/\r
2844 EFI_STATUS\r
2845 PciIoWrite (\r
2846   IN       EFI_PCI_IO_PROTOCOL                    *PciIo,\r
2847   IN       EFI_PCI_IO_PROTOCOL_WIDTH              Width,\r
2848   IN       UINT32                                 Address,\r
2849   IN       UINTN                                  Count,\r
2850   IN OUT   VOID                                   *Buffer\r
2851   )\r
2852 {\r
2853   if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2854 \r
2855     //\r
2856     // if PCI incompatibility check enabled\r
2857     //\r
2858     return  PciIncompatibilityCheckWrite (\r
2859                    NULL,\r
2860                    PciIo,\r
2861                    NULL,\r
2862                    Width,\r
2863                    Address,\r
2864                    Count,\r
2865                    Buffer\r
2866                    );\r
2867 \r
2868   } else {\r
2869     return PciIo->Pci.Write (\r
2870                    PciIo,\r
2871                    Width,\r
2872                    Address,\r
2873                    Count,\r
2874                    Buffer\r
2875                    );\r
2876   }\r
2877 }\r