]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
StartPciDevicesOnBridge() should correct return value.
[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 other 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 PciIo->Pci.Write (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 Bus Specific Driver Override 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 other 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 I/O protocol
507 // and Bus Specific Driver Override protocol if needed.
508 //
509 if (PciIoDevice->BusOverride) {
510 Status = gBS->UninstallMultipleProtocolInterfaces (
511 Handle,
512 &gEfiDevicePathProtocolGuid,
513 PciIoDevice->DevicePath,
514 &gEfiPciIoProtocolGuid,
515 &PciIoDevice->PciIo,
516 &gEfiBusSpecificDriverOverrideProtocolGuid,
517 &PciIoDevice->PciDriverOverride,
518 NULL
519 );
520 } else {
521 Status = gBS->UninstallMultipleProtocolInterfaces (
522 Handle,
523 &gEfiDevicePathProtocolGuid,
524 PciIoDevice->DevicePath,
525 &gEfiPciIoProtocolGuid,
526 &PciIoDevice->PciIo,
527 NULL
528 );
529 }
530
531 if (!EFI_ERROR (Status)) {
532 //
533 // Try to uninstall LoadFile2 protocol if exists
534 //
535 Status = gBS->OpenProtocol (
536 Handle,
537 &gEfiLoadFile2ProtocolGuid,
538 NULL,
539 gPciBusDriverBinding.DriverBindingHandle,
540 Controller,
541 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
542 );
543 if (!EFI_ERROR (Status)) {
544 Status = gBS->UninstallMultipleProtocolInterfaces (
545 Handle,
546 &gEfiLoadFile2ProtocolGuid,
547 &PciIoDevice->LoadFile2,
548 NULL
549 );
550 }
551 //
552 // Restore Status
553 //
554 Status = EFI_SUCCESS;
555 }
556
557
558 if (EFI_ERROR (Status)) {
559 gBS->OpenProtocol (
560 Controller,
561 &gEfiPciRootBridgeIoProtocolGuid,
562 (VOID **) &PciRootBridgeIo,
563 gPciBusDriverBinding.DriverBindingHandle,
564 Handle,
565 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
566 );
567 return Status;
568 }
569
570 //
571 // The Device Driver should disable this device after disconnect
572 // so the Pci Bus driver will not touch this device any more.
573 // Restore the register field to the original value
574 //
575 PciIoDevice->Registered = FALSE;
576 PciIoDevice->Handle = NULL;
577 } else {
578
579 //
580 // Handle may be closed before
581 //
582 return EFI_SUCCESS;
583 }
584
585 return EFI_SUCCESS;
586 }
587
588 /**
589 Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
590
591 @param Controller The root bridge handle.
592 @param RootBridge A pointer to the PCI_IO_DEVICE.
593 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
594 @param NumberOfChildren Children number.
595 @param ChildHandleBuffer A pointer to the child handle buffer.
596
597 @retval EFI_NOT_READY Device is not allocated.
598 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
599 @retval EFI_NOT_FOUND Can not find the specific device.
600 @retval EFI_SUCCESS Success to start Pci devices on bridge.
601
602 **/
603 EFI_STATUS
604 StartPciDevicesOnBridge (
605 IN EFI_HANDLE Controller,
606 IN PCI_IO_DEVICE *RootBridge,
607 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
608 IN OUT UINT8 *NumberOfChildren,
609 IN OUT EFI_HANDLE *ChildHandleBuffer
610 )
611
612 {
613 PCI_IO_DEVICE *PciIoDevice;
614 EFI_DEV_PATH_PTR Node;
615 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
616 EFI_STATUS Status;
617 LIST_ENTRY *CurrentLink;
618 UINT64 Supports;
619
620 PciIoDevice = NULL;
621 CurrentLink = RootBridge->ChildList.ForwardLink;
622
623 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
624
625 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
626 if (RemainingDevicePath != NULL) {
627
628 Node.DevPath = RemainingDevicePath;
629
630 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
631 Node.Pci->Function != PciIoDevice->FunctionNumber) {
632 CurrentLink = CurrentLink->ForwardLink;
633 continue;
634 }
635
636 //
637 // Check if the device has been assigned with required resource
638 //
639 if (!PciIoDevice->Allocated) {
640 return EFI_NOT_READY;
641 }
642
643 //
644 // Check if the current node has been registered before
645 // If it is not, register it
646 //
647 if (!PciIoDevice->Registered) {
648 Status = RegisterPciDevice (
649 Controller,
650 PciIoDevice,
651 NULL
652 );
653
654 }
655
656 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
657 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
658 (*NumberOfChildren)++;
659 }
660
661 //
662 // Get the next device path
663 //
664 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
665 if (IsDevicePathEnd (CurrentDevicePath)) {
666 return EFI_SUCCESS;
667 }
668
669 //
670 // If it is a PPB
671 //
672 if (!IsListEmpty (&PciIoDevice->ChildList)) {
673 Status = StartPciDevicesOnBridge (
674 Controller,
675 PciIoDevice,
676 CurrentDevicePath,
677 NumberOfChildren,
678 ChildHandleBuffer
679 );
680
681 PciIoDevice->PciIo.Attributes (
682 &(PciIoDevice->PciIo),
683 EfiPciIoAttributeOperationSupported,
684 0,
685 &Supports
686 );
687 Supports &= EFI_PCI_DEVICE_ENABLE;
688 PciIoDevice->PciIo.Attributes (
689 &(PciIoDevice->PciIo),
690 EfiPciIoAttributeOperationEnable,
691 Supports,
692 NULL
693 );
694
695 return Status;
696 } else {
697
698 //
699 // Currently, the PCI bus driver only support PCI-PCI bridge
700 //
701 return EFI_UNSUPPORTED;
702 }
703
704 } else {
705
706 //
707 // If remaining device path is NULL,
708 // try to enable all the pci devices under this bridge
709 //
710 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
711 Status = RegisterPciDevice (
712 Controller,
713 PciIoDevice,
714 NULL
715 );
716
717 }
718
719 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
720 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
721 (*NumberOfChildren)++;
722 }
723
724 if (!IsListEmpty (&PciIoDevice->ChildList)) {
725 Status = StartPciDevicesOnBridge (
726 Controller,
727 PciIoDevice,
728 RemainingDevicePath,
729 NumberOfChildren,
730 ChildHandleBuffer
731 );
732
733 PciIoDevice->PciIo.Attributes (
734 &(PciIoDevice->PciIo),
735 EfiPciIoAttributeOperationSupported,
736 0,
737 &Supports
738 );
739 Supports &= EFI_PCI_DEVICE_ENABLE;
740 PciIoDevice->PciIo.Attributes (
741 &(PciIoDevice->PciIo),
742 EfiPciIoAttributeOperationEnable,
743 Supports,
744 NULL
745 );
746
747 }
748
749 CurrentLink = CurrentLink->ForwardLink;
750 }
751 }
752
753 if (PciIoDevice == NULL) {
754 return EFI_NOT_FOUND;
755 } else {
756 return EFI_SUCCESS;
757 }
758 }
759
760 /**
761 Start to manage all the PCI devices it found previously under
762 the entire host bridge.
763
764 @param Controller The root bridge handle.
765
766 @retval EFI_NOT_READY Device is not allocated.
767 @retval EFI_SUCCESS Success to start Pci device on host bridge.
768
769 **/
770 EFI_STATUS
771 StartPciDevices (
772 IN EFI_HANDLE Controller
773 )
774 {
775 PCI_IO_DEVICE *RootBridge;
776 EFI_HANDLE ThisHostBridge;
777 LIST_ENTRY *CurrentLink;
778
779 RootBridge = GetRootBridgeByHandle (Controller);
780 ASSERT (RootBridge != NULL);
781 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
782
783 CurrentLink = mPciDevicePool.ForwardLink;
784
785 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
786
787 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
788 //
789 // Locate the right root bridge to start
790 //
791 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
792 StartPciDevicesOnBridge (
793 RootBridge->Handle,
794 RootBridge,
795 NULL,
796 NULL,
797 NULL
798 );
799 }
800
801 CurrentLink = CurrentLink->ForwardLink;
802 }
803
804 return EFI_SUCCESS;
805 }
806
807 /**
808 Create root bridge device.
809
810 @param RootBridgeHandle Specified root bridge hanle.
811
812 @return The crated root bridge device instance, NULL means no
813 root bridge device instance created.
814
815 **/
816 PCI_IO_DEVICE *
817 CreateRootBridge (
818 IN EFI_HANDLE RootBridgeHandle
819 )
820 {
821 EFI_STATUS Status;
822 PCI_IO_DEVICE *Dev;
823 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
824 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
825
826 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
827 if (Dev == NULL) {
828 return NULL;
829 }
830
831 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
832 Dev->Handle = RootBridgeHandle;
833 InitializeListHead (&Dev->ChildList);
834
835 Status = gBS->OpenProtocol (
836 RootBridgeHandle,
837 &gEfiDevicePathProtocolGuid,
838 (VOID **) &ParentDevicePath,
839 gPciBusDriverBinding.DriverBindingHandle,
840 RootBridgeHandle,
841 EFI_OPEN_PROTOCOL_GET_PROTOCOL
842 );
843
844 if (EFI_ERROR (Status)) {
845 FreePool (Dev);
846 return NULL;
847 }
848
849 //
850 // Record the root bridge parent device path
851 //
852 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
853
854 //
855 // Get the pci root bridge io protocol
856 //
857 Status = gBS->OpenProtocol (
858 RootBridgeHandle,
859 &gEfiPciRootBridgeIoProtocolGuid,
860 (VOID **) &PciRootBridgeIo,
861 gPciBusDriverBinding.DriverBindingHandle,
862 RootBridgeHandle,
863 EFI_OPEN_PROTOCOL_GET_PROTOCOL
864 );
865
866 if (EFI_ERROR (Status)) {
867 FreePciDevice (Dev);
868 return NULL;
869 }
870
871 Dev->PciRootBridgeIo = PciRootBridgeIo;
872
873 //
874 // Initialize the PCI I/O instance structure
875 //
876 InitializePciIoInstance (Dev);
877 InitializePciDriverOverrideInstance (Dev);
878 InitializePciLoadFile2 (Dev);
879
880 //
881 // Initialize reserved resource list and
882 // option rom driver list
883 //
884 InitializeListHead (&Dev->ReservedResourceList);
885 InitializeListHead (&Dev->OptionRomDriverList);
886
887 return Dev;
888 }
889
890 /**
891 Get root bridge device instance by specific root bridge handle.
892
893 @param RootBridgeHandle Given root bridge handle.
894
895 @return The root bridge device instance, NULL means no root bridge
896 device instance found.
897
898 **/
899 PCI_IO_DEVICE *
900 GetRootBridgeByHandle (
901 EFI_HANDLE RootBridgeHandle
902 )
903 {
904 PCI_IO_DEVICE *RootBridgeDev;
905 LIST_ENTRY *CurrentLink;
906
907 CurrentLink = mPciDevicePool.ForwardLink;
908
909 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
910
911 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
912 if (RootBridgeDev->Handle == RootBridgeHandle) {
913 return RootBridgeDev;
914 }
915
916 CurrentLink = CurrentLink->ForwardLink;
917 }
918
919 return NULL;
920 }
921
922 /**
923 Judege whether Pci device existed.
924
925 @param Bridge Parent bridege instance.
926 @param PciIoDevice Device instance.
927
928 @retval TRUE Pci device existed.
929 @retval FALSE Pci device did not exist.
930
931 **/
932 BOOLEAN
933 PciDeviceExisted (
934 IN PCI_IO_DEVICE *Bridge,
935 IN PCI_IO_DEVICE *PciIoDevice
936 )
937 {
938
939 PCI_IO_DEVICE *Temp;
940 LIST_ENTRY *CurrentLink;
941
942 CurrentLink = Bridge->ChildList.ForwardLink;
943
944 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
945
946 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
947
948 if (Temp == PciIoDevice) {
949 return TRUE;
950 }
951
952 if (!IsListEmpty (&Temp->ChildList)) {
953 if (PciDeviceExisted (Temp, PciIoDevice)) {
954 return TRUE;
955 }
956 }
957
958 CurrentLink = CurrentLink->ForwardLink;
959 }
960
961 return FALSE;
962 }
963
964 /**
965 Get the active VGA device on the same segment.
966
967 @param VgaDevice PCI IO instance for the VGA device.
968
969 @return The active VGA device on the same segment.
970
971 **/
972 PCI_IO_DEVICE *
973 ActiveVGADeviceOnTheSameSegment (
974 IN PCI_IO_DEVICE *VgaDevice
975 )
976 {
977 LIST_ENTRY *CurrentLink;
978 PCI_IO_DEVICE *Temp;
979
980 CurrentLink = mPciDevicePool.ForwardLink;
981
982 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
983
984 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
985
986 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
987
988 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
989
990 if (Temp != NULL) {
991 return Temp;
992 }
993 }
994
995 CurrentLink = CurrentLink->ForwardLink;
996 }
997
998 return NULL;
999 }
1000
1001 /**
1002 Get the active VGA device on the root bridge.
1003
1004 @param RootBridge PCI IO instance for the root bridge.
1005
1006 @return The active VGA device.
1007
1008 **/
1009 PCI_IO_DEVICE *
1010 ActiveVGADeviceOnTheRootBridge (
1011 IN PCI_IO_DEVICE *RootBridge
1012 )
1013 {
1014 LIST_ENTRY *CurrentLink;
1015 PCI_IO_DEVICE *Temp;
1016
1017 CurrentLink = RootBridge->ChildList.ForwardLink;
1018
1019 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1020
1021 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1022
1023 if (IS_PCI_VGA(&Temp->Pci) &&
1024 (Temp->Attributes &
1025 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
1026 EFI_PCI_IO_ATTRIBUTE_VGA_IO |
1027 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
1028 return Temp;
1029 }
1030
1031 if (IS_PCI_BRIDGE (&Temp->Pci)) {
1032
1033 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1034
1035 if (Temp != NULL) {
1036 return Temp;
1037 }
1038 }
1039
1040 CurrentLink = CurrentLink->ForwardLink;
1041 }
1042
1043 return NULL;
1044 }
1045
1046
1047 /**
1048 Get HPC PCI address according to its device path.
1049
1050 @param RootBridge Root bridege Io instance.
1051 @param RemainingDevicePath Given searching device path.
1052 @param PciAddress Buffer holding searched result.
1053
1054 @retval EFI_SUCCESS PCI address was stored in PciAddress
1055 @retval EFI_NOT_FOUND Can not find the specific device path.
1056
1057 **/
1058 EFI_STATUS
1059 GetHpcPciAddressFromRootBridge (
1060 IN PCI_IO_DEVICE *RootBridge,
1061 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
1062 OUT UINT64 *PciAddress
1063 )
1064 {
1065 EFI_DEV_PATH_PTR Node;
1066 PCI_IO_DEVICE *Temp;
1067 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1068 LIST_ENTRY *CurrentLink;
1069 BOOLEAN MisMatch;
1070
1071 MisMatch = FALSE;
1072
1073 CurrentDevicePath = RemainingDevicePath;
1074 Node.DevPath = CurrentDevicePath;
1075 Temp = NULL;
1076
1077 while (!IsDevicePathEnd (CurrentDevicePath)) {
1078
1079 CurrentLink = RootBridge->ChildList.ForwardLink;
1080 Node.DevPath = CurrentDevicePath;
1081
1082 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1083 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1084
1085 if (Node.Pci->Device == Temp->DeviceNumber &&
1086 Node.Pci->Function == Temp->FunctionNumber) {
1087 RootBridge = Temp;
1088 break;
1089 }
1090
1091 CurrentLink = CurrentLink->ForwardLink;
1092 }
1093
1094 //
1095 // Check if we find the bridge
1096 //
1097 if (CurrentLink == &RootBridge->ChildList) {
1098
1099 MisMatch = TRUE;
1100 break;
1101
1102 }
1103
1104 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1105 }
1106
1107 if (MisMatch) {
1108
1109 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1110
1111 if (IsDevicePathEnd (CurrentDevicePath)) {
1112 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
1113 return EFI_SUCCESS;
1114 }
1115
1116 return EFI_NOT_FOUND;
1117 }
1118
1119 if (Temp != NULL) {
1120 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1121 } else {
1122 return EFI_NOT_FOUND;
1123 }
1124
1125 return EFI_SUCCESS;
1126
1127 }
1128