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