3 Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>
4 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
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.
18 This file provides routine to support Pci device node manipulation
27 // This device structure is serviced as a header.
28 // Its Next field points to the first root bridge device node
30 LIST_ENTRY gPciDevicePool
;
33 InitializePciDevicePool (
40 Initialize the gPciDevicePool
50 InitializeListHead (&gPciDevicePool
);
57 IN PCI_IO_DEVICE
*RootBridge
63 Insert a root bridge into PCI device pool
67 RootBridge - A pointer to the PCI_IO_DEVICE.
75 InsertTailList (&gPciDevicePool
, &(RootBridge
->Link
));
82 PCI_IO_DEVICE
*Bridge
,
83 PCI_IO_DEVICE
*PciDeviceNode
89 This function is used to insert a PCI device node under
93 Bridge - A pointer to the PCI_IO_DEVICE.
94 PciDeviceNode - A pointer to the PCI_IO_DEVICE.
104 InsertTailList (&Bridge
->ChildList
, &(PciDeviceNode
->Link
));
105 PciDeviceNode
->Parent
= Bridge
;
112 IN PCI_IO_DEVICE
*RootBridge
121 RootBridge - A pointer to the PCI_IO_DEVICE.
129 DestroyPciDeviceTree (RootBridge
);
131 gBS
->FreePool (RootBridge
);
137 DestroyPciDeviceTree (
138 IN PCI_IO_DEVICE
*Bridge
144 Destroy all the pci device node under the bridge.
145 Bridge itself is not included.
149 Bridge - A pointer to the PCI_IO_DEVICE.
157 LIST_ENTRY
*CurrentLink
;
160 while (!IsListEmpty (&Bridge
->ChildList
)) {
162 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
165 // Remove this node from the linked list
167 RemoveEntryList (CurrentLink
);
169 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
171 if (IS_PCI_BRIDGE (&(Temp
->Pci
))) {
172 DestroyPciDeviceTree (Temp
);
174 gBS
->FreePool (Temp
);
181 DestroyRootBridgeByHandle (
182 EFI_HANDLE Controller
188 Destroy all device nodes under the root bridge
189 specified by Controller.
190 The root bridge itself is also included.
194 Controller - An efi handle.
203 LIST_ENTRY
*CurrentLink
;
206 CurrentLink
= gPciDevicePool
.ForwardLink
;
208 while (CurrentLink
&& CurrentLink
!= &gPciDevicePool
) {
209 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
211 if (Temp
->Handle
== Controller
) {
213 RemoveEntryList (CurrentLink
);
215 DestroyPciDeviceTree (Temp
);
222 CurrentLink
= CurrentLink
->ForwardLink
;
225 return EFI_NOT_FOUND
;
230 IN EFI_HANDLE Controller
,
231 IN PCI_IO_DEVICE
*PciIoDevice
,
232 OUT EFI_HANDLE
*Handle OPTIONAL
238 This function registers the PCI IO device. It creates a handle for this PCI IO device
239 (if the handle does not exist), attaches appropriate protocols onto the handle, does
240 necessary initialization, and sets up parent/child relationship with its bus controller.
244 Controller - An EFI handle for the PCI bus controller.
245 PciIoDevice - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
246 Handle - A pointer to hold the EFI handle for the PCI IO device.
250 EFI_SUCCESS - The PCI device is successfully registered.
251 Others - An error occurred when registering the PCI device.
256 UINT8 PciExpressCapRegOffset
;
259 // Install the pciio protocol, device path protocol and
260 // Bus Specific Driver Override Protocol
263 if (PciIoDevice
->BusOverride
) {
264 Status
= gBS
->InstallMultipleProtocolInterfaces (
265 &PciIoDevice
->Handle
,
266 &gEfiDevicePathProtocolGuid
,
267 PciIoDevice
->DevicePath
,
268 &gEfiPciIoProtocolGuid
,
270 &gEfiBusSpecificDriverOverrideProtocolGuid
,
271 &PciIoDevice
->PciDriverOverride
,
275 Status
= gBS
->InstallMultipleProtocolInterfaces (
276 &PciIoDevice
->Handle
,
277 &gEfiDevicePathProtocolGuid
,
278 PciIoDevice
->DevicePath
,
279 &gEfiPciIoProtocolGuid
,
285 if (EFI_ERROR (Status
)) {
288 Status
= gBS
->OpenProtocol (
290 &gEfiPciRootBridgeIoProtocolGuid
,
291 (VOID
**)&(PciIoDevice
->PciRootBridgeIo
),
292 gPciBusDriverBinding
.DriverBindingHandle
,
294 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
296 if (EFI_ERROR (Status
)) {
301 if (Handle
!= NULL
) {
302 *Handle
= PciIoDevice
->Handle
;
306 // Detect if PCI Express Device
308 PciExpressCapRegOffset
= 0;
309 Status
= LocateCapabilityRegBlock (
311 EFI_PCI_CAPABILITY_ID_PCIEXP
,
312 &PciExpressCapRegOffset
,
315 if (!EFI_ERROR (Status
)) {
316 PciIoDevice
->IsPciExp
= TRUE
;
317 DEBUG ((EFI_D_ERROR
, "PciExp - %x (B-%x, D-%x, F-%x)\n", PciIoDevice
->IsPciExp
, PciIoDevice
->BusNumber
, PciIoDevice
->DeviceNumber
, PciIoDevice
->FunctionNumber
));
321 // Indicate the pci device is registered
323 PciIoDevice
->Registered
= TRUE
;
330 DeRegisterPciDevice (
331 IN EFI_HANDLE Controller
,
338 This function is used to de-register the PCI device from the EFI,
339 That includes un-installing PciIo protocol from the specified PCI
344 Controller - An efi handle.
345 Handle - An efi handle.
353 EFI_PCI_IO_PROTOCOL
*PciIo
;
355 PCI_IO_DEVICE
*PciIoDevice
;
357 LIST_ENTRY
*CurrentLink
;
358 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
360 Status
= gBS
->OpenProtocol (
362 &gEfiPciIoProtocolGuid
,
364 gPciBusDriverBinding
.DriverBindingHandle
,
366 EFI_OPEN_PROTOCOL_GET_PROTOCOL
368 if (!EFI_ERROR (Status
)) {
369 PciIoDevice
= PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo
);
372 // If it is already de-registered
374 if (!PciIoDevice
->Registered
) {
379 // If it is PPB, first de-register its children
382 if (IS_PCI_BRIDGE (&(PciIoDevice
->Pci
))) {
384 CurrentLink
= PciIoDevice
->ChildList
.ForwardLink
;
386 while (CurrentLink
&& CurrentLink
!= &PciIoDevice
->ChildList
) {
387 Node
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
388 Status
= DeRegisterPciDevice (Controller
, Node
->Handle
);
390 if (EFI_ERROR (Status
)) {
394 CurrentLink
= CurrentLink
->ForwardLink
;
399 // First disconnect this device
401 // PciIoDevice->PciIo.Attributes(&(PciIoDevice->PciIo),
402 // EfiPciIoAttributeOperationDisable,
403 // EFI_PCI_DEVICE_ENABLE,
408 // Close the child handle
410 Status
= gBS
->CloseProtocol (
412 &gEfiPciRootBridgeIoProtocolGuid
,
413 gPciBusDriverBinding
.DriverBindingHandle
,
418 // Un-install the device path protocol and pci io protocol
420 if (PciIoDevice
->BusOverride
) {
421 Status
= gBS
->UninstallMultipleProtocolInterfaces (
423 &gEfiDevicePathProtocolGuid
,
424 PciIoDevice
->DevicePath
,
425 &gEfiPciIoProtocolGuid
,
427 &gEfiBusSpecificDriverOverrideProtocolGuid
,
428 &PciIoDevice
->PciDriverOverride
,
432 Status
= gBS
->UninstallMultipleProtocolInterfaces (
434 &gEfiDevicePathProtocolGuid
,
435 PciIoDevice
->DevicePath
,
436 &gEfiPciIoProtocolGuid
,
442 if (EFI_ERROR (Status
)) {
445 &gEfiPciRootBridgeIoProtocolGuid
,
446 (VOID
**) &PciRootBridgeIo
,
447 gPciBusDriverBinding
.DriverBindingHandle
,
449 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
455 // The Device Driver should disable this device after disconnect
456 // so the Pci Bus driver will not touch this device any more.
457 // Restore the register field to the original value
459 PciIoDevice
->Registered
= FALSE
;
460 PciIoDevice
->Handle
= NULL
;
464 // Handle may be closed before
473 EnableBridgeAttributes (
474 IN PCI_IO_DEVICE
*PciIoDevice
480 // NOTE: We should not set EFI_PCI_DEVICE_ENABLE for a bridge
481 // directly, because some legacy BIOS will NOT assign
482 // IO or Memory resource for a bridge who has no child
483 // device. So we add check IO or Memory here.
486 PciIoDevice
->PciIo
.Pci
.Read (
494 if ((((PciData
.Bridge
.IoBase
& 0xF) == 0) &&
495 (PciData
.Bridge
.IoBase
!= 0 || PciData
.Bridge
.IoLimit
!= 0)) ||
496 (((PciData
.Bridge
.IoBase
& 0xF) == 1) &&
497 ((PciData
.Bridge
.IoBase
& 0xF0) != 0 || (PciData
.Bridge
.IoLimit
& 0xF0) != 0 || PciData
.Bridge
.IoBaseUpper16
!= 0 || PciData
.Bridge
.IoLimitUpper16
!= 0))) {
498 PciIoDevice
->PciIo
.Attributes(
499 &(PciIoDevice
->PciIo
),
500 EfiPciIoAttributeOperationEnable
,
501 (EFI_PCI_IO_ATTRIBUTE_IO
| EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
505 if ((PciData
.Bridge
.MemoryBase
& 0xFFF0) != 0 || (PciData
.Bridge
.MemoryLimit
& 0xFFF0) != 0) {
506 PciIoDevice
->PciIo
.Attributes(
507 &(PciIoDevice
->PciIo
),
508 EfiPciIoAttributeOperationEnable
,
509 (EFI_PCI_IO_ATTRIBUTE_MEMORY
| EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
513 if ((((PciData
.Bridge
.PrefetchableMemoryBase
& 0xF) == 0) &&
514 (PciData
.Bridge
.PrefetchableMemoryBase
!= 0 || PciData
.Bridge
.PrefetchableMemoryLimit
!= 0)) ||
515 (((PciData
.Bridge
.PrefetchableMemoryBase
& 0xF) == 1) &&
516 ((PciData
.Bridge
.PrefetchableMemoryBase
& 0xFFF0) != 0 || (PciData
.Bridge
.PrefetchableMemoryLimit
& 0xFFF0) != 0 || PciData
.Bridge
.PrefetchableBaseUpper32
!= 0 || PciData
.Bridge
.PrefetchableLimitUpper32
!= 0))) {
517 PciIoDevice
->PciIo
.Attributes(
518 &(PciIoDevice
->PciIo
),
519 EfiPciIoAttributeOperationEnable
,
520 (EFI_PCI_IO_ATTRIBUTE_MEMORY
| EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
),
529 StartPciDevicesOnBridge (
530 IN EFI_HANDLE Controller
,
531 IN PCI_IO_DEVICE
*RootBridge
,
532 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
538 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
542 Controller - An efi handle.
543 RootBridge - A pointer to the PCI_IO_DEVICE.
544 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
545 NumberOfChildren - Children number.
546 ChildHandleBuffer - A pointer to the child handle buffer.
555 PCI_IO_DEVICE
*PciIoDevice
;
556 EFI_DEV_PATH_PTR Node
;
557 EFI_DEVICE_PATH_PROTOCOL
*CurrentDevicePath
;
559 LIST_ENTRY
*CurrentLink
;
561 CurrentLink
= RootBridge
->ChildList
.ForwardLink
;
563 while (CurrentLink
&& CurrentLink
!= &RootBridge
->ChildList
) {
565 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
566 if (RemainingDevicePath
!= NULL
) {
568 Node
.DevPath
= RemainingDevicePath
;
570 if (Node
.Pci
->Device
!= Temp
->DeviceNumber
||
571 Node
.Pci
->Function
!= Temp
->FunctionNumber
) {
572 CurrentLink
= CurrentLink
->ForwardLink
;
577 // Check if the device has been assigned with required resource
579 if (!Temp
->Allocated
) {
580 return EFI_NOT_READY
;
584 // Check if the current node has been registered before
585 // If it is not, register it
587 if (!Temp
->Registered
) {
590 Status
= RegisterPciDevice (
599 // Get the next device path
601 CurrentDevicePath
= NextDevicePathNode (RemainingDevicePath
);
602 if (IsDevicePathEnd (CurrentDevicePath
)) {
609 if (IS_PCI_BRIDGE (&(Temp
->Pci
))) {
610 Status
= StartPciDevicesOnBridge (
615 EnableBridgeAttributes (Temp
);
621 // Currently, the PCI bus driver only support PCI-PCI bridge
623 return EFI_UNSUPPORTED
;
629 // If remaining device path is NULL,
630 // try to enable all the pci devices under this bridge
633 if (!Temp
->Registered
&& Temp
->Allocated
) {
637 Status
= RegisterPciDevice (
645 if (IS_PCI_BRIDGE (&(Temp
->Pci
))) {
646 Status
= StartPciDevicesOnBridge (
651 EnableBridgeAttributes (Temp
);
654 CurrentLink
= CurrentLink
->ForwardLink
;
659 return EFI_NOT_FOUND
;
664 IN EFI_HANDLE Controller
,
665 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
671 Start to manage the PCI device according to RemainingDevicePath
672 If RemainingDevicePath == NULL, the PCI bus driver will start
673 to manage all the PCI devices it found previously
676 Controller - An efi handle.
677 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
685 EFI_DEV_PATH_PTR Node
;
686 PCI_IO_DEVICE
*RootBridge
;
687 LIST_ENTRY
*CurrentLink
;
689 if (RemainingDevicePath
!= NULL
) {
692 // Check if the RemainingDevicePath is valid
694 Node
.DevPath
= RemainingDevicePath
;
695 if (Node
.DevPath
->Type
!= HARDWARE_DEVICE_PATH
||
696 Node
.DevPath
->SubType
!= HW_PCI_DP
||
697 DevicePathNodeLength (Node
.DevPath
) != sizeof (PCI_DEVICE_PATH
)
699 return EFI_UNSUPPORTED
;
703 CurrentLink
= gPciDevicePool
.ForwardLink
;
705 while (CurrentLink
&& CurrentLink
!= &gPciDevicePool
) {
707 RootBridge
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
709 // Locate the right root bridge to start
711 if (RootBridge
->Handle
== Controller
) {
712 StartPciDevicesOnBridge (
719 CurrentLink
= CurrentLink
->ForwardLink
;
727 IN EFI_HANDLE RootBridgeHandle
735 RootBridgeHandle - An efi handle.
748 Status
= gBS
->AllocatePool (
750 sizeof (PCI_IO_DEVICE
),
754 if (EFI_ERROR (Status
)) {
758 ZeroMem (Dev
, sizeof (PCI_IO_DEVICE
));
759 Dev
->Signature
= PCI_IO_DEVICE_SIGNATURE
;
760 Dev
->Handle
= RootBridgeHandle
;
761 InitializeListHead (&Dev
->ChildList
);
767 GetRootBridgeByHandle (
768 EFI_HANDLE RootBridgeHandle
777 RootBridgeHandle - An efi handle.
785 PCI_IO_DEVICE
*RootBridgeDev
;
786 LIST_ENTRY
*CurrentLink
;
788 CurrentLink
= gPciDevicePool
.ForwardLink
;
790 while (CurrentLink
&& CurrentLink
!= &gPciDevicePool
) {
792 RootBridgeDev
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
793 if (RootBridgeDev
->Handle
== RootBridgeHandle
) {
794 return RootBridgeDev
;
797 CurrentLink
= CurrentLink
->ForwardLink
;
805 IN EFI_HANDLE RootBridgeHandle
811 This function searches if RootBridgeHandle has already existed
812 in current device pool.
814 If so, it means the given root bridge has been already enumerated.
818 RootBridgeHandle - An efi handle.
826 PCI_IO_DEVICE
*Bridge
;
828 Bridge
= GetRootBridgeByHandle (RootBridgeHandle
);
830 if (Bridge
!= NULL
) {
839 IN PCI_IO_DEVICE
*Bridge
,
840 IN PCI_IO_DEVICE
*PciIoDevice
848 Bridge - A pointer to the PCI_IO_DEVICE.
849 PciIoDevice - A pointer to the PCI_IO_DEVICE.
859 LIST_ENTRY
*CurrentLink
;
861 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
863 while (CurrentLink
&& CurrentLink
!= &Bridge
->ChildList
) {
865 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
867 if (Temp
== PciIoDevice
) {
871 if (!IsListEmpty (&Temp
->ChildList
)) {
872 if (PciDeviceExisted (Temp
, PciIoDevice
)) {
877 CurrentLink
= CurrentLink
->ForwardLink
;
884 ActiveVGADeviceOnTheSameSegment (
885 IN PCI_IO_DEVICE
*VgaDevice
893 VgaDevice - A pointer to the PCI_IO_DEVICE.
901 LIST_ENTRY
*CurrentLink
;
904 CurrentLink
= gPciDevicePool
.ForwardLink
;
906 while (CurrentLink
&& CurrentLink
!= &gPciDevicePool
) {
908 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
910 if (Temp
->PciRootBridgeIo
->SegmentNumber
== VgaDevice
->PciRootBridgeIo
->SegmentNumber
) {
912 Temp
= ActiveVGADeviceOnTheRootBridge (Temp
);
919 CurrentLink
= CurrentLink
->ForwardLink
;
926 ActiveVGADeviceOnTheRootBridge (
927 IN PCI_IO_DEVICE
*RootBridge
935 RootBridge - A pointer to the PCI_IO_DEVICE.
943 LIST_ENTRY
*CurrentLink
;
946 CurrentLink
= RootBridge
->ChildList
.ForwardLink
;
948 while (CurrentLink
&& CurrentLink
!= &RootBridge
->ChildList
) {
950 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
952 if (IS_PCI_VGA(&Temp
->Pci
) &&
954 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
|
955 EFI_PCI_IO_ATTRIBUTE_VGA_IO
|
956 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
))) {
960 if (IS_PCI_BRIDGE (&Temp
->Pci
)) {
962 Temp
= ActiveVGADeviceOnTheRootBridge (Temp
);
969 CurrentLink
= CurrentLink
->ForwardLink
;