1 /** @file
2 Supporting functions implementaion for PCI devices management.
3
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PciBus.h"
16
17 //
18 // This device structure is serviced as a header.
19 // Its next field points to the first root bridge device node.
20 //
21 LIST_ENTRY mPciDevicePool;
22
23 /**
24 Initialize the PCI devices pool.
25
26 **/
27 VOID
InitializePciDevicePool(VOID)28 InitializePciDevicePool (
29 VOID
30 )
31 {
32 InitializeListHead (&mPciDevicePool);
33 }
34
35 /**
36 Insert a root bridge into PCI device pool.
37
38 @param RootBridge A pointer to the PCI_IO_DEVICE.
39
40 **/
41 VOID
InsertRootBridge(IN PCI_IO_DEVICE * RootBridge)42 InsertRootBridge (
43 IN PCI_IO_DEVICE *RootBridge
44 )
45 {
46 InsertTailList (&mPciDevicePool, &(RootBridge->Link));
47 }
48
49 /**
50 This function is used to insert a PCI device node under
51 a bridge.
52
53 @param Bridge The PCI bridge.
54 @param PciDeviceNode The PCI device needs inserting.
55
56 **/
57 VOID
InsertPciDevice(IN PCI_IO_DEVICE * Bridge,IN PCI_IO_DEVICE * PciDeviceNode)58 InsertPciDevice (
59 IN PCI_IO_DEVICE *Bridge,
60 IN PCI_IO_DEVICE *PciDeviceNode
61 )
62 {
63 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
64 PciDeviceNode->Parent = Bridge;
65 }
66
67 /**
68 Destroy root bridge and remove it from deivce tree.
69
70 @param RootBridge The bridge want to be removed.
71
72 **/
73 VOID
DestroyRootBridge(IN PCI_IO_DEVICE * RootBridge)74 DestroyRootBridge (
75 IN PCI_IO_DEVICE *RootBridge
76 )
77 {
78 DestroyPciDeviceTree (RootBridge);
79
80 FreePciDevice (RootBridge);
81 }
82
83 /**
84 Destroy a pci device node.
85
86 All direct or indirect allocated resource for this node will be freed.
87
88 @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.
89
90 **/
91 VOID
FreePciDevice(IN PCI_IO_DEVICE * PciIoDevice)92 FreePciDevice (
93 IN PCI_IO_DEVICE *PciIoDevice
94 )
95 {
96 ASSERT (PciIoDevice != NULL);
97 //
98 // Assume all children have been removed underneath this device
99 //
100 if (PciIoDevice->ResourcePaddingDescriptors != NULL) {
101 FreePool (PciIoDevice->ResourcePaddingDescriptors);
102 }
103
104 if (PciIoDevice->DevicePath != NULL) {
105 FreePool (PciIoDevice->DevicePath);
106 }
107
108 FreePool (PciIoDevice);
109 }
110
111 /**
112 Destroy all the pci device node under the bridge.
113 Bridge itself is not included.
114
115 @param Bridge A pointer to the PCI_IO_DEVICE.
116
117 **/
118 VOID
DestroyPciDeviceTree(IN PCI_IO_DEVICE * Bridge)119 DestroyPciDeviceTree (
120 IN PCI_IO_DEVICE *Bridge
121 )
122 {
123 LIST_ENTRY *CurrentLink;
124 PCI_IO_DEVICE *Temp;
125
126 while (!IsListEmpty (&Bridge->ChildList)) {
127
128 CurrentLink = Bridge->ChildList.ForwardLink;
129
130 //
131 // Remove this node from the linked list
132 //
133 RemoveEntryList (CurrentLink);
134
135 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
136
137 if (!IsListEmpty (&Temp->ChildList)) {
138 DestroyPciDeviceTree (Temp);
139 }
140
141 FreePciDevice (Temp);
142 }
143 }
144
145 /**
146 Destroy all device nodes under the root bridge
147 specified by Controller.
148
149 The root bridge itself is also included.
150
151 @param Controller Root bridge handle.
152
153 @retval EFI_SUCCESS Destory all devcie nodes successfully.
154 @retval EFI_NOT_FOUND Cannot find any PCI device under specified
155 root bridge.
156
157 **/
158 EFI_STATUS
DestroyRootBridgeByHandle(IN EFI_HANDLE Controller)159 DestroyRootBridgeByHandle (
160 IN EFI_HANDLE Controller
161 )
162 {
163
164 LIST_ENTRY *CurrentLink;
165 PCI_IO_DEVICE *Temp;
166
167 CurrentLink = mPciDevicePool.ForwardLink;
168
169 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
170 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
171
172 if (Temp->Handle == Controller) {
173
174 RemoveEntryList (CurrentLink);
175
176 DestroyPciDeviceTree (Temp);
177
178 FreePciDevice (Temp);
179
180 return EFI_SUCCESS;
181 }
182
183 CurrentLink = CurrentLink->ForwardLink;
184 }
185
186 return EFI_NOT_FOUND;
187 }
188
189 /**
190 This function registers the PCI IO device.
191
192 It creates a handle for this PCI IO device (if the handle does not exist), attaches
193 appropriate protocols onto the handle, does necessary initialization, and sets up
194 parent/child relationship with its bus controller.
195
196 @param Controller An EFI handle for the PCI bus controller.
197 @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
198 @param Handle A pointer to hold the returned EFI handle for the PCI IO device.
199
200 @retval EFI_SUCCESS The PCI device is successfully registered.
201 @retval other An error occurred when registering the PCI device.
202
203 **/
204 EFI_STATUS
RegisterPciDevice(IN EFI_HANDLE Controller,IN PCI_IO_DEVICE * PciIoDevice,OUT EFI_HANDLE * Handle OPTIONAL)205 RegisterPciDevice (
206 IN EFI_HANDLE Controller,
207 IN PCI_IO_DEVICE *PciIoDevice,
208 OUT EFI_HANDLE *Handle OPTIONAL
209 )
210 {
211 EFI_STATUS Status;
212 VOID *PlatformOpRomBuffer;
213 UINTN PlatformOpRomSize;
214 UINT8 PciExpressCapRegOffset;
215 EFI_PCI_IO_PROTOCOL *PciIo;
216 UINT8 Data8;
217 BOOLEAN HasEfiImage;
218
219 //
220 // Install the pciio protocol, device path protocol
221 //
222 Status = gBS->InstallMultipleProtocolInterfaces (
223 &PciIoDevice->Handle,
224 &gEfiDevicePathProtocolGuid,
225 PciIoDevice->DevicePath,
226 &gEfiPciIoProtocolGuid,
227 &PciIoDevice->PciIo,
228 NULL
229 );
230 if (EFI_ERROR (Status)) {
231 return Status;
232 }
233
234 //
235 // Detect if PCI Express Device
236 //
237 PciExpressCapRegOffset = 0;
238 Status = LocateCapabilityRegBlock (
239 PciIoDevice,
240 EFI_PCI_CAPABILITY_ID_PCIEXP,
241 &PciExpressCapRegOffset,
242 NULL
243 );
244 if (!EFI_ERROR (Status)) {
245 PciIoDevice->IsPciExp = TRUE;
246 }
247
248 //
249 // Force Interrupt line to "Unknown" or "No Connection"
250 //
251 PciIo = &(PciIoDevice->PciIo);
252 Data8 = PCI_INT_LINE_UNKNOWN;
253 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
254
255 //
256 // Process OpRom
257 //
258 if (!PciIoDevice->AllOpRomProcessed) {
259
260 //
261 // Get the OpRom provided by platform
262 //
263 if (gPciPlatformProtocol != NULL) {
264 Status = gPciPlatformProtocol->GetPciRom (
265 gPciPlatformProtocol,
266 PciIoDevice->Handle,
267 &PlatformOpRomBuffer,
268 &PlatformOpRomSize
269 );
270 if (!EFI_ERROR (Status)) {
271 PciIoDevice->EmbeddedRom = FALSE;
272 PciIoDevice->RomSize = PlatformOpRomSize;
273 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
274 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
275 //
276 // For OpROM read from gPciPlatformProtocol:
277 // Add the Rom Image to internal database for later PCI light enumeration
278 //
279 PciRomAddImageMapping (
280 NULL,
281 PciIoDevice->PciRootBridgeIo->SegmentNumber,
282 PciIoDevice->BusNumber,
283 PciIoDevice->DeviceNumber,
284 PciIoDevice->FunctionNumber,
285 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
286 PciIoDevice->PciIo.RomSize
287 );
288 }
289 } else if (gPciOverrideProtocol != NULL) {
290 Status = gPciOverrideProtocol->GetPciRom (
291 gPciOverrideProtocol,
292 PciIoDevice->Handle,
293 &PlatformOpRomBuffer,
294 &PlatformOpRomSize
295 );
296 if (!EFI_ERROR (Status)) {
297 PciIoDevice->EmbeddedRom = FALSE;
298 PciIoDevice->RomSize = PlatformOpRomSize;
299 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
300 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
301 //
302 // For OpROM read from gPciOverrideProtocol:
303 // Add the Rom Image to internal database for later PCI light enumeration
304 //
305 PciRomAddImageMapping (
306 NULL,
307 PciIoDevice->PciRootBridgeIo->SegmentNumber,
308 PciIoDevice->BusNumber,
309 PciIoDevice->DeviceNumber,
310 PciIoDevice->FunctionNumber,
311 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
312 PciIoDevice->PciIo.RomSize
313 );
314 }
315 }
316 }
317
318 //
319 // Determine if there are EFI images in the option rom
320 //
321 HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);
322
323 if (HasEfiImage) {
324 Status = gBS->InstallMultipleProtocolInterfaces (
325 &PciIoDevice->Handle,
326 &gEfiLoadFile2ProtocolGuid,
327 &PciIoDevice->LoadFile2,
328 NULL
329 );
330 if (EFI_ERROR (Status)) {
331 gBS->UninstallMultipleProtocolInterfaces (
332 &PciIoDevice->Handle,
333 &gEfiDevicePathProtocolGuid,
334 PciIoDevice->DevicePath,
335 &gEfiPciIoProtocolGuid,
336 &PciIoDevice->PciIo,
337 NULL
338 );
339 return Status;
340 }
341 }
342
343
344 if (!PciIoDevice->AllOpRomProcessed) {
345
346 PciIoDevice->AllOpRomProcessed = TRUE;
347
348 //
349 // Dispatch the EFI OpRom for the PCI device.
350 // The OpRom is got from platform in the above code
351 // or loaded from device in the previous round of bus enumeration
352 //
353 if (HasEfiImage) {
354 ProcessOpRomImage (PciIoDevice);
355 }
356 }
357
358 if (PciIoDevice->BusOverride) {
359 //
360 // Install Bus Specific Driver Override Protocol
361 //
362 Status = gBS->InstallMultipleProtocolInterfaces (
363 &PciIoDevice->Handle,
364 &gEfiBusSpecificDriverOverrideProtocolGuid,
365 &PciIoDevice->PciDriverOverride,
366 NULL
367 );
368 if (EFI_ERROR (Status)) {
369 gBS->UninstallMultipleProtocolInterfaces (
370 &PciIoDevice->Handle,
371 &gEfiDevicePathProtocolGuid,
372 PciIoDevice->DevicePath,
373 &gEfiPciIoProtocolGuid,
374 &PciIoDevice->PciIo,
375 NULL
376 );
377 if (HasEfiImage) {
378 gBS->UninstallMultipleProtocolInterfaces (
379 &PciIoDevice->Handle,
380 &gEfiLoadFile2ProtocolGuid,
381 &PciIoDevice->LoadFile2,
382 NULL
383 );
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 if (Handle != NULL) {
403 *Handle = PciIoDevice->Handle;
404 }
405
406 //
407 // Indicate the pci device is registered
408 //
409 PciIoDevice->Registered = TRUE;
410
411 return EFI_SUCCESS;
412 }
413
414 /**
415 This function is used to remove the whole PCI devices on the specified bridge from
416 the root bridge.
417
418 @param RootBridgeHandle The root bridge device handle.
419 @param Bridge The bridge device to be removed.
420
421 **/
422 VOID
RemoveAllPciDeviceOnBridge(EFI_HANDLE RootBridgeHandle,PCI_IO_DEVICE * Bridge)423 RemoveAllPciDeviceOnBridge (
424 EFI_HANDLE RootBridgeHandle,
425 PCI_IO_DEVICE *Bridge
426 )
427 {
428 LIST_ENTRY *CurrentLink;
429 PCI_IO_DEVICE *Temp;
430
431 while (!IsListEmpty (&Bridge->ChildList)) {
432
433 CurrentLink = Bridge->ChildList.ForwardLink;
434 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
435
436 //
437 // Check if the current node has been deregistered before
438 // If it is not, then deregister it
439 //
440 if (Temp->Registered) {
441 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
442 }
443
444 //
445 // Remove this node from the linked list
446 //
447 RemoveEntryList (CurrentLink);
448
449 if (!IsListEmpty (&Temp->ChildList)) {
450 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
451 }
452
453 FreePciDevice (Temp);
454 }
455 }
456
457 /**
458 This function is used to de-register the PCI IO device.
459
460 That includes un-installing PciIo protocol from the specified PCI
461 device handle.
462
463 @param Controller An EFI handle for the PCI bus controller.
464 @param Handle PCI device handle.
465
466 @retval EFI_SUCCESS The PCI device is successfully de-registered.
467 @retval other An error occurred when de-registering the PCI device.
468
469 **/
470 EFI_STATUS
DeRegisterPciDevice(IN EFI_HANDLE Controller,IN EFI_HANDLE Handle)471 DeRegisterPciDevice (
472 IN EFI_HANDLE Controller,
473 IN EFI_HANDLE Handle
474 )
475
476 {
477 EFI_PCI_IO_PROTOCOL *PciIo;
478 EFI_STATUS Status;
479 PCI_IO_DEVICE *PciIoDevice;
480 PCI_IO_DEVICE *Node;
481 LIST_ENTRY *CurrentLink;
482 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
483
484 Status = gBS->OpenProtocol (
485 Handle,
486 &gEfiPciIoProtocolGuid,
487 (VOID **) &PciIo,
488 gPciBusDriverBinding.DriverBindingHandle,
489 Controller,
490 EFI_OPEN_PROTOCOL_GET_PROTOCOL
491 );
492 if (!EFI_ERROR (Status)) {
493 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
494
495 //
496 // If it is already de-registered
497 //
498 if (!PciIoDevice->Registered) {
499 return EFI_SUCCESS;
500 }
501
502 //
503 // If it is PPB, first de-register its children
504 //
505
506 if (!IsListEmpty (&PciIoDevice->ChildList)) {
507
508 CurrentLink = PciIoDevice->ChildList.ForwardLink;
509
510 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
511 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
512 Status = DeRegisterPciDevice (Controller, Node->Handle);
513
514 if (EFI_ERROR (Status)) {
515 return Status;
516 }
517
518 CurrentLink = CurrentLink->ForwardLink;
519 }
520 }
521
522 //
523 // Close the child handle
524 //
525 Status = gBS->CloseProtocol (
526 Controller,
527 &gEfiPciRootBridgeIoProtocolGuid,
528 gPciBusDriverBinding.DriverBindingHandle,
529 Handle
530 );
531
532 //
533 // Un-install the Device Path protocol and PCI I/O protocol
534 // and Bus Specific Driver Override protocol if needed.
535 //
536 if (PciIoDevice->BusOverride) {
537 Status = gBS->UninstallMultipleProtocolInterfaces (
538 Handle,
539 &gEfiDevicePathProtocolGuid,
540 PciIoDevice->DevicePath,
541 &gEfiPciIoProtocolGuid,
542 &PciIoDevice->PciIo,
543 &gEfiBusSpecificDriverOverrideProtocolGuid,
544 &PciIoDevice->PciDriverOverride,
545 NULL
546 );
547 } else {
548 Status = gBS->UninstallMultipleProtocolInterfaces (
549 Handle,
550 &gEfiDevicePathProtocolGuid,
551 PciIoDevice->DevicePath,
552 &gEfiPciIoProtocolGuid,
553 &PciIoDevice->PciIo,
554 NULL
555 );
556 }
557
558 if (!EFI_ERROR (Status)) {
559 //
560 // Try to uninstall LoadFile2 protocol if exists
561 //
562 Status = gBS->OpenProtocol (
563 Handle,
564 &gEfiLoadFile2ProtocolGuid,
565 NULL,
566 gPciBusDriverBinding.DriverBindingHandle,
567 Controller,
568 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
569 );
570 if (!EFI_ERROR (Status)) {
571 Status = gBS->UninstallMultipleProtocolInterfaces (
572 Handle,
573 &gEfiLoadFile2ProtocolGuid,
574 &PciIoDevice->LoadFile2,
575 NULL
576 );
577 }
578 //
579 // Restore Status
580 //
581 Status = EFI_SUCCESS;
582 }
583
584
585 if (EFI_ERROR (Status)) {
586 gBS->OpenProtocol (
587 Controller,
588 &gEfiPciRootBridgeIoProtocolGuid,
589 (VOID **) &PciRootBridgeIo,
590 gPciBusDriverBinding.DriverBindingHandle,
591 Handle,
592 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
593 );
594 return Status;
595 }
596
597 //
598 // The Device Driver should disable this device after disconnect
599 // so the Pci Bus driver will not touch this device any more.
600 // Restore the register field to the original value
601 //
602 PciIoDevice->Registered = FALSE;
603 PciIoDevice->Handle = NULL;
604 } else {
605
606 //
607 // Handle may be closed before
608 //
609 return EFI_SUCCESS;
610 }
611
612 return EFI_SUCCESS;
613 }
614
615 /**
616 Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
617
618 @param Controller The root bridge handle.
619 @param RootBridge A pointer to the PCI_IO_DEVICE.
620 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
621 @param NumberOfChildren Children number.
622 @param ChildHandleBuffer A pointer to the child handle buffer.
623
624 @retval EFI_NOT_READY Device is not allocated.
625 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
626 @retval EFI_NOT_FOUND Can not find the specific device.
627 @retval EFI_SUCCESS Success to start Pci devices on bridge.
628
629 **/
630 EFI_STATUS
StartPciDevicesOnBridge(IN EFI_HANDLE Controller,IN PCI_IO_DEVICE * RootBridge,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath,IN OUT UINT8 * NumberOfChildren,IN OUT EFI_HANDLE * ChildHandleBuffer)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 PCI_IO_DEVICE *PciIoDevice;
641 EFI_DEV_PATH_PTR Node;
642 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
643 EFI_STATUS Status;
644 LIST_ENTRY *CurrentLink;
645 UINT64 Supports;
646
647 PciIoDevice = NULL;
648 CurrentLink = RootBridge->ChildList.ForwardLink;
649
650 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
651
652 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
653 if (RemainingDevicePath != NULL) {
654
655 Node.DevPath = RemainingDevicePath;
656
657 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
658 Node.Pci->Function != PciIoDevice->FunctionNumber) {
659 CurrentLink = CurrentLink->ForwardLink;
660 continue;
661 }
662
663 //
664 // Check if the device has been assigned with required resource
665 //
666 if (!PciIoDevice->Allocated) {
667 return EFI_NOT_READY;
668 }
669
670 //
671 // Check if the current node has been registered before
672 // If it is not, register it
673 //
674 if (!PciIoDevice->Registered) {
675 Status = RegisterPciDevice (
676 Controller,
677 PciIoDevice,
678 NULL
679 );
680
681 }
682
683 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
684 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
685 (*NumberOfChildren)++;
686 }
687
688 //
689 // Get the next device path
690 //
691 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
692 if (IsDevicePathEnd (CurrentDevicePath)) {
693 return EFI_SUCCESS;
694 }
695
696 //
697 // If it is a PPB
698 //
699 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
700 Status = StartPciDevicesOnBridge (
701 Controller,
702 PciIoDevice,
703 CurrentDevicePath,
704 NumberOfChildren,
705 ChildHandleBuffer
706 );
707
708 PciIoDevice->PciIo.Attributes (
709 &(PciIoDevice->PciIo),
710 EfiPciIoAttributeOperationSupported,
711 0,
712 &Supports
713 );
714 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
715 PciIoDevice->PciIo.Attributes (
716 &(PciIoDevice->PciIo),
717 EfiPciIoAttributeOperationEnable,
718 Supports,
719 NULL
720 );
721
722 return Status;
723 } else {
724
725 //
726 // Currently, the PCI bus driver only support PCI-PCI bridge
727 //
728 return EFI_UNSUPPORTED;
729 }
730
731 } else {
732
733 //
734 // If remaining device path is NULL,
735 // try to enable all the pci devices under this bridge
736 //
737 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
738 Status = RegisterPciDevice (
739 Controller,
740 PciIoDevice,
741 NULL
742 );
743
744 }
745
746 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
747 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
748 (*NumberOfChildren)++;
749 }
750
751 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
752 Status = StartPciDevicesOnBridge (
753 Controller,
754 PciIoDevice,
755 RemainingDevicePath,
756 NumberOfChildren,
757 ChildHandleBuffer
758 );
759
760 PciIoDevice->PciIo.Attributes (
761 &(PciIoDevice->PciIo),
762 EfiPciIoAttributeOperationSupported,
763 0,
764 &Supports
765 );
766 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
767 PciIoDevice->PciIo.Attributes (
768 &(PciIoDevice->PciIo),
769 EfiPciIoAttributeOperationEnable,
770 Supports,
771 NULL
772 );
773
774 }
775
776 CurrentLink = CurrentLink->ForwardLink;
777 }
778 }
779
780 if (PciIoDevice == NULL) {
781 return EFI_NOT_FOUND;
782 } else {
783 return EFI_SUCCESS;
784 }
785 }
786
787 /**
788 Start to manage all the PCI devices it found previously under
789 the entire host bridge.
790
791 @param Controller The root bridge handle.
792
793 @retval EFI_NOT_READY Device is not allocated.
794 @retval EFI_SUCCESS Success to start Pci device on host bridge.
795
796 **/
797 EFI_STATUS
StartPciDevices(IN EFI_HANDLE Controller)798 StartPciDevices (
799 IN EFI_HANDLE Controller
800 )
801 {
802 PCI_IO_DEVICE *RootBridge;
803 EFI_HANDLE ThisHostBridge;
804 LIST_ENTRY *CurrentLink;
805
806 RootBridge = GetRootBridgeByHandle (Controller);
807 ASSERT (RootBridge != NULL);
808 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
809
810 CurrentLink = mPciDevicePool.ForwardLink;
811
812 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
813
814 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
815 //
816 // Locate the right root bridge to start
817 //
818 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
819 StartPciDevicesOnBridge (
820 RootBridge->Handle,
821 RootBridge,
822 NULL,
823 NULL,
824 NULL
825 );
826 }
827
828 CurrentLink = CurrentLink->ForwardLink;
829 }
830
831 return EFI_SUCCESS;
832 }
833
834 /**
835 Create root bridge device.
836
837 @param RootBridgeHandle Specified root bridge hanle.
838
839 @return The crated root bridge device instance, NULL means no
840 root bridge device instance created.
841
842 **/
843 PCI_IO_DEVICE *
CreateRootBridge(IN EFI_HANDLE RootBridgeHandle)844 CreateRootBridge (
845 IN EFI_HANDLE RootBridgeHandle
846 )
847 {
848 EFI_STATUS Status;
849 PCI_IO_DEVICE *Dev;
850 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
851 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
852
853 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
854 if (Dev == NULL) {
855 return NULL;
856 }
857
858 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
859 Dev->Handle = RootBridgeHandle;
860 InitializeListHead (&Dev->ChildList);
861
862 Status = gBS->OpenProtocol (
863 RootBridgeHandle,
864 &gEfiDevicePathProtocolGuid,
865 (VOID **) &ParentDevicePath,
866 gPciBusDriverBinding.DriverBindingHandle,
867 RootBridgeHandle,
868 EFI_OPEN_PROTOCOL_GET_PROTOCOL
869 );
870
871 if (EFI_ERROR (Status)) {
872 FreePool (Dev);
873 return NULL;
874 }
875
876 //
877 // Record the root bridge parent device path
878 //
879 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
880
881 //
882 // Get the pci root bridge io protocol
883 //
884 Status = gBS->OpenProtocol (
885 RootBridgeHandle,
886 &gEfiPciRootBridgeIoProtocolGuid,
887 (VOID **) &PciRootBridgeIo,
888 gPciBusDriverBinding.DriverBindingHandle,
889 RootBridgeHandle,
890 EFI_OPEN_PROTOCOL_GET_PROTOCOL
891 );
892
893 if (EFI_ERROR (Status)) {
894 FreePciDevice (Dev);
895 return NULL;
896 }
897
898 Dev->PciRootBridgeIo = PciRootBridgeIo;
899
900 //
901 // Initialize the PCI I/O instance structure
902 //
903 InitializePciIoInstance (Dev);
904 InitializePciDriverOverrideInstance (Dev);
905 InitializePciLoadFile2 (Dev);
906
907 //
908 // Initialize reserved resource list and
909 // option rom driver list
910 //
911 InitializeListHead (&Dev->ReservedResourceList);
912 InitializeListHead (&Dev->OptionRomDriverList);
913
914 return Dev;
915 }
916
917 /**
918 Get root bridge device instance by specific root bridge handle.
919
920 @param RootBridgeHandle Given root bridge handle.
921
922 @return The root bridge device instance, NULL means no root bridge
923 device instance found.
924
925 **/
926 PCI_IO_DEVICE *
GetRootBridgeByHandle(EFI_HANDLE RootBridgeHandle)927 GetRootBridgeByHandle (
928 EFI_HANDLE RootBridgeHandle
929 )
930 {
931 PCI_IO_DEVICE *RootBridgeDev;
932 LIST_ENTRY *CurrentLink;
933
934 CurrentLink = mPciDevicePool.ForwardLink;
935
936 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
937
938 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
939 if (RootBridgeDev->Handle == RootBridgeHandle) {
940 return RootBridgeDev;
941 }
942
943 CurrentLink = CurrentLink->ForwardLink;
944 }
945
946 return NULL;
947 }
948
949 /**
950 Judege whether Pci device existed.
951
952 @param Bridge Parent bridege instance.
953 @param PciIoDevice Device instance.
954
955 @retval TRUE Pci device existed.
956 @retval FALSE Pci device did not exist.
957
958 **/
959 BOOLEAN
PciDeviceExisted(IN PCI_IO_DEVICE * Bridge,IN PCI_IO_DEVICE * PciIoDevice)960 PciDeviceExisted (
961 IN PCI_IO_DEVICE *Bridge,
962 IN PCI_IO_DEVICE *PciIoDevice
963 )
964 {
965
966 PCI_IO_DEVICE *Temp;
967 LIST_ENTRY *CurrentLink;
968
969 CurrentLink = Bridge->ChildList.ForwardLink;
970
971 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
972
973 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
974
975 if (Temp == PciIoDevice) {
976 return TRUE;
977 }
978
979 if (!IsListEmpty (&Temp->ChildList)) {
980 if (PciDeviceExisted (Temp, PciIoDevice)) {
981 return TRUE;
982 }
983 }
984
985 CurrentLink = CurrentLink->ForwardLink;
986 }
987
988 return FALSE;
989 }
990
991 /**
992 Get the active VGA device on the same segment.
993
994 @param VgaDevice PCI IO instance for the VGA device.
995
996 @return The active VGA device on the same segment.
997
998 **/
999 PCI_IO_DEVICE *
ActiveVGADeviceOnTheSameSegment(IN PCI_IO_DEVICE * VgaDevice)1000 ActiveVGADeviceOnTheSameSegment (
1001 IN PCI_IO_DEVICE *VgaDevice
1002 )
1003 {
1004 LIST_ENTRY *CurrentLink;
1005 PCI_IO_DEVICE *Temp;
1006
1007 CurrentLink = mPciDevicePool.ForwardLink;
1008
1009 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
1010
1011 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1012
1013 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
1014
1015 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1016
1017 if (Temp != NULL) {
1018 return Temp;
1019 }
1020 }
1021
1022 CurrentLink = CurrentLink->ForwardLink;
1023 }
1024
1025 return NULL;
1026 }
1027
1028 /**
1029 Get the active VGA device on the root bridge.
1030
1031 @param RootBridge PCI IO instance for the root bridge.
1032
1033 @return The active VGA device.
1034
1035 **/
1036 PCI_IO_DEVICE *
ActiveVGADeviceOnTheRootBridge(IN PCI_IO_DEVICE * RootBridge)1037 ActiveVGADeviceOnTheRootBridge (
1038 IN PCI_IO_DEVICE *RootBridge
1039 )
1040 {
1041 LIST_ENTRY *CurrentLink;
1042 PCI_IO_DEVICE *Temp;
1043
1044 CurrentLink = RootBridge->ChildList.ForwardLink;
1045
1046 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1047
1048 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1049
1050 if (IS_PCI_VGA(&Temp->Pci) &&
1051 (Temp->Attributes &
1052 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
1053 EFI_PCI_IO_ATTRIBUTE_VGA_IO |
1054 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
1055 return Temp;
1056 }
1057
1058 if (IS_PCI_BRIDGE (&Temp->Pci)) {
1059
1060 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1061
1062 if (Temp != NULL) {
1063 return Temp;
1064 }
1065 }
1066
1067 CurrentLink = CurrentLink->ForwardLink;
1068 }
1069
1070 return NULL;
1071 }
1072
1073
1074 /**
1075 Get HPC PCI address according to its device path.
1076
1077 @param RootBridge Root bridege Io instance.
1078 @param RemainingDevicePath Given searching device path.
1079 @param PciAddress Buffer holding searched result.
1080
1081 @retval EFI_SUCCESS PCI address was stored in PciAddress
1082 @retval EFI_NOT_FOUND Can not find the specific device path.
1083
1084 **/
1085 EFI_STATUS
GetHpcPciAddressFromRootBridge(IN PCI_IO_DEVICE * RootBridge,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath,OUT UINT64 * PciAddress)1086 GetHpcPciAddressFromRootBridge (
1087 IN PCI_IO_DEVICE *RootBridge,
1088 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
1089 OUT UINT64 *PciAddress
1090 )
1091 {
1092 EFI_DEV_PATH_PTR Node;
1093 PCI_IO_DEVICE *Temp;
1094 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1095 LIST_ENTRY *CurrentLink;
1096 BOOLEAN MisMatch;
1097
1098 MisMatch = FALSE;
1099
1100 CurrentDevicePath = RemainingDevicePath;
1101 Node.DevPath = CurrentDevicePath;
1102 Temp = NULL;
1103
1104 while (!IsDevicePathEnd (CurrentDevicePath)) {
1105
1106 CurrentLink = RootBridge->ChildList.ForwardLink;
1107 Node.DevPath = CurrentDevicePath;
1108
1109 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1110 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1111
1112 if (Node.Pci->Device == Temp->DeviceNumber &&
1113 Node.Pci->Function == Temp->FunctionNumber) {
1114 RootBridge = Temp;
1115 break;
1116 }
1117
1118 CurrentLink = CurrentLink->ForwardLink;
1119 }
1120
1121 //
1122 // Check if we find the bridge
1123 //
1124 if (CurrentLink == &RootBridge->ChildList) {
1125
1126 MisMatch = TRUE;
1127 break;
1128
1129 }
1130
1131 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1132 }
1133
1134 if (MisMatch) {
1135
1136 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1137
1138 if (IsDevicePathEnd (CurrentDevicePath)) {
1139 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
1140 return EFI_SUCCESS;
1141 }
1142
1143 return EFI_NOT_FOUND;
1144 }
1145
1146 if (Temp != NULL) {
1147 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1148 } else {
1149 return EFI_NOT_FOUND;
1150 }
1151
1152 return EFI_SUCCESS;
1153
1154 }
1155
1156