3 Copyright (c) 2005 - 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
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.
17 EFI PC AT PCI Root Bridge Io Protocol
23 #include "PcatPciRootBridge.h"
25 BOOLEAN mPciOptionRomTableInstalled
= FALSE
;
26 EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable
= {0, NULL
};
29 PcatRootBridgeIoIoRead (
30 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
31 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
32 IN UINT64 UserAddress
,
34 IN OUT VOID
*UserBuffer
37 return gCpuIo
->Io
.Read (
39 (EFI_CPU_IO_PROTOCOL_WIDTH
) Width
,
47 PcatRootBridgeIoIoWrite (
48 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
49 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
50 IN UINT64 UserAddress
,
52 IN OUT VOID
*UserBuffer
55 return gCpuIo
->Io
.Write (
57 (EFI_CPU_IO_PROTOCOL_WIDTH
) Width
,
66 PcatRootBridgeIoGetIoPortMapping (
67 OUT EFI_PHYSICAL_ADDRESS
*IoPortMapping
,
68 OUT EFI_PHYSICAL_ADDRESS
*MemoryPortMapping
72 Get the IO Port Mapping. For IA-32 it is always 0.
77 *MemoryPortMapping
= 0;
83 PcatRootBridgeIoPciRW (
84 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
86 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
87 IN UINT64 UserAddress
,
89 IN OUT VOID
*UserBuffer
92 PCI_CONFIG_ACCESS_CF8 Pci
;
93 PCI_CONFIG_ACCESS_CF8 PciAligned
;
98 PCAT_PCI_ROOT_BRIDGE_INSTANCE
*PrivateData
;
99 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress
;
100 UINT64 PciExpressRegAddr
;
101 BOOLEAN UsePciExpressAccess
;
103 if (Width
< 0 || Width
>= EfiPciWidthMaximum
) {
104 return EFI_INVALID_PARAMETER
;
107 if ((Width
& 0x03) >= EfiPciWidthUint64
) {
108 return EFI_INVALID_PARAMETER
;
111 PrivateData
= DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This
);
113 InStride
= 1 << (Width
& 0x03);
114 OutStride
= InStride
;
115 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
119 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
123 UsePciExpressAccess
= FALSE
;
125 CopyMem (&PciAddress
, &UserAddress
, sizeof(UINT64
));
127 if (PciAddress
.ExtendedRegister
> 0xFF) {
129 // Check PciExpressBaseAddress
131 if ((PrivateData
->PciExpressBaseAddress
== 0) ||
132 (PrivateData
->PciExpressBaseAddress
>= MAX_ADDRESS
)) {
133 return EFI_UNSUPPORTED
;
135 UsePciExpressAccess
= TRUE
;
138 if (PciAddress
.ExtendedRegister
!= 0) {
139 Pci
.Bits
.Reg
= PciAddress
.ExtendedRegister
& 0xFF;
141 Pci
.Bits
.Reg
= PciAddress
.Register
;
144 // Note: We can also use PciExpress access here, if wanted.
148 if (!UsePciExpressAccess
) {
149 Pci
.Bits
.Func
= PciAddress
.Function
;
150 Pci
.Bits
.Dev
= PciAddress
.Device
;
151 Pci
.Bits
.Bus
= PciAddress
.Bus
;
152 Pci
.Bits
.Reserved
= 0;
156 // PCI Config access are all 32-bit alligned, but by accessing the
157 // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types
158 // are possible on PCI.
160 // To read a byte of PCI config space you load 0xcf8 and
161 // read 0xcfc, 0xcfd, 0xcfe, 0xcff
163 PciDataStride
= Pci
.Bits
.Reg
& 0x03;
167 PciAligned
.Bits
.Reg
&= 0xfc;
168 PciData
= (UINTN
)PrivateData
->PciData
+ PciDataStride
;
169 EfiAcquireLock(&PrivateData
->PciLock
);
170 This
->Io
.Write (This
, EfiPciWidthUint32
, PrivateData
->PciAddress
, 1, &PciAligned
);
172 This
->Io
.Write (This
, Width
, PciData
, 1, UserBuffer
);
174 This
->Io
.Read (This
, Width
, PciData
, 1, UserBuffer
);
176 EfiReleaseLock(&PrivateData
->PciLock
);
177 UserBuffer
= ((UINT8
*)UserBuffer
) + OutStride
;
178 PciDataStride
= (PciDataStride
+ InStride
) % 4;
179 Pci
.Bits
.Reg
+= InStride
;
184 // Access PCI-Express space by using memory mapped method.
186 PciExpressRegAddr
= (PrivateData
->PciExpressBaseAddress
) |
187 (PciAddress
.Bus
<< 20) |
188 (PciAddress
.Device
<< 15) |
189 (PciAddress
.Function
<< 12);
190 if (PciAddress
.ExtendedRegister
!= 0) {
191 PciExpressRegAddr
+= PciAddress
.ExtendedRegister
;
193 PciExpressRegAddr
+= PciAddress
.Register
;
197 This
->Mem
.Write (This
, Width
, (UINTN
) PciExpressRegAddr
, 1, UserBuffer
);
199 This
->Mem
.Read (This
, Width
, (UINTN
) PciExpressRegAddr
, 1, UserBuffer
);
202 UserBuffer
= ((UINT8
*) UserBuffer
) + OutStride
;
203 PciExpressRegAddr
+= InStride
;
213 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*IoDev
,
220 EFI_PCI_BUS_SCAN_CALLBACK Callback
,
229 PCI_TYPE00 PciHeader
;
232 // Loop through all busses
234 for (Bus
= MinBus
; Bus
<= MaxBus
; Bus
++) {
236 // Loop 32 devices per bus
238 for (Device
= MinDevice
; Device
<= MaxDevice
; Device
++) {
240 // Loop through 8 functions per device
242 for (Func
= MinFunc
; Func
<= MaxFunc
; Func
++) {
245 // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device
247 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 0);
250 // Read the VendorID from this PCI Device's Confioguration Header
252 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint16
, Address
, 1, &PciHeader
.Hdr
.VendorId
);
255 // If VendorId = 0xffff, there does not exist a device at this
256 // location. For each device, if there is any function on it,
257 // there must be 1 function at Function 0. So if Func = 0, there
258 // will be no more functions in the same device, so we can break
259 // loop to deal with the next device.
261 if (PciHeader
.Hdr
.VendorId
== 0xffff && Func
== 0) {
265 if (PciHeader
.Hdr
.VendorId
!= 0xffff) {
268 // Read the HeaderType to determine if this is a multi-function device
270 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint8
, Address
+ 0x0e, 1, &PciHeader
.Hdr
.HeaderType
);
273 // Call the callback function for the device that was found
278 MinDevice
, MaxDevice
,
287 // If this is not a multi-function device, we can leave the loop
288 // to deal with the next device.
290 if ((PciHeader
.Hdr
.HeaderType
& HEADER_TYPE_MULTI_FUNCTION
) == 0x00 && Func
== 0) {
301 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*IoDev
,
315 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT
*Context
;
317 PCI_TYPE00 PciHeader
;
318 PCI_TYPE01
*PciBridgeHeader
;
322 EFI_PHYSICAL_ADDRESS RomBuffer
;
324 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader
;
325 PCI_DATA_STRUCTURE Pcir
;
326 EFI_PCI_OPTION_ROM_DESCRIPTOR
*TempPciOptionRomDescriptors
;
329 Context
= (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT
*)VoidContext
;
331 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 0);
334 // Save the contents of the PCI Configuration Header
336 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint32
, Address
, sizeof(PciHeader
)/sizeof(UINT32
), &PciHeader
);
338 if (IS_PCI_BRIDGE(&PciHeader
)) {
340 PciBridgeHeader
= (PCI_TYPE01
*)(&PciHeader
);
343 // See if the PCI-PCI Bridge has its secondary interface enabled.
345 if (PciBridgeHeader
->Bridge
.SubordinateBus
>= PciBridgeHeader
->Bridge
.SecondaryBus
) {
348 // Disable the Prefetchable Memory Window
350 Register
= 0x00000000;
351 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 0x26, 1, &Register
);
352 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint32
, Address
+ 0x2c, 1, &Register
);
353 Register
= 0xffffffff;
354 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 0x24, 1, &Register
);
355 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 0x28, 1, &Register
);
358 // Program Memory Window to the PCI Root Bridge Memory Window
360 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 0x20, 4, &Context
->PpbMemoryWindow
);
363 // Enable the Memory decode for the PCI-PCI Bridge
365 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint16
, Address
+ 4, 1, &Register
);
367 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 4, 1, &Register
);
370 // Recurse on the Secondary Bus Number
374 PciBridgeHeader
->Bridge
.SecondaryBus
, PciBridgeHeader
->Bridge
.SecondaryBus
,
383 // Check if an Option ROM Register is present and save the Option ROM Window Register
386 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint32
, Address
+ 0x30, 1, &RomBar
);
387 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint32
, Address
+ 0x30, 1, &RomBar
);
389 RomBarSize
= (~(RomBar
& 0xfffff800)) + 1;
392 // Make sure the size of the ROM is between 0 and 16 MB
394 if (RomBarSize
> 0 && RomBarSize
<= 0x01000000) {
397 // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window
399 RomBar
= (Context
->PpbMemoryWindow
& 0xffff) << 16;
400 RomBar
= ((RomBar
- 1) & (~(RomBarSize
- 1))) + RomBarSize
;
401 if (RomBar
< (Context
->PpbMemoryWindow
& 0xffff0000)) {
402 MaxRomSize
= (Context
->PpbMemoryWindow
& 0xffff0000) - RomBar
;
404 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint32
, Address
+ 0x30, 1, &RomBar
);
405 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint32
, Address
+ 0x30, 1, &RomBar
);
409 // Enable the Memory decode for the PCI Device
411 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint16
, Address
+ 4, 1, &Register
);
413 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 4, 1, &Register
);
416 // Follow the chain of images to determine the size of the Option ROM present
417 // Keep going until the last image is found by looking at the Indicator field
418 // or the size of an image is 0, or the size of all the images is bigger than the
419 // size of the window programmed into the PPB.
426 ZeroMem (&EfiRomHeader
, sizeof(EfiRomHeader
));
431 sizeof(EfiRomHeader
),
435 Pcir
.ImageLength
= 0;
437 if (EfiRomHeader
.Signature
== 0xaa55) {
439 ZeroMem (&Pcir
, sizeof(Pcir
));
443 RomBar
+ RomBarSize
+ EfiRomHeader
.PcirOffset
,
448 if ((Pcir
.Indicator
& 0x80) == 0x00) {
452 RomBarSize
+= Pcir
.ImageLength
* 512;
454 } while (!LastImage
&& RomBarSize
< MaxRomSize
&& Pcir
.ImageLength
!=0);
456 if (RomBarSize
> 0) {
459 // Allocate a memory buffer for the Option ROM contents.
461 Status
= gBS
->AllocatePages(
464 EFI_SIZE_TO_PAGES(RomBarSize
),
468 if (!EFI_ERROR (Status
)) {
471 // Copy the contents of the Option ROM to the memory buffer
473 IoDev
->Mem
.Read (IoDev
, EfiPciWidthUint32
, RomBar
, RomBarSize
/ sizeof(UINT32
), (VOID
*)(UINTN
)RomBuffer
);
475 Status
= gBS
->AllocatePool(
477 ((UINT32
)mPciOptionRomTable
.PciOptionRomCount
+ 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR
),
478 (VOID
**) &TempPciOptionRomDescriptors
480 if (mPciOptionRomTable
.PciOptionRomCount
> 0) {
482 TempPciOptionRomDescriptors
,
483 mPciOptionRomTable
.PciOptionRomDescriptors
,
484 (UINT32
)mPciOptionRomTable
.PciOptionRomCount
* sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR
)
487 gBS
->FreePool(mPciOptionRomTable
.PciOptionRomDescriptors
);
490 mPciOptionRomTable
.PciOptionRomDescriptors
= TempPciOptionRomDescriptors
;
492 TempPciOptionRomDescriptors
= &(mPciOptionRomTable
.PciOptionRomDescriptors
[(UINT32
)mPciOptionRomTable
.PciOptionRomCount
]);
494 TempPciOptionRomDescriptors
->RomAddress
= RomBuffer
;
495 TempPciOptionRomDescriptors
->MemoryType
= EfiBootServicesData
;
496 TempPciOptionRomDescriptors
->RomLength
= RomBarSize
;
497 TempPciOptionRomDescriptors
->Seg
= (UINT32
)IoDev
->SegmentNumber
;
498 TempPciOptionRomDescriptors
->Bus
= (UINT8
)Bus
;
499 TempPciOptionRomDescriptors
->Dev
= (UINT8
)Device
;
500 TempPciOptionRomDescriptors
->Func
= (UINT8
)Func
;
501 TempPciOptionRomDescriptors
->ExecutedLegacyBiosImage
= TRUE
;
502 TempPciOptionRomDescriptors
->DontLoadEfiRom
= FALSE
;
504 mPciOptionRomTable
.PciOptionRomCount
++;
509 // Disable the Memory decode for the PCI-PCI Bridge
511 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint16
, Address
+ 4, 1, &Register
);
513 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
+ 4, 1, &Register
);
519 // Restore the PCI Configuration Header
521 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint32
, Address
, sizeof(PciHeader
)/sizeof(UINT32
), &PciHeader
);
525 SaveCommandRegister (
526 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*IoDev
,
540 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT
*Context
;
545 Context
= (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT
*)VoidContext
;
547 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 4);
549 Index
= (Bus
- MinBus
) * (PCI_MAX_DEVICE
+1) * (PCI_MAX_FUNC
+1) + Device
* (PCI_MAX_FUNC
+1) + Func
;
551 IoDev
->Pci
.Read (IoDev
, EfiPciWidthUint16
, Address
, 1, &Context
->CommandRegisterBuffer
[Index
]);
554 // Clear the memory enable bit
556 Command
= (UINT16
) (Context
->CommandRegisterBuffer
[Index
] & (~0x02));
558 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
, 1, &Command
);
562 RestoreCommandRegister (
563 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*IoDev
,
577 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT
*Context
;
581 Context
= (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT
*)VoidContext
;
583 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Func
, 4);
585 Index
= (Bus
- MinBus
) * (PCI_MAX_DEVICE
+1) * (PCI_MAX_FUNC
+1) + Device
* (PCI_MAX_FUNC
+1) + Func
;
587 IoDev
->Pci
.Write (IoDev
, EfiPciWidthUint16
, Address
, 1, &Context
->CommandRegisterBuffer
[Index
]);
591 ScanPciRootBridgeForRoms(
592 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*IoDev
597 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
600 UINT64 RootWindowBase
;
601 UINT64 RootWindowLimit
;
602 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context
;
604 if (mPciOptionRomTableInstalled
== FALSE
) {
605 gBS
->InstallConfigurationTable(&gEfiPciOptionRomTableGuid
, &mPciOptionRomTable
);
606 mPciOptionRomTableInstalled
= TRUE
;
609 Status
= IoDev
->Configuration(IoDev
, (VOID
**) &Descriptors
);
610 if (EFI_ERROR (Status
) || Descriptors
== NULL
) {
611 return EFI_NOT_FOUND
;
618 while (Descriptors
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
622 if (Descriptors
->ResType
== ACPI_ADDRESS_SPACE_TYPE_BUS
) {
623 MinBus
= (UINT16
)Descriptors
->AddrRangeMin
;
624 MaxBus
= (UINT16
)Descriptors
->AddrRangeMax
;
627 // Find memory descriptors that are not prefetchable
629 if (Descriptors
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
&& Descriptors
->SpecificFlag
== 0) {
631 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices
633 if (Descriptors
->AddrRangeMax
< 0x100000000ULL
) {
635 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB
637 if ((Descriptors
->AddrRangeMax
- Descriptors
->AddrRangeMin
) > (RootWindowLimit
- RootWindowBase
)) {
638 RootWindowBase
= Descriptors
->AddrRangeMin
;
639 RootWindowLimit
= Descriptors
->AddrRangeMax
;
647 // Make sure a bus range was found
649 if (MinBus
== 0xffff || MaxBus
== 0xffff) {
650 return EFI_NOT_FOUND
;
654 // Make sure a non-prefetchable memory region was found
656 if (RootWindowBase
== 0 && RootWindowLimit
== 0) {
657 return EFI_NOT_FOUND
;
661 // Round the Base and Limit values to 1 MB boudaries
663 RootWindowBase
= ((RootWindowBase
- 1) & 0xfff00000) + 0x00100000;
664 RootWindowLimit
= ((RootWindowLimit
+ 1) & 0xfff00000) - 1;
667 // Make sure that the size of the rounded window is greater than zero
669 if (RootWindowLimit
<= RootWindowBase
) {
670 return EFI_NOT_FOUND
;
674 // Allocate buffer to save the Command register from all the PCI devices
676 Context
.CommandRegisterBuffer
= NULL
;
677 Status
= gBS
->AllocatePool(
679 sizeof(UINT16
) * (MaxBus
- MinBus
+ 1) * (PCI_MAX_DEVICE
+1) * (PCI_MAX_FUNC
+1),
680 (VOID
**) &Context
.CommandRegisterBuffer
683 if (EFI_ERROR (Status
)) {
687 Context
.PpbMemoryWindow
= (((UINT32
)RootWindowBase
) >> 16) | ((UINT32
)RootWindowLimit
& 0xffff0000);
690 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits
697 SaveCommandRegister
, &Context
701 // Recursively scan all the busses for PCI Option ROMs
708 CheckForRom
, &Context
712 // Restore the Command register in all the PCI devices
719 RestoreCommandRegister
, &Context
723 // Free the buffer used to save all the Command register values
725 gBS
->FreePool(Context
.CommandRegisterBuffer
);