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