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