]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
Update PCI bus driver to support non-standard PCI to PCI bridge I/O window alignment...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciLib.c
1 /** @file
2 Internal library implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PciBus.h"
16
17
18 /**
19 Retrieve the PCI Card device BAR information via PciIo interface.
20
21 @param PciIoDevice PCI Card device instance.
22
23 **/
24 VOID
25 GetBackPcCardBar (
26 IN PCI_IO_DEVICE *PciIoDevice
27 )
28 {
29 UINT32 Address;
30
31 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
32 return;
33 }
34
35 //
36 // Read PciBar information from the bar register
37 //
38 if (!gFullEnumeration) {
39 Address = 0;
40 PciIoDevice->PciIo.Pci.Read (
41 &(PciIoDevice->PciIo),
42 EfiPciIoWidthUint32,
43 PCI_CARD_MEMORY_BASE_0,
44 1,
45 &Address
46 );
47
48 (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
49 (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
50 (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
51
52 Address = 0;
53 PciIoDevice->PciIo.Pci.Read (
54 &(PciIoDevice->PciIo),
55 EfiPciIoWidthUint32,
56 PCI_CARD_MEMORY_BASE_1,
57 1,
58 &Address
59 );
60 (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
61 (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
62 (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
63
64 Address = 0;
65 PciIoDevice->PciIo.Pci.Read (
66 &(PciIoDevice->PciIo),
67 EfiPciIoWidthUint32,
68 PCI_CARD_IO_BASE_0_LOWER,
69 1,
70 &Address
71 );
72 (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
73 (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
74 (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
75
76 Address = 0;
77 PciIoDevice->PciIo.Pci.Read (
78 &(PciIoDevice->PciIo),
79 EfiPciIoWidthUint32,
80 PCI_CARD_IO_BASE_1_LOWER,
81 1,
82 &Address
83 );
84 (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
85 (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
86 (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
87
88 }
89
90 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
91 GetResourcePaddingForHpb (PciIoDevice);
92 }
93 }
94
95 /**
96 Remove rejected pci device from specific root bridge
97 handle.
98
99 @param RootBridgeHandle Specific parent root bridge handle.
100 @param Bridge Bridge device instance.
101
102 **/
103 VOID
104 RemoveRejectedPciDevices (
105 IN EFI_HANDLE RootBridgeHandle,
106 IN PCI_IO_DEVICE *Bridge
107 )
108 {
109 PCI_IO_DEVICE *Temp;
110 LIST_ENTRY *CurrentLink;
111 LIST_ENTRY *LastLink;
112
113 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
114 return;
115 }
116
117 CurrentLink = Bridge->ChildList.ForwardLink;
118
119 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
120
121 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
122
123 if (IS_PCI_BRIDGE (&Temp->Pci)) {
124 //
125 // Remove rejected devices recusively
126 //
127 RemoveRejectedPciDevices (RootBridgeHandle, Temp);
128 } else {
129 //
130 // Skip rejection for all PPBs, while detect rejection for others
131 //
132 if (IsPciDeviceRejected (Temp)) {
133
134 //
135 // For P2C, remove all devices on it
136 //
137 if (!IsListEmpty (&Temp->ChildList)) {
138 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
139 }
140
141 //
142 // Finally remove itself
143 //
144 LastLink = CurrentLink->BackLink;
145 RemoveEntryList (CurrentLink);
146 FreePciDevice (Temp);
147
148 CurrentLink = LastLink;
149 }
150 }
151
152 CurrentLink = CurrentLink->ForwardLink;
153 }
154 }
155
156 /**
157 Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
158
159 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
160
161 @retval EFI_SUCCESS Successfully finished resource allocation.
162 @retval EFI_NOT_FOUND Cannot get root bridge instance.
163 @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
164 @retval other Some error occurred when allocating resources for the PCI Host Bridge.
165
166 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
167
168 **/
169 EFI_STATUS
170 PciHostBridgeResourceAllocator (
171 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
172 )
173 {
174 PCI_IO_DEVICE *RootBridgeDev;
175 EFI_HANDLE RootBridgeHandle;
176 VOID *AcpiConfig;
177 EFI_STATUS Status;
178 UINT64 IoBase;
179 UINT64 Mem32Base;
180 UINT64 PMem32Base;
181 UINT64 Mem64Base;
182 UINT64 PMem64Base;
183 UINT64 IoResStatus;
184 UINT64 Mem32ResStatus;
185 UINT64 PMem32ResStatus;
186 UINT64 Mem64ResStatus;
187 UINT64 PMem64ResStatus;
188 UINT64 MaxOptionRomSize;
189 PCI_RESOURCE_NODE *IoBridge;
190 PCI_RESOURCE_NODE *Mem32Bridge;
191 PCI_RESOURCE_NODE *PMem32Bridge;
192 PCI_RESOURCE_NODE *Mem64Bridge;
193 PCI_RESOURCE_NODE *PMem64Bridge;
194 PCI_RESOURCE_NODE IoPool;
195 PCI_RESOURCE_NODE Mem32Pool;
196 PCI_RESOURCE_NODE PMem32Pool;
197 PCI_RESOURCE_NODE Mem64Pool;
198 PCI_RESOURCE_NODE PMem64Pool;
199 BOOLEAN ReAllocate;
200 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
201 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
202
203 //
204 // Reallocate flag
205 //
206 ReAllocate = FALSE;
207
208 //
209 // It may try several times if the resource allocation fails
210 //
211 while (TRUE) {
212 //
213 // Initialize resource pool
214 //
215 InitializeResourcePool (&IoPool, PciBarTypeIo16);
216 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
217 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
218 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
219 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
220
221 RootBridgeDev = NULL;
222 RootBridgeHandle = 0;
223
224 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
225 //
226 // Get Root Bridge Device by handle
227 //
228 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
229
230 if (RootBridgeDev == NULL) {
231 return EFI_NOT_FOUND;
232 }
233
234 //
235 // Create the entire system resource map from the information collected by
236 // enumerator. Several resource tree was created
237 //
238
239 //
240 // If non-stardard PCI Bridge I/O window alignment is supported,
241 // set I/O aligment to minimum possible alignment for root bridge.
242 //
243 IoBridge = CreateResourceNode (
244 RootBridgeDev,
245 0,
246 FeaturePcdGet (PcdPciBridgeIoAlignmentProbe) ? 0x1FF: 0xFFF,
247 0,
248 PciBarTypeIo16,
249 PciResUsageTypical
250 );
251
252 Mem32Bridge = CreateResourceNode (
253 RootBridgeDev,
254 0,
255 0xFFFFF,
256 0,
257 PciBarTypeMem32,
258 PciResUsageTypical
259 );
260
261 PMem32Bridge = CreateResourceNode (
262 RootBridgeDev,
263 0,
264 0xFFFFF,
265 0,
266 PciBarTypePMem32,
267 PciResUsageTypical
268 );
269
270 Mem64Bridge = CreateResourceNode (
271 RootBridgeDev,
272 0,
273 0xFFFFF,
274 0,
275 PciBarTypeMem64,
276 PciResUsageTypical
277 );
278
279 PMem64Bridge = CreateResourceNode (
280 RootBridgeDev,
281 0,
282 0xFFFFF,
283 0,
284 PciBarTypePMem64,
285 PciResUsageTypical
286 );
287
288 //
289 // Create resourcemap by going through all the devices subject to this root bridge
290 //
291 CreateResourceMap (
292 RootBridgeDev,
293 IoBridge,
294 Mem32Bridge,
295 PMem32Bridge,
296 Mem64Bridge,
297 PMem64Bridge
298 );
299
300 //
301 // Get the max ROM size that the root bridge can process
302 //
303 RootBridgeDev->RomSize = Mem32Bridge->Length;
304
305 //
306 // Skip to enlarge the resource request during realloction
307 //
308 if (!ReAllocate) {
309 //
310 // Get Max Option Rom size for current root bridge
311 //
312 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
313
314 //
315 // Enlarger the mem32 resource to accomdate the option rom
316 // if the mem32 resource is not enough to hold the rom
317 //
318 if (MaxOptionRomSize > Mem32Bridge->Length) {
319
320 Mem32Bridge->Length = MaxOptionRomSize;
321 RootBridgeDev->RomSize = MaxOptionRomSize;
322
323 //
324 // Alignment should be adjusted as well
325 //
326 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {
327 Mem32Bridge->Alignment = MaxOptionRomSize - 1;
328 }
329 }
330 }
331
332 //
333 // Based on the all the resource tree, contruct ACPI resource node to
334 // submit the resource aperture to pci host bridge protocol
335 //
336 Status = ConstructAcpiResourceRequestor (
337 RootBridgeDev,
338 IoBridge,
339 Mem32Bridge,
340 PMem32Bridge,
341 Mem64Bridge,
342 PMem64Bridge,
343 &AcpiConfig
344 );
345
346 //
347 // Insert these resource nodes into the database
348 //
349 InsertResourceNode (&IoPool, IoBridge);
350 InsertResourceNode (&Mem32Pool, Mem32Bridge);
351 InsertResourceNode (&PMem32Pool, PMem32Bridge);
352 InsertResourceNode (&Mem64Pool, Mem64Bridge);
353 InsertResourceNode (&PMem64Pool, PMem64Bridge);
354
355 if (Status == EFI_SUCCESS) {
356 //
357 // Submit the resource requirement
358 //
359 Status = PciResAlloc->SubmitResources (
360 PciResAlloc,
361 RootBridgeDev->Handle,
362 AcpiConfig
363 );
364 }
365
366 //
367 // Free acpi resource node
368 //
369 if (AcpiConfig != NULL) {
370 FreePool (AcpiConfig);
371 }
372
373 if (EFI_ERROR (Status)) {
374 //
375 // Destroy all the resource tree
376 //
377 DestroyResourceTree (&IoPool);
378 DestroyResourceTree (&Mem32Pool);
379 DestroyResourceTree (&PMem32Pool);
380 DestroyResourceTree (&Mem64Pool);
381 DestroyResourceTree (&PMem64Pool);
382 return Status;
383 }
384 }
385 //
386 // End while, at least one Root Bridge should be found.
387 //
388 ASSERT (RootBridgeDev != NULL);
389
390 //
391 // Notify platform to start to program the resource
392 //
393 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
394 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
395 //
396 // If Hot Plug is not supported
397 //
398 if (EFI_ERROR (Status)) {
399 //
400 // Allocation failed, then return
401 //
402 return EFI_OUT_OF_RESOURCES;
403 }
404 //
405 // Allocation succeed.
406 // Get host bridge handle for status report, and then skip the main while
407 //
408 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
409
410 break;
411
412 } else {
413 //
414 // If Hot Plug is supported
415 //
416 if (!EFI_ERROR (Status)) {
417 //
418 // Allocation succeed, then continue the following
419 //
420 break;
421 }
422
423 //
424 // If the resource allocation is unsuccessful, free resources on bridge
425 //
426
427 RootBridgeDev = NULL;
428 RootBridgeHandle = 0;
429
430 IoResStatus = EFI_RESOURCE_SATISFIED;
431 Mem32ResStatus = EFI_RESOURCE_SATISFIED;
432 PMem32ResStatus = EFI_RESOURCE_SATISFIED;
433 Mem64ResStatus = EFI_RESOURCE_SATISFIED;
434 PMem64ResStatus = EFI_RESOURCE_SATISFIED;
435
436 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
437 //
438 // Get RootBridg Device by handle
439 //
440 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
441 if (RootBridgeDev == NULL) {
442 return EFI_NOT_FOUND;
443 }
444
445 //
446 // Get host bridge handle for status report
447 //
448 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
449
450 //
451 // Get acpi resource node for all the resource types
452 //
453 AcpiConfig = NULL;
454
455 Status = PciResAlloc->GetProposedResources (
456 PciResAlloc,
457 RootBridgeDev->Handle,
458 &AcpiConfig
459 );
460
461 if (EFI_ERROR (Status)) {
462 return Status;
463 }
464
465 if (AcpiConfig != NULL) {
466 //
467 // Adjust resource allocation policy for each RB
468 //
469 GetResourceAllocationStatus (
470 AcpiConfig,
471 &IoResStatus,
472 &Mem32ResStatus,
473 &PMem32ResStatus,
474 &Mem64ResStatus,
475 &PMem64ResStatus
476 );
477 FreePool (AcpiConfig);
478 }
479 }
480 //
481 // End while
482 //
483
484 //
485 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
486 //
487 //
488 // It is very difficult to follow the spec here
489 // Device path , Bar index can not be get here
490 //
491 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
492
493 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
494 EFI_PROGRESS_CODE,
495 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
496 (VOID *) &AllocFailExtendedData,
497 sizeof (AllocFailExtendedData)
498 );
499
500 Status = PciHostBridgeAdjustAllocation (
501 &IoPool,
502 &Mem32Pool,
503 &PMem32Pool,
504 &Mem64Pool,
505 &PMem64Pool,
506 IoResStatus,
507 Mem32ResStatus,
508 PMem32ResStatus,
509 Mem64ResStatus,
510 PMem64ResStatus
511 );
512
513 //
514 // Destroy all the resource tree
515 //
516 DestroyResourceTree (&IoPool);
517 DestroyResourceTree (&Mem32Pool);
518 DestroyResourceTree (&PMem32Pool);
519 DestroyResourceTree (&Mem64Pool);
520 DestroyResourceTree (&PMem64Pool);
521
522 NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
523
524 if (EFI_ERROR (Status)) {
525 return Status;
526 }
527
528 ReAllocate = TRUE;
529 }
530 }
531 //
532 // End main while
533 //
534
535 //
536 // Raise the EFI_IOB_PCI_RES_ALLOC status code
537 //
538 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
539 EFI_PROGRESS_CODE,
540 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,
541 (VOID *) &HandleExtendedData,
542 sizeof (HandleExtendedData)
543 );
544
545 //
546 // Notify pci bus driver starts to program the resource
547 //
548 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
549
550 RootBridgeDev = NULL;
551
552 RootBridgeHandle = 0;
553
554 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
555 //
556 // Get RootBridg Device by handle
557 //
558 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
559
560 if (RootBridgeDev == NULL) {
561 return EFI_NOT_FOUND;
562 }
563
564 //
565 // Get acpi resource node for all the resource types
566 //
567 AcpiConfig = NULL;
568 Status = PciResAlloc->GetProposedResources (
569 PciResAlloc,
570 RootBridgeDev->Handle,
571 &AcpiConfig
572 );
573
574 if (EFI_ERROR (Status)) {
575 return Status;
576 }
577
578 //
579 // Get the resource base by interpreting acpi resource node
580 //
581 //
582 GetResourceBase (
583 AcpiConfig,
584 &IoBase,
585 &Mem32Base,
586 &PMem32Base,
587 &Mem64Base,
588 &PMem64Base
589 );
590
591 //
592 // Process option rom for this root bridge
593 //
594 ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);
595
596 //
597 // Create the entire system resource map from the information collected by
598 // enumerator. Several resource tree was created
599 //
600 GetResourceMap (
601 RootBridgeDev,
602 &IoBridge,
603 &Mem32Bridge,
604 &PMem32Bridge,
605 &Mem64Bridge,
606 &PMem64Bridge,
607 &IoPool,
608 &Mem32Pool,
609 &PMem32Pool,
610 &Mem64Pool,
611 &PMem64Pool
612 );
613
614 //
615 // Program IO resources
616 //
617 ProgramResource (
618 IoBase,
619 IoBridge
620 );
621
622 //
623 // Program Mem32 resources
624 //
625 ProgramResource (
626 Mem32Base,
627 Mem32Bridge
628 );
629
630 //
631 // Program PMem32 resources
632 //
633 ProgramResource (
634 PMem32Base,
635 PMem32Bridge
636 );
637
638 //
639 // Program Mem64 resources
640 //
641 ProgramResource (
642 Mem64Base,
643 Mem64Bridge
644 );
645
646 //
647 // Program PMem64 resources
648 //
649 ProgramResource (
650 PMem64Base,
651 PMem64Bridge
652 );
653
654 FreePool (AcpiConfig);
655 }
656
657 //
658 // Destroy all the resource tree
659 //
660 DestroyResourceTree (&IoPool);
661 DestroyResourceTree (&Mem32Pool);
662 DestroyResourceTree (&PMem32Pool);
663 DestroyResourceTree (&Mem64Pool);
664 DestroyResourceTree (&PMem64Pool);
665
666 //
667 // Notify the resource allocation phase is to end
668 //
669 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
670
671 return EFI_SUCCESS;
672 }
673
674 /**
675 Scan pci bus and assign bus number to the given PCI bus system.
676
677 @param Bridge Bridge device instance.
678 @param StartBusNumber start point.
679 @param SubBusNumber Point to sub bus number.
680 @param PaddedBusRange Customized bus number.
681
682 @retval EFI_SUCCESS Successfully scanned and assigned bus number.
683 @retval other Some error occurred when scanning pci bus.
684
685 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
686
687 **/
688 EFI_STATUS
689 PciScanBus (
690 IN PCI_IO_DEVICE *Bridge,
691 IN UINT8 StartBusNumber,
692 OUT UINT8 *SubBusNumber,
693 OUT UINT8 *PaddedBusRange
694 )
695 {
696 EFI_STATUS Status;
697 PCI_TYPE00 Pci;
698 UINT8 Device;
699 UINT8 Func;
700 UINT64 Address;
701 UINTN SecondBus;
702 UINT16 Register;
703 UINTN HpIndex;
704 PCI_IO_DEVICE *PciDevice;
705 EFI_EVENT Event;
706 EFI_HPC_STATE State;
707 UINT64 PciAddress;
708 EFI_HPC_PADDING_ATTRIBUTES Attributes;
709 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
710 UINT16 BusRange;
711 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
712 BOOLEAN BusPadding;
713 UINT32 TempReservedBusNum;
714
715 PciRootBridgeIo = Bridge->PciRootBridgeIo;
716 SecondBus = 0;
717 Register = 0;
718 State = 0;
719 Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
720 BusRange = 0;
721 BusPadding = FALSE;
722 PciDevice = NULL;
723 PciAddress = 0;
724
725 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
726 TempReservedBusNum = 0;
727 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
728
729 //
730 // Check to see whether a pci device is present
731 //
732 Status = PciDevicePresent (
733 PciRootBridgeIo,
734 &Pci,
735 StartBusNumber,
736 Device,
737 Func
738 );
739
740 if (EFI_ERROR (Status)) {
741 if (Func == 0) {
742 //
743 // Skip sub functions, this is not a multi function device
744 //
745 Func = PCI_MAX_FUNC;
746 }
747
748 continue;
749 }
750
751 DEBUG((EFI_D_INFO, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));
752
753 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
754 //
755 // Get the PCI device information
756 //
757 Status = PciSearchDevice (
758 Bridge,
759 &Pci,
760 StartBusNumber,
761 Device,
762 Func,
763 &PciDevice
764 );
765
766 ASSERT (!EFI_ERROR (Status));
767
768 PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
769
770 if (!IS_PCI_BRIDGE (&Pci)) {
771 //
772 // PCI bridges will be called later
773 // Here just need for PCI device or PCI to cardbus controller
774 // EfiPciBeforeChildBusEnumeration for PCI Device Node
775 //
776 PreprocessController (
777 PciDevice,
778 PciDevice->BusNumber,
779 PciDevice->DeviceNumber,
780 PciDevice->FunctionNumber,
781 EfiPciBeforeChildBusEnumeration
782 );
783 }
784
785 //
786 // For Pci Hotplug controller devcie only
787 //
788 if (gPciHotPlugInit != NULL) {
789 //
790 // Check if it is a Hotplug PCI controller
791 //
792 if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
793
794 if (!gPciRootHpcData[HpIndex].Initialized) {
795
796 Status = CreateEventForHpc (HpIndex, &Event);
797
798 ASSERT (!EFI_ERROR (Status));
799
800 Status = gPciHotPlugInit->InitializeRootHpc (
801 gPciHotPlugInit,
802 gPciRootHpcPool[HpIndex].HpcDevicePath,
803 PciAddress,
804 Event,
805 &State
806 );
807
808 PreprocessController (
809 PciDevice,
810 PciDevice->BusNumber,
811 PciDevice->DeviceNumber,
812 PciDevice->FunctionNumber,
813 EfiPciBeforeChildBusEnumeration
814 );
815 }
816 }
817 }
818 }
819
820 if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
821 //
822 // For PPB
823 //
824 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
825 //
826 // If Hot Plug is not supported,
827 // get the bridge information
828 //
829 Status = PciSearchDevice (
830 Bridge,
831 &Pci,
832 StartBusNumber,
833 Device,
834 Func,
835 &PciDevice
836 );
837
838 if (EFI_ERROR (Status)) {
839 return Status;
840 }
841 } else {
842 //
843 // If Hot Plug is supported,
844 // Get the bridge information
845 //
846 BusPadding = FALSE;
847 if (gPciHotPlugInit != NULL) {
848
849 if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {
850
851 //
852 // If it is initialized, get the padded bus range
853 //
854 Status = gPciHotPlugInit->GetResourcePadding (
855 gPciHotPlugInit,
856 gPciRootHpcPool[HpIndex].HpbDevicePath,
857 PciAddress,
858 &State,
859 (VOID **) &Descriptors,
860 &Attributes
861 );
862
863 if (EFI_ERROR (Status)) {
864 return Status;
865 }
866
867 BusRange = 0;
868 Status = PciGetBusRange (
869 &Descriptors,
870 NULL,
871 NULL,
872 &BusRange
873 );
874
875 FreePool (Descriptors);
876
877 if (EFI_ERROR (Status)) {
878 return Status;
879 }
880
881 BusPadding = TRUE;
882 }
883 }
884 }
885
886 //
887 // Add feature to support customized secondary bus number
888 //
889 if (*SubBusNumber == 0) {
890 *SubBusNumber = *PaddedBusRange;
891 *PaddedBusRange = 0;
892 }
893
894 (*SubBusNumber)++;
895 SecondBus = *SubBusNumber;
896
897 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
898 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
899
900 Status = PciRootBridgeIo->Pci.Write (
901 PciRootBridgeIo,
902 EfiPciWidthUint16,
903 Address,
904 1,
905 &Register
906 );
907
908
909 //
910 // If it is PPB, resursively search down this bridge
911 //
912 if (IS_PCI_BRIDGE (&Pci)) {
913
914 //
915 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
916 // PCI configuration transaction to go through any PPB
917 //
918 Register = 0xFF;
919 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
920 Status = PciRootBridgeIo->Pci.Write (
921 PciRootBridgeIo,
922 EfiPciWidthUint8,
923 Address,
924 1,
925 &Register
926 );
927
928 //
929 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
930 //
931 PreprocessController (
932 PciDevice,
933 PciDevice->BusNumber,
934 PciDevice->DeviceNumber,
935 PciDevice->FunctionNumber,
936 EfiPciBeforeChildBusEnumeration
937 );
938
939 DEBUG((EFI_D_INFO, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber));
940 Status = PciScanBus (
941 PciDevice,
942 (UINT8) (SecondBus),
943 SubBusNumber,
944 PaddedBusRange
945 );
946 if (EFI_ERROR (Status)) {
947 return Status;
948 }
949 }
950
951 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
952 //
953 // Ensure the device is enabled and initialized
954 //
955 if ((Attributes == EfiPaddingPciRootBridge) &&
956 (State & EFI_HPC_STATE_ENABLED) != 0 &&
957 (State & EFI_HPC_STATE_INITIALIZED) != 0) {
958 *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);
959 } else {
960 *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);
961 }
962 }
963
964 //
965 // Set the current maximum bus number under the PPB
966 //
967 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
968
969 Status = PciRootBridgeIo->Pci.Write (
970 PciRootBridgeIo,
971 EfiPciWidthUint8,
972 Address,
973 1,
974 SubBusNumber
975 );
976 } else {
977 //
978 // It is device. Check PCI IOV for Bus reservation
979 //
980 if (PciDevice == NULL) {
981 //
982 // No PciDevice found, conitue Scan
983 //
984 continue;
985 }
986 //
987 // Go through each function, just reserve the MAX ReservedBusNum for one device
988 //
989 if ((PciDevice->AriCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
990
991 if (TempReservedBusNum < PciDevice->ReservedBusNum) {
992
993 (*SubBusNumber) = (UINT8)((*SubBusNumber) + PciDevice->ReservedBusNum - TempReservedBusNum);
994 TempReservedBusNum = PciDevice->ReservedBusNum;
995
996 if (Func == 0) {
997 DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n", *SubBusNumber));
998 } else {
999 DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x (Update)\n", *SubBusNumber));
1000 }
1001 }
1002 }
1003 }
1004
1005 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
1006
1007 //
1008 // Skip sub functions, this is not a multi function device
1009 //
1010
1011 Func = PCI_MAX_FUNC;
1012 }
1013 }
1014 }
1015
1016 return EFI_SUCCESS;
1017 }
1018
1019 /**
1020 Process Option Rom on the specified root bridge.
1021
1022 @param Bridge Pci root bridge device instance.
1023
1024 @retval EFI_SUCCESS Success process.
1025 @retval other Some error occurred when processing Option Rom on the root bridge.
1026
1027 **/
1028 EFI_STATUS
1029 PciRootBridgeP2CProcess (
1030 IN PCI_IO_DEVICE *Bridge
1031 )
1032 {
1033 LIST_ENTRY *CurrentLink;
1034 PCI_IO_DEVICE *Temp;
1035 EFI_HPC_STATE State;
1036 UINT64 PciAddress;
1037 EFI_STATUS Status;
1038
1039 CurrentLink = Bridge->ChildList.ForwardLink;
1040
1041 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
1042
1043 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1044
1045 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
1046
1047 if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1048
1049 //
1050 // Raise the EFI_IOB_PCI_HPC_INIT status code
1051 //
1052 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1053 EFI_PROGRESS_CODE,
1054 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,
1055 Temp->DevicePath
1056 );
1057
1058 PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1059 Status = gPciHotPlugInit->InitializeRootHpc (
1060 gPciHotPlugInit,
1061 Temp->DevicePath,
1062 PciAddress,
1063 NULL,
1064 &State
1065 );
1066
1067 if (!EFI_ERROR (Status)) {
1068 Status = PciBridgeEnumerator (Temp);
1069
1070 if (EFI_ERROR (Status)) {
1071 return Status;
1072 }
1073 }
1074
1075 CurrentLink = CurrentLink->ForwardLink;
1076 continue;
1077
1078 }
1079 }
1080
1081 if (!IsListEmpty (&Temp->ChildList)) {
1082 Status = PciRootBridgeP2CProcess (Temp);
1083 }
1084
1085 CurrentLink = CurrentLink->ForwardLink;
1086 }
1087
1088 return EFI_SUCCESS;
1089 }
1090
1091 /**
1092 Process Option Rom on the specified host bridge.
1093
1094 @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
1095
1096 @retval EFI_SUCCESS Success process.
1097 @retval EFI_NOT_FOUND Can not find the root bridge instance.
1098 @retval other Some error occurred when processing Option Rom on the host bridge.
1099
1100 **/
1101 EFI_STATUS
1102 PciHostBridgeP2CProcess (
1103 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1104 )
1105 {
1106 EFI_HANDLE RootBridgeHandle;
1107 PCI_IO_DEVICE *RootBridgeDev;
1108 EFI_STATUS Status;
1109
1110 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1111 return EFI_SUCCESS;
1112 }
1113
1114 RootBridgeHandle = NULL;
1115
1116 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1117
1118 //
1119 // Get RootBridg Device by handle
1120 //
1121 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
1122
1123 if (RootBridgeDev == NULL) {
1124 return EFI_NOT_FOUND;
1125 }
1126
1127 Status = PciRootBridgeP2CProcess (RootBridgeDev);
1128 if (EFI_ERROR (Status)) {
1129 return Status;
1130 }
1131
1132 }
1133
1134 return EFI_SUCCESS;
1135 }
1136
1137 /**
1138 This function is used to enumerate the entire host bridge
1139 in a given platform.
1140
1141 @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
1142
1143 @retval EFI_SUCCESS Successfully enumerated the host bridge.
1144 @retval EFI_OUT_OF_RESOURCES No enough memory available.
1145 @retval other Some error occurred when enumerating the host bridge.
1146
1147 **/
1148 EFI_STATUS
1149 PciHostBridgeEnumerator (
1150 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1151 )
1152 {
1153 EFI_HANDLE RootBridgeHandle;
1154 PCI_IO_DEVICE *RootBridgeDev;
1155 EFI_STATUS Status;
1156 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1157 UINT16 MinBus;
1158 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1159 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
1160 UINT8 StartBusNumber;
1161 LIST_ENTRY RootBridgeList;
1162 LIST_ENTRY *Link;
1163
1164 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1165 InitializeHotPlugSupport ();
1166 }
1167
1168 InitializeListHead (&RootBridgeList);
1169
1170 //
1171 // Notify the bus allocation phase is about to start
1172 //
1173 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1174
1175 DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n"));
1176 RootBridgeHandle = NULL;
1177 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1178
1179 //
1180 // if a root bridge instance is found, create root bridge device for it
1181 //
1182
1183 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1184
1185 if (RootBridgeDev == NULL) {
1186 return EFI_OUT_OF_RESOURCES;
1187 }
1188
1189 //
1190 // Enumerate all the buses under this root bridge
1191 //
1192 Status = PciRootBridgeEnumerator (
1193 PciResAlloc,
1194 RootBridgeDev
1195 );
1196
1197 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1198 InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
1199 } else {
1200 DestroyRootBridge (RootBridgeDev);
1201 }
1202 if (EFI_ERROR (Status)) {
1203 return Status;
1204 }
1205 }
1206
1207 //
1208 // Notify the bus allocation phase is finished for the first time
1209 //
1210 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1211
1212 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1213 //
1214 // Reset all assigned PCI bus number in all PPB
1215 //
1216 RootBridgeHandle = NULL;
1217 Link = GetFirstNode (&RootBridgeList);
1218 while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&
1219 (!IsNull (&RootBridgeList, Link))) {
1220 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
1221 //
1222 // Get the Bus information
1223 //
1224 Status = PciResAlloc->StartBusEnumeration (
1225 PciResAlloc,
1226 RootBridgeHandle,
1227 (VOID **) &Configuration
1228 );
1229 if (EFI_ERROR (Status)) {
1230 return Status;
1231 }
1232
1233 //
1234 // Get the bus number to start with
1235 //
1236 StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
1237
1238 ResetAllPpbBusNumber (
1239 RootBridgeDev,
1240 StartBusNumber
1241 );
1242
1243 FreePool (Configuration);
1244 Link = GetNextNode (&RootBridgeList, Link);
1245 DestroyRootBridge (RootBridgeDev);
1246 }
1247
1248 //
1249 // Wait for all HPC initialized
1250 //
1251 Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
1252
1253 if (EFI_ERROR (Status)) {
1254 return Status;
1255 }
1256
1257 //
1258 // Notify the bus allocation phase is about to start for the 2nd time
1259 //
1260 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1261
1262 DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n"));
1263 RootBridgeHandle = NULL;
1264 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1265
1266 //
1267 // if a root bridge instance is found, create root bridge device for it
1268 //
1269 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1270
1271 if (RootBridgeDev == NULL) {
1272 return EFI_OUT_OF_RESOURCES;
1273 }
1274
1275 //
1276 // Enumerate all the buses under this root bridge
1277 //
1278 Status = PciRootBridgeEnumerator (
1279 PciResAlloc,
1280 RootBridgeDev
1281 );
1282
1283 DestroyRootBridge (RootBridgeDev);
1284 if (EFI_ERROR (Status)) {
1285 return Status;
1286 }
1287 }
1288
1289 //
1290 // Notify the bus allocation phase is to end for the 2nd time
1291 //
1292 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1293 }
1294
1295 //
1296 // Notify the resource allocation phase is to start
1297 //
1298 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
1299
1300 RootBridgeHandle = NULL;
1301 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1302
1303 //
1304 // if a root bridge instance is found, create root bridge device for it
1305 //
1306 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1307
1308 if (RootBridgeDev == NULL) {
1309 return EFI_OUT_OF_RESOURCES;
1310 }
1311
1312 Status = StartManagingRootBridge (RootBridgeDev);
1313
1314 if (EFI_ERROR (Status)) {
1315 return Status;
1316 }
1317
1318 PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
1319 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1320
1321 if (EFI_ERROR (Status)) {
1322 return Status;
1323 }
1324
1325 Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
1326
1327 if (EFI_ERROR (Status)) {
1328 return Status;
1329 }
1330
1331 //
1332 // Determine root bridge attribute by calling interface of Pcihostbridge
1333 // protocol
1334 //
1335 DetermineRootBridgeAttributes (
1336 PciResAlloc,
1337 RootBridgeDev
1338 );
1339
1340 //
1341 // Collect all the resource information under this root bridge
1342 // A database that records all the information about pci device subject to this
1343 // root bridge will then be created
1344 //
1345 Status = PciPciDeviceInfoCollector (
1346 RootBridgeDev,
1347 (UINT8) MinBus
1348 );
1349
1350 if (EFI_ERROR (Status)) {
1351 return Status;
1352 }
1353
1354 InsertRootBridge (RootBridgeDev);
1355
1356 //
1357 // Record the hostbridge handle
1358 //
1359 AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
1360 }
1361
1362 return EFI_SUCCESS;
1363 }