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