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