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