]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c
The updating (change the Interrupt Line to 0xFF for unknown setting) is only for...
[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 // based on the PCI spec, the Interrupt line for x86 should be set as 0xFF for unknown.
342 //
343 PciIo = &(PciIoDevice->PciIo);
344 #ifndef MDE_CPU_IPF
345 Data8 = PCI_INT_LINE_UNKNOWN;
346 #else
347 Data8 = 0;
348 #endif
349 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
350
351 //
352 // Process Platform OpRom
353 //
354 if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {
355 PciIoDevice->AllOpRomProcessed = TRUE;
356
357 Status = gPciPlatformProtocol->GetPciRom (
358 gPciPlatformProtocol,
359 PciIoDevice->Handle,
360 &PlatformOpRomBuffer,
361 &PlatformOpRomSize
362 );
363
364 if (!EFI_ERROR (Status)) {
365
366 //
367 // Have Platform OpRom
368 //
369 PciIoDevice->RomSize = PlatformOpRomSize;
370 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
371 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
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 }