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