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