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