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