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