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