]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
Fix K8 report bugs.
[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 //
382 // Install Pccard Hotplug GUID for Pccard device so that
383 // to notify CardBus driver to stop the device when de-register happens
384 //
385 InstallPciHotplugGuid (PciIoDevice);
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 from the bridge.
401
402 @param RootBridgeHandle An efi handle.
403 @param Bridge A pointer to the PCI_IO_DEVICE.
404
405 @retval EFI_SUCCESS
406 **/
407 EFI_STATUS
408 RemoveAllPciDeviceOnBridge (
409 EFI_HANDLE RootBridgeHandle,
410 PCI_IO_DEVICE *Bridge
411 )
412
413 {
414
415 LIST_ENTRY *CurrentLink;
416 PCI_IO_DEVICE *Temp;
417
418 while (!IsListEmpty (&Bridge->ChildList)) {
419
420 CurrentLink = Bridge->ChildList.ForwardLink;
421 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
422
423 //
424 // Check if the current node has been deregistered before
425 // If it is not, then deregister it
426 //
427 if (Temp->Registered) {
428 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
429 }
430
431 //
432 // Remove this node from the linked list
433 //
434 RemoveEntryList (CurrentLink);
435
436 if (!IsListEmpty (&Temp->ChildList)) {
437 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
438 }
439
440 FreePciDevice (Temp);
441 }
442
443 return EFI_SUCCESS;
444 }
445
446 /**
447
448 This function is used to de-register the PCI device from the EFI,
449 That includes un-installing PciIo protocol from the specified PCI
450 device handle.
451
452 @param Controller - controller handle
453 @param Handle - device handle
454
455 @return Status of de-register pci device
456 **/
457 EFI_STATUS
458 DeRegisterPciDevice (
459 IN EFI_HANDLE Controller,
460 IN EFI_HANDLE Handle
461 )
462
463 {
464 EFI_PCI_IO_PROTOCOL *PciIo;
465 EFI_STATUS Status;
466 PCI_IO_DEVICE *PciIoDevice;
467 PCI_IO_DEVICE *Node;
468 LIST_ENTRY *CurrentLink;
469 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
470
471 Status = gBS->OpenProtocol (
472 Handle,
473 &gEfiPciIoProtocolGuid,
474 (VOID **) &PciIo,
475 gPciBusDriverBinding.DriverBindingHandle,
476 Controller,
477 EFI_OPEN_PROTOCOL_GET_PROTOCOL
478 );
479 if (!EFI_ERROR (Status)) {
480 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
481
482 //
483 // If it is already de-registered
484 //
485 if (!PciIoDevice->Registered) {
486 return EFI_SUCCESS;
487 }
488
489 //
490 // If it is PPB, first de-register its children
491 //
492
493 if (!IsListEmpty (&PciIoDevice->ChildList)) {
494
495 CurrentLink = PciIoDevice->ChildList.ForwardLink;
496
497 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
498 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
499 Status = DeRegisterPciDevice (Controller, Node->Handle);
500
501 if (EFI_ERROR (Status)) {
502 return Status;
503 }
504
505 CurrentLink = CurrentLink->ForwardLink;
506 }
507 }
508 //
509 // Uninstall Pccard Hotplug GUID for Pccard device
510 //
511 UninstallPciHotplugGuid (PciIoDevice);
512
513 //
514 // Close the child handle
515 //
516 Status = gBS->CloseProtocol (
517 Controller,
518 &gEfiPciRootBridgeIoProtocolGuid,
519 gPciBusDriverBinding.DriverBindingHandle,
520 Handle
521 );
522
523 //
524 // Un-install the device path protocol and pci io protocol
525 //
526 if (PciIoDevice->BusOverride) {
527 Status = gBS->UninstallMultipleProtocolInterfaces (
528 Handle,
529 &gEfiDevicePathProtocolGuid,
530 PciIoDevice->DevicePath,
531 &gEfiPciIoProtocolGuid,
532 &PciIoDevice->PciIo,
533 &gEfiBusSpecificDriverOverrideProtocolGuid,
534 &PciIoDevice->PciDriverOverride,
535 NULL
536 );
537 } else {
538 Status = gBS->UninstallMultipleProtocolInterfaces (
539 Handle,
540 &gEfiDevicePathProtocolGuid,
541 PciIoDevice->DevicePath,
542 &gEfiPciIoProtocolGuid,
543 &PciIoDevice->PciIo,
544 NULL
545 );
546 }
547
548 if (!EFI_ERROR (Status)) {
549 //
550 // Try to uninstall LoadFile2 protocol if exists
551 //
552 Status = gBS->OpenProtocol (
553 Handle,
554 &gEfiLoadFile2ProtocolGuid,
555 NULL,
556 gPciBusDriverBinding.DriverBindingHandle,
557 Controller,
558 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
559 );
560 if (!EFI_ERROR (Status)) {
561 Status = gBS->UninstallMultipleProtocolInterfaces (
562 Handle,
563 &gEfiLoadFile2ProtocolGuid,
564 &PciIoDevice->LoadFile2,
565 NULL
566 );
567 }
568 //
569 // Restore Status
570 //
571 Status = EFI_SUCCESS;
572 }
573
574
575 if (EFI_ERROR (Status)) {
576 gBS->OpenProtocol (
577 Controller,
578 &gEfiPciRootBridgeIoProtocolGuid,
579 (VOID **) &PciRootBridgeIo,
580 gPciBusDriverBinding.DriverBindingHandle,
581 Handle,
582 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
583 );
584 return Status;
585 }
586
587 //
588 // The Device Driver should disable this device after disconnect
589 // so the Pci Bus driver will not touch this device any more.
590 // Restore the register field to the original value
591 //
592 PciIoDevice->Registered = FALSE;
593 PciIoDevice->Handle = NULL;
594 } else {
595
596 //
597 // Handle may be closed before
598 //
599 return EFI_SUCCESS;
600 }
601
602 return EFI_SUCCESS;
603 }
604
605 /**
606 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
607
608 @param Controller An efi handle.
609 @param RootBridge A pointer to the PCI_IO_DEVICE.
610 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
611 @param NumberOfChildren Children number.
612 @param ChildHandleBuffer A pointer to the child handle buffer.
613
614 @retval EFI_NOT_READY Device is not allocated
615 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
616 @retval EFI_NOT_FOUND Can not find the specific device
617 @retval EFI_SUCCESS Success to start Pci device on bridge
618
619 **/
620 EFI_STATUS
621 StartPciDevicesOnBridge (
622 IN EFI_HANDLE Controller,
623 IN PCI_IO_DEVICE *RootBridge,
624 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
625 IN OUT UINT8 *NumberOfChildren,
626 IN OUT EFI_HANDLE *ChildHandleBuffer
627 )
628
629 {
630 PCI_IO_DEVICE *PciIoDevice;
631 EFI_DEV_PATH_PTR Node;
632 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
633 EFI_STATUS Status;
634 LIST_ENTRY *CurrentLink;
635 UINT64 Supports;
636
637 CurrentLink = RootBridge->ChildList.ForwardLink;
638
639 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
640
641 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
642 if (RemainingDevicePath != NULL) {
643
644 Node.DevPath = RemainingDevicePath;
645
646 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
647 Node.Pci->Function != PciIoDevice->FunctionNumber) {
648 CurrentLink = CurrentLink->ForwardLink;
649 continue;
650 }
651
652 //
653 // Check if the device has been assigned with required resource
654 //
655 if (!PciIoDevice->Allocated) {
656 return EFI_NOT_READY;
657 }
658
659 //
660 // Check if the current node has been registered before
661 // If it is not, register it
662 //
663 if (!PciIoDevice->Registered) {
664 Status = RegisterPciDevice (
665 Controller,
666 PciIoDevice,
667 NULL
668 );
669
670 }
671
672 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
673 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
674 (*NumberOfChildren)++;
675 }
676
677 //
678 // Get the next device path
679 //
680 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
681 if (IsDevicePathEnd (CurrentDevicePath)) {
682 return EFI_SUCCESS;
683 }
684
685 //
686 // If it is a PPB
687 //
688 if (!IsListEmpty (&PciIoDevice->ChildList)) {
689 Status = StartPciDevicesOnBridge (
690 Controller,
691 PciIoDevice,
692 CurrentDevicePath,
693 NumberOfChildren,
694 ChildHandleBuffer
695 );
696
697 PciIoDevice->PciIo.Attributes (
698 &(PciIoDevice->PciIo),
699 EfiPciIoAttributeOperationSupported,
700 0,
701 &Supports
702 );
703 Supports &= EFI_PCI_DEVICE_ENABLE;
704 PciIoDevice->PciIo.Attributes (
705 &(PciIoDevice->PciIo),
706 EfiPciIoAttributeOperationEnable,
707 Supports,
708 NULL
709 );
710
711 return Status;
712 } else {
713
714 //
715 // Currently, the PCI bus driver only support PCI-PCI bridge
716 //
717 return EFI_UNSUPPORTED;
718 }
719
720 } else {
721
722 //
723 // If remaining device path is NULL,
724 // try to enable all the pci devices under this bridge
725 //
726
727 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
728 Status = RegisterPciDevice (
729 Controller,
730 PciIoDevice,
731 NULL
732 );
733
734 }
735
736 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
737 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
738 (*NumberOfChildren)++;
739 }
740
741 if (!IsListEmpty (&PciIoDevice->ChildList)) {
742 Status = StartPciDevicesOnBridge (
743 Controller,
744 PciIoDevice,
745 RemainingDevicePath,
746 NumberOfChildren,
747 ChildHandleBuffer
748 );
749
750 PciIoDevice->PciIo.Attributes (
751 &(PciIoDevice->PciIo),
752 EfiPciIoAttributeOperationSupported,
753 0,
754 &Supports
755 );
756 Supports &= EFI_PCI_DEVICE_ENABLE;
757 PciIoDevice->PciIo.Attributes (
758 &(PciIoDevice->PciIo),
759 EfiPciIoAttributeOperationEnable,
760 Supports,
761 NULL
762 );
763
764 }
765
766 CurrentLink = CurrentLink->ForwardLink;
767 }
768 }
769
770 return EFI_NOT_FOUND;
771 }
772
773 /**
774 Start to manage all the PCI devices it found previously under
775 the entire host bridge.
776
777 @param Controller - root bridge handle.
778
779 **/
780 EFI_STATUS
781 StartPciDevices (
782 IN EFI_HANDLE Controller
783 )
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 = gPciDevicePool.ForwardLink;
795
796 while (CurrentLink != NULL && CurrentLink != &gPciDevicePool) {
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 - Parent bridge handle.
822
823 @return pointer to new root bridge
824 **/
825 PCI_IO_DEVICE *
826 CreateRootBridge (
827 IN EFI_HANDLE RootBridgeHandle
828 )
829 {
830
831 EFI_STATUS Status;
832 PCI_IO_DEVICE *Dev;
833 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
834 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
835
836 Dev = NULL;
837 Status = gBS->AllocatePool (
838 EfiBootServicesData,
839 sizeof (PCI_IO_DEVICE),
840 (VOID **) &Dev
841 );
842
843 if (EFI_ERROR (Status)) {
844 return NULL;
845 }
846
847 ZeroMem (Dev, sizeof (PCI_IO_DEVICE));
848 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
849 Dev->Handle = RootBridgeHandle;
850 InitializeListHead (&Dev->ChildList);
851
852 Status = gBS->OpenProtocol (
853 RootBridgeHandle,
854 &gEfiDevicePathProtocolGuid,
855 (VOID **) &ParentDevicePath,
856 gPciBusDriverBinding.DriverBindingHandle,
857 RootBridgeHandle,
858 EFI_OPEN_PROTOCOL_GET_PROTOCOL
859 );
860
861 if (EFI_ERROR (Status)) {
862 gBS->FreePool (Dev);
863 return NULL;
864 }
865
866 //
867 // Record the root bridge parent device path
868 //
869 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
870
871 //
872 // Get the pci root bridge io protocol
873 //
874 Status = gBS->OpenProtocol (
875 RootBridgeHandle,
876 &gEfiPciRootBridgeIoProtocolGuid,
877 (VOID **) &PciRootBridgeIo,
878 gPciBusDriverBinding.DriverBindingHandle,
879 RootBridgeHandle,
880 EFI_OPEN_PROTOCOL_GET_PROTOCOL
881 );
882
883 if (EFI_ERROR (Status)) {
884 FreePciDevice (Dev);
885 return NULL;
886 }
887
888 Dev->PciRootBridgeIo = PciRootBridgeIo;
889
890 //
891 // Initialize the PCI I/O instance structure
892 //
893 InitializePciIoInstance (Dev);
894 InitializePciDriverOverrideInstance (Dev);
895 InitializePciLoadFile2 (Dev);
896
897 //
898 // Initialize reserved resource list and
899 // option rom driver list
900 //
901 InitializeListHead (&Dev->ReservedResourceList);
902 InitializeListHead (&Dev->OptionRomDriverList);
903
904 return Dev;
905 }
906
907 /**
908 Get root bridge device instance by specific handle.
909
910 @param RootBridgeHandle Given root bridge handle.
911
912 @return root bridge device instance.
913 **/
914 PCI_IO_DEVICE *
915 GetRootBridgeByHandle (
916 EFI_HANDLE RootBridgeHandle
917 )
918 {
919 PCI_IO_DEVICE *RootBridgeDev;
920 LIST_ENTRY *CurrentLink;
921
922 CurrentLink = gPciDevicePool.ForwardLink;
923
924 while (CurrentLink != NULL && CurrentLink != &gPciDevicePool) {
925
926 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
927 if (RootBridgeDev->Handle == RootBridgeHandle) {
928 return RootBridgeDev;
929 }
930
931 CurrentLink = CurrentLink->ForwardLink;
932 }
933
934 return NULL;
935 }
936
937 /**
938 Judege whether Pci device existed.
939
940 @param Bridge Parent bridege instance.
941 @param PciIoDevice Device instance.
942
943 @return whether Pci device existed.
944 **/
945 BOOLEAN
946 PciDeviceExisted (
947 IN PCI_IO_DEVICE *Bridge,
948 IN PCI_IO_DEVICE *PciIoDevice
949 )
950 {
951
952 PCI_IO_DEVICE *Temp;
953 LIST_ENTRY *CurrentLink;
954
955 CurrentLink = Bridge->ChildList.ForwardLink;
956
957 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
958
959 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
960
961 if (Temp == PciIoDevice) {
962 return TRUE;
963 }
964
965 if (!IsListEmpty (&Temp->ChildList)) {
966 if (PciDeviceExisted (Temp, PciIoDevice)) {
967 return TRUE;
968 }
969 }
970
971 CurrentLink = CurrentLink->ForwardLink;
972 }
973
974 return FALSE;
975 }
976
977 /**
978 Active VGA device.
979
980 @param VgaDevice device instance for VGA.
981
982 @return device instance.
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 = gPciDevicePool.ForwardLink;
993
994 while (CurrentLink != NULL && CurrentLink != &gPciDevicePool) {
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 Active VGA device on root bridge.
1015
1016 @param RootBridge Root bridge device instance.
1017
1018 @return VGA device instance.
1019 **/
1020 PCI_IO_DEVICE *
1021 ActiveVGADeviceOnTheRootBridge (
1022 IN PCI_IO_DEVICE *RootBridge
1023 )
1024 {
1025 LIST_ENTRY *CurrentLink;
1026 PCI_IO_DEVICE *Temp;
1027
1028 CurrentLink = RootBridge->ChildList.ForwardLink;
1029
1030 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1031
1032 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1033
1034 if (IS_PCI_VGA(&Temp->Pci) &&
1035 (Temp->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 Temp;
1040 }
1041
1042 if (IS_PCI_BRIDGE (&Temp->Pci)) {
1043
1044 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1045
1046 if (Temp != NULL) {
1047 return Temp;
1048 }
1049 }
1050
1051 CurrentLink = CurrentLink->ForwardLink;
1052 }
1053
1054 return NULL;
1055 }
1056
1057 /**
1058 Get HPC PCI address according to its device path.
1059 @param PciRootBridgeIo Root bridege Io instance.
1060 @param HpcDevicePath Given searching device path.
1061 @param PciAddress Buffer holding searched result.
1062
1063 @retval EFI_NOT_FOUND Can not find the specific device path.
1064 @retval EFI_SUCCESS Success to get the device path.
1065 **/
1066 EFI_STATUS
1067 GetHpcPciAddress (
1068 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
1069 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
1070 OUT UINT64 *PciAddress
1071 )
1072 {
1073 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1074 EFI_DEV_PATH_PTR Node;
1075 LIST_ENTRY *CurrentLink;
1076 PCI_IO_DEVICE *RootBridge;
1077 EFI_STATUS Status;
1078
1079 CurrentDevicePath = HpcDevicePath;
1080
1081 //
1082 // Get the remaining device path for this PCI device, if it is a PCI device
1083 //
1084 while (!IsDevicePathEnd (CurrentDevicePath)) {
1085
1086 Node.DevPath = CurrentDevicePath;
1087
1088 //
1089 // Check if it is PCI device Path?
1090 //
1091 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||
1092 ((Node.DevPath->SubType != HW_PCI_DP) &&
1093 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {
1094 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1095 continue;
1096 }
1097
1098 break;
1099 }
1100
1101 //
1102 // Check if it is not PCI device path
1103 //
1104 if (IsDevicePathEnd (CurrentDevicePath)) {
1105 return EFI_NOT_FOUND;
1106 }
1107
1108 CurrentLink = gPciDevicePool.ForwardLink;
1109
1110 while (CurrentLink != NULL && CurrentLink != &gPciDevicePool) {
1111
1112 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1113 //
1114 // Locate the right root bridge to start
1115 //
1116 if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {
1117 Status = GetHpcPciAddressFromRootBridge (
1118 RootBridge,
1119 CurrentDevicePath,
1120 PciAddress
1121 );
1122 if (EFI_ERROR (Status)) {
1123 return EFI_NOT_FOUND;
1124 }
1125
1126 return EFI_SUCCESS;
1127
1128 }
1129
1130 CurrentLink = CurrentLink->ForwardLink;
1131 }
1132
1133 return EFI_NOT_FOUND;
1134 }
1135
1136 /**
1137 Get HPC PCI address according to its device path.
1138 @param RootBridge Root bridege Io instance.
1139 @param RemainingDevicePath Given searching device path.
1140 @param PciAddress Buffer holding searched result.
1141
1142 @retval EFI_NOT_FOUND Can not find the specific device path.
1143 **/
1144 EFI_STATUS
1145 GetHpcPciAddressFromRootBridge (
1146 IN PCI_IO_DEVICE *RootBridge,
1147 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
1148 OUT UINT64 *PciAddress
1149 )
1150 {
1151 EFI_DEV_PATH_PTR Node;
1152 PCI_IO_DEVICE *Temp;
1153 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1154 LIST_ENTRY *CurrentLink;
1155 BOOLEAN MisMatch;
1156
1157 MisMatch = FALSE;
1158
1159 CurrentDevicePath = RemainingDevicePath;
1160 Node.DevPath = CurrentDevicePath;
1161 Temp = NULL;
1162
1163 while (!IsDevicePathEnd (CurrentDevicePath)) {
1164
1165 CurrentLink = RootBridge->ChildList.ForwardLink;
1166 Node.DevPath = CurrentDevicePath;
1167
1168 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1169 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1170
1171 if (Node.Pci->Device == Temp->DeviceNumber &&
1172 Node.Pci->Function == Temp->FunctionNumber) {
1173 RootBridge = Temp;
1174 break;
1175 }
1176
1177 CurrentLink = CurrentLink->ForwardLink;
1178 }
1179
1180 //
1181 // Check if we find the bridge
1182 //
1183 if (CurrentLink == &RootBridge->ChildList) {
1184
1185 MisMatch = TRUE;
1186 break;
1187
1188 }
1189
1190 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1191 }
1192
1193 if (MisMatch) {
1194
1195 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1196
1197 if (IsDevicePathEnd (CurrentDevicePath)) {
1198 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
1199 return EFI_SUCCESS;
1200 }
1201
1202 return EFI_NOT_FOUND;
1203 }
1204
1205 if (Temp != NULL) {
1206 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1207 } else {
1208 return EFI_NOT_FOUND;
1209 }
1210
1211 return EFI_SUCCESS;
1212
1213 }
1214