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