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