]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
4872e2206e34a87da1af4bf2d7140ab0d4fb317a
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
1 /** @file
2 Supporting functions implementaion for PCI devices management.
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 // This device structure is serviced as a header.
19 // Its next field points to the first root bridge device node.
20 //
21 LIST_ENTRY mPciDevicePool;
22
23 /**
24 Initialize the PCI devices pool.
25
26 **/
27 VOID
28 InitializePciDevicePool (
29 VOID
30 )
31 {
32 InitializeListHead (&mPciDevicePool);
33 }
34
35 /**
36 Insert a root bridge into PCI device pool.
37
38 @param RootBridge A pointer to the PCI_IO_DEVICE.
39
40 **/
41 VOID
42 InsertRootBridge (
43 IN PCI_IO_DEVICE *RootBridge
44 )
45 {
46 InsertTailList (&mPciDevicePool, &(RootBridge->Link));
47 }
48
49 /**
50 This function is used to insert a PCI device node under
51 a bridge.
52
53 @param Bridge The PCI bridge.
54 @param PciDeviceNode The PCI device needs inserting.
55
56 **/
57 VOID
58 InsertPciDevice (
59 IN PCI_IO_DEVICE *Bridge,
60 IN PCI_IO_DEVICE *PciDeviceNode
61 )
62 {
63 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
64 PciDeviceNode->Parent = Bridge;
65 }
66
67 /**
68 Destroy root bridge and remove it from deivce tree.
69
70 @param RootBridge The bridge want to be removed.
71
72 **/
73 VOID
74 DestroyRootBridge (
75 IN PCI_IO_DEVICE *RootBridge
76 )
77 {
78 DestroyPciDeviceTree (RootBridge);
79
80 FreePciDevice (RootBridge);
81 }
82
83 /**
84 Destroy a pci device node.
85
86 All direct or indirect allocated resource for this node will be freed.
87
88 @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.
89
90 **/
91 VOID
92 FreePciDevice (
93 IN PCI_IO_DEVICE *PciIoDevice
94 )
95 {
96 ASSERT (PciIoDevice != NULL);
97 //
98 // Assume all children have been removed underneath this device
99 //
100 if (PciIoDevice->ResourcePaddingDescriptors != NULL) {
101 FreePool (PciIoDevice->ResourcePaddingDescriptors);
102 }
103
104 if (PciIoDevice->DevicePath != NULL) {
105 FreePool (PciIoDevice->DevicePath);
106 }
107
108 FreePool (PciIoDevice);
109 }
110
111 /**
112 Destroy all the pci device node under the bridge.
113 Bridge itself is not included.
114
115 @param Bridge A pointer to the PCI_IO_DEVICE.
116
117 **/
118 VOID
119 DestroyPciDeviceTree (
120 IN PCI_IO_DEVICE *Bridge
121 )
122 {
123 LIST_ENTRY *CurrentLink;
124 PCI_IO_DEVICE *Temp;
125
126 while (!IsListEmpty (&Bridge->ChildList)) {
127
128 CurrentLink = Bridge->ChildList.ForwardLink;
129
130 //
131 // Remove this node from the linked list
132 //
133 RemoveEntryList (CurrentLink);
134
135 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
136
137 if (!IsListEmpty (&Temp->ChildList)) {
138 DestroyPciDeviceTree (Temp);
139 }
140
141 FreePciDevice (Temp);
142 }
143 }
144
145 /**
146 Destroy all device nodes under the root bridge
147 specified by Controller.
148
149 The root bridge itself is also included.
150
151 @param Controller Root bridge handle.
152
153 @retval EFI_SUCCESS Destory all devcie nodes successfully.
154 @retval EFI_NOT_FOUND Cannot find any PCI device under specified
155 root bridge.
156
157 **/
158 EFI_STATUS
159 DestroyRootBridgeByHandle (
160 IN EFI_HANDLE Controller
161 )
162 {
163
164 LIST_ENTRY *CurrentLink;
165 PCI_IO_DEVICE *Temp;
166
167 CurrentLink = mPciDevicePool.ForwardLink;
168
169 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
170 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
171
172 if (Temp->Handle == Controller) {
173
174 RemoveEntryList (CurrentLink);
175
176 DestroyPciDeviceTree (Temp);
177
178 FreePciDevice (Temp);
179
180 return EFI_SUCCESS;
181 }
182
183 CurrentLink = CurrentLink->ForwardLink;
184 }
185
186 return EFI_NOT_FOUND;
187 }
188
189 /**
190 This function registers the PCI IO device.
191
192 It creates a handle for this PCI IO device (if the handle does not exist), attaches
193 appropriate protocols onto the handle, does necessary initialization, and sets up
194 parent/child relationship with its bus controller.
195
196 @param Controller An EFI handle for the PCI bus controller.
197 @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
198 @param Handle A pointer to hold the returned EFI handle for the PCI IO device.
199
200 @retval EFI_SUCCESS The PCI device is successfully registered.
201 @retval Others An error occurred when registering the PCI device.
202
203 **/
204 EFI_STATUS
205 RegisterPciDevice (
206 IN EFI_HANDLE Controller,
207 IN PCI_IO_DEVICE *PciIoDevice,
208 OUT EFI_HANDLE *Handle OPTIONAL
209 )
210 {
211 EFI_STATUS Status;
212 VOID *PlatformOpRomBuffer;
213 UINTN PlatformOpRomSize;
214 UINT8 PciExpressCapRegOffset;
215 EFI_PCI_IO_PROTOCOL *PciIo;
216 UINT8 Data8;
217 BOOLEAN HasEfiImage;
218
219 //
220 // Install the pciio protocol, device path protocol
221 //
222 Status = gBS->InstallMultipleProtocolInterfaces (
223 &PciIoDevice->Handle,
224 &gEfiDevicePathProtocolGuid,
225 PciIoDevice->DevicePath,
226 &gEfiPciIoProtocolGuid,
227 &PciIoDevice->PciIo,
228 NULL
229 );
230 if (EFI_ERROR (Status)) {
231 return Status;
232 }
233
234 //
235 // Detect if PCI Express Device
236 //
237 PciExpressCapRegOffset = 0;
238 Status = LocateCapabilityRegBlock (
239 PciIoDevice,
240 EFI_PCI_CAPABILITY_ID_PCIEXP,
241 &PciExpressCapRegOffset,
242 NULL
243 );
244 if (!EFI_ERROR (Status)) {
245 PciIoDevice->IsPciExp = TRUE;
246 }
247
248 //
249 // Force Interrupt line to "Unknown" or "No Connection"
250 //
251 PciIo = &(PciIoDevice->PciIo);
252 Data8 = PCI_INT_LINE_UNKNOWN;
253 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
254
255 //
256 // Process OpRom
257 //
258 if (!PciIoDevice->AllOpRomProcessed) {
259
260 //
261 // Get the OpRom provided by platform
262 //
263 if (gPciPlatformProtocol != NULL) {
264 Status = gPciPlatformProtocol->GetPciRom (
265 gPciPlatformProtocol,
266 PciIoDevice->Handle,
267 &PlatformOpRomBuffer,
268 &PlatformOpRomSize
269 );
270 if (!EFI_ERROR (Status)) {
271 PciIoDevice->RomSize = PlatformOpRomSize;
272 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
273 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
274 //
275 // For OpROM read from gPciPlatformProtocol:
276 // Add the Rom Image to internal database for later PCI light enumeration
277 //
278 PciRomAddImageMapping (
279 NULL,
280 PciIoDevice->PciRootBridgeIo->SegmentNumber,
281 PciIoDevice->BusNumber,
282 PciIoDevice->DeviceNumber,
283 PciIoDevice->FunctionNumber,
284 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
285 PciIoDevice->PciIo.RomSize
286 );
287 }
288 }
289 }
290
291 //
292 // Determine if there are EFI images in the option rom
293 //
294 HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);
295
296 if (HasEfiImage) {
297 Status = gBS->InstallMultipleProtocolInterfaces (
298 &PciIoDevice->Handle,
299 &gEfiLoadFile2ProtocolGuid,
300 &PciIoDevice->LoadFile2,
301 NULL
302 );
303 if (EFI_ERROR (Status)) {
304 gBS->UninstallMultipleProtocolInterfaces (
305 &PciIoDevice->Handle,
306 &gEfiDevicePathProtocolGuid,
307 PciIoDevice->DevicePath,
308 &gEfiPciIoProtocolGuid,
309 &PciIoDevice->PciIo,
310 NULL
311 );
312 return Status;
313 }
314 }
315
316
317 if (!PciIoDevice->AllOpRomProcessed) {
318
319 PciIoDevice->AllOpRomProcessed = TRUE;
320
321 //
322 // Dispatch the EFI OpRom for the PCI device.
323 // The OpRom is got from platform in the above code
324 // or loaded from device in the previous round of bus enumeration
325 //
326 if (HasEfiImage) {
327 ProcessOpRomImage (PciIoDevice);
328 }
329 }
330
331 if (PciIoDevice->BusOverride) {
332 //
333 // Install BusSpecificDriverOverride Protocol
334 //
335 Status = gBS->InstallMultipleProtocolInterfaces (
336 &PciIoDevice->Handle,
337 &gEfiBusSpecificDriverOverrideProtocolGuid,
338 &PciIoDevice->PciDriverOverride,
339 NULL
340 );
341 if (EFI_ERROR (Status)) {
342 gBS->UninstallMultipleProtocolInterfaces (
343 &PciIoDevice->Handle,
344 &gEfiDevicePathProtocolGuid,
345 PciIoDevice->DevicePath,
346 &gEfiPciIoProtocolGuid,
347 &PciIoDevice->PciIo,
348 NULL
349 );
350 if (HasEfiImage) {
351 gBS->UninstallMultipleProtocolInterfaces (
352 &PciIoDevice->Handle,
353 &gEfiLoadFile2ProtocolGuid,
354 &PciIoDevice->LoadFile2,
355 NULL
356 );
357 }
358
359 return Status;
360 }
361 }
362
363 Status = gBS->OpenProtocol (
364 Controller,
365 &gEfiPciRootBridgeIoProtocolGuid,
366 (VOID **) &(PciIoDevice->PciRootBridgeIo),
367 gPciBusDriverBinding.DriverBindingHandle,
368 PciIoDevice->Handle,
369 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
370 );
371 if (EFI_ERROR (Status)) {
372 return Status;
373 }
374
375 if (Handle != NULL) {
376 *Handle = PciIoDevice->Handle;
377 }
378
379 //
380 // Indicate the pci device is registered
381 //
382 PciIoDevice->Registered = TRUE;
383
384 return EFI_SUCCESS;
385 }
386
387 /**
388 This function is used to remove the whole PCI devices on the specified bridge from
389 the root bridge.
390
391 @param RootBridgeHandle The root bridge device handle.
392 @param Bridge The bridge device to be removed.
393
394 **/
395 VOID
396 RemoveAllPciDeviceOnBridge (
397 EFI_HANDLE RootBridgeHandle,
398 PCI_IO_DEVICE *Bridge
399 )
400 {
401 LIST_ENTRY *CurrentLink;
402 PCI_IO_DEVICE *Temp;
403
404 while (!IsListEmpty (&Bridge->ChildList)) {
405
406 CurrentLink = Bridge->ChildList.ForwardLink;
407 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
408
409 //
410 // Check if the current node has been deregistered before
411 // If it is not, then deregister it
412 //
413 if (Temp->Registered) {
414 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
415 }
416
417 //
418 // Remove this node from the linked list
419 //
420 RemoveEntryList (CurrentLink);
421
422 if (!IsListEmpty (&Temp->ChildList)) {
423 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
424 }
425
426 FreePciDevice (Temp);
427 }
428 }
429
430 /**
431 This function is used to de-register the PCI IO device.
432
433 That includes un-installing PciIo protocol from the specified PCI
434 device handle.
435
436 @param Controller An EFI handle for the PCI bus controller.
437 @param Handle PCI device handle.
438
439 @retval EFI_SUCCESS The PCI device is successfully de-registered.
440 @retval Others An error occurred when de-registering the PCI device.
441
442 **/
443 EFI_STATUS
444 DeRegisterPciDevice (
445 IN EFI_HANDLE Controller,
446 IN EFI_HANDLE Handle
447 )
448
449 {
450 EFI_PCI_IO_PROTOCOL *PciIo;
451 EFI_STATUS Status;
452 PCI_IO_DEVICE *PciIoDevice;
453 PCI_IO_DEVICE *Node;
454 LIST_ENTRY *CurrentLink;
455 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
456
457 Status = gBS->OpenProtocol (
458 Handle,
459 &gEfiPciIoProtocolGuid,
460 (VOID **) &PciIo,
461 gPciBusDriverBinding.DriverBindingHandle,
462 Controller,
463 EFI_OPEN_PROTOCOL_GET_PROTOCOL
464 );
465 if (!EFI_ERROR (Status)) {
466 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
467
468 //
469 // If it is already de-registered
470 //
471 if (!PciIoDevice->Registered) {
472 return EFI_SUCCESS;
473 }
474
475 //
476 // If it is PPB, first de-register its children
477 //
478
479 if (!IsListEmpty (&PciIoDevice->ChildList)) {
480
481 CurrentLink = PciIoDevice->ChildList.ForwardLink;
482
483 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
484 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
485 Status = DeRegisterPciDevice (Controller, Node->Handle);
486
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 CurrentLink = CurrentLink->ForwardLink;
492 }
493 }
494
495 //
496 // Close the child handle
497 //
498 Status = gBS->CloseProtocol (
499 Controller,
500 &gEfiPciRootBridgeIoProtocolGuid,
501 gPciBusDriverBinding.DriverBindingHandle,
502 Handle
503 );
504
505 //
506 // Un-install the device path protocol and pci io protocol
507 //
508 if (PciIoDevice->BusOverride) {
509 Status = gBS->UninstallMultipleProtocolInterfaces (
510 Handle,
511 &gEfiDevicePathProtocolGuid,
512 PciIoDevice->DevicePath,
513 &gEfiPciIoProtocolGuid,
514 &PciIoDevice->PciIo,
515 &gEfiBusSpecificDriverOverrideProtocolGuid,
516 &PciIoDevice->PciDriverOverride,
517 NULL
518 );
519 } else {
520 Status = gBS->UninstallMultipleProtocolInterfaces (
521 Handle,
522 &gEfiDevicePathProtocolGuid,
523 PciIoDevice->DevicePath,
524 &gEfiPciIoProtocolGuid,
525 &PciIoDevice->PciIo,
526 NULL
527 );
528 }
529
530 if (!EFI_ERROR (Status)) {
531 //
532 // Try to uninstall LoadFile2 protocol if exists
533 //
534 Status = gBS->OpenProtocol (
535 Handle,
536 &gEfiLoadFile2ProtocolGuid,
537 NULL,
538 gPciBusDriverBinding.DriverBindingHandle,
539 Controller,
540 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
541 );
542 if (!EFI_ERROR (Status)) {
543 Status = gBS->UninstallMultipleProtocolInterfaces (
544 Handle,
545 &gEfiLoadFile2ProtocolGuid,
546 &PciIoDevice->LoadFile2,
547 NULL
548 );
549 }
550 //
551 // Restore Status
552 //
553 Status = EFI_SUCCESS;
554 }
555
556
557 if (EFI_ERROR (Status)) {
558 gBS->OpenProtocol (
559 Controller,
560 &gEfiPciRootBridgeIoProtocolGuid,
561 (VOID **) &PciRootBridgeIo,
562 gPciBusDriverBinding.DriverBindingHandle,
563 Handle,
564 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
565 );
566 return Status;
567 }
568
569 //
570 // The Device Driver should disable this device after disconnect
571 // so the Pci Bus driver will not touch this device any more.
572 // Restore the register field to the original value
573 //
574 PciIoDevice->Registered = FALSE;
575 PciIoDevice->Handle = NULL;
576 } else {
577
578 //
579 // Handle may be closed before
580 //
581 return EFI_SUCCESS;
582 }
583
584 return EFI_SUCCESS;
585 }
586
587 /**
588 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
589
590 @param Controller The root bridge handle.
591 @param RootBridge A pointer to the PCI_IO_DEVICE.
592 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
593 @param NumberOfChildren Children number.
594 @param ChildHandleBuffer A pointer to the child handle buffer.
595
596 @retval EFI_NOT_READY Device is not allocated.
597 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
598 @retval EFI_NOT_FOUND Can not find the specific device
599 @retval EFI_SUCCESS Success to start Pci device on bridge
600
601 **/
602 EFI_STATUS
603 StartPciDevicesOnBridge (
604 IN EFI_HANDLE Controller,
605 IN PCI_IO_DEVICE *RootBridge,
606 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
607 IN OUT UINT8 *NumberOfChildren,
608 IN OUT EFI_HANDLE *ChildHandleBuffer
609 )
610
611 {
612 PCI_IO_DEVICE *PciIoDevice;
613 EFI_DEV_PATH_PTR Node;
614 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
615 EFI_STATUS Status;
616 LIST_ENTRY *CurrentLink;
617 UINT64 Supports;
618
619 CurrentLink = RootBridge->ChildList.ForwardLink;
620
621 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
622
623 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
624 if (RemainingDevicePath != NULL) {
625
626 Node.DevPath = RemainingDevicePath;
627
628 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
629 Node.Pci->Function != PciIoDevice->FunctionNumber) {
630 CurrentLink = CurrentLink->ForwardLink;
631 continue;
632 }
633
634 //
635 // Check if the device has been assigned with required resource
636 //
637 if (!PciIoDevice->Allocated) {
638 return EFI_NOT_READY;
639 }
640
641 //
642 // Check if the current node has been registered before
643 // If it is not, register it
644 //
645 if (!PciIoDevice->Registered) {
646 Status = RegisterPciDevice (
647 Controller,
648 PciIoDevice,
649 NULL
650 );
651
652 }
653
654 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
655 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
656 (*NumberOfChildren)++;
657 }
658
659 //
660 // Get the next device path
661 //
662 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
663 if (IsDevicePathEnd (CurrentDevicePath)) {
664 return EFI_SUCCESS;
665 }
666
667 //
668 // If it is a PPB
669 //
670 if (!IsListEmpty (&PciIoDevice->ChildList)) {
671 Status = StartPciDevicesOnBridge (
672 Controller,
673 PciIoDevice,
674 CurrentDevicePath,
675 NumberOfChildren,
676 ChildHandleBuffer
677 );
678
679 PciIoDevice->PciIo.Attributes (
680 &(PciIoDevice->PciIo),
681 EfiPciIoAttributeOperationSupported,
682 0,
683 &Supports
684 );
685 Supports &= EFI_PCI_DEVICE_ENABLE;
686 PciIoDevice->PciIo.Attributes (
687 &(PciIoDevice->PciIo),
688 EfiPciIoAttributeOperationEnable,
689 Supports,
690 NULL
691 );
692
693 return Status;
694 } else {
695
696 //
697 // Currently, the PCI bus driver only support PCI-PCI bridge
698 //
699 return EFI_UNSUPPORTED;
700 }
701
702 } else {
703
704 //
705 // If remaining device path is NULL,
706 // try to enable all the pci devices under this bridge
707 //
708 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
709 Status = RegisterPciDevice (
710 Controller,
711 PciIoDevice,
712 NULL
713 );
714
715 }
716
717 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
718 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
719 (*NumberOfChildren)++;
720 }
721
722 if (!IsListEmpty (&PciIoDevice->ChildList)) {
723 Status = StartPciDevicesOnBridge (
724 Controller,
725 PciIoDevice,
726 RemainingDevicePath,
727 NumberOfChildren,
728 ChildHandleBuffer
729 );
730
731 PciIoDevice->PciIo.Attributes (
732 &(PciIoDevice->PciIo),
733 EfiPciIoAttributeOperationSupported,
734 0,
735 &Supports
736 );
737 Supports &= EFI_PCI_DEVICE_ENABLE;
738 PciIoDevice->PciIo.Attributes (
739 &(PciIoDevice->PciIo),
740 EfiPciIoAttributeOperationEnable,
741 Supports,
742 NULL
743 );
744
745 }
746
747 CurrentLink = CurrentLink->ForwardLink;
748 }
749 }
750
751 return EFI_NOT_FOUND;
752 }
753
754 /**
755 Start to manage all the PCI devices it found previously under
756 the entire host bridge.
757
758 @param Controller The root bridge handle.
759
760 **/
761 EFI_STATUS
762 StartPciDevices (
763 IN EFI_HANDLE Controller
764 )
765
766 {
767 PCI_IO_DEVICE *RootBridge;
768 EFI_HANDLE ThisHostBridge;
769 LIST_ENTRY *CurrentLink;
770
771 RootBridge = GetRootBridgeByHandle (Controller);
772 ASSERT (RootBridge != NULL);
773 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
774
775 CurrentLink = mPciDevicePool.ForwardLink;
776
777 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
778
779 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
780 //
781 // Locate the right root bridge to start
782 //
783 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
784 StartPciDevicesOnBridge (
785 RootBridge->Handle,
786 RootBridge,
787 NULL,
788 NULL,
789 NULL
790 );
791 }
792
793 CurrentLink = CurrentLink->ForwardLink;
794 }
795
796 return EFI_SUCCESS;
797 }
798
799 /**
800 Create root bridge device.
801
802 @param RootBridgeHandle Specified root bridge hanle.
803
804 @return The crated root bridge device instance, NULL means no
805 root bridge device instance created.
806
807 **/
808 PCI_IO_DEVICE *
809 CreateRootBridge (
810 IN EFI_HANDLE RootBridgeHandle
811 )
812 {
813 EFI_STATUS Status;
814 PCI_IO_DEVICE *Dev;
815 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
816 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
817
818 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
819 if (Dev == NULL) {
820 return NULL;
821 }
822
823 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
824 Dev->Handle = RootBridgeHandle;
825 InitializeListHead (&Dev->ChildList);
826
827 Status = gBS->OpenProtocol (
828 RootBridgeHandle,
829 &gEfiDevicePathProtocolGuid,
830 (VOID **) &ParentDevicePath,
831 gPciBusDriverBinding.DriverBindingHandle,
832 RootBridgeHandle,
833 EFI_OPEN_PROTOCOL_GET_PROTOCOL
834 );
835
836 if (EFI_ERROR (Status)) {
837 FreePool (Dev);
838 return NULL;
839 }
840
841 //
842 // Record the root bridge parent device path
843 //
844 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
845
846 //
847 // Get the pci root bridge io protocol
848 //
849 Status = gBS->OpenProtocol (
850 RootBridgeHandle,
851 &gEfiPciRootBridgeIoProtocolGuid,
852 (VOID **) &PciRootBridgeIo,
853 gPciBusDriverBinding.DriverBindingHandle,
854 RootBridgeHandle,
855 EFI_OPEN_PROTOCOL_GET_PROTOCOL
856 );
857
858 if (EFI_ERROR (Status)) {
859 FreePciDevice (Dev);
860 return NULL;
861 }
862
863 Dev->PciRootBridgeIo = PciRootBridgeIo;
864
865 //
866 // Initialize the PCI I/O instance structure
867 //
868 InitializePciIoInstance (Dev);
869 InitializePciDriverOverrideInstance (Dev);
870 InitializePciLoadFile2 (Dev);
871
872 //
873 // Initialize reserved resource list and
874 // option rom driver list
875 //
876 InitializeListHead (&Dev->ReservedResourceList);
877 InitializeListHead (&Dev->OptionRomDriverList);
878
879 return Dev;
880 }
881
882 /**
883 Get root bridge device instance by specific root bridge handle.
884
885 @param RootBridgeHandle Given root bridge handle.
886
887 @return The root bridge device instance, NULL means no root bridge
888 device instance found.
889
890 **/
891 PCI_IO_DEVICE *
892 GetRootBridgeByHandle (
893 EFI_HANDLE RootBridgeHandle
894 )
895 {
896 PCI_IO_DEVICE *RootBridgeDev;
897 LIST_ENTRY *CurrentLink;
898
899 CurrentLink = mPciDevicePool.ForwardLink;
900
901 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
902
903 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
904 if (RootBridgeDev->Handle == RootBridgeHandle) {
905 return RootBridgeDev;
906 }
907
908 CurrentLink = CurrentLink->ForwardLink;
909 }
910
911 return NULL;
912 }
913
914 /**
915 Judege whether Pci device existed.
916
917 @param Bridge Parent bridege instance.
918 @param PciIoDevice Device instance.
919
920 @retval TRUE Pci device existed.
921 @retval FALSE Pci device did not exist.
922
923 **/
924 BOOLEAN
925 PciDeviceExisted (
926 IN PCI_IO_DEVICE *Bridge,
927 IN PCI_IO_DEVICE *PciIoDevice
928 )
929 {
930
931 PCI_IO_DEVICE *Temp;
932 LIST_ENTRY *CurrentLink;
933
934 CurrentLink = Bridge->ChildList.ForwardLink;
935
936 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
937
938 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
939
940 if (Temp == PciIoDevice) {
941 return TRUE;
942 }
943
944 if (!IsListEmpty (&Temp->ChildList)) {
945 if (PciDeviceExisted (Temp, PciIoDevice)) {
946 return TRUE;
947 }
948 }
949
950 CurrentLink = CurrentLink->ForwardLink;
951 }
952
953 return FALSE;
954 }
955
956 /**
957 Get the active VGA device on the same segment.
958
959 @param VgaDevice PCI IO instance for the VGA device.
960
961 @return The active VGA device on the same segment.
962
963 **/
964 PCI_IO_DEVICE *
965 ActiveVGADeviceOnTheSameSegment (
966 IN PCI_IO_DEVICE *VgaDevice
967 )
968 {
969 LIST_ENTRY *CurrentLink;
970 PCI_IO_DEVICE *Temp;
971
972 CurrentLink = mPciDevicePool.ForwardLink;
973
974 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
975
976 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
977
978 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
979
980 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
981
982 if (Temp != NULL) {
983 return Temp;
984 }
985 }
986
987 CurrentLink = CurrentLink->ForwardLink;
988 }
989
990 return NULL;
991 }
992
993 /**
994 Get the active VGA device on the root bridge.
995
996 @param RootBridge PCI IO instance for the root bridge.
997
998 @return The active VGA device.
999
1000 **/
1001 PCI_IO_DEVICE *
1002 ActiveVGADeviceOnTheRootBridge (
1003 IN PCI_IO_DEVICE *RootBridge
1004 )
1005 {
1006 LIST_ENTRY *CurrentLink;
1007 PCI_IO_DEVICE *Temp;
1008
1009 CurrentLink = RootBridge->ChildList.ForwardLink;
1010
1011 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1012
1013 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1014
1015 if (IS_PCI_VGA(&Temp->Pci) &&
1016 (Temp->Attributes &
1017 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
1018 EFI_PCI_IO_ATTRIBUTE_VGA_IO |
1019 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
1020 return Temp;
1021 }
1022
1023 if (IS_PCI_BRIDGE (&Temp->Pci)) {
1024
1025 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1026
1027 if (Temp != NULL) {
1028 return Temp;
1029 }
1030 }
1031
1032 CurrentLink = CurrentLink->ForwardLink;
1033 }
1034
1035 return NULL;
1036 }
1037
1038
1039 /**
1040 Get HPC PCI address according to its device path.
1041
1042 @param RootBridge Root bridege Io instance.
1043 @param RemainingDevicePath Given searching device path.
1044 @param PciAddress Buffer holding searched result.
1045
1046 @retval EFI_SUCCESS PCI address was stored in PciAddress
1047 @retval EFI_NOT_FOUND Can not find the specific device path.
1048
1049 **/
1050 EFI_STATUS
1051 GetHpcPciAddressFromRootBridge (
1052 IN PCI_IO_DEVICE *RootBridge,
1053 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
1054 OUT UINT64 *PciAddress
1055 )
1056 {
1057 EFI_DEV_PATH_PTR Node;
1058 PCI_IO_DEVICE *Temp;
1059 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1060 LIST_ENTRY *CurrentLink;
1061 BOOLEAN MisMatch;
1062
1063 MisMatch = FALSE;
1064
1065 CurrentDevicePath = RemainingDevicePath;
1066 Node.DevPath = CurrentDevicePath;
1067 Temp = NULL;
1068
1069 while (!IsDevicePathEnd (CurrentDevicePath)) {
1070
1071 CurrentLink = RootBridge->ChildList.ForwardLink;
1072 Node.DevPath = CurrentDevicePath;
1073
1074 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1075 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1076
1077 if (Node.Pci->Device == Temp->DeviceNumber &&
1078 Node.Pci->Function == Temp->FunctionNumber) {
1079 RootBridge = Temp;
1080 break;
1081 }
1082
1083 CurrentLink = CurrentLink->ForwardLink;
1084 }
1085
1086 //
1087 // Check if we find the bridge
1088 //
1089 if (CurrentLink == &RootBridge->ChildList) {
1090
1091 MisMatch = TRUE;
1092 break;
1093
1094 }
1095
1096 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1097 }
1098
1099 if (MisMatch) {
1100
1101 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1102
1103 if (IsDevicePathEnd (CurrentDevicePath)) {
1104 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
1105 return EFI_SUCCESS;
1106 }
1107
1108 return EFI_NOT_FOUND;
1109 }
1110
1111 if (Temp != NULL) {
1112 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1113 } else {
1114 return EFI_NOT_FOUND;
1115 }
1116
1117 return EFI_SUCCESS;
1118
1119 }
1120