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