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