diff options
Diffstat (limited to 'Core/EM/PCI/PciBus.c')
-rw-r--r-- | Core/EM/PCI/PciBus.c | 13734 |
1 files changed, 13734 insertions, 0 deletions
diff --git a/Core/EM/PCI/PciBus.c b/Core/EM/PCI/PciBus.c new file mode 100644 index 0000000..bbd51a8 --- /dev/null +++ b/Core/EM/PCI/PciBus.c @@ -0,0 +1,13734 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2012, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/PCI/PciBus.c 3 12/19/12 7:07a Wesleychen $ +// +// $Revision: 3 $ +// +// $Date: 12/19/12 7:07a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/PCI/PciBus.c $ +// +// 3 12/19/12 7:07a Wesleychen +// Update to rev#152 for EIP107491. +// +// 152 11/26/12 4:23p Yakovlevs +// [TAG] EIP107491 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] PciBus can not detect some pcie card (LSI). +// [RootCause] A config write is required in order for the device to +// re-capture the Bus number +// [Solution] Add a dummy config write to VID/DID register offset 0 +// [Files] PciBus.c +// +// 150 9/20/12 12:15p Yakovlevs +// [TAG] EIP100249 +// [Category] New Feature +// [Description] Token to set PCIE capabilities Clock PM default value. +// Clock PM Settings was excluded for GEN1 devices. +// +// [Files] PciBus.c +// +// 149 9/12/12 11:55a Yakovlevs +// Restoring overrided Artem's changes. +// +// 148 9/12/12 11:51a Yakovlevs +// [TAG] EIP99393 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] I350 Powerville LOM UEFI driver is not loading +// [RootCause] Issue in invocation following function. +// DoubleCheckOpRom((VOID*)&PciRomHdr, &Pcir); +// variable PciRomHd was defined as buffer in stack but function requeres +// actual pointer at the ROM +// [Solution] Replace Parameters passing from PciRomHd to (base + trs) +// [Files] PciBus,c +// +// 146 9/10/12 12:51p Yakovlevs +// [TAG] EIP93341 +// [Category] Improvement +// [Description] Preserve PCI DEV/LNK/SLT control register in S3 resume +// path. +// [Files] PciBus.c PciBus.sd PciBus.uni PciSetup.h PciPort.c +// +// 145 7/20/12 12:50p Artems +// [TAG] EIP N/A +// [Category] Improvement +// [Description] Call GetOptRom before installing PciIO protocol, so ROM +// pointer has valid vaule +// [Files] Pcibus.c +// +// 144 7/13/12 5:14p Yakovlevs +// [TAG] EIP94699 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Coding error in PciBus.c +// [RootCause] Typo +// [Solution] fixing typo replace tBarMmio64 with tBarMmio64pf +// [Files] PciBus.c +// +// 143 6/26/12 5:53p Yakovlevs +// [TAG] EIP93341 +// [Category] Improvement +// [Description] Preserve PCI DEV/LNK/SLT control register in S3 resume +// path. +// [Files] PciBus.c +// +// 142 6/20/12 12:25p Olegi +// [TAG] EIP93141 +// [Description] PCI_IO_PROTOCOL.Attributes may fail +// +// 141 5/22/12 4:49p Yakovlevs +// Removing wrong comment +// +// 140 5/21/12 3:39p Artems +// [TAG] EIP86097 +// [Category] Improvement +// [Description] Separate control for loading UEFI Oprom Driver +// Added porting hook to CsmOptOut to enable/disable UEFI +// OpROM execution for particular PCI device, identified by PCI handle +// [Files] PciBus.c CsmOptOut.c +// +// 139 5/01/12 5:07p Yakovlevs +// [TAG] EIP84986 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Yellow mark issue in windows device manager on +// PCIe slots if only 2 CPU for potter city platform. +// [RootCause] For multy root system where root socets partialy +// populated SDL data interfered with +// Actual Hardware configuration. +// [Solution] Allow control flow keep going when certain +// ERROR_STATUS received. +// [Files] PciBus.c; PciHostBridge.c +// +// 138 5/01/12 4:25p Yakovlevs +// [TAG] EIP88259 +// [Category] Improvement +// [Description] Have valid PCI handle before processing OpROM +// [Files] PciBus.c +// +// 137 4/10/12 10:16a Yakovlevs +// [TAG] EIP87005 +// [Category] Bug Fix +// [Symptom] Aptio4.6.5.3...SCT Execution test failed.(PCI Bus Support +// Test\PCI IO Protocol Test) +// [RootCause] In DevAttributes() function we have masking +// Platform specific attributes since they don't affect +// functionality but may hung the system when somebody ties +// to set or reset it. +// [Solution] Remove code masking attributes 0x2000 0x4000 +// [Files] PciBus.c +// +// 136 12/19/11 2:08p Yakovlevs +// [TAG] EIP73172 +// [Category] Bug Fix +// [RootCause] It tires to read the PCI ROM header in DWORD unit. +// However the size of PCI_STD_OPT_ROM_HEADER is 26 which can not be +// divided by 4 without reminders. +// After this change it will only read 24 bytes, the last 2 bytes +// (PCI_STD_OPT_ROM_HEADER.PcirOffset) will not be read. +// The code then read memory from the PcirOffset pointer which is +// undefined.... +// +// [Solution] Roll back changes keeping 1 Byte access to the opt ROM +// header +// [Files] PCiBus.c +// +// 135 12/19/11 11:06a Yakovlevs +// +// 134 12/19/11 11:05a Yakovlevs +// [TAG] EIP73172 +// [Description] (JPJP000D) It stops POST Code 94h, when connected PCIE +// media read/write device. +// [Files] Added 4 byte alligned structure definition to handle 4 byte +// header read. +// +// 133 12/14/11 6:44p Yakovlevs +// [TAG] EIP73172 +// [Description] (JPJP000D) It stops POST Code 94h, when connected PCIE +// media read/write device. +// Also: fixed Init pci_address var in SetSlotProprties(); +// Fixed reconnect -r issue in PciBusStart() +// Changed size of access to the ROM BAR register in GetOpRom() from 1 +// byte to 4 - some cards could hang the system if 1 byte is used +// +// [Files] PciBus.c +// +// 132 12/07/11 11:00a Yakovlevs +// Fixed potential bug in PcieSetSlotProperties() routine. It was using +// uninitialized ADDRESS var. +// +// 131 12/02/11 2:30p Yakovlevs +// According to AMD GOP Driver GetBarAttributes() must return _GRA field +// set as a bar type NOT A RESOURCE TYPE. +// +// 130 11/09/11 2:03p Yakovlevs +// [TAG] EIP71380 +// [Category] New Feature +// [Description] Core support for CSM opt-out feature +// [Files] PciBus.c; PciPort.c; PciBus.sd; PciBus.uni; PciSetup.h; +// PciBusSetup.c; +// +// 129 11/08/11 11:03a Yakovlevs +// [TAG] EIP72803 +// [Category] Improvement +// [Description] Small fixes of previous checkin +// [Files] PciBus.c +// +// 128 11/03/11 5:59p Yakovlevs +// Added some debug messages. +// +// 127 11/03/11 5:39p Yakovlevs +// [TAG] EIP72803 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Incorrect Max Payload setting +// [RootCause] The issue was that recorded MPL value was updated before +// PcieProgramPayloadUp() function was invoked. +// In that function we check condition again since it was needed to +// maintain loop exit. +// But control newer enter the loop since conditions were not met at that +// point for reason stated above. +// +// [Solution] Move code that updates recorded MPL with a new value +// after call to PcieProgramPayloadUp(). +// [Files] PciBus.c +// +// 126 10/17/11 2:39p Yakovlevs +// [TAG] EIP71694 +// [Category] Bug Fix +// [Symptom] Option ROM is corrupted when copied from device on Rosecity +// Core 4.6.5.1. +// [RootCause] MemCopy routine was updated to use 64 bit access but PCI +// BAR +// Copy cannot handle this +// +// [Solution] Introduced MemCpy32 routine to handle fast copy 4 byte at +// a time +// [Files] PciBus.c; MemCpy32.asm; AmiLib.h +// +// 124 8/03/11 2:19p Artems +// Added changes discarded by previous check-in +// +// 123 8/03/11 1:14p Artems +// EIP 64107: Added changes for module to be compliant with UEFI +// specification v 2.3.1 +// 122 8/02/11 3:51p Yakovlevs +// [TAG] EIP66216 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Hotplug resource padding not working for ROOT bridges other +// than 0 +// [RootCause] Hot plug slots was incorrectly associated alvays withthe +// RootBridge #0 +// [Solution] Changed algorithm to beter distinguish between Root +// Bridges. +// Added debug messagers to monitor HPC_LOCATION_DATA. +// [Files] PciBus.c; PciHostBridge.c. +// +// 121 7/20/11 11:59a Yakovlevs +// Added IO 3C0-3DF reservation when VGA attributes set. +// +// 120 7/06/11 11:52a Yakovlevs +// Fixed build issue when PCI_EXPRESS_GEN2_SUPPORT token set to OFF. +// +// 119 6/28/11 5:33p Yakovlevs +// [TAG] EIP63430; 61101 +// [Category] Improvement +// [Description] 1. Replace use of PciIo->MemRead with MemCpy() for +// Option ROMs. +// 2.The secondary bus reset in the link retraining code causes downstream +// PLX bridges to disappear. +// [Files] PciBus.c +// +// 118 6/11/11 1:24p Yakovlevs +// [TAG] EIP 61311 +// [Category] Improvement +// [Description] PCI Express controllers may not be correctly +// initialized, because of missing delays, while resetting the link. +// +// [Files] Added delay code and tokens PCI_T_RST and PCI_T_RST_RECOVERY +// to fine tune delay. +// +// 117 6/11/11 1:05p Yakovlevs +// [TAG] EIP 61310 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Unable to enter OpROM on Adaptec 1430 card. OpROM executes, +// attached drives will boot but pressing Ctrl A to enter utility hangs +// system +// [RootCause] Card option ROM has 2 images The second one was a BOOT +// AGENT which does not have MATCHING DID in PCIR Header. +// [Solution] Considered DID==0 as a valid option meaning all devices. +// +// +// [Files] PciBus.c +// +// 116 5/12/11 11:30a Yakovlevs +// Fixed bug in PcieRetrainLink function it was not doing other attempts +// to retrain link because of missing else statement. +// +// 115 5/05/11 12:27p Yakovlevs +// Added LinkSpeed trace when link reset or retrain called. +// +// 114 5/04/11 6:18p Yakovlevs +// [TAG] EIP53475; 54911 +// [Category] New Feature +// [Description] PCI Express support issue fixed. +// Reconnect -r issue fixed. +// [Files] PCIBus.c +// +// 113 4/25/11 4:26p Yakovlevs +// Revert back changes in DeviceAttributes() function it was done by +// mistake. +// +// 112 4/21/11 6:04p Yakovlevs +// [TAG] EIP54911 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Calling Stop function was causing ASSERT +// [RootCause] Incorrect setting of the attributes and handling Stop +// function for Device of Type tRootBridge. +// [Solution] Change functions DeviceAttribute StopPciDevice. +// [Files] PciBus.c +// +// 111 4/20/11 11:54a Yakovlevs +// +// 110 4/19/11 5:39p Yakovlevs +// [TAG] EIP58702 +// [Category] New Feature +// [Description] Aptio PI 1.2; UEFI 2.3.1 Support +// Changes in Bus Drivers protocols (PCI bus driver) +// +// [Files] PciBus.c +// +// 109 4/19/11 11:02a Yakovlevs +// [TAG] EIP 57664 +// [Category] New Feature +// [Description] Aptio PI 1.2; UEFI 2.3.1 Support Extended PCI bus +// driver functionality +// Genericaly supported PCI_DEV_REVERSE_SCAN_ORDER. +// [Files] DevicePath.h; LoadFile2.h; PciBus.h; PciBus.c. +// +// 108 4/05/11 11:36a Yakovlevs +// [TAG] EIP 38174 EIP 53475; +// [Category] New Feature +// [Description] 38174 Generic support to handle PCI OUT OF RESOURDCES +// added. +// 53475 PCI Express 3.0 support added. +// +// [Files] PciBus.c; PciHostBridge.c; +// +// 107 2/02/11 3:42p Yakovlevs +// +// 106 1/28/11 4:26p Yakovlevs +// [TAG] EIP48290 +// [Category] New Feature +// [Description] Added PCI_AMI_COMBINE_MEM_PMEM32 token that tells to +// map 32 bit sized PF MMIO BARs trough NON PF MMIO Bridge registers. +// +// [Files] PciBus.c; PciBus.sdl; +// +// 105 1/28/11 2:55p Yakovlevs +// [TAG] EIP43879 +// [Category] New Feature +// [Description] Added PciPortOemGetOptRom() OEM Hook to override +// content of the PCI Device Option ROM. +// [Files] PciBus.c; PciPort.c; PciPort.h; PciBus.mak; PciBus.sdl +// +// 104 1/20/11 3:07p Yakovlevs +// [TAG] EIP45278 +// [Category] Improvement +// [Description] Added PCI_MMIO_RES_TOP_ALLIGN token to control Resource +// allocation algorithm selection. +// [Files] PciBus.c; PciHostBridge.c; PciBus.sdl. +// +// 103 1/14/11 10:50a Yakovlevs +// [TAG] EIPEIP49743 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Incorrect initialization complicated PCI infrastructure +// [RootCause] wrong condition to breake {do while loop}. +// [Solution] Change conditions +// [Files] PciBus.c +// +// 102 1/13/11 2:59p Yakovlevs +// [TAG] EIP49743 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] In the PcieCalcLatency(), the do-while loop condition have +// issue in this. +// [RootCause] It may be a condition when while loop in function +// PcieCalcLatency(), will never break. +// [Solution] Cahnge conditiondn iinstead of logical OR use AND. +// [Files] PciBus.c +// +// 101 1/13/11 1:31p Yakovlevs +// [TAG] EIP45278 +// [Category] Improvement +// [Description] Changed default resource allocation algorithm to work +// more efficiently. +// [Files] PciBus.c; PciHostBridge.c. +// +// 100 1/13/11 1:21p Yakovlevs +// [TAG] EIP49743 +// [Category] Improvement +// [Description] Workaround for devices which having Link Retrain bit +// "sticky" +// [Files] PciBus.c +// +// 99 1/13/11 1:14p Yakovlevs +// [TAG] EIP50097 +// [Category] Improvement +// [Description] Fixed issue when with PCI_FIXED_BUS_ASSIGNMENT==1 +// system was ASSERTING. +// Reason was that with complicated PCI structure next bridge XLAT entry +// that used to determine Subordinate bus #, selected incorrectly. +// +// [Files] PciBus.c +// +// 98 12/09/10 2:53p Yakovlevs +// Fixed bug in PcieCalcLatency() function. It was not calculating L1 +// latency correctly. +// +// 97 12/08/10 3:17p Yakovlevs +// Removed Setup Option "Selectable DeEmphasis" since it is HwInit Bit. +// +// 96 11/18/10 3:50p Yakovlevs +// 1.Changed Install Option ROM debug messages to make it more precise. +// 2. Added call to DoubleCheckOpRom() to verify ROM size before +// processing UEFI OpROM. +// +// 95 11/12/10 6:37p Yakovlevs +// PcieDoubleCheckCard() routine added to support cards that slowly +// respond on CFG transactions. +// +// 94 11/08/10 6:16p Felixp +// +// 93 11/08/10 6:13p Felixp +// The Core source files are updated to remove upper ASCII characters +// (above 128) +// from the comment blocks. The characters caused build errors +// with Japanese version of Microsoft compiler. +// +// 92 11/05/10 5:06p Yakovlevs +// Changed if Default (AUTO) MaxReadRequest selected don't change value +// sitting there. +// Removed assert in PcieConvertLatency function. +// +// 90 10/07/10 12:13p Felixp +// PEI_TRACE on TPL_HIGH is removed. +// Headers updated. +// +// 89 10/05/10 4:46p Yakovlevs +// Changed Default (AUTO) MaxReadRequest Size value from == MPL to spec. +// default == 512. +// +// 88 10/01/10 6:05p Yakovlevs +// Fixed issue with low level PciCfgXX() access functions. When +// ExtendedRgister used. +// +// 87 9/01/10 11:52a Yakovlevs +// Improved Override ASPM Porting hook, now it called for UPSTREAM as well +// as DOWNSTREAM port. +// +// 86 8/16/10 1:05p Yakovlevs +// New Incompatibility Type Sypport: icBad64BitBar - Device has a bar that +// is 64bit capable, but the card does not function properly when it is +// allocated. +// +// 85 7/08/10 6:00p Yakovlevs +// Removed EFI_EADLOOP() left in InstallEfiRom() function +// +// 84 7/08/10 3:12p Yakovlevs +// Fixed UEFI Option ROM Size miscalculation. +// +// 83 6/30/10 11:11a Yakovlevs +// Fixed WDK Build Issue EIP 40554 +// +// 82 6/08/10 3:31p Yakovlevs +// Minor fix for EIP 38289 Klocwork Issues II. +// +// 81 6/07/10 3:36p Yakovlevs +// Improved logic to select matching PCI Bus Xlat table entry. +// +// 80 5/25/10 3:16p Yakovlevs +// Fixed condition to disable device using 64 bit resource threshold +// +// 79 5/19/10 12:43p Yakovlevs +// +// 78 5/07/10 12:24p Yakovlevs +// Bug fix in PcieProgramPayloadUp() function. canged order when recording +// calculated PayLoad. +// It use to recursive call was made after reduced value of MPL was +// recorded. It was preventing function to program MPL correctly. +// +// 77 4/28/10 11:33a Yakovlevs +// Fixed bug in DoubleCheckOpRom() when OpROM is a Single Image ROM. +// +// 76 4/20/10 5:46p Yakovlevs +// Fixed build error with SRIOV token ON; Fixed InitDevCahain() function +// Logic. +// +// 75 4/15/10 4:28p Yakovlevs +// Fixed issue with PCIe Switches and MPL programming UP +// +// 74 4/14/10 4:43p Yakovlevs +// Fixed Possible issue with incorrect MPL Programming. +// +// 73 3/03/10 12:46p Yakovlevs +// Fixed bug in IsFunc0() function. +// +// 72 3/01/10 6:18p Yakovlevs +// PCI Express V2.1 support added. +// +// 68 12/24/09 10:45a Yakovlevs +// Fixed issue when removing unused entries from IRQ routing tables, PIC +// and APIC. +// +// 67 9/24/09 1:51p Yakovlevs +// Fixed EIP 26787. If P2P Bridge has ExpROM BAR, value that has to go +// there was programmed as Secondary Interface Forward Range. +// +// 66 9/22/09 6:09p Yakovlevs +// 6. Fixed conditions in ApplyAcpiResources() where function assumes +// validity of Resource Range. In case of Fixed Resource Allocation +// Resource window allocated by custom unction might be bigger than actual +// hardware resource request +// +// 65 9/08/09 12:57p Yakovlevs +// Fixed ~0LU statement to 0ULL. This is correct statement for 64 bit +// Value +// Made QueryPciDevice() routine set Interrupt Line register(0x3C) to 0xFF +// +// 64 8/28/09 10:27a Felixp +// Component Name protocol implementation is upadted to support both +// ComponentName and ComponentName2 protocols +// (based on value of the EFI_SPECIFICATION_VERSION SDL token). +// +// 63 8/21/09 3:53p Yakovlevs +// Fixed: EIP 19106 If 1 Bus set to be paded in Setup, PCI Bus driver +// still creates 1 BUS for this bridge instead of 2. +// +// +// 62 7/07/09 12:39p Yakovlevs +// Moved DisableBridgeDecoding() call before Disable device decoding since +// it could decode 0-4K of IO and 0-1M of Mem. +// +// 61 5/22/09 2:16p Yakovlevs +// +// 60 5/05/09 5:46p Yakovlevs +// Fixed build issue in IA32 mode with SRIOV_SUPPORT == ON. +// +// 59 4/24/09 11:49a Yakovlevs +// +// 58 4/23/09 8:28p Yakovlevs +// Fixed some minor issues related to PCI IRQ entries usage and updating. +// +// 57 4/23/09 2:02p Yakovlevs +// Fixed potentiial Memory Coruption issue when assigning Ext->XlatEntry +// ->BusRun +// for bridges who doesnot have it's XlatTbl Entry. +// +// 56 4/19/09 2:14p Yakovlevs +// Fixed issue with Multiple Root Bridges, when PCI Bus Driver was +// incorrectly calculating ranges buses to scan. +// +// 55 4/17/09 6:38p Yakovlevs +// Fixed issue EIP 21366 with OptimizeBrgResource() function see EIP for +// more details. +// +// 54 4/16/09 1:49p Yakovlevs +// Fixed issue where for Second Root Bridge Bus numbers were assifned +// started fron LAST ROOT_0_BUS + 1 +// +// 53 4/01/09 9:57a Yakovlevs +// Minor fixes +// +// 52 3/30/09 5:23p Yakovlevs +// Fixed issue in AssignBridgeResources function when there are no bars to +// program function was returning ERROR Status. +// +// 51 3/27/09 7:02p Yakovlevs +// Fixed Uninitialized PCI DB issue. +// +// 50 3/27/09 11:47a Yakovlevs +// Fixed some issues with re starting driver. +// +// 49 3/25/09 11:02a Yakovlevs +// ADDED Generic implementation of #PERR, #SERR; and VGA Palette Snoop. +// +// 48 3/23/09 2:27p Yakovlevs +// ADDED support for VGA_16_BIT_DECODE. VGA aliasing support pending. +// +// 47 2/04/09 4:03p Yakovlevs +// Fixed PciPortSkipThisDevice() function was not preserving PCI.CMD +// register. +// +// 46 2/04/09 4:01p Yakovlevs +// +// 45 2/03/09 3:27p Yakovlevs +// Added fixes for EIP 19144. Break the PCI Express Extended Capability +// header access routine if read of offset 0x100 returns 0xFFFF +// +// 44 1/30/09 1:03p Yakovlevs +// Minor bug fixes and improuvements EIP 8874; EIP 17947 +// +// 43 11/26/08 3:55p Yakovlevs +// +// 42 11/26/08 3:54p Yakovlevs +// Start function NOW returns EFI_ALREADY_STARTED, when all PCI devices +// installed PciIo interface. +// +// 41 11/26/08 11:37a Yakovlevs +// Fixed connect -r issue when shell was hunging in infinite loop. +// +// 40 11/14/08 3:34p Yakovlevs +// Removed EFI_DEADLOOP() used for debug +// +// 39 11/14/08 1:21p Yakovlevs +// Introduced AMI Board Info Protocol which has *.inc OUTPUTS generated +// by AMISDL tool. To keep it in one place and Make PciBus Driver use it. +// +// 38 10/31/08 6:10p Yakovlevs +// +// 36 10/15/08 10:45a Yakovlevs +// Fixed EIP 16990 CsmVideo can't work +// +// 35 10/14/08 1:15p Yakovlevs +// Rearrange Function order to support ROM BARs as PCI incompatible BARs +// +// 33 10/10/08 5:40p Yakovlevs +// Added Pci Compliance tests workarounds +// +// 32 10/01/08 7:12p Yakovlevs +// Updated AMI FUNC HEADER information +// +// 31 9/24/08 6:41p Yakovlevs +// New features and bug fixes: +// New features. +// 1. Make PCI Bus Driver use VeB generated structures. +// 2. Added SRIOV support +// 3. Added Fixed Bus Allocation (Buses for the bridges will be allocated +// same way as in Build time) +// 4. Scan full bus ranges. +// 5. Added support for UEFI 2.1 PCI requirements. +// 6. Added Token to disable PCI Bus Driver Debug Messages. +// 7. Removed dependency from SETUP_DATA fields layout. +// 8. Progress/Error codes. +// 9. Support for S3 Video Repost. +// +// Bug fixes: +// 1. Attribute function. +// 2. If device decodes only PFMMIO Bridge MMIO Base and Limit register +// was initialized with 0 making it decode space from 0x10000. +// 3. OptimizeBridgeResources() function was not working correctly in some +// rare cases. +// +// 29 5/13/08 11:59a Felixp +// ComponentName protocol converted to ComponentName2 +// +// 28 4/29/08 6:55p Yakovlevs +// Generic S3 Video Repost support added. +// Added mechanism to suppress PCI BUs driver debug messages(Latest +// PciBus.sdl and PciBus.h required). +// +// 27 4/24/08 12:19p Yakovlevs +// Added generic support for S3 VIDEO Repost feature. +// +// 26 4/18/08 3:53p Yakovlevs +// Added missing function headers +// +// 25 4/17/08 6:23p Yakovlevs +// fixed potencial issue in OptimizeBridgeResources. +// +// 24 3/12/08 12:45p Felixp +// Progress/Error codes reporting added +// +// 23 2/21/08 4:37p Felixp +// 1. Bug fix in StartPciChildDevice. Handling of remaining device path +// has changed. +// 2. Handling of setup data structure in PciBusStart updated to work fine +// without PCI sources +// +// 22 1/31/08 8:31p Yakovlevs +// Fixed issue with hotplug resource padding. +// +// 21 1/31/08 2:51p Yakovlevs +// 1. Fixed resource allocation issue on bridges only branches. +// 2. Cahnged Default Padding routine for Card bus bridges. +// +// 20 12/10/07 4:15p Yakovlevs +// 1.Fixed bug in OprimizeBrgResources() function, (it might hung in +// infinite loop). +// 2.Corrected ApplyCrdPadding () implementation to take care of +// EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM allocation attribute. +// +// 19 11/08/07 4:51p Felixp +// Code updated to compile and work without CSM. +// +// 18 10/23/07 5:28p Felixp +// VC8 warnings fixed +// +// 17 10/18/07 11:22a Felixp +// ASPN SDL tokens replaced with external constants defined in PciPort.c +// +// 16 10/15/07 4:11p Yakovlevs +// Fixed bug in OptimizeResources function. +// +// 15 10/08/07 5:26p Yakovlevs +// Fix to handle not compliant PCI Option Roms. +// +// 4 9/21/07 6:38p Yakovlevs +// Sinchronize with recent PCI Bus updates +// +// 14 9/21/07 6:24p Yakovlevs +// Fixed ASPM related bugs. +// +// 13 9/18/07 5:23p Yakovlevs +// Inplemented Intel's recomendation of calculating EP Acceptable ASPM +// Latency. +// +// 12 8/31/07 11:18a Yakovlevs +// Improuvements in PCI Resource Allocation Algorithm. +// +// 10 7/25/07 12:54p Felixp +// AMI Debugger-related code is updated to enable Debugger in non-debug +// mode. +// The code is enabled when USB_DEBUG_TRANSPORT or EFI_DEBUG is on. +// +// 9 7/17/07 6:29p Felixp +// Minor bug fix in GetOptRom: GetEmbeddedRom was called with UINT32 image +// size pointer instead of UINTN +// +// 8 7/04/07 5:51a Yakovlevs +// Version of this file will work with 4.5.3_CSM.6.37_51 label of CSM, +// which requires USB module upgrade to Label 4.05.03_USB_08.07.11. +// 1. Fixed Disabling VGA attributes for Devices behind multiple bridges. +// 2. Added some debug messages for Installing Devices PciIo interface. +// 3. Changed GetOptRom() function to search for Embeded ROMs(onboard) as +// well and populate PciIo.OptionRom*. +// +// 7 5/23/07 5:32p Yakovlevs +// Previouse fix had some side effects on protocol installation side - +// this one fixes these. +// Also some debug messages at protocol installation phase was added. +// +// 6 5/18/07 6:30p Yakovlevs +// Fixed Issue with incorrect Status returning from StartPciChildDevice(). +// +// 5 5/14/07 7:49p Yakovlevs +// Somehow changes to impruve PCI Config Acces were lost. Resored them. +// +// 4 5/04/07 3:50p Yakovlevs +// +// 3 5/04/07 11:51a Yakovlevs +// +// 2 5/02/07 4:41p Yakovlevs +// +// 1 3/12/07 12:02p Yakovlevs +// +// 48 12/28/06 7:16p Yakovlevs +// In ActivateOptRom function removed upate of OptROM size where +// PciIo->OptionRom points +// It is not needed. +// +// 47 12/22/06 9:42p Yakovlevs +// Code Cleanup and CHM headers added +// +// 46 12/21/06 5:13p Yakovlevs +// Code cleanup. Added CHM headers. +// +// 44 12/19/06 11:54a Yakovlevs +// Fixed Padding for the bridge if CombineMemPmem Allocation Attribute is +// set +// +// 43 12/05/06 3:27p Yakovlevs +// Fixed SCT 2.0 PciIo Disable Attributes ISSUE. +// +// 42 12/05/06 11:54a Felixp +// +// 41 11/22/06 10:27a Olegi +// +// 40 11/22/06 10:26a Olegi +// InstallPciDevice is modified so that the device with DebugPort +// enumeration will not be skipped. +// +// 39 10/20/06 5:50p Yakovlevs +// +// 38 10/13/06 4:42p Yakovlevs +// +// 37 10/13/06 4:10p Yakovlevs +// Function Headers Added!!!!! IDE Attributes support added, Hotplug +// support fix (NULL pointer). +// +// 36 9/11/06 11:51a Yakovlevs +// Fixed CacheLineSize rergister programming issue +// +// 35 8/24/06 10:11a Felixp +// x64 support: warning/error fixes +// +// 34 8/09/06 5:08p Yakovlevs +// VC initialization and boot sript support for PCI Express. +// This fixes NVIDIA 7800 GT issue +// +// 31 6/04/06 9:06p Yakovlevs +// Fixed issue when PciBus driver was writting in IRQ Line Reg some junk. +// +// 30 6/04/06 8:22p Yakovlevs +// Fixed PCI_EXPRESS_SUPPORT and HOTPLUG_SUPPORT featueses. +// Added some debug messages during PCI bus enumeration process. +// +// 29 6/01/06 12:21p Yakovlevs +// Changes to accomodate HbCspAdjustMemoryMmioOverlap function in PciRB. +// +// 28 5/19/06 10:45p Felixp +// Device Path code updated to use NEXT_NODE/NODE_LENGTH/SET_NODE_LENGTH +// macros to remove direct access to the Length field +// +// 27 4/25/06 4:49p Stacyh +// +// 26 4/03/06 3:52p Felixp +// Major changes in PCI and Super I/O: +// PCI - Root Bridge Resource Allocation Sepcification support +// Super I/O - multiple Super I/O support; SIO Setup page added; +// +// 25 3/20/06 9:26a Felixp +// Bug fix in attribute clearing logic. +// +// 24 3/13/06 10:07a Felixp +// +// 21 11/08/05 4:08a Felixp +// AMI Debugger ifdefs changed from AMI_DEBUGGER_SUPPORT to EFI_DEBUG +// +// 20 10/27/05 5:39p Felixp +// +// 19 10/12/05 7:19p Felixp +// AMI Debugger support added +// +// 18 7/18/05 3:25p Felixp +// +// 17 6/26/05 6:50p Olegi +// Incompatible PCI device list updated. +// +// 16 6/26/05 6:43p Yakovlevs +// Card Bus Support Added +// Some other bug fixes +// Incompatibility list extended with icBarFixedSize. +// +// 15 5/25/05 6:26p Yakovlevs +// +// 14 5/11/05 3:09p Yakovlevs +// Fixed: CacheLine Size register Latency timer Reg, gets programmed, +// IO resource lesser than 16 bytes padded to 16 bytes. +// +// 13 4/21/05 2:03p Sivagarn +// - Option ROM signature is validated before copying into the memory +// - Option ROM size is obtained from the header instead of using size +// calculated from PCI base register +// +// 12 4/06/05 10:33a Felixp +// Bug fix in StartPciDevices +// +// 11 3/29/05 5:16p Olegi +// Problem with ATI Video fixed. +// +// 10 3/23/05 6:17p Yakovlevs +// +// 9 3/23/05 5:48p Yakovlevs +// Changes to avoid clearing HostBridge Command register. +// +// 8 3/15/05 5:23p Yakovlevs +// Option ROM issue for on bord device with implemented ROM BAR and ROM +// image at ROM BIOS fixed. +// Now if ActivateOptionRom routine fails to validate option rom it frees +// OptROM buffer. +// +// 7 3/04/05 9:26a Mandal +// +// 6 2/14/05 7:36p Yakovlevs +// Handled situation when Start Function calls multiple times for every +// next DP node. +// Fixed Option Rom Size issue +// +// 5 2/14/05 6:12p Yakovlevs +// +// 4 2/13/05 4:54p Yakovlevs +// Fixed issue with 64 bit width BARs; PCI incompatible device support +// added. +// +// 3 2/11/05 7:48p Yakovlevs +// Incompatible Pci Device Support added. +// +// 2 2/01/05 1:16a Felixp +// +// 1 1/28/05 12:45p Felixp +// +// 8 1/21/05 7:00p Yakovlevs +// +// 7 1/21/05 5:19p Yakovlevs +// Fixed some stuff from TODO list: +// 1.Made ajustments to exchange information with RB Driver. +// 2.Support of 64 bit resources on P2P Brg (EnableBrgPfmmDecoding) +// routine, +// +// 4 1/13/05 8:26p Yakovlevs +// +// 3 1/11/05 5:25p Yakovlevs +// +// 1 12/22/04 6:19p Admin +// +// 1 12/22/04 6:18p Admin +// +// 55 12/21/04 4:20p Markw +// Renamed hardware device path definition for consistency. +// +// 54 12/06/04 5:14p Yakovlevs +// +// 53 12/06/04 4:51p Robert +// PciIoCheckConfig - the comparison for the buffer length should not +// exceed 256 bytes. Therefore it should be > not >= +// +// 52 10/22/04 7:26p Yakovlevs +// +// 51 10/20/04 3:02p Yakovlevs +// +// 50 10/20/04 11:43a Yakovlevs +// InstallMultipleProtocol and Close Protocol opened by Child Controller +// added +// +// 49 10/20/04 9:28a Yakovlevs +// +// 48 10/04/04 1:44p Yakovlevs +// Make use of AcpuRes.h resource Tamplete Definitions +// +// 47 9/24/04 9:31p Yakovlevs +// Uncachable Attributes set for PCI Bus MMIO regions +// +// 46 9/22/04 6:51p Yakovlevs +// +// 45 9/16/04 10:24a Yakovlevs +// +// 44 9/15/04 6:01p Yakovlevs +// +// 43 9/15/04 9:42a Yakovlevs +// +// 42 9/09/04 3:06p Yakovlevs +// Bug fixes: +// 1. Handling of RemainingDevicePath in Start routine +// 2. Option ROM handling +// Path: +// Temporary patch to make Cirrus Logic and some other Add-On cards work +// +// 41 9/03/04 11:58a Yakovlevs +// +// 40 8/27/04 6:36p Yakovlevs +// +// 39 8/26/04 7:47p Yakovlevs +// SCT PCI Bus Support -> OK! +// +// 38 8/24/04 1:01p Yakovlevs +// +// 37 8/15/04 7:32p Yakovlevs +// +// 36 8/13/04 9:21a Yakovlevs +// +// 35 7/13/04 10:42a Felixp +// +// 34 5/27/04 10:30a Yakovlevs +// +// 33 5/06/04 8:20p Felixp +// +// 32 5/06/04 6:31p Felixp +// +// 31 5/06/04 10:25a Yakovlevs +// +// 30 5/05/04 8:14p Yakovlevs +// +// 28 5/03/04 8:13p Felixp +// +// 27 5/03/04 6:15p Yakovlevs +// +// 26 5/03/04 6:04p Yakovlevs +// +// 25 5/03/04 12:24p Yakovlevs +// +// 24 5/03/04 11:52a Yakovlevs +// Changes to avoid hardcoded Array size and accomodate all resource types +// +// 23 4/23/04 5:43p Felixp +// +// 22 4/23/04 3:20p Felixp +// +// 21 4/23/04 2:36p Felixp +// +// 20 4/23/04 12:08p Felixp +// +// 19 4/22/04 12:27p Yakovlevs +// +// 18 4/21/04 8:33p Yakovlevs +// +// 17 4/21/04 12:49p Yakovlevs +// +// 16 4/20/04 9:19p Yakovlevs +// +// 15 4/20/04 11:51a Yakovlevs +// +// 14 4/19/04 11:56a Yakovlevs +// +// 13 4/18/04 4:05p Felixp +// +// 12 4/16/04 7:12p Felixp +// +// 11 4/12/04 4:59p Yakovlevs +// +// 10 4/12/04 4:12p Yakovlevs +// +// 9 4/09/04 6:40p Yakovlevs +// +// 8 4/02/04 6:28p Yakovlevs +// +// 7 4/02/04 6:23p Yakovlevs +// +// 6 4/02/04 6:05p Yakovlevs +// +// 5 3/28/04 2:11p Felixp +// 1. PE Loader and some other commonly used code moved to the Library +// 2. Warnings fixed (from now on warning will be treated as error) +// +// 4 3/26/04 1:50p Yakovlevs +// +// 3 3/26/04 1:19p Felixp +// +// 2 3/22/04 10:29a Yakovlevs +// +// 1 3/15/04 11:20a Felixp +// +// 1 3/12/04 6:47p Yakovlevs +// +// 3 2/04/04 6:50p Yakovlevs +// +// 2 2/04/04 4:22p Yakovlevs +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: <PciBus.c> +// +// Description: EFI PCI Bus Generic Driver. +// +// Tabsize: 4 +// +//<AMI_FHDR_END> +//********************************************************************** + +//--------------------------------------------------------------------------- +// Include Files +//--------------------------------------------------------------------------- +#include <Efi.h> +#include <Token.h> +#include <Protocol\PciRootBridgeIo.h> +#include <Protocol\DevicePath.h> +#include <Protocol\DriverBinding.h> +#include <Protocol\BusSpecificDriverOverride.h> +#include <Protocol\Decompress.h> +#include <Protocol\ComponentName2.h> +#include <Protocol\PciHostBridgeResourceAllocation.h> +#include <Protocol\PciHotplugInit.h> +#include <Protocol\PciPlatform.h> +#include <Protocol\IncompatiblePciDeviceSupport.h> +#include <Protocol\BootScriptSave.h> +#include <Dxe.h> +#include <AmiDxeLib.h> +#include <AMIHobs.h> +#include <PciBus.h> +#include <PciBusEx.h> +#include <AcpiRes.h> +#include <AmiLoadCsmPolicy.h> + +#if PCI_OUT_OF_RESOURCE_SETUP_SUPPORT +#include <Setup.h> +#endif +#include "PciPort.h" + +#if CSM_SUPPORT +#include <Protocol\LegacyBiosExt.h> +#endif + +#if EFI_DEBUG || USB_DEBUG_TRANSPORT +#include <AmiDebugPort.h> +#endif + +#include "PciSetup.h" + +//================================================================================== +//Function Prototypes for Driver Binding Protocol Interface +//================================================================================== +EFI_STATUS PciBusSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); + +EFI_STATUS PciBusStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ); + +EFI_STATUS PciBusStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer); + +EFI_STATUS EnumerateAll(EFI_HANDLE Controller); + +EFI_STATUS StartPciDevices(IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); + +//------------------------------------------------------- +//Forward declarations for Extended PCI Bus Protocol +EFI_STATUS PciExtIsPciExpresss( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCIE_DATA **PciExpData OPTIONAL +); + +EFI_STATUS PciExtIsPciX( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCIX_DATA **PciXData OPTIONAL +); + +EFI_STATUS PciExtIsPciBrg( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_BRG_EXT **BrgData OPTIONAL +); + + +EFI_STATUS PciExtIsCrdBrg( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_BRG_EXT **BrgData OPTIONAL +); + + +EFI_STATUS PciExtIsDevice( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL +); + + +EFI_STATUS PciExtClassCodes( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_DEV_CLASS *CassCodes +); + + +EFI_STATUS PciExtPicIrqRout ( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_IRQ_PIC_ROUTE **PicIrqTblEntry, + OUT EFI_PCI_CONFIGURATION_ADDRESS **ParentDevices, + OUT UINTN *EntryCount +); + +EFI_STATUS PciExtApicIrqRout ( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_IRQ_APIC_ROUTE **ApicIrqTblEntry, + OUT EFI_PCI_CONFIGURATION_ADDRESS **ParentDevices, + OUT UINTN *EntryCount +); + +EFI_STATUS ReadEfiRom(PCI_DEV_INFO *Dev, PCI_ROM_IMAGE_DATA *RomData, VOID **ImgBase, UINT32 *ImgSize); + +//================================================================================== +//Some Protocole GUIDs needed here +//================================================================================== +static EFI_GUID gDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; +static EFI_GUID gPciRootBridgeIoProtocolGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID; +static EFI_GUID gDevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID; +static EFI_GUID gPciIoProtocolGuid = EFI_PCI_IO_PROTOCOL_GUID; +static EFI_GUID gBusSpecificDriverOverrideProtocolGuid = EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID; +static EFI_GUID gEfiDecompressProtocolGuid = EFI_DECOMPRESS_PROTOCOL_GUID; +static EFI_GUID gEfiPciHostBrgResAllocProtocolGuid = EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL_GUID; +static EFI_GUID gEfiPciHotPlugInitProtocolGuid = EFI_PCI_HOT_PLUG_INIT_PROTOCOL_GUID; +static EFI_GUID gEfiPciPlatformProtocolGuid = EFI_PCI_PLATFORM_PROTOCOL_GUID; +static EFI_GUID gEfiIncompatiblePciDeviceProtocolGuid = EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL_GUID; +static EFI_GUID gEfiBootScriptSaveGuid = EFI_BOOT_SCRIPT_SAVE_GUID; +static EFI_GUID gAmiExtPciBusProtocolGuid = AMI_PCI_BUS_EXT_PROTOCOL_GUID; +static EFI_GUID gAmiBoardInfoProtocolGuid = AMI_BOARD_INFO_PROTOCOL_GUID; + +#if CSM_SUPPORT +static EFI_GUID gEfiLegacyBiosExtProtocolGuid = EFI_LEGACY_BIOS_EXT_PROTOCOL_GUID; +#endif + + +#if PCI_EXPRESS_SUPPORT +static T_ITEM_LIST gPcieEpList = {0,0,NULL}; +#endif + + +//============================================================================= +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gBadPciDevList +// +// Description: Incompatible PCI Devices List known so far. +// +// Notes: +// See PCI_BAD_BAR for field names and usage details. +// If BarType field == tBarMaxType then BarOffset field should be used. +// For "BarType" field only tBarIo, tBarMem and tBarMaxType allowed! +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +PCI_BAD_BAR gBadPciDevList[]={ +//----------------------------------------------------------------------------------------------------------------------- +//enum UINT16 UINT16 UINT16 UINT16 PCI_BAR_TYPE UINTN UINT64 UINT64 +//IncompType; VendorId; DeviceId; DevIdMask; Reserved; BarType; BarOffset; BarBase; BarLength; +//----------------------------------------------------------------------------------------------------------------------- +//Device Adaptec 9004 +{ icBarBad, 0x9004, 0xFFFF, 0x0000, 0x0000, tBarIo, 0x0000, 0, 0 }, +//Device Adaptec 9005 +{ icBarBad, 0x9005, 0xFFFF, 0x0000, 0x0000, tBarIo, 0x0000, 0, 0 }, +//Device QLogic 1007 +{ icBarBad, 0x1007, 0xFFFF, 0x0000, 0x0000, tBarIo, 0x0000, 0, 0 }, +//Device Agilent 103C +{ icBarBad, 0x103C, 0xFFFF, 0x0000, 0x0000, tBarIo, 0x0000, 0, 0 }, +//Device Agilent 15BC +{ icBarBad, 0x15BC, 0xFFFF, 0x0000, 0x0000, tBarIo, 0x0000, 0, 0 }, +//Device AMI Mega RAID 493 +{icBarFixedSize,0x1077, 0x1216, 0xFFFF, 0x0000, tBarMaxType,0x0014, 0, 0x400000 }, +//ICH8 smbus controller +{icNotBar, 0x8086, 0x283E, 0xFFFF, 0x0000, tBarMaxType,0x0014, 0, 0 }, +//RTL8111E +{ icNotBar, 0x10EC, 0x8168, 0xFFFF, 0x0000, tBarMaxType,0x0030, 0, 0 }, +//NVIDIA 7200 GS +{icBad64BitBar, 0x10de, 0x01d3, 0xFFFF, 0x0000, tBarMaxType,0x0014, 0, 0 } +}; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gBadPciDevCount +// +// Description: Number or records in gBadPciDevList table. +// Notes: UINTN +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +UINTN gBadPciDevCount=sizeof(gBadPciDevList)/sizeof(PCI_BAD_BAR); + + +//================================================================================== +// PCI Bus Driver Global Variables +//================================================================================== + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gAllocationAttributes +// +// Description: Root Bridge Allocation Attributes +// Notes: UINT64 +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +UINT64 gAllocationAttributes=0; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gPciOutOfRes +// +// Description: Indicates Out Of Resources Condition. +// Notes: BOOLEAN +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +BOOLEAN gPciOutOfRes=FALSE; + +BOOLEAN gPciOutOfResHit=FALSE; + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gLowResType +// +// Description: Indicates what type of resource has Out Of Resources Condition. +// Notes: MRES_TYPE +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +MRES_TYPE gLowResType=rtMaxRes; + +AMI_OUT_OF_RES_VAR gPciOutOfResData={0}; + + +//---------------------------------------------------------------------------------- +//EfiDBE Key field definition used to sort resources by size +//Function prototypes used for Compare keys we will use a custom way. +//We will be using combination UINT64 Length (LS64) + UINT64 Granularity (MS64). +INTN Cmp128IntRR(IN VOID *pContext, VOID *pRecord1, VOID *pRecord2); +INTN Cmp128IntKR(IN DBE_OFFSET_KEY_CONTEXT *pContext, VOID *pKey, VOID *pRecord); +//Initialize BAR DataBase KeyField Structure +DBE_OFFSET_KEY_CONTEXT BarKeyInfo = { EFI_FIELD_OFFSET(PCI_BAR,Length), + EFI_FIELD_SIZE(PCI_BAR,Length)+EFI_FIELD_SIZE(PCI_BAR,Gran)}; +DBE_KEY_FIELD gBarKey = {&Cmp128IntRR, &Cmp128IntKR, &BarKeyInfo}; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gPciBusDb +// +// Description: Bus order Data Base if fixed bus allocation selected we need +// to know how many buses does this bridge suppose to decode +// Notes: T_ITEM_LIST +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +T_ITEM_LIST gPciBusDb={0,0,NULL}; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: *gPciSetupData +// +// Description: Global Setup Variable to get the setup settings pointer. +// +// Notes: PCI_SETUP_DATA +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +PCI_SETUP_DATA *gPciSetupData=NULL; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: mMaxBusFound; mMaxBusScan; mMaxBusReport. +// +// Description: Global counter of buses found. +// +// Notes: UINT8 +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +UINT8 mMaxBusFound; +UINTN mMaxBusScan; +UINT8 mMaxBusReport=0; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gHostCnt +// +// Description: Initial Global Variable to store Host Bridge Count. +// +// Notes: UINTN +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +UINTN gHostCnt; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gPciHost +// +// Description: Initial Global Variable to store pointer on PCI Subsystem +// Host (This is very ROOT of the PCI Bus Driver Data). +// +// Notes: PCI_HOST_INFO +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +PCI_HOST_INFO *gPciHost=NULL; + +//---------------------------------------------------------------------------------- +//Bot script save protocol interface +EFI_BOOT_SCRIPT_SAVE_PROTOCOL *gBootScriptSave=NULL; + +//---------------------------------------------------------------------------------- +#if CSM_SUPPORT +EFI_LEGACY_BIOS_EXT_PROTOCOL *gLegacyBiosExt=NULL; +#endif + +//---------------------------------------------------------------------------------- +#if S3_VIDEO_REPOST_SUPPORT == 1 +EFI_EVENT gVgaS3Event=NULL; +#endif + +//---------------------------------------------------------------------------------- +//Initial Global Variable to store RootBridge info +UINT16 gCpuCaheLineSize=0x10; +UINT8 gPciCaheLineSize=0; + +//---------------------------------------------------------------------------------- +//To Avoid Enumerating AmiDebug Port Usb Device +#if EFI_DEBUG || USB_DEBUG_TRANSPORT +AMI_DEBUGPORT_INFORMATION_HOB *gDbgPortHob=NULL; +DEBUG_PORT_INFO gDbgPortInfo={0,0,0,0,0,0,0,0}; +#endif + +//================================================================================== +//Externals produced by VeB used by Pci Bus Driver +//================================================================================== +//Legacy IRQ routing table delivered from oempir.inc and PCIBoard.ASM +//IOAPIC IRQ routing table delivered from mppciirq.inc and PCIBoard.ASM +//PCI Buses Xlate Table +//Instead we have now AMI_BOARD_INFO_PROTOCOL +AMI_BOARD_INFO_PROTOCOL *gAmiBoardInfo=NULL; + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gPciBusDriverBinding +// +// Description: Extended PCI Bus Protocol instance for PciBus Driver +// +// Notes: AMI_PCI_EXT_PROTOCOL +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +AMI_PCI_EXT_PROTOCOL gAmiExtPciBusProtocol = { + PciExtIsPciExpresss, + PciExtIsPciX, + PciExtIsPciBrg, + PciExtIsCrdBrg, + PciExtIsDevice, + PciExtClassCodes, + PciExtPicIrqRout, + PciExtApicIrqRout, + NULL +}; + + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gPciBusDriverBinding +// +// Description: Driver binding protocol instance for PciBus Driver +// +// Notes: EFI_DRIVER_BINDING_PROTOCOL +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding = { + PciBusSupported, //Supported + PciBusStart, //PciBusDrvStart, + PciBusStop, //PciBusDrvStop, + ((PCI_BUS_MAJOR_VER<<16)|(PCI_BUS_MINOR_VER<<8)|(PCI_BUS_REVISION)), //Version + NULL, //Image Handle + NULL //DriverBindingHandle +}; + +#ifdef EFI_DEBUG +#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID //old Core +#ifndef LANGUAGE_CODE_ENGLISH +#define LANGUAGE_CODE_ENGLISH "eng" +#endif +static BOOLEAN LanguageCodesEqual( + CONST CHAR8* LangCode1, CONST CHAR8* LangCode2 +){ + return LangCode1[0]==LangCode2[0] + && LangCode1[1]==LangCode2[1] + && LangCode1[2]==LangCode2[2]; +} +static EFI_GUID gEfiComponentName2ProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +#endif +//--------------------------------------------------------------------------- +//Driver Name Interface of the PCI Bus Driver +//--------------------------------------------------------------------------- +static UINT16 *gDriverName=L"AMI PCI Bus Driver"; + + +//--------------------------------------------------------------------------- +// Function Definitions +//--------------------------------------------------------------------------- + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ComponentNameGetControllerName() +// +// Description: This function is the one of interface functions of the +// OPTIONAL, EFI_COMPONENT_NAME_PROTOCOL. Suppose to retun Controller +// Name String. Currently returning EFI_UNSUPPORTED. +// +// Input: +// EFI_COMPONENT_NAME_PROTOCOL +// *This Pointer to EFI_COMPONENT_NAME_PROTOCOL. +// EFI_HANDLE ControllerHandle EFI_HANDLE of the device which to return. +// EFI_HANDLE ChildHandle OPTIONAL, an EFI_HANDLE of child device. +// CHAR8 *Language Pointer to 3 char Language name. +// CHAR16 **ControllerName Pointer to the data buffer for Name Sring. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When feature not supported by the Driver. +// +// Reference: EFI_COMPONENT_NAME2_PROTOCOL +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +static EFI_STATUS ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName ) +{ + return EFI_UNSUPPORTED; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ComponentNameGetDriverName() +// +// Description: This function is the one of interface functions of the OPTIONAL +// EFI_COMPONENT_NAME_PROTOCOL. Retuning Driver Name String of the PCI BUS Driver. +// +// Input: +// EFI_COMPONENT_NAME_PROTOCOL +// *This Pointer to EFI_COMPONENT_NAME_PROTOCOL. +// CHAR8 *Language Pointer to 3 char Language name. +// CHAR16 **ControllerName Pointer to the data buffer for Name Sring. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When feature not supported by the Driver. +// +// Reference: EFI_COMPONENT_NAME_PROTOCOL +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +static EFI_STATUS ComponentNameGetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName) +{ + //Supports only English + if(!Language || !DriverName) return EFI_INVALID_PARAMETER; + + if (!LanguageCodesEqual( Language, LANGUAGE_CODE_ENGLISH)) + return EFI_UNSUPPORTED; + else + *DriverName=gDriverName; + + return EFI_SUCCESS; +} + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gComponentName +// +// Description: Declaration of the EFI_COMPONENT_NAME_PROTOCOL +// +// Fields: Name Type Description +// ------------------------------------------------------------------ +// ComponentNameGetDriverName, F_PTR DriverName function pointer. +// ComponentNameGetControllerName, F_PTR ControllerName function pointer. +// "eng" CHAR8 Language list Buffer. +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +static EFI_COMPONENT_NAME2_PROTOCOL gComponentName = { + ComponentNameGetDriverName, + ComponentNameGetControllerName, + LANGUAGE_CODE_ENGLISH +}; + +#endif + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//PCI BUS Driver Entry Point +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciBusEntryPoint() +// +// Description: This function is the entry point for PCI BUS Driver. +// Since PCI BUS Driver follows EFI 1.1 driver model in it's entry point +// it will initialize some global data and install +// EFI_DRIVER_BINDING_PROTOCOL. +// +// Input: +// EFI_HANDLE ImageHandle Image handle. +// EFI_SYSTEM_TABLE *SystemTable Pointer to the EFI system table. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When something required is not found! +// EFI_DEVICE_ERROR When the device is not responding! +// +// Notes: +// Entry Points are used to locate or install protocol interfaces and +// notification events. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciBusEntryPoint(IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable ) +{ + static EFI_GUID CpuInfoHobGuid = AMI_CPUINFO_HOB_GUID; +#if EFI_DEBUG || USB_DEBUG_TRANSPORT + static EFI_GUID DbgPortHobGuid = AMI_DEBUGPORT_HOB_GUID; +#endif + static EFI_GUID HobListGuid = HOB_LIST_GUID; + CPUINFO_HOB *CpuInfoHob; + EFI_STATUS Status; +//-------------------------------------------------------------------- + + //Init some Global Data + InitAmiLib(ImageHandle,SystemTable); + gPciBusDriverBinding.DriverBindingHandle=NULL; + gPciBusDriverBinding.ImageHandle=ImageHandle; + + //Get CPU Cache Line Size + CpuInfoHob=(CPUINFO_HOB*)GetEfiConfigurationTable(pST,&HobListGuid); + if(CpuInfoHob==NULL) Status=EFI_UNSUPPORTED; + else Status=FindNextHobByGuid(&CpuInfoHobGuid,(VOID**)&CpuInfoHob); + + if(!EFI_ERROR(Status)){ + gCpuCaheLineSize=CpuInfoHob->CacheLineSize; //in bytes + gPciCaheLineSize=(UINT8)gCpuCaheLineSize/4; //in DWORDs + PCI_TRACE((TRACE_PCI,"PciBus: Find CpuInfo HOB! gCpuCaheLineSize=%X; gPciCaheLineSize=%X;\n", gCpuCaheLineSize, gPciCaheLineSize)); + } else { + PCI_TRACE((TRACE_PCI,"PciBus: Unable to find CpuInfo HOB! Setting default CacheLineSize -> %X\n", gCpuCaheLineSize)); + } + +#if EFI_DEBUG || USB_DEBUG_TRANSPORT +//Get Ami Debug Port Settings + gDbgPortHob=(AMI_DEBUGPORT_INFORMATION_HOB*)GetEfiConfigurationTable(pST,&HobListGuid); + if(gDbgPortHob) Status=FindNextHobByGuid(&DbgPortHobGuid,(VOID**)&gDbgPortHob); + if(EFI_ERROR(Status)) gDbgPortHob=NULL; + else { + Status=gDbgPortHob->GetDebugPortProperties(gDbgPortHob, &gDbgPortInfo); + ASSERT_EFI_ERROR(Status); + } +#endif + + //Install Multiple Prot Drv. Binding and Comp. Name + Status = pBS->InstallMultipleProtocolInterfaces( + &gPciBusDriverBinding.DriverBindingHandle, + &gDriverBindingProtocolGuid,&gPciBusDriverBinding, +#ifdef EFI_DEBUG + &gEfiComponentName2ProtocolGuid,&gComponentName, +#endif + NULL); + //Here we can set up notification events if needed + + + //------------------------------------ + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsFunc0OfMfDev() +// +// Description: Checks if PCI_DEV_INFO data passed belongs to Function 0 of +// Multy-Functional device. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: BOOLEAN +// TRUE Device is Function 0 of Mulifunctional device. +// FALSE Device is not Function 0 of Mulifunctional device. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN IsFunc0OfMfDev(PCI_DEV_INFO *Device ){ + //If (Func0==NULL && FuncCount==0) function is a single function device, following fields are not used and reserved; + //If (Func0!=NULL && FuncCount==0) function is one of the Func1..Func7 of multyfunc device Func0 points on DevFunc0; + //If (Func0!=NULL && (FuncCount!=0 || FuncInitCnt!=0)) function is Func0 of multyfunc device DevFunc holds pointers at all other Func1..7 found + //If (Func0==NULL && FuncCount!=0) Illehgal combination - reserved! + if((Device->Func0!=NULL) && ((Device->FuncInitCnt!=0)||(Device->FuncCount!=0))) return TRUE; + return FALSE; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsFunc0() +// +// Description: Checks if PCI_DEV_INFO is Function 0 of PCI device. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: BOOLEAN +// TRUE Device is Function 0 of Mulifunctional device. +// FALSE Device is not Function 0 of Mulifunctional device. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN IsFunc0(PCI_DEV_INFO *Device ){ + //If (Func0==NULL && FuncCount==0) function is a single function device, following fields are not used and reserved; + //If (Func0!=NULL && FuncCount==0) function is one of the Func1..Func7 of multyfunc device Func0 points on DevFunc0; + //If (Func0!=NULL && (FuncCount!=0 || FuncInitCnt!=0)) function is Func0 of multyfunc device DevFunc holds pointers at all other Func1..7 found + //If (Func0==NULL && FuncCount!=0) Illehgal combination - reserved! + if(IsFunc0OfMfDev(Device)) return TRUE; + if((Device->Func0==NULL) && (Device->FuncInitCnt==0) && (Device->FuncCount==0)) return TRUE; + return FALSE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CpyItemLst() +// +// Description: Creates a copy of T_ITEM_LST structure. +// +// Input: +// T_ITEM_LIST *Lst Pointer to the structure to copy. +// T_ITEM_LIST **NewLstPtr Double Pointer to the copied data (Memory allocation is done by this function). +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CpyItemLst(T_ITEM_LIST *Lst, T_ITEM_LIST **NewLstPtr) +{ + T_ITEM_LIST *NewLst; +//-------------------------- + if(*NewLstPtr == NULL) *NewLstPtr = MallocZ(sizeof(T_ITEM_LIST)); + + if (*NewLstPtr==NULL) return EFI_OUT_OF_RESOURCES; + + NewLst = *NewLstPtr; + NewLst->InitialCount = Lst->InitialCount; + if (Lst->InitialCount == 0) return EFI_SUCCESS; + + NewLst->Items = MallocZ( Lst->InitialCount * sizeof(VOID*) ); + if (!NewLst->Items) return EFI_OUT_OF_RESOURCES; + + pBS->CopyMem((VOID*)NewLst->Items,(VOID*)Lst->Items,sizeof(VOID*)*Lst->ItemCount); + + NewLst->ItemCount = Lst->ItemCount; + + return EFI_SUCCESS; +} + + +#if HOTPLUG_SUPPORT +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//Following function to initialize PCI Root Hotplug Controller +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CheckRootHotplug() +// +// Description: This function will update pointer to PCI_RHPC_INFO of +// Bridge Type device which creates a hot plug bus. Also if "Device" +// creates the 'home bus' for Root HPC it will initialize Root HPC and +// record the HPC state; +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CheckRootHotplug(PCI_DEV_INFO *Device){ + EFI_STATUS Status=EFI_SUCCESS; + EFI_DEVICE_PATH_PROTOCOL *dp=NULL; + PCI_HPC_INFO *rhpc; + UINTN i; +//--------------- + if(Device->Type==tPci2PciBrg || Device->Type==tPci2CrdBrg || Device->Type==tPciRootBrg){ + //we have identify and Init all the Root Hpc and HPB + if(Device->HostData->InitRhpcCount==Device->HostData->RhpcCount) return EFI_SUCCESS; + PROGRESS_CODE(DXE_PCI_BUS_HPC_INIT); + //here we must check if 2 things: + // 1.If "Device" Device Path mutches with one of Root Hpc Device pathes + // 2.If "Device" Device Path mutches with one of Root Hpb Device pathes + for(i=0; i<Device->HostData->RhpcCount; i++){ + rhpc=Device->HostData->RhpcList[i]; + //if this controller already has been initialized - keep going + if(rhpc->Initialized && rhpc->BusFound) continue; + + + //check if it is a secondary interface of the bridge where RHPC is sitting + if(!rhpc->BusFound){ + if(!DPCmp(Device->DevicePath, rhpc->HpcLocation->HpbDevicePath)){ + rhpc->HpbBridge=Device; + rhpc->BusFound=TRUE; + Device->HotPlug=rhpc; + PCI_TRACE((TRACE_PCI,"PciBus: Found HP Bus Bridge @ B%X|D%X|F%X \n\n", Device->Address.Addr.Bus,Device->Address.Addr.Device, Device->Address.Addr.Function)); + } + } + + if(!rhpc->Initialized){ + //We will cut the last node of the HPC device path + //resulting Device Path will correspond to the ParentBridge.DevicePath of the HPC + dp=DPCut(rhpc->HpcLocation->HpcDevicePath); + //if the HPC sits behind this bridge get the secondary I/F bus number + if(!DPCmp(Device->DevicePath,dp)){ + EFI_DEVICE_PATH_PROTOCOL *tdp; + //----------------------------------- + rhpc->HpcPciAddr.Addr.Bus=mMaxBusFound; + tdp=DPGetLastNode(rhpc->HpcLocation->HpcDevicePath); + + rhpc->HpcPciAddr.Addr.Device=((PCI_DEVICE_PATH*)tdp)->Device; + rhpc->HpcPciAddr.Addr.Function=((PCI_DEVICE_PATH*)tdp)->Function; + + //we will not set up an event to signal when HPC initialization is ready + //that will give us a possibility to enumerate PCI BUS in one pass + Status=Device->HostData->HpInitProt->InitializeRootHpc( + Device->HostData->HpInitProt, rhpc->HpcLocation->HpcDevicePath, + rhpc->HpcPciAddr.ADDR, NULL, &rhpc->HpcState); + + ASSERT_EFI_ERROR(Status); + rhpc->Owner=Device; + rhpc->Initialized=TRUE; + PCI_TRACE((TRACE_PCI,"PciBus: Found RHPC @ B%X|D%X|F%X \n", Device->Address.Addr.Bus,Device->Address.Addr.Device, Device->Address.Addr.Function)); + } + } + + //if we come here we did some step of the initialization process + //let's check if this controller has been completly initialized. + //if so we did our job. there are no reasons to stay in this loop any longer + if(rhpc->Initialized && rhpc->BusFound) { + Device->HostData->InitRhpcCount++; + break; + } + + }//for + } + if(dp)pBS->FreePool(dp); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsHpb() +// +// Description: This function will check if "Device" passed is the Bridge +// Type Device with hotplug support. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: BOOLEAN +// TRUE If "Device" is a Bridge with HPC on it. +// FALSE Otherwice. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN IsHpb(PCI_DEV_INFO *Device){ + + //check if it is the right type of device to have Hotplug capabilities + if(!((Device->Type==tPci2PciBrg)||(Device->Type==tPci2CrdBrg)||(Device->Type==tPciRootBrg))) return FALSE; + + //Check if it has Root Hpc or PciExpress capabilities + if(!Device->HotPlug && !Device->PciExpress) return FALSE; + + //If Device is PciExpress, check if SLOT CAPABILITIES Register supports Hotplug + if(Device->PciExpress && (!Device->PciExpress->SlotCap.HpCapable))return FALSE; + + return TRUE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetHpbResPadding() +// +// Description: This function will get and apply resource padding +// requirements for the PCI to PCI Bridge or Card Bus Bridge, if this +// Bridge is supports hot plug. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetHpbResPadding(PCI_DEV_INFO *Device){ + EFI_STATUS Status=0; +//----------------------------- + if(IsHpb(Device)){ + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Device+1); + ASLR_QWORD_ASD *cnf, *res; + PCI_BAR *bar; + //---------------------------- + Status=Device->HostData->HpInitProt->GetResourcePadding(Device->HostData->HpInitProt, + Device->HotPlug->HpcLocation->HpcDevicePath, Device->HotPlug->HpcPciAddr.ADDR, + &Device->HotPlug->HpcState,&cnf,&ext->PaddAttr); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + if(ext->PaddAttr==EfiPaddingPciRootBridge){ + pBS->FreePool(cnf); + return Status; + } + + //Check if we got a valid descriptors in cfg buffer + if(!ValidateDescriptorBlock(cnf, tResAll, FALSE))return EFI_INVALID_PARAMETER; + + res=cnf; + while(res->Hdr.HDR!=ASLV_END_TAG_HDR) { + bar=NULL; + switch(res->Type){ + case ASLRV_SPC_TYPE_BUS : + bar=&ext->Pad[rtBus]; + break; + case ASLRV_SPC_TYPE_IO : + bar=&ext->Pad[rtIo16]; + bar->Type=tBarIo16; + if(res->_GRA==32){ + bar=&ext->Pad[rtIo32]; + bar->Type=tBarIo32; + } + break; + case ASLRV_SPC_TYPE_MEM : + if(res->_GRA==32){ + if(res->TFlags.MEM_FLAGS._MEM==ASLRV_MEM_CEPF) { + bar=&ext->Pad[rtMmio32p]; + bar->Type=tBarMmio32pf; + } else { + bar=&ext->Pad[rtMmio32]; + bar->Type=tBarMmio32; + } + } else { + if(res->_GRA==64){ + if(res->TFlags.MEM_FLAGS._MEM==ASLRV_MEM_CEPF){ + bar=&ext->Pad[rtMmio64p]; + bar->Type=tBarMmio64pf; + } else { + bar=&ext->Pad[rtMmio64]; + bar->Type=tBarMmio64; + } + } else return EFI_INVALID_PARAMETER; //no other options alloud + } + break; + default: return EFI_INVALID_PARAMETER; + } //switch + + bar->Length=res->_LEN; + bar->Gran=res->_MAX; + res++; + } //while + pBS->FreePool(cnf); + } + return Status; +} + +//============================================================================== +#endif + +//============================================================================== +// Device Handle Helper Functions +//============================================================================== + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: MakePciDevicePath() +// +// Description: This function will take Parent DevPath and extand it with +// Current ""Dev", Device Path and update pointer of the "Dev->DevPath" +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS MakePciDevicePath(PCI_DEV_INFO *Dev) +{ + static PCI_DEVICE_PATH pcidp; +//------------------------------------------- + //we have a wonderful Lib function DPAddNode - use it! + pcidp.Header.SubType=HW_PCI_DP; + pcidp.Header.Type=HARDWARE_DEVICE_PATH; + SET_NODE_LENGTH(&pcidp.Header,HW_PCI_DEVICE_PATH_LENGTH); + + pcidp.Function=Dev->Address.Addr.Function; + pcidp.Device=Dev->Address.Addr.Device; + + Dev->DevicePath=DPAddNode(Dev->ParentBrg->DevicePath, &pcidp.Header); + if(Dev->DevicePath)return EFI_SUCCESS; + else return EFI_OUT_OF_RESOURCES; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindRbHandle() +// +// Description: This function will finds Root Bridge Device Handle for +// the "Device". +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_HANDLE +// !=NULL When everything is going on fine! +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_HANDLE FindRbHandle(PCI_DEV_INFO *Device){ + EFI_HANDLE rbh=NULL; + PCI_DEV_INFO *dev=Device; +//--------------------- + while(dev->Type!=tPciRootBrg)dev=dev->ParentBrg; + rbh=dev->Handle; + return rbh; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindPciDeviceByHandleBrg() +// +// Description: This function Searches PCI Bridge Subsystem Database to find +// device which have passed "Handle" +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Bridge Device Private Data structure. +// EFI_HANDLE Handle Device Handle to search for. +// +// Output: PCI_DEV_INFO +// !=NULL When everything is going on fine! +// ==NULL Not Found. +// +// Notes: This is a subordinate function of FindPciDeviceByHandle() +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +PCI_DEV_INFO *FindPciDeviceByHandleBrg(PCI_BRG_INFO *Brg, EFI_HANDLE Handle) +{ + PCI_DEV_INFO *dev, *res=NULL; + INTN i; +//-------------------------------------------------------------------- + if(Brg->Common.Handle==Handle) return &Brg->Common; + + for(i=0; i<(INTN)Brg->Bridge.ChildCount; i++){ + dev=Brg->Bridge.ChildList[i]; + res=NULL; + if(dev->Handle==Handle) { + res=dev; + break; + } + + if(dev->Type==tPci2PciBrg) res=FindPciDeviceByHandleBrg((PCI_BRG_INFO*)dev,Handle); + + if(res) break; + } + return res; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindPciDeviceByHandle() +// +// Description: This function finds Pci Device by "Handle" passed +// +// Input: +// EFI_HANDLE Handle PCI Device Handle. +// +// Output: PCI_DEV_INFO +// !=NULL When everything is going on fine! +// ==NULL Not Found. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +PCI_DEV_INFO *FindPciDeviceByHandle(EFI_HANDLE Handle) +{ + PCI_BRG_INFO *brg; + UINTN i,j; + PCI_HOST_INFO *lhst; + PCI_DEV_INFO *res; +//-------------------------------------------------------------------- + for(j=0; j<gHostCnt; j++){ + lhst=&gPciHost[j]; + for(i=0; i<lhst->RbCount; i++){ + brg=(PCI_BRG_INFO*)lhst->RootBridges[i]; + res=FindPciDeviceByHandleBrg(brg, Handle); + if(res) return res; + } + } + return NULL; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DoPrepController() +// +// Description: This function will follow the rules of calling seqence of +// Platform Preprocess Controller it will call: +// 1.Platform PreprocessController with ChipsetEntery +// 2.Host Brg Preprocess Controller +// 3.Platform PreprocessController with ChipsetExit +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DoPrepController(PCI_DEV_INFO* Device) +{ + EFI_STATUS Status=0; + EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE ph; + EFI_HANDLE rbh=FindRbHandle(Device); +//----------- + if(Device->Type==tPci2PciBrg) ph=EfiPciBeforeChildBusEnumeration; + else ph=EfiPciBeforeResourceCollection; + + //If System has PciPlatform protocol installed + if(Device->HostData->PlatformProt){ + Status=Device->HostData->PlatformProt->PlatformPrepController( + Device->HostData->PlatformProt, Device->HostData->HostHandle, + rbh,Device->Address.Addr, ph, ChipsetEntry); + ASSERT_EFI_ERROR(Status); + } + + Status=Device->HostData->ResAllocProt->PreprocessController( + Device->HostData->ResAllocProt,rbh,Device->Address.Addr, ph); + ASSERT_EFI_ERROR(Status); + + if(Device->HostData->PlatformProt){ + Status=Device->HostData->PlatformProt->PlatformPrepController( + Device->HostData->PlatformProt, Device->HostData->HostHandle, + rbh, Device->Address.Addr, ph, ChipsetExit); + ASSERT_EFI_ERROR(Status); + } + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DoPciNotify() +// +// Description: This function will follow the rules of calling seqence of +// Platform Notify it will call: +// 1.Platform NotifyPhase with ChipsetEntery +// 2.Host Brg NotifyPhase +// 3.Platform NotifyPhase with ChipsetExit +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DoPciNotify(PCI_HOST_INFO *Host, EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase) +{ + EFI_STATUS Status=0; +//----------- + if(Host->PlatformProt){ + Status=Host->PlatformProt->PhaseNotify(Host->PlatformProt,Host->HostHandle,Phase,ChipsetEntry); + ASSERT_EFI_ERROR(Status); + } + + Status=Host->ResAllocProt->NotifyPhase(Host->ResAllocProt,Phase); + ASSERT_EFI_ERROR(Status); + + if(Host->PlatformProt){ + Status=Host->PlatformProt->PhaseNotify(Host->PlatformProt,Host->HostHandle,Phase,ChipsetExit); + ASSERT_EFI_ERROR(Status); + } + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciCfg8() +// +// Description: Will do PCI Configuration Space Access 8 bit width +// +// Input: +// ROOT_BRIDGE_IO_PROTOCOL *RbIo Pointer to PciRootBridgeIO Protocol. +// PCI_CFG_ADDR addr PCI_CFG_ADDR filled by caller +// BOOLEAN wr TRUE = Write FALSE = Read +// UINT8 *buff Pointer Data Buffer. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Referals:PCI_CFG_ADDR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciCfg8(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RbIo, PCI_CFG_ADDR addr, BOOLEAN wr, UINT8 *buff){ + if(wr)return RbIo->Pci.Write(RbIo, EfiPciWidthUint8, addr.ADDR, 1, (VOID*)buff); + else return RbIo->Pci.Read(RbIo, EfiPciWidthUint8, addr.ADDR, 1, (VOID*)buff); +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciCfg16() +// +// Description: Will do PCI Configuration Space Access 16 bit width +// +// Input: +// ROOT_BRIDGE_IO_PROTOCOL *RbIo Pointer to PciRootBridgeIO Protocol. +// PCI_CFG_ADDR addr PCI_CFG_ADDR filled by caller +// BOOLEAN wr TRUE = Write FALSE = Read +// UINT16 *buff Pointer Data Buffer. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Referals:PCI_CFG_ADDR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciCfg16(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RbIo, PCI_CFG_ADDR addr, BOOLEAN wr, UINT16 *buff){ + EFI_STATUS Status; +//------------ + if(wr)Status=RbIo->Pci.Write(RbIo, EfiPciWidthUint16, addr.ADDR, 1, (VOID*)buff); + else Status=RbIo->Pci.Read(RbIo, EfiPciWidthUint16, addr.ADDR, 1, (VOID*)buff); + //it might be a Width issue on Pci Root bridge level + if(Status==EFI_INVALID_PARAMETER) { + UINT8 *b=(UINT8*)buff; + //-------------------- + Status=PciCfg8(RbIo, addr, wr, b); + if(EFI_ERROR(Status)) return Status; + + //Check if Extended register used then Addr.Register is ignored. + if( addr.Addr.ExtendedRegister != 0) addr.Addr.ExtendedRegister += 1; + else addr.Addr.Register += 1; + + b++; + Status=PciCfg8(RbIo, addr, wr, b); + } + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciCfg32() +// +// Description: Will do PCI Configuration Space Access 32 bit width +// +// Input: +// ROOT_BRIDGE_IO_PROTOCOL *RbIo Pointer to PciRootBridgeIO Protocol. +// PCI_CFG_ADDR addr PCI_CFG_ADDR filled by caller +// BOOLEAN wr TRUE = Write FALSE = Read +// UINT32 *buff Pointer Data Buffer. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Referals:PCI_CFG_ADDR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciCfg32(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RbIo, PCI_CFG_ADDR addr, BOOLEAN wr, UINT32 *buff){ + EFI_STATUS Status; +//------------ + if(wr)Status=RbIo->Pci.Write(RbIo, EfiPciWidthUint32, addr.ADDR, 1, (VOID*)buff); + else Status=RbIo->Pci.Read(RbIo, EfiPciWidthUint32, addr.ADDR, 1, (VOID*)buff); + //it might be a Width issue on Pci Root bridge level + if(Status==EFI_INVALID_PARAMETER) { + UINT16 *b=(UINT16*)buff; + //-------------------- + Status=PciCfg16(RbIo, addr, wr, b); + if(EFI_ERROR(Status)) return Status; + + //Check if Extended register used then Addr.Register is ignored. + if( addr.Addr.ExtendedRegister != 0) addr.Addr.ExtendedRegister += 2; + else addr.Addr.Register += 2; + + b++; + Status=PciCfg16(RbIo, addr, wr, b); + } + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciCfg64() +// +// Description: Will do PCI Configuration Space Access 64 bit width +// +// Input: +// ROOT_BRIDGE_IO_PROTOCOL *RbIo Pointer to PciRootBridgeIO Protocol. +// PCI_CFG_ADDR addr PCI_CFG_ADDR filled by caller +// BOOLEAN wr TRUE = Write FALSE = Read +// UINT64 *buff Pointer Data Buffer. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Referals:PCI_CFG_ADDR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciCfg64(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RbIo, PCI_CFG_ADDR addr, BOOLEAN wr, UINT64 *buff){ + EFI_STATUS Status; +//------------ + if(wr)Status=RbIo->Pci.Write(RbIo, EfiPciWidthUint64, addr.ADDR, 1, (VOID*)buff); + else Status=RbIo->Pci.Read(RbIo, EfiPciWidthUint64, addr.ADDR, 1, (VOID*)buff); + //it might be a Width issue on Pci Root bridge level + if((Status==EFI_INVALID_PARAMETER) && (buff!=NULL)) { + UINT32 *b=(UINT32*)buff; + //-------------------- + Status=PciCfg32(RbIo, addr, wr, b); + if(EFI_ERROR(Status)) return Status; + + //Check if Extended register used then Addr.Register is ignored. + if( addr.Addr.ExtendedRegister != 0) addr.Addr.ExtendedRegister += 4; + else addr.Addr.Register += 4; + + b++; + Status=PciCfg32(RbIo, addr, wr, b); + } + return Status; +} + + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// PCI IO Protocol Functions Implementation Protocol +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +//================================================================================== +// PciIoProtocol Supporting Functions +//================================================================================== + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: BarCheckType() +// +// Description: +// This helper function will check if Base Address Register(BAR) selected +// for PciIo operation is of valid type and has been initialized; +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PciDevice Info structure. +// UINT8 BarIndex Index of the BAR within PCI device +// PCI_BAR_TYPE BarType Indicating what to check - IO or Memory. +// +// Output: BOOLEAN +// TRUE BAR supports selected transaction. +// FALSE BAR does not support selected transaction. +// +// Referals: PCI_DEV_INFO; PCI_BAR_TYPE +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN BarCheckType(PCI_DEV_INFO *Dev, UINT8 BarIndex, PCI_BAR_TYPE BarType) +{ + PCI_BAR *bar=&Dev->Bar[BarIndex]; +//------------------------------------- + switch(BarType){ + case tBarMem: + if (bar->Type != tBarMmio32 && + bar->Type != tBarMmio32pf && + bar->Type != tBarMmio64 && + bar->Type != tBarMmio64pf ) return FALSE; + break; + + case tBarIo: + if (bar->Type != tBarIo32 && bar->Type != tBarIo16) + return FALSE; + break; + default: return FALSE; + } + + return TRUE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoCheckBar() +// +// Description: This helper function will check if parameters passed to the +// PCI IO Protocol to read or write a PCI resources are correct. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PciDevice Info structure. +// UINT8 BarInd Index of the BAR within PCI device. +// PCI_BAR_TYPE BarType Indicating what to check - IO or Memory. +// EFI_PCI_IO_PROTOCOL_WIDTH Width Width of transaction. +// UINTN Count Number of bytes been transfered. +// UINT64 *Offset Offset within BAR address space to start from. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BAR_TYPE;EFI_PCI_IO_PROTOCOL_WIDTH +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoCheckBar(PCI_DEV_INFO *Dev, UINT8 BarInd, PCI_BAR_TYPE Type, + EFI_PCI_IO_PROTOCOL_WIDTH Width, UINTN Count, UINT64 *Offset) +{ + if ( Width<0 || Width>=EfiPciIoWidthMaximum ) return EFI_INVALID_PARAMETER; + + if (BarInd==0xFF) return EFI_SUCCESS; + + if (BarInd>=MAX_PCI_BAR) return EFI_INVALID_PARAMETER; + + if (!BarCheckType(Dev,BarInd,Type))return EFI_INVALID_PARAMETER; + + // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) Count = 1; + Width &= 0x03; + + if((*Offset+Count*((UINTN)1<<Width))-1 >= Dev->Bar[BarInd].Length) return EFI_INVALID_PARAMETER; + + *Offset = *Offset+(UINTN)Dev->Bar[BarInd].Base; + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoCheckConfig() +// +// Description: This helper function will check if parameters passed to the +// PCI IO Protocol to made a PCI Config Space Access are correct +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PciDevice Info structure. +// EFI_PCI_IO_PROTOCOL_WIDTH Width Width of transaction been performed. +// UINTN Count Number of bytes been transfered. +// UINT64 *Offset Offset to start from. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BAR_TYPE; EFI_PCI_IO_PROTOCOL_WIDTH +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS PciIoCheckConfig(PCI_DEV_INFO *Dev, EFI_PCI_IO_PROTOCOL_WIDTH Width, + UINTN Count, UINT64 *Offset) +{ + if(Width<0 || Width>= EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER; + + // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX + Width &= 0x03; + if((*Offset + Count * ((UINTN)1 << Width)) - 1 > 0xFF) return EFI_UNSUPPORTED; + + *Offset=PCI_ASSEMBLE_ADDR(Dev->Address.Addr.Bus, + Dev->Address.Addr.Device,Dev->Address.Addr.Function,*Offset); + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SetIdeDevMode() +// +// Description: This function will Change IDE Device Mode LEGACY/NATIVE +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// BOOLEAN Primary Indicate Primary/Secondary controller +// BOOLEAN Legacy Indicate Mode to programm +// UINT8 *Override If not NULL value to programm in PI register +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When device does not support mode programming. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; +// +// Notes: +// This function does not check if SecIde/PriIde Property of the Dev->HostData +// is tacken already caller must do that before call; +// This function does not update SecIde/PriIde Property of the Dev->HostData +// object. Caller must do that upon successfull return. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS SetIdeDevMode(PCI_DEV_INFO *Dev, BOOLEAN Primary, BOOLEAN Legacy, UINT8 *Override){ + + PCI_CFG_ADDR addr; + EFI_STATUS Status=EFI_SUCCESS; + UINT8 newpi=0, oldpi=Dev->Class.ProgInterface, tmp=oldpi=Dev->Class.ProgInterface; + BOOLEAN canprog=FALSE, needprog=FALSE; +//-------- + if(Dev->Class.BaseClassCode!=PCI_CL_MASS_STOR && Dev->Class.SubClassCode!=PCI_CL_MASS_STOR_SCL_IDE) + return EFI_INVALID_PARAMETER; + + addr.ADDR=Dev->Address.ADDR; + addr.Addr.Register=PCI_PI_OFFSET; + + + if(Override!=NULL){ + Status=PciCfg8(Dev->RbIo,addr,TRUE,Override); + if(!EFI_ERROR(Status)) { + UINT8 b=0; + //---------------- + //read back what we have write there + Status=PciCfg8(Dev->RbIo,addr,FALSE,&b); + if(b==(*Override))Dev->Class.ProgInterface=(*Override); + else Status=EFI_UNSUPPORTED; + PCI_TRACE((TRACE_PCI, "\nPciBus: SetIdeMode(Pri=N/A, Legacy=N/A, PciPI=0x%X) @ B%X|D%X|F%X = %r,\n",*Override, + Dev->Address.Addr.Bus,Dev->Address.Addr.Device,Dev->Address.Addr.Function, Status)); + } + } else { + if(Primary){ + canprog=(Dev->Class.ProgInterface & 0x02); + oldpi&=(~0x01); + tmp&=0x01; + if(!Legacy) newpi|=0x01; + } else { + canprog=(Dev->Class.ProgInterface & 0x08); + oldpi&=(~0x04); + tmp&=0x04; + if(!Legacy) newpi|=0x04; + } + needprog = (tmp ^ newpi); + if(needprog){ + if(canprog){ + newpi|=oldpi; + Status=PciCfg8(Dev->RbIo,addr,TRUE,&newpi); + if(!EFI_ERROR(Status)) Dev->Class.ProgInterface=newpi; + } else Status=EFI_UNSUPPORTED; + } + PCI_TRACE((TRACE_PCI, "\nPciBus: SetIdeMode(Pri=%d, Legacy=%d, PciPI=0x%X) @ B%X|D%X|F%X = %r,\n", Primary, Legacy, + newpi,Dev->Address.Addr.Bus,Dev->Address.Addr.Device,Dev->Address.Addr.Function, Status)); + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InCurVgaChain() +// +// Description: Helper function to check if device referenced as "Dev" sits +// within Current VGA device parents bridges. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PciDevice Info structure. +// +// Output: BOOLEAN +// TRUE "Dev" in Current VGA device parents bridges. +// FALSE "Dev" is not in Current VGA device parents bridges. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN InCurVgaChain(PCI_DEV_INFO *Dev) +{ + PCI_DEV_INFO *d=Dev->HostData->VgaDev; +//------------------------------------ + if(!d) return FALSE; + while (d->Type!=tPciRootBrg){ + if(d==Dev) return TRUE; + d=d->ParentBrg; + } + return FALSE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DeviceAttributes() +// +// Description: Protocol Function Sets or resets PCI Device Arttributs. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PciDevice Info structure. +// UINT64 Attributes Attributes bitmask which caller whants to change. +// BOOLEAN Set Specifies weathere to set or reset given "Attributes". +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When some of the "Attributes" not supported by the "Dev". +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DeviceAttributes(PCI_DEV_INFO *Dev, UINT64 Attributes, BOOLEAN Set) +{ + EFI_STATUS Status=0; + UINT16 tmp=0; + PCI_CMD_REG cmd; + PCI_BRG_CNT_REG bc; + PCI_CFG_ADDR addr; + UINT64 newattr=0, capab=Dev->Capab; //| PCI_ALLOWED_ATTRIBUTES; +//------------------------------ + + addr.ADDR=Dev->Address.ADDR; + bc.BRG_CNT_REG=0; + cmd.CMD_REG=0; + + //Remove platform specific attributes... + //Attributes&=(~(PCI_ALLOWED_ATTRIBUTES)); + + //If Devices for special attributes has been selected already we can't set it for different device + if(Dev->HostData->VgaDev != NULL){ + if(Dev != Dev->HostData->VgaDev){ + if(!InCurVgaChain(Dev) ) capab&=(~PCI_VGA_ATTRIBUTES); + } + } + + if((Dev->HostData->PriIde!=NULL)&& (Dev!=Dev->HostData->PriIde)) + capab&=(~EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO); + if((Dev->HostData->SecIde!=NULL)&& (Dev!=Dev->HostData->SecIde)) + capab&=(~EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO); + + //If OEMs want to add some more filters... + Status=PciPortOemAttributes(Dev, &Attributes, capab, Set); + + //if Attributes requested NOT SUPPORTED by the device... + if((capab & Attributes)!=Attributes) { + Status=EFI_UNSUPPORTED; + goto Exit; + } + + //if requested Attributes already match Device current Attributes + if( (((Dev->Attrib & Attributes)==Attributes) && Set ) || (((Dev->Attrib & Attributes)==0) && (!Set)) ) + { + Status=EFI_SUCCESS; + goto Exit; + } + + //So far so good - apply attributes + + //For IDE controller it is a special case + if( Attributes & (EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO)){ + BOOLEAN Primary=(BOOLEAN)(Attributes & EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO); + //-------------- + Status=SetIdeDevMode(Dev, Primary, Set, NULL); + if(EFI_ERROR(Status))goto Exit; + + if(Set){ + if(Primary) Dev->HostData->PriIde=Dev; + else Dev->HostData->SecIde=Dev; + } else { + if(Primary) Dev->HostData->PriIde=Dev; + else Dev->HostData->SecIde=Dev; + } + } + + //the + if(Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO || + Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) bc.IsaEnable=1; + + if(Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY || + Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO){ + DXE_SERVICES *dxe; + EFI_PHYSICAL_ADDRESS addr=0x3C0; + //----------------------------- + Status=LibGetDxeSvcTbl(&dxe); + if(EFI_ERROR(Status)) return Status; + + + bc.VgaEnable=1; + if (gPciSetupData->VgaPallete) cmd.VgaPaletteSnoop=1; + + if(Set) Status=dxe->AllocateIoSpace(EfiGcdAllocateAddress, + EfiGcdIoTypeIo, + 0, + 0x20, + &addr, + gPciBusDriverBinding.ImageHandle, + gPciBusDriverBinding.DriverBindingHandle); + else Status=dxe->FreeIoSpace(addr,0x20); + if(EFI_ERROR(Status)){ + PCI_TRACE((TRACE_PCI, "\nPciBus: Fail to allocate/free IO 0x3C0 ~ 0x3DF; Set=%d; Status=%r,\n", Set, Status)); + //If it was allocated - fine just keep going. + Status=EFI_SUCCESS; + } + } + + if(Attributes & EFI_PCI_IO_ATTRIBUTE_IO) cmd.IoSpace=1; + + if(Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) cmd.MemSpace=1; + + if(Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) cmd.BusMaster=1; + + //Recoursevely Set attributes to all parents + //if Parent bridge is the RootBrg use it native function to set Attributes + //keep in mind that per UIEFI 2.1 Spec Bridges are suppose to be always open, + //so we will filter Device Enable attributes from setting/resetting them for bridges. + newattr=(Attributes & (~(EFI_PCI_IO_ATTRIBUTE_IO|EFI_PCI_IO_ATTRIBUTE_MEMORY|EFI_PCI_IO_ATTRIBUTE_BUS_MASTER|PCI_ALLOWED_ATTRIBUTES))); + if(Dev->ParentBrg->Type == tPciRootBrg )Status=Dev->RbIo->SetAttributes(Dev->RbIo,newattr,NULL,NULL); + else Status=DeviceAttributes(Dev->ParentBrg,newattr,Set); + if(EFI_ERROR(Status))goto Exit; + + //bridge control register for P2P and P2C at the same place + if((Dev->Type==tPci2PciBrg || Dev->Type==tPci2CrdBrg) && bc.BRG_CNT_REG){ + //update bridge control reg if we have to + addr.Addr.Register=PCI_BRIDGE_CNTL; //brg controll reg + + //read what it has + Status=PciCfg16(Dev->RbIo,addr,FALSE,&tmp); + if(EFI_ERROR(Status)) goto Exit; + + if(Set) bc.BRG_CNT_REG=bc.BRG_CNT_REG|tmp; + else bc.BRG_CNT_REG=tmp&(~bc.BRG_CNT_REG); + + //write updated value + Status=PciCfg16(Dev->RbIo,addr,TRUE,&bc.BRG_CNT_REG); + if(EFI_ERROR(Status)) goto Exit; + } + + if(cmd.CMD_REG){ + //update PCI command reg if we have to + addr.Addr.Register=PCI_CMD; //command reg + + //read what it has + Status=PciCfg16(Dev->RbIo,addr,FALSE,&tmp); + if(EFI_ERROR(Status)) goto Exit; + + if(Set) cmd.CMD_REG=cmd.CMD_REG|tmp; + else cmd.CMD_REG=tmp&(~cmd.CMD_REG); + + //write updated value + Status=PciCfg16(Dev->RbIo,addr,TRUE,&cmd.CMD_REG); + if(EFI_ERROR(Status)) goto Exit; + } + //Update Recorded Attributes + if(Set)Dev->Attrib|=Attributes; + else Dev->Attrib&=(~Attributes); + +Exit: + PCI_TRACE((TRACE_PCI, "\nPciBus: SetAttributes(%d) @ B%X|D%X|F%X Attr=0x%lX; Capab=0x%lX; Status=%r,\n", Set, + Dev->Address.Addr.Bus,Dev->Address.Addr.Device,Dev->Address.Addr.Function, Attributes, capab, Status)); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoPollMem() +// +// Description: Protocol Function Poll PCI Memmory +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoPollMem(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//---------------------------------------------------------------------- + + if (((UINT32)Width) > ((UINT32)EfiPciIoWidthUint64)) return EFI_INVALID_PARAMETER; + + Status = PciIoCheckBar(dev, BarIndex, tBarMem, Width, 1, &Offset); + if(EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + Status=dev->RbIo->PollMem(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,Offset, + Mask,Value,Delay,Result); + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoPollIo() +// +// Description: Protocol Function Poll PCI IO +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoPollIo (IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result ) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//---------------------------------- + if (((UINT32)Width) > ((UINT32)EfiPciIoWidthUint64)) return EFI_INVALID_PARAMETER; + + Status=PciIoCheckBar(dev, BarIndex, tBarIo, Width, 1, &Offset); + if(EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + if (Width > EfiPciIoWidthUint64) return EFI_INVALID_PARAMETER; + + Status=dev->RbIo->PollIo(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Offset, Mask, Value, Delay, Result); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoMemRead() +// +// Description: Protocol Function Performs a PCI Memory Read Cycle +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoMemRead(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//--------------------------------------------- + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER; + + Status=PciIoCheckBar(dev, BarIndex, tBarMem, Width, Count, &Offset); + if(EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + Status=dev->RbIo->Mem.Read(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Offset, Count, Buffer); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoMemWrite() +// +// Description: Protocol Function Performs a PCI Memory Write Cycle +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoMemWrite(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//------------------------------------------- + + if(Width<0 || Width>=EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER; + + Status = PciIoCheckBar(dev, BarIndex, tBarMem, Width, Count, &Offset); + if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + Status=dev->RbIo->Mem.Write(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Offset, Count, Buffer); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoIoRead() +// +// Description: Protocol Function Performs a PCI I/O Read Cycle +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoIoRead(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//---------------------------------------------------- + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER; + + Status=PciIoCheckBar(dev, BarIndex, tBarIo, Width, Count, &Offset); + if (EFI_ERROR(Status))return EFI_UNSUPPORTED; + + Status=dev->RbIo->Io.Read(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Offset, Count, Buffer); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoIoWrite() +// +// Description: Protocol Function Performs a PCI I/O Write Cycle +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoIoWrite(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//---------------------------------------------------- + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER; + + Status=PciIoCheckBar(dev, BarIndex, tBarIo, Width, Count, &Offset); + if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + Status=dev->RbIo->Io.Write(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Offset, Count, Buffer); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoConfigRead() +// +// Description: Protocol Function Performs a PCI Configuration Read Cycle +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoConfigRead(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer) +{ + + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; + UINT64 Address; +//--------------------------------------------------- + Address = Offset; + Status = PciIoCheckConfig(dev, Width, Count, &Address); + if(EFI_ERROR(Status))return Status; + + Status=dev->RbIo->Pci.Read(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Address, Count, Buffer); + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoConfigWrite() +// +// Description: Protocol Function Performs a PCI Configuration Write Cycle +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoConfigWrite(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; + UINT64 Address; +//--------------------------------------------------- + Address = Offset; + Status = PciIoCheckConfig(dev, Width, Count, &Address); + if (EFI_ERROR(Status)) return Status; + + Status=dev->RbIo->Pci.Write(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Address, Count, Buffer); + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoCopyMem() +// +// Description: Protocol Function Copyes PCI Memory +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoCopyMem(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//--------------------------------------------------- + + if (Width < 0 || Width >= EfiPciIoWidthMaximum) return EFI_INVALID_PARAMETER; + + if(Width == EfiPciIoWidthFifoUint8 || + Width == EfiPciIoWidthFifoUint16 || + Width == EfiPciIoWidthFifoUint32 || + Width == EfiPciIoWidthFifoUint64 || + Width == EfiPciIoWidthFillUint8 || + Width == EfiPciIoWidthFillUint16 || + Width == EfiPciIoWidthFillUint32 || + Width == EfiPciIoWidthFillUint64) return EFI_INVALID_PARAMETER; + + Status=PciIoCheckBar(dev, DestBarIndex, tBarMem, Width, Count, &DestOffset); + if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + Status=PciIoCheckBar(dev, SrcBarIndex, tBarMem, Width, Count, &SrcOffset); + if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + Status=dev->RbIo->CopyMem(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + DestOffset, SrcOffset, Count); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoMap() +// +// Description: Protocol Function Maps a memory region for DMA +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoMap(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//--------------------------------------------------- + + if(Operation<0 || Operation>=EfiPciIoOperationMaximum) return EFI_INVALID_PARAMETER; + + if(HostAddress==NULL || NumberOfBytes==NULL || DeviceAddress==NULL || Mapping==NULL) + return EFI_INVALID_PARAMETER; + + if (dev->Attrib & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) + Operation = Operation + EfiPciOperationBusMasterRead64; + + Status=dev->RbIo->Map(dev->RbIo,(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)Operation, + HostAddress, NumberOfBytes, DeviceAddress, Mapping); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoUnmap() +// +// Description: Protocol Function Unmaps a memory region for DMA +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoUnmap(IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//--------------------------------------------------- + + Status=dev->RbIo->Unmap(dev->RbIo,Mapping); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoAllocateBuffer() +// +// Description: Protocol Function Allocates a common buffer for DMA +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoAllocateBuffer(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//--------------------------------------------------- + + if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) + return EFI_UNSUPPORTED; + + if (dev->Attrib & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) + Attributes|=EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE; + + Status=dev->RbIo->AllocateBuffer(dev->RbIo,Type,MemoryType,Pages,HostAddress,Attributes); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoFreeBuffer() +// +// Description: Protocol Function Frees a common buffer +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoFreeBuffer(IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//--------------------------------------------------- + + Status=dev->RbIo->FreeBuffer(dev->RbIo,Pages,HostAddress); + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoFlush() +// +// Description: Protocol Function Flushes a DMA buffer +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoFlush (IN EFI_PCI_IO_PROTOCOL *This) +{ + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//-------------------------------------------- + return dev->RbIo->Flush(dev->RbIo); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoGetLocation() +// +// Description: Protocol Function Proides Device Address on PCI BUS like +// Bus#, Dev#, Fun# for the device who has PciIoProtocol == "This". +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoGetLocation(IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *Segment, + OUT UINTN *Bus, + OUT UINTN *Device, + OUT UINTN *Function) +{ + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; +//-------------------------------------------- + + if(Segment==NULL || Bus==NULL || Device==NULL || Function==NULL) + return EFI_INVALID_PARAMETER; + + *Segment = dev->RbIo->SegmentNumber; + *Bus = dev->Address.Addr.Bus; + *Device = dev->Address.Addr.Device; + *Function = dev->Address.Addr.Function; + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoAttributes() +// +// Description: Protocol Function Provides Arttribute operation for the PCI device +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoAttributes(IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL ) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; + BOOLEAN f=FALSE; + UINT64 capab=dev->Capab; +//-------------------------------------------- + + switch (Operation) { + case EfiPciIoAttributeOperationGet: + case EfiPciIoAttributeOperationSupported: + if (Result == NULL) return EFI_INVALID_PARAMETER; + if(Operation==EfiPciIoAttributeOperationGet)*Result = dev->Attrib; + else { + + if(dev->HostData->VgaDev != NULL){ + if(dev != dev->HostData->VgaDev){ + if(!InCurVgaChain(dev) ) capab&=(~PCI_VGA_ATTRIBUTES); + } + } + *Result=capab; + } + return EFI_SUCCESS; + break; + case EfiPciIoAttributeOperationSet: + case EfiPciIoAttributeOperationEnable: + //only one VGA legacy resources may be decoded + if(Attributes&PCI_VGA_ATTRIBUTES){ //special case for VGA attr + if(dev->HostData->VgaDev==NULL)f=TRUE; + } + //else if (dev!=dev->HostData->VgaDev) return EFI_UNSUPPORTED; + Status=DeviceAttributes(dev, Attributes,TRUE); + if((!EFI_ERROR(Status))&& f) dev->HostData->VgaDev=dev; + break; + case EfiPciIoAttributeOperationDisable: + if(Attributes&PCI_VGA_ATTRIBUTES) {//special case for VGA attr + if(dev->HostData->VgaDev==dev)f=TRUE; + } + Status=DeviceAttributes(dev, Attributes,FALSE); + if((!EFI_ERROR(Status))&& f ) dev->HostData->VgaDev=NULL; //clear default VGA Device ptr somebody reset it's status + break; + default : return EFI_INVALID_PARAMETER; + }//switch + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoGetBarAttributes() +// +// Description: Protocol Function Gets respective BAR Attributes +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoGetBarAttributes(IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL ) +{ + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; + ASLR_QWORD_ASD *resdsc; + ASLR_EndTag *enddsc; +//-------------------------------------------- + + if(Supports==NULL && Resources == NULL) return EFI_INVALID_PARAMETER; + if(BarIndex>=MAX_PCI_BAR) return EFI_UNSUPPORTED; + + if(Supports!=NULL) { +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO +//implement changing attributes for BAR using Cpu Protocol + *Supports = (dev->Capab & (BAR_ATTR)); +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO + } + if(Resources != NULL) { + UINTN sz=sizeof(ASLR_EndTag); + //------------------------------------------------ + if(dev->Bar[BarIndex].Type!=tBarUnused)sz+=sizeof(ASLR_QWORD_ASD); + + resdsc=MallocZ(sz); + if(!resdsc) return EFI_OUT_OF_RESOURCES; + + + if(dev->Bar[BarIndex].Type!=tBarUnused){ + + enddsc=(ASLR_EndTag*)(resdsc+1); + + //fill BAR descriptor + resdsc->Hdr.Name=ASLV_RT_QWORD_ASD; + resdsc->Hdr.Type=ASLV_LARGE_RES; + resdsc->Hdr.Length=sizeof(ASLR_QWORD_ASD)-sizeof(ASLRF_L_HDR); + resdsc->_MIN=dev->Bar[BarIndex].Base; + resdsc->_LEN=dev->Bar[BarIndex].Length; + resdsc->_MAX=resdsc->_MIN+resdsc->_LEN-1; + + switch (dev->Bar[BarIndex].DiscoveredType) { + case tBarIo16: + case tBarIo32: + resdsc->Type=ASLRV_SPC_TYPE_IO; // Io + break; + case tBarMmio32: + resdsc->Type=ASLRV_SPC_TYPE_MEM; // Mem + resdsc->_GRA=32; // 32 bit + break; + case tBarMmio32pf: + resdsc->Type=ASLRV_SPC_TYPE_MEM; // Mem + resdsc->TFlags.TFLAGS=0x6; // prefechable + resdsc->_GRA=32; // 32 bit + break; + case tBarMmio64: + resdsc->Type=ASLRV_SPC_TYPE_MEM; // Mem + resdsc->_GRA=64; // 32 bit + break; + case tBarMmio64pf: + resdsc->Type=ASLRV_SPC_TYPE_MEM; // Mem + resdsc->TFlags.TFLAGS=0x6; // prefechable + resdsc->_GRA=64; // 32 bit + break; + }//switch + } else enddsc=(ASLR_EndTag*)(resdsc); + //fix End tag + enddsc->Hdr.Name=ASLV_SR_EndTag; + enddsc->Hdr.Type=ASLV_SMALL_RES; + enddsc->Hdr.Length=sizeof(ASLR_EndTag)-sizeof(ASLRF_S_HDR); + enddsc->Chsum=0; + *Resources = resdsc; + }//if(Resources!=NULL) + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciIoSetBarAttributes() +// +// Description: Protocol Function Sets respective BAR Attributes +// +// Notes: See EFI Specification for detail description +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciIoSetBarAttributes(IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=(PCI_DEV_INFO*)This; + UINT64 offs, attr; +//-------------------------------------------------- + + if(Offset==NULL || Length==NULL) return EFI_INVALID_PARAMETER; + + if(dev->Bar[BarIndex].Type==tBarUnused) return EFI_UNSUPPORTED; + + // This driver does not support setting the WRITE_COMBINE or the CACHED attributes. + // If Attributes is not 0, then return EFI_UNSUPPORTED. + attr = Attributes & (~BAR_ATTR); +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO +//implement changing attributes for bar trough Cpu Protocol + if (attr)return EFI_UNSUPPORTED; +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO + + //Make sure the BAR range describd by BarIndex, Offset, and Length are valid for this PCI device. + offs = *Offset; + Status=PciIoCheckBar(dev, BarIndex, tBarMem, EfiPciIoWidthUint8, (UINT32)*Length, &offs); + + if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; + + return Status; +} + + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//============================================================================ +// Pci Io Protocol Interface +//============================================================================ +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: gPciIoInstance +// +// Description: PCI IO Protocol Instance for Child Devices of the PciBus Driver. +// +// Notes: EFI_PCI_IO_PROTOCOL +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +static EFI_PCI_IO_PROTOCOL gPciIoInstance = { + PciIoPollMem, + PciIoPollIo, + { + PciIoMemRead, + PciIoMemWrite + }, + { + PciIoIoRead, + PciIoIoWrite + }, + { + PciIoConfigRead, + PciIoConfigWrite + }, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, //RomSize; + NULL //RomImage +}; + + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//====================================================================== +// Here follows worker functions used for +// PCI Bus Enumeration and Resource Allocation +//====================================================================== +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: EnableDeviceDecoding() +// +// Description: Enables PCI Device Decoding. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// PCI_SPACE_TYPE WhatSpace Type of PCI Device Space for Action. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_SPACE_TYPE. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS EnableDeviceDecoding(PCI_DEV_INFO *Dev, PCI_SPACE_TYPE WhatSpace) +{ + EFI_STATUS Status; + UINT16 b16; + PCI_CFG_ADDR addr; +//------------------ + + if(Dev->Type<tPci2PciBrg) return EFI_SUCCESS; +#if EFI_DEBUG || USB_DEBUG_TRANSPORT + if(Dev->DebugPort) return EFI_SUCCESS; +#endif + + addr.ADDR=Dev->Address.ADDR; + //first read Command reg contents + addr.Addr.Register=PCI_COMMAND_REGISTER_OFFSET; + Status=PciCfg16(Dev->RbIo,addr,FALSE,&b16); + if(EFI_ERROR(Status)) return Status; + + switch (WhatSpace){ + case stOptRomSpace: + case stMemSpace: b16|=(PCI_CMD_MEMORY_SPACE); break; + case stIoSpace: b16|=(PCI_CMD_IO_SPACE); break; + case stMemIoSpace: b16|=(PCI_CMD_IO_SPACE | PCI_CMD_MEMORY_SPACE); break; + default: return EFI_INVALID_PARAMETER; + } //switch + //if Enabling PCI ROM space + if(WhatSpace==stOptRomSpace && Dev->Bar[PCI_MAX_BAR_NO].Type!=tBarUnused){ + UINT32 b32; + //---------------------- + addr.Addr.Register=Dev->Bar[PCI_MAX_BAR_NO].Offset; + + Status=PciCfg32(Dev->RbIo,addr,FALSE,&b32); + if(EFI_ERROR(Status)) return Status; + + b32|=1; + Status=PciCfg32(Dev->RbIo,addr,TRUE,&b32); + if(EFI_ERROR(Status)) return Status; + } + + //Write Data to the Command Register + addr.Addr.Register=PCI_COMMAND_REGISTER_OFFSET; + return PciCfg16(Dev->RbIo,addr,TRUE,&b16); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DisableDeviceDecoding() +// +// Description: Disables PCI Device Decoding. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// PCI_SPACE_TYPE WhatSpace Type of PCI Device Space for Action. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_SPACE_TYPE. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DisableDeviceDecoding(PCI_DEV_INFO *Dev, PCI_SPACE_TYPE WhatSpace) +{ + EFI_STATUS Status; + UINT16 b16; + PCI_CFG_ADDR addr; +//------------------ + //Don't toch Host brg device as a PCI Device + if(Dev->Type==tPciHostDev || Dev->Type==tUncompatibleDevice) return EFI_SUCCESS; +#if EFI_DEBUG || USB_DEBUG_TRANSPORT + if(Dev->DebugPort) return EFI_SUCCESS; +#endif + + addr.ADDR=Dev->Address.ADDR; + //first read Command reg contents + addr.Addr.Register=PCI_COMMAND_REGISTER_OFFSET; + Status=PciCfg16(Dev->RbIo,addr,FALSE,&b16); + if(EFI_ERROR(Status)) return Status; + + switch (WhatSpace){ + case stOptRomSpace: + case stMemSpace: + b16 &= (~PCI_CMD_MEMORY_SPACE); + break; + case stIoSpace: + b16 &= (~PCI_CMD_IO_SPACE); + break; + case stMemIoSpace: + b16 &= (~(PCI_CMD_IO_SPACE | PCI_CMD_MEMORY_SPACE)); + break; + case stDisableAll: + b16 &= (~(PCI_CMD_IO_SPACE | PCI_CMD_MEMORY_SPACE | PCI_CMD_BUS_MASTER)); + break; + default: return EFI_INVALID_PARAMETER; + } //switch + + //if Disabling PCI ROM space + if( (WhatSpace == stOptRomSpace ) && (Dev->Bar[PCI_MAX_BAR_NO].Type!=tBarUnused)){ + UINT32 b32; + //---------------------- + addr.Addr.Register=Dev->Bar[PCI_MAX_BAR_NO].Offset; + + Status=PciCfg32(Dev->RbIo,addr,FALSE,&b32); + if(EFI_ERROR(Status)) return Status; + + b32&=(~1); + Status=PciCfg32(Dev->RbIo,addr,TRUE,&b32); + if(EFI_ERROR(Status)) return Status; + } + + //Write Data to the Command Register + addr.Addr.Register=PCI_COMMAND_REGISTER_OFFSET; + Status=PciCfg16(Dev->RbIo,addr,TRUE,&b16); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: EnableBridgeIoDecoding() +// +// Description: Enables PCI Bridge I/O Space Decoding. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Bridge Private Data structure. +// UINT64 Base Base Address of the Bridge I/O Window. +// UINT64 Length Length of the Bridge I/O Window. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS EnableBridgeIoDecoding(PCI_DEV_INFO *Brg, UINT64 Base, UINT64 Length) +{ + PCI_CFG_ADDR BrgDevAddr; + UINT64 buff; + EFI_STATUS Status; +//---------------------------------------- + PCI_TRACE((TRACE_PCI,"PciBus: Enabling Brg I/O @ B%X|D%X|F%X\n, B=%lX; L=%lX\n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device,Brg->Address.Addr.Function, + Base, Length)); + + BrgDevAddr.ADDR=Brg->Address.ADDR; + //Set IObase to 0xFF and IO limit to 0 + BrgDevAddr.Addr.Register=0x1C; + buff=Shr64(Base,8); + + Status = PciCfg8(Brg->RbIo, BrgDevAddr,TRUE,(UINT8*)&buff); + if(EFI_ERROR(Status))return Status; + + buff=Shr64(Base,16); + BrgDevAddr.Addr.Register=0x30; //Upper 16 Base Reg + + Status = PciCfg16(Brg->RbIo, BrgDevAddr,TRUE,(UINT16*)&buff); + if(EFI_ERROR(Status))return Status; + + //Set IO limit + buff=Shr64(Base+(Length-1),8); + BrgDevAddr.Addr.Register=0x1D; + + Status = PciCfg8(Brg->RbIo, BrgDevAddr,TRUE,(UINT8*)&buff); + if(EFI_ERROR(Status))return Status; + + //Set IO limit Upper 16 + buff=Shr64(Base+(Length-1),16); + BrgDevAddr.Addr.Register=0x32; + + return PciCfg16(Brg->RbIo, BrgDevAddr,TRUE,(UINT16*)&buff); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DisableBridgeIoDecoding() +// +// Description: Disables PCI Bridge I/O Space Decoding. +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Bridge Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_BRG_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DisableBridgeIoDecoding(PCI_BRG_INFO *Brg) +{ + PCI_CFG_ADDR BrgDevAddr; + UINT32 buff=0x00FF; + EFI_STATUS Status; +//---------------------------------------- + BrgDevAddr.ADDR=Brg->Common.Address.ADDR; + //Set IObase to 0xFF and IO limit to 0 + BrgDevAddr.Addr.Register=0x1C; + Status = PciCfg16(Brg->Common.RbIo, BrgDevAddr,TRUE,(UINT16*)&buff); + if(EFI_ERROR(Status))return Status; + + //Set IO limit upper 32 base and limit to 0 + BrgDevAddr.Addr.Register=0x30; + return PciCfg32(Brg->Common.RbIo, BrgDevAddr,TRUE,&buff); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: EnableBridgeMmioDecoding() +// +// Description: Enables PCI Bridge MMIO Space Decoding. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Bridge Private Data structure. +// UINT64 Base Base Address of the Bridge I/O Window. +// UINT64 Length Length of the Bridge I/O Window. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS EnableBridgeMmioDecoding(PCI_DEV_INFO *Brg, UINT64 Base, UINT64 Length) +{ + PCI_CFG_ADDR BrgDevAddr; + UINT64 buff; + EFI_STATUS Status; +//---------------------------------------- + PCI_TRACE((TRACE_PCI,"PciBus: Enabling Brg MMIO @ [B%X|D%X|F%X] --> B=%lX; L=%lX\n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device,Brg->Address.Addr.Function, + Base, Length)); + + BrgDevAddr.ADDR=Brg->Address.ADDR; + //Set Memory Base + BrgDevAddr.Addr.Register=PCI_MEMBASE; + //buff=Base>>16; + buff=Shr64(Base,16); + + Status=PciCfg16(Brg->RbIo, BrgDevAddr,TRUE,(UINT16*)&buff); + if(EFI_ERROR(Status))return Status; + + //Set Memory limt + BrgDevAddr.Addr.Register=PCI_MEMLIMIT; + buff=Shr64(Base+(Length-1),16); + return PciCfg16(Brg->RbIo, BrgDevAddr,TRUE,(UINT16*)&buff); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DisableBridgeMmioDecoding() +// +// Description: Disables PCI Bridge MMIO Space Decoding. +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Bridge Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_BRG_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DisableBridgeMmioDecoding(PCI_BRG_INFO *Brg) +{ + PCI_CFG_ADDR BrgDevAddr; + UINT32 buff=0x0000FFFF; +//---------------------------------------- + BrgDevAddr.ADDR=Brg->Common.Address.ADDR; + //Set Memory Base to FFFF and Limit to 0; + BrgDevAddr.Addr.Register=0x20; + return PciCfg32(Brg->Common.RbIo, BrgDevAddr,TRUE,&buff); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: EnableBridgePfmmDecoding() +// +// Description: Enables PCI Bridge Prefetchable MMIO Space Decoding. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Bridge Private Data structure. +// UINT64 Base Base Address of the Bridge I/O Window. +// UINT64 Length Length of the Bridge I/O Window. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS EnableBridgePfmmDecoding(PCI_DEV_INFO *Brg, UINT64 Base, UINT64 Length) +{ + PCI_CFG_ADDR BrgDevAddr; + UINT64 buff; + EFI_STATUS Status; +//---------------------------------------- + PCI_TRACE((TRACE_PCI,"PciBus: Enabling Brg PFMM @ B%X|D%X|F%X\n, B=%lX; L=%lX\n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device,Brg->Address.Addr.Function, + Base, Length)); + + BrgDevAddr.ADDR=Brg->Address.ADDR; + + //Set Pf Memory Base + BrgDevAddr.Addr.Register=0x24; + buff=Shr64(Base,16); + + Status = PciCfg16(Brg->RbIo, BrgDevAddr, TRUE,(UINT16*)&buff); + if(EFI_ERROR(Status))return Status; + + //Set PF Memory Limit + BrgDevAddr.Addr.Register=0x26; + buff=Shr64(Base+(Length-1),16); + + Status = PciCfg16(Brg->RbIo, BrgDevAddr, TRUE, (UINT16*)&buff); + if(EFI_ERROR(Status))return Status; + + buff=Shr64(Base,32); + //Set Pf Memory Upper 32 Base + BrgDevAddr.Addr.Register=0x28; + Status = PciCfg32(Brg->RbIo, BrgDevAddr,TRUE,(UINT32*)&buff); + if(EFI_ERROR(Status))return Status; + + buff=Shr64(Base+(Length-1),32); + //Set Pf Memory Upper 32 Limit + BrgDevAddr.Addr.Register=0x2C; + return PciCfg32(Brg->RbIo, BrgDevAddr,TRUE,(UINT32*)&buff); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DisableBridgePfmmDecoding() +// +// Description: Disables PCI Bridge Prefetchable MMIO Space Decoding. +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Bridge Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_BRG_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DisableBridgePfmmDecoding(PCI_BRG_INFO *Brg) +{ + PCI_CFG_ADDR BrgDevAddr; + UINT32 buff=0x0000FFFF; + EFI_STATUS Status; +//---------------------------------------- + BrgDevAddr.ADDR=Brg->Common.Address.ADDR; + + //Set Pf Memory Base to FFFF Limit to 0; + BrgDevAddr.Addr.Register=0x24; + Status = PciCfg32(Brg->Common.RbIo, BrgDevAddr,TRUE,&buff); + if(EFI_ERROR(Status))return Status; + + buff=0; + //Set Pf Memory Upper 32 Base to 0; + BrgDevAddr.Addr.Register=0x28; + Status = PciCfg32(Brg->Common.RbIo, BrgDevAddr,TRUE,&buff); + if(EFI_ERROR(Status))return Status; + + //Set Pf Memory Upper 32 Limit to 0; + BrgDevAddr.Addr.Register=0x2c; + return PciCfg32(Brg->Common.RbIo, BrgDevAddr,TRUE,&buff); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DisableBridgeDecoding() +// +// Description: Disables PCI Bridge Decoding of ALL resources. +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Bridge Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_BRG_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DisableBridgeDecoding(PCI_BRG_INFO *Brg) +{ + EFI_STATUS Status; +//--------------------------------------- + + PCI_TRACE((TRACE_PCI,"PciBus: Disabling Brg @ B%X|D%X|F%X\n", + Brg->Common.Address.Addr.Bus, Brg->Common.Address.Addr.Device,Brg->Common.Address.Addr.Function)); + Status=DisableBridgeIoDecoding(Brg); + if(EFI_ERROR(Status))return Status; + + Status=DisableBridgeMmioDecoding(Brg); + if(EFI_ERROR(Status))return Status; + + return DisableBridgePfmmDecoding(Brg); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SetSubBus() +// +// Description: Programm SubordinateBusNumber Register of PCI Bridge. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Bridge Private Data structure. +// UINT8 SubBusNo Number to programm. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_BRG_INFO. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS SetSubBus(PCI_DEV_INFO *Brg, UINT8 SubBusNo) +{ + PCI_CFG_ADDR addr; +//--------------------------------------- + addr.ADDR=Brg->Address.ADDR; + addr.Addr.Register=PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET; //Sub Bus No reg + + return PciCfg8(Brg->RbIo, addr,TRUE,&SubBusNo); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AddBusDbEntry() +// +// Description: Fills gPciBusDb Array in ascending order. +// +// Input: +// PCI_BRG_EXT *Ext Pointer to PCI Bridge Extension Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AddBusDbEntry(PCI_BUS_XLAT_HDR *BusHdr, T_ITEM_LIST *BusDb){ + EFI_STATUS Status; + UINTN i; + PCI_BUS_XLAT_HDR *xhdr; +//-------------------------- + + if(BusDb->ItemCount==0) { + Status=AppendItemLst(BusDb, BusHdr); + } else { + for(i=0; i<BusDb->ItemCount; i++){ + xhdr = (PCI_BUS_XLAT_HDR*)BusDb->Items[i]; + if(xhdr->BusBuild > BusHdr->BusBuild){ + return InsertItemLst(BusDb, BusHdr, i); + } + }//for + // if we here and didn't returned yet - BusHdr->BusBuild is the bidggest one. + Status = AppendItemLst(BusDb, BusHdr); + } +#if AMI_BOARD_VER_COMBINED >= 100 + //Increase BusXlatTable entry count... + if(!EFI_ERROR(Status)) gAmiBoardInfo->BusXlatEntries++; +#endif + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PopulateBusDb() +// +// Description: Fills gPciBusDb Array in ascending order. +// +// Input: Nothing; +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PopulateBusDb(){ + PCI_BUS_XLAT_HDR *xhdr=gAmiBoardInfo->BusXlatTable; + PCI_DEV_FUN *devf = (PCI_DEV_FUN*)(xhdr+1); + EFI_STATUS Status=EFI_SUCCESS; +//-------------------------------- + while((UINTN)devf<=(UINTN)(gAmiBoardInfo->BusXlatTable) + gAmiBoardInfo->BusXlatLength){ + if(devf->DEV_FUN == 0xFF){ + //if we are looking for host device it shouldn't be any other guys in it's chain. + Status=AddBusDbEntry(xhdr, &gPciBusDb); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + //Advance to the next record in BusXlatTbl. +#if AMI_BOARD_VER_COMBINED >= 100 + //Now we have AslName[5] following devf data (sizeof(PCI_DEV_FUN)==1 byte) + xhdr=(PCI_BUS_XLAT_HDR*)(devf+1+5); +#else + xhdr=(PCI_BUS_XLAT_HDR*)(devf+1); +#endif + devf = (PCI_DEV_FUN*)(xhdr+1); + continue; + } else { + devf++; + } + } + return Status; +} + +/* +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindRootXlatEntry() +// +// Description: Finds corresponded BusXlatTable entry for the bridge. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Bridge Private Data structure. +// PCI_BUS_XLAT_HDR *XlatHdr Double Pointer to XLAT_HEADER will be initialized by this function +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BRG_INFO; PCI_BRG_EXT. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS FindRootXlatEntry(PCI_DEV_INFO *Dev, PCI_BUS_XLAT_HDR **XlatHdr){ + PCI_DEV_INFO *brg=Dev; + PCI_BRG_EXT *ext=NULL; +//------------------------- + while(brg->Type==tPciRootBrg){ + brg=brg->ParentBrg; + //this code just to double check the loop will be exited. + // + if(brg->ParentBrg==NULL){ + ext=(PCI_BRG_EXT*)(brg+1); + + if(ext->XlatTblEntry==NULL) return EFI_NOT_FOUND; + + *XlatHdr=ext->XlatTblEntry; + + break; + } + } + + if(ext==NULL) return EFI_NOT_FOUND; + + return EFI_SUCCESS; + +} +*/ + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindBridgeXlatEntry() +// +// Description: Finds corresponded BusXlatTable entry for the bridge. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Bridge Private Data structure. +// PCI_BRG_EXT *Ext Pointer to PCI Bridge Extension Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BRG_INFO; PCI_BRG_EXT. +// +// Notes: +// BaseBus = PCI_DEV_INFO->Address.Addr.Bus; +// SecondaryBus = PCI_BRG_EXT->Res[rtBus].Base; +// SubordinateBus = PCI_BRG_EXT->Res[rtBus].Base + PCI_BRG_EXT->Res[rtBus].Length-1; +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS FindBridgeXlatEntry(PCI_DEV_INFO *Dev, PCI_BRG_EXT *Ext){ + PCI_BUS_XLAT_HDR *xhdr; + PCI_DEV_FUN *devf; + UINTN i, chncnt; //Xlat Tbl Elemnts count (number of Dev/Fn instances) + PCI_BRG_EXT *ext; +//----------------------------- + //Now we will go trough BusXlatTbl entryes. + for(i=0; i<gPciBusDb.ItemCount; i++){ + xhdr=gPciBusDb.Items[i]; + devf = (PCI_DEV_FUN*)(xhdr+1); + for (chncnt=0; ; devf++,chncnt++){ + //Got to the end of PCI device chain + if(devf->DEV_FUN == 0xFF){ + //if we are looking for host device it shouldn't be any other guys in it's chain. + if((Dev->ParentBrg == NULL) && (chncnt==1) && (Dev->Type==tPciRootBrg)){ + //Check first if it is a correct host. + if( (xhdr->BusBuild == Dev->Address.Addr.Bus) ) + { + //xhdr->BusRun = Dev->Address.Addr.Bus; + Ext->XlatTblEntry=xhdr; + Ext->ChainNumber=(UINT8)chncnt; + Ext->ItemNumber=(UINT8)i; + + PCI_TRACE((TRACE_PCI,"PciBus: Found BusXlat for Host [B%X|D%X|F%X] BusBuild=%X\n", + Dev->Address.Addr.Bus,Dev->Address.Addr.Device, Dev->Address.Addr.Function, xhdr->BusBuild)); + + return EFI_SUCCESS; + } + } else { + //NOT HOST Device !((Dev->ParentBrg == NULL) && (chncnt==1)) + PCI_DEV_FUN *df=devf-1; + //---------------------- + if(Dev->ParentBrg!=NULL){ + + //Here we will define a criteria when XLAT TBL entrie considered a match.. + //1. ParentBrg->Ext->XlatTblEntry must be initialized + //2. ParentBrg->ChainNumber must be (chncnt-1) so this one will be the same elememnt + //3. ParentBrg->Ext->XlatTblEntry->BusBuild must not exceed THIS xhdr->BusBuild + //4. df->Dev==Dev->Address.Addr.Device AND df->Fun==Dev->Address.Addr.Function + //5. THIS Dev->Ext->XlatTbEntry must not be initialized yet.. + + //Get Parent Bridge ext of this device. + ext=(PCI_BRG_EXT*)(Dev->ParentBrg+1); + + //1. ParentBrg->Ext->XlatTblEntry must be initialized + //2. ParentBrg->Ext->ChainNumber must be (chncnt-1) so this one will be the same elememnt in it's Chain + //5. THIS Dev->Ext->XlatTbEntry must not be initialized yet... + if((Ext->XlatTblEntry==NULL)&&(ext->XlatTblEntry!=NULL) && (ext->ChainNumber == (UINT8)chncnt-1)){ + + //3. ParentBrg->Ext->XlatTblEntry->BusBuild must not exceed THIS xhdr->BusBuild + if( xhdr->BusBuild > ext->XlatTblEntry->BusBuild ) { + + //4. df->Dev==Dev->Address.Addr.Device AND df->Fun==Dev->Address.Addr.Function + if((Dev->Address.Addr.Device == df->Dev)&&(Dev->Address.Addr.Function == df->Fun)){ + + if(MemCmp((VOID*)(ext->XlatTblEntry+1),(VOID*)(xhdr+1), ext->ChainNumber)==0){ + //xhdr->BusRun = Dev->Address.Addr.Bus; + Ext->XlatTblEntry=xhdr; + Ext->ChainNumber=(UINT8)chncnt; + Ext->ItemNumber=(UINT8)i; + PCI_TRACE((TRACE_PCI,"PciBus: Found BusXlat for Brg [B%X|D%X|F%X] BusBuild=%X\n", + Dev->Address.Addr.Bus,Dev->Address.Addr.Device, Dev->Address.Addr.Function, xhdr->BusBuild)); + return EFI_SUCCESS; + } + }//Cond 4 + + }//cond 3; + + }//cond 1;2;5; + }//if(Dev->ParentBrg!=NULL) + } //else + break; + }//devf->DEV_FUN == 0xFF + } //for chncnt + } //for i + + return EFI_NOT_FOUND; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindBridgeXlatEntry() +// +// Description: Finds corresponded BusXlatTable entry for the next bridge +// of the same level (same number of nodes/chain-counts). +// +// Input: +// PCI_BRG_EXT *Ext Pointer to PCI Bridge Extension Private Data structure. +// +// Output: UINT8 Number of buses decoded by the Bridge which "Ext" passed. +// +// Notes: +// BaseBus = PCI_DEV_INFO->Address.Addr.Bus; +// SecondaryBus = PCI_BRG_EXT->Res[rtBus].Base; +// SubordinateBus = PCI_BRG_EXT->Res[rtBus].Base + PCI_BRG_EXT->Res[rtBus].Length-1; +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 FindNextSameLevelBrgXlatEntry(PCI_BRG_EXT *Ext){ + PCI_BUS_XLAT_HDR *xhdr; + PCI_DEV_FUN *devf; + UINTN i, chncnt; //Xlat Tbl Elemnts count (number of Dev/Fn instances) +//----------------------------- + //Now we will go trough BusXlatTbl entryes. + if(gPciBusDb.ItemCount <= (UINTN)(Ext->ItemNumber+1) ) return (UINT8)mMaxBusScan; + + for(i=Ext->ItemNumber+1; i<gPciBusDb.ItemCount; i++){ + xhdr=gPciBusDb.Items[i]; + devf = (PCI_DEV_FUN*)(xhdr+1); + for (chncnt=0; ; devf++,chncnt++){ + //Got to the end of PCI device chain + if(devf->DEV_FUN == 0xFF) break; + } //for chncnt + //here we found record terminator + //go and check the following. + //1. if this Xlat node of the same or less + if(chncnt<=Ext->ChainNumber) return (UINT8)(xhdr->BusBuild-1); + } //for i + + return (UINT8)mMaxBusScan; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindDevIrqEntry() +// +// Description: Finds corresponded BusXlatTable entry for the bridge. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Bridge Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BRG_INFO; PCI_BRG_EXT. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS FindDevIrqEntry(PCI_DEV_INFO *Dev){ + UINTN i, cnt; + PCI_DEV_INFO *brg=Dev->ParentBrg; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(brg+1); + PCI_BUS_XLAT_HDR *xhdr=ext->XlatTblEntry; + PCI_IRQ_PIC_ROUTE *pic; + PCI_IRQ_APIC_ROUTE *apic; +//----------------------------------- + + //Find Matching IRQ Routing entry for PIC + //cnt=((UINTN)gPicIrqTblEnd-(UINTN)gPicIrqRoutTbl)/sizeof(PCI_IRQ_PIC_ROUTE)-1; + cnt=gAmiBoardInfo->PicRoutLength/sizeof(PCI_IRQ_PIC_ROUTE); + + for(i=0; i<cnt; i++){ + pic=&gAmiBoardInfo->PicRoutTable[i]; + if(xhdr->BusBuild==pic->PciBusNumber){ + //pic->PciBusNumber=xhdr->BusRun; + + if( pic->DevFun.Dev == Dev->Address.Addr.Device){ + Dev->PicIrqEntry = pic; + break; + } + } + } + //Find Matching IRQ Routing entry for APIC + //cnt=((UINTN)gApicIrqTblEnd-(UINTN)gApicIrqRoutTbl)/sizeof(PCI_IRQ_APIC_ROUTE)-1; + cnt=gAmiBoardInfo->ApicRoutLength/sizeof(PCI_IRQ_APIC_ROUTE); + + for(i=0; i<cnt; i++){ + apic=&gAmiBoardInfo->ApicRoutTable[i]; + if(xhdr->BusBuild==apic->PciBusNumber){ + //apic->PciBusNumber=xhdr->BusRun; + + if( apic->DeviceNumber == Dev->Address.Addr.Device){ + Dev->ApicIrqEntry = apic; + break; + } + } + } + + return EFI_SUCCESS; +} + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: *mPicIrqSta[]; *mPicIrqSta[] +// +// Description: To make sure we are not updating entries we have updated +// already, we would need array of BBOLEANs to mark updated entries. +// +// NOTE: BOOLEAN Aarray [IrqRoiting Table enytries Number] +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +BOOLEAN *mPicIrqSta = NULL; +BOOLEAN *mApicIrqSta= NULL; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UpdateItqTbl() +// +// Description: Updtaes all matching entries in Irqrouting tables with +// runtime values. +// +// Input: +// PCI_BUS_XLAT_HDR *XlatHdr Updated BusTranslate table entry. +// +// Output: NOTHING +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID UpdateIrqTables(PCI_BUS_XLAT_HDR *XlatHdr){ + UINTN i; + PCI_IRQ_PIC_ROUTE *pic; + PCI_IRQ_APIC_ROUTE *apic; +//------------------------------ + + if(mPicIrqSta==NULL) mPicIrqSta=MallocZ(gAmiBoardInfo->PicRoutLength/sizeof(PCI_IRQ_PIC_ROUTE)); + if(mApicIrqSta==NULL) mApicIrqSta=MallocZ(gAmiBoardInfo->ApicRoutLength/sizeof(PCI_IRQ_APIC_ROUTE)); + + for(i=0; i<gAmiBoardInfo->PicRoutLength/sizeof(PCI_IRQ_PIC_ROUTE); i++){ + pic=&gAmiBoardInfo->PicRoutTable[i]; + if(pic->PciBusNumber==XlatHdr->BusBuild && mPicIrqSta[i]==FALSE) { + pic->PciBusNumber=XlatHdr->BusRun; + mPicIrqSta[i]=TRUE; + } + } + + //Not likely but who knows... it could be that gAmiBoardInfo->PicRoutLength + //different from gAmiBoardInfo->ApicRoutLength... so teke care of that! + for(i=0; i<gAmiBoardInfo->ApicRoutLength/sizeof(PCI_IRQ_APIC_ROUTE); i++){ + apic=&gAmiBoardInfo->ApicRoutTable[i]; + if(apic->PciBusNumber==XlatHdr->BusBuild && mApicIrqSta[i]==FALSE) { + apic->PciBusNumber=XlatHdr->BusRun; + mApicIrqSta[i]=TRUE; + } + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: RemoveUnusedIrqEntries() +// +// Description: Removes IRQ routing entries which got there by porting mistake +// in order not to confuse other consumers of AmiBoardInfoProtocol... +// +// Input: NOTHING +// +// Output: NOTHING +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID RemoveUnusedIrqEntries(){ + UINTN i, j, cnt; + PCI_IRQ_PIC_ROUTE *tmpp; + PCI_IRQ_APIC_ROUTE *tmpa; +//------------------------------ + cnt=gAmiBoardInfo->PicRoutLength/sizeof(PCI_IRQ_PIC_ROUTE); + tmpp=(PCI_IRQ_PIC_ROUTE*)Malloc(gAmiBoardInfo->PicRoutLength); + ASSERT(tmpp); + + for(j=0,i=0; j<cnt; j++){ + if(mPicIrqSta[j]==TRUE){ + MemCpy(&tmpp[i],&gAmiBoardInfo->PicRoutTable[j],sizeof(PCI_IRQ_PIC_ROUTE)); + i++; + } else { + gAmiBoardInfo->PicRoutLength -= sizeof(PCI_IRQ_PIC_ROUTE); + PCI_TRACE((TRACE_PCI,"PciBus: Removing unused entry #%d from PIC Routing Table\n", j)); + } + } + //Copy updated tabe from tmp buffer to AmiBoardInfo Location + MemCpy(&gAmiBoardInfo->PicRoutTable[0], &tmpp[0], gAmiBoardInfo->PicRoutLength); + + //Not likely but who knows... it could be that gAmiBoardInfo->PicRoutLength + //different from gAmiBoardInfo->ApicRoutLength... so teke care of that! + cnt=gAmiBoardInfo->ApicRoutLength/sizeof(PCI_IRQ_APIC_ROUTE); + tmpa=(PCI_IRQ_APIC_ROUTE*)Malloc(gAmiBoardInfo->ApicRoutLength); + ASSERT(tmpa); + + for(j=0,i=0; j<cnt;j++){ + if(mApicIrqSta[j]==TRUE){ + MemCpy(&tmpa[i],&gAmiBoardInfo->ApicRoutTable[j],sizeof(PCI_IRQ_APIC_ROUTE)); + i++; + } else { + gAmiBoardInfo->ApicRoutLength -= sizeof(PCI_IRQ_APIC_ROUTE); + PCI_TRACE((TRACE_PCI,"PciBus: Removing unused entry #%d from APIC Routing Table\n", j)); + } + } + //Copy updated tabe from tmp buffer to AmiBoardInfo Location + MemCpy(&gAmiBoardInfo->ApicRoutTable[0], &tmpa[0], gAmiBoardInfo->ApicRoutLength); + + //free buffers allocated, functions depending on it + //not suppose to be called anymore. + if(mPicIrqSta!=NULL){ + pBS->FreePool(mPicIrqSta); + mPicIrqSta=NULL; + } + if(mApicIrqSta!=NULL){ + pBS->FreePool(mApicIrqSta); + mApicIrqSta=NULL; + } + if(tmpp!=NULL) pBS->FreePool(tmpp); + if(tmpa!=NULL) pBS->FreePool(tmpa); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: MapBridgeBuses() +// +// Description: Maps Bridge's Primary Secondary Subordinate Bus Numbers +// according information stored in PCI_DEV_INFO and PCI_BRG_EXT structures +// of the PCI Bridge. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Bridge Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BRG_INFO; PCI_BRG_EXT. +// +// Notes: +// BaseBus = PCI_DEV_INFO->Address.Addr.Bus; +// SecondaryBus = PCI_BRG_EXT->Res[rtBus].Base; +// SubordinateBus = PCI_BRG_EXT->Res[rtBus].Base + PCI_BRG_EXT->Res[rtBus].Length-1; +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS MapBridgeBuses(PCI_DEV_INFO *Brg) +{ + EFI_STATUS Status; + PCI_CFG_ADDR addr; + UINT8 bus; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Brg+1); +//-------------------------------- + //Get Bridge Initial Address + addr.ADDR=Brg->Address.ADDR; + //Primary bus; + addr.Addr.Register=PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET; //Primary BusNo + bus=Brg->Address.Addr.Bus; + Status=PciCfg8(Brg->RbIo,addr,TRUE,&bus); + if(EFI_ERROR(Status))return Status; + + //SecondaryBus Register + addr.Addr.Register=PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET; //Secondary BusNo + + bus=(UINT8)ext->Res[rtBus].Base; + Status=PciCfg8(Brg->RbIo,addr,TRUE,&bus); + if(EFI_ERROR(Status))return Status; + + //Now Programm SubordinateBusNo reg + bus=(UINT8)(ext->Res[rtBus].Base+ext->Res[rtBus].Length-1); + return SetSubBus(Brg, bus); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CheckPciCompatibility() +// +// Description: This function will check if PCI "Device" listed in Bad PCI +// Device Table - gBadPciDevList[]. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// PCI_BAR_TYPE BarType Type of Bar Register. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO; PCI_BAR_TYPE. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +PCI_BAD_BAR *CheckPciCompatibility(PCI_DEV_INFO *Device, PCI_BAR *Bar, PCI_BAR_TYPE BarType) //(EIP41687) +{ + UINTN i; + PCI_BAD_BAR *bbp; + PCI_DEV_ID d,t; +//----------------------- + d.DEV_VEN_ID=Device->DevVenId.DEV_VEN_ID; + for(i=0; i<gBadPciDevCount; i++){ + bbp=&gBadPciDevList[i]; + //(EIP41687)> + if(Bar) { + if (bbp->BarOffset) { + if (Bar->Offset != bbp->BarOffset) continue; + } + } + //<(EIP41687) + t.VenId=bbp->VendorId; + t.DevId=bbp->DeviceId & bbp->DevIdMask; + d.DevId=Device->DevVenId.DevId & bbp->DevIdMask; + if(d.DEV_VEN_ID==t.DEV_VEN_ID){ + if(BarType) { + if(BarType==bbp->BarType) return bbp; + } else return bbp; + } + } + return NULL; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AdjustBarGra() +// +// Description: This function will Check and Adjust PCI Device's BAR +// Granularity according information found in gBadPciDevList[]. +// +// Input: +// PCI_BAR Bar Type of Bar Register. +// +// Output: NOTHING +// +// Referals: PCI_BAR; PCI_BAR_TYPE; gBadPciDevList. +// +// Notes: +// This function will be invoked only if PCI Device owning this BAR is in +// gBadPciDevList. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID AdjustBarGra(PCI_BAR *Bar){ + UINTN i,s,e; + PCI_BAR_TYPE bt; + PCI_BAD_BAR *bbp; + UINT64 t=0,g=~(Bar->Gran); +//---------------------------- + switch(Bar->Type){ + case tBarIo16: //2 + case tBarIo32: //3 + bt=tBarIo; + s=2; + break; + case tBarMmio32: //4 + case tBarMmio32pf: //5 + case tBarMmio64: //6 + case tBarMmio64pf: //7 + bt=tBarMem; + s=4; + break; + default: + bt=tBarUnused; + s=0; + } + + bbp=CheckPciCompatibility(Bar->Owner,Bar,bt); //(EIP41687) + if(!bbp)bbp=CheckPciCompatibility(Bar->Owner,Bar,tBarMaxType); //(EIP41687) + //this function will be called only if compatibility issue exists with the device + //so bbp must be valid or this is not the BAR which needs Adjustment; + if(!bbp) return; + if(bbp->BarType==tBarMaxType && Bar->Offset!=bbp->BarOffset) return; + + //Here let's do the adjustment... + switch(bbp->IncompType){ + case icBarBad: + for(i=s; i<64; i++){ + //find the very first bit set as 1; + t=Shl64(1,(UINT8)i); + if(g&t)break; + } + //Assume that all other bits must be 1 + e=i; + t=0; + //Generate Granularity value for this BAR + for(i=0;i<e;i++)t|=Shl64(1,(UINT8)i); + if(Bar->Type!= tBarMmio64pf && Bar->Type!=tBarMmio64) t&=0xFFFFFFFF; + Bar->Gran=t; + break; + + case icBarFixedSize: + Bar->Length=bbp->BarLength; + Bar->Gran=bbp->BarLength-1; + break; + + case icNotBar : + Bar->Type=tBarUnused; + Bar->Length=0; + Bar->Gran=0; + break; + + case icBad64BitBar : + if(Bar->Type == tBarMmio64pf) Bar->Type=tBarMmio32pf; + else if (Bar->Type == tBarMmio64) Bar->Type=tBarMmio32; + break; + }//switch + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: OptionRom() +// +// Description: This function will detect PCI Option ROMs BAR requirements. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS OptionRom(PCI_DEV_INFO *Device) +{ + PCI_CFG_ADDR devaddr; + EFI_STATUS Status=0; + UINT32 b32; + PCI_BAR *rombar; +//--------------------------------- + //Our Device still in disable decoding mode which it entered in + //Now Query Expansion ROM reg + // the bit0 is 0 to prevent the enabling of the Rom address decoder + devaddr.ADDR=Device->Address.ADDR; + switch (Device->Type){ + case tPci2PciBrg : devaddr.Addr.Register=PCI_P2P_ROM_BAR; + break; + case tPciDevice : + case tPciHostDev : + devaddr.Addr.Register=PCI_DEV_ROM_BAR; + break; + case tPci2CrdBrg : //this one doesnot have ROM BAR + default : return EFI_SUCCESS; //other devices not suppose to be examined + } + + rombar=&Device->Bar[PCI_MAX_BAR_NO]; + rombar->Offset=devaddr.Addr.Register; + + b32=0xFFFFFFFE; + + //Write query pattern to PCI Rom Bar Register + Status=PciCfg32(Device->RbIo,devaddr,TRUE,&b32); + if(EFI_ERROR (Status)) return Status; + + Status=PciCfg32(Device->RbIo,devaddr,FALSE,&b32); + if(EFI_ERROR (Status)) return Status; + + b32&=0xFFFFFFFE; + if ((b32 != 0) && (b32 != 0xFFFFFFFE)){ + rombar->Type=tBarMmio32; + rombar->Gran=~b32; + rombar->Length=(~b32)+1; + } + + if(Device->Incompatible) AdjustBarGra(rombar); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetDeviceCapabilities() +// +// Description: This function will detect PCI Device Capabilities of the Device's +// Command Cegister and Bridge Command register (if any). +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters are invalid. +// +// Referals: PCI_DEV_INFO. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetDeviceCapabilities(PCI_DEV_INFO *Dev) +{ + PCI_CFG_ADDR addr; + EFI_STATUS Status; + UINT16 oldcmd, tstcmd, oldbc, tstbc=0; + EFI_TPL OldTpl; + UINT8 z, tcls; +//-------------------------------- + + if(Dev->ParentBrg)Dev->Capab=Dev->ParentBrg->Capab; + + addr.ADDR=Dev->Address.ADDR; + tstcmd=(PCI_CMD_IO_SPACE | PCI_CMD_MEMORY_SPACE | PCI_CMD_MEMORY_WRITE_AND_INVALIDATE | + PCI_CMD_BUS_MASTER | PCI_CMD_VGA_PALETTE_SNOOP); + + OldTpl=pBS->RaiseTPL(TPL_HIGH_LEVEL); + + //Set Latency Timer to 20 and Cacheline size to 0 - just in case + addr.Addr.Register=0x0c;//Cacheline size & Latency Timer + Status=PciCfg16(Dev->RbIo,addr,FALSE,&oldcmd); + //PciX devices upon reset initialize Latency Timer reg with value of 0x40 + //regular PCI devices initialize it with 0 + if(!(oldcmd&0xff00)){//so we will program it only for Regular PCI devices + oldcmd=0x2000; + Status=PciCfg16(Dev->RbIo,addr,TRUE,&oldcmd); + if(EFI_ERROR(Status))return Status; + } + addr.Addr.Register=0x04;//Command Reg + + //Read initial value + Status=PciCfg16(Dev->RbIo,addr,FALSE,&oldcmd); + if(EFI_ERROR(Status))return Status; + + //Write cmdval there and see if it supports it; + Status=PciCfg16(Dev->RbIo,addr,TRUE,&tstcmd); + if(EFI_ERROR(Status))return Status; + + //Read it back and see which bits remains set + Status=PciCfg16(Dev->RbIo,addr,FALSE,&tstcmd); + if(EFI_ERROR(Status))return Status; + + //Restore what was there + Status=PciCfg16(Dev->RbIo,addr,TRUE,&oldcmd); + if(EFI_ERROR(Status))return Status; + + if(Dev->Type==tPci2PciBrg){ + //Set Latency Timer to 20 and Cacheline size to 0 - just in case + addr.Addr.Register=0x1b;//Secondary Latency Timer + oldcmd=0x20; + Status=PciCfg8(Dev->RbIo,addr,TRUE,(UINT8*)&oldcmd); + if(EFI_ERROR(Status))return Status; + + addr.Addr.Register=0x3E; //Bridge controll reg + tstbc=(P2P_BRG_CONTROL_ISA | P2P_BRG_CONTROL_VGA | P2P_BRG_CONTROL_VGA_16); + + //Read initial value + Status=PciCfg16(Dev->RbIo,addr,FALSE,&oldbc); + if(EFI_ERROR(Status))return Status; + + //Write cmdval there and see if it supports it; + Status=PciCfg16(Dev->RbIo,addr,TRUE,&tstbc); + if(EFI_ERROR(Status))return Status; + + //Read it back and see which bits remains set + Status=PciCfg16(Dev->RbIo,addr,FALSE,&tstbc); + if(EFI_ERROR(Status))return Status; + + //Restore what was there + Status=PciCfg16(Dev->RbIo,addr,TRUE,&oldbc); + if(EFI_ERROR(Status))return Status; + } + + //Analize tstcmd Value and update Device->Capab; + if(tstcmd & PCI_CMD_IO_SPACE)Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_IO; + else Dev->Capab&=(~EFI_PCI_IO_ATTRIBUTE_IO); + + if(tstcmd & PCI_CMD_MEMORY_SPACE)Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_MEMORY; + else Dev->Capab&=(~EFI_PCI_IO_ATTRIBUTE_MEMORY); + + if(tstcmd & PCI_CMD_BUS_MASTER)Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_BUS_MASTER; + else Dev->Capab&=(~EFI_PCI_IO_ATTRIBUTE_BUS_MASTER); + + if(tstcmd & PCI_CMD_VGA_PALETTE_SNOOP)Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + else Dev->Capab&=(~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO); + +//BUG//BUG//BUG//BUG//BUG//BUG//BUG +// This bits in cmd register does not identically maps to EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE +// if( (tstcmd & PCI_CMD_MEMORY_WRITE_AND_INVALIDATE)||(tstcmd & PCI_CMD_FAST_BACK_TO_BACK) ) +// Dev->Capab|= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE; + + //Check Device Capability on CacheLine Size Register + Dev->Capab|=MY_PCI_IO_ATTRIBUTE_MEM_WR_INVALIDATE; + addr.Addr.Register=0x0c;//Cacheline size & Latency Timer + + //probe Cache Line Size register if it will accept proposed Cache line size + tcls=0xFF; + Status=PciCfg8(Dev->RbIo,addr,TRUE,&tcls); + if(EFI_ERROR(Status))return Status; + + //Read it back and see which bits remains set + Status=PciCfg8(Dev->RbIo,addr,FALSE,&z); + if(EFI_ERROR(Status))return Status; + + tcls=gPciCaheLineSize; + + //we have tested CLS register it will not accept any value we are proposing + if(!( z && (z&(tcls-1)) ))Dev->Capab&=(~MY_PCI_IO_ATTRIBUTE_MEM_WR_INVALIDATE); + else{ + while(!(tcls&z)) tcls=tcls>>1; //same as div 2 + if(tcls<gPciCaheLineSize) gPciCaheLineSize=tcls; + } + //clear the register we will program it later when resources will be allocated + tcls=0; + Status=PciCfg8(Dev->RbIo,addr,TRUE,&tcls); + if(EFI_ERROR(Status))return Status; + + //we have additional work to do if Device is P2P bridge + if(Dev->Type==tPci2PciBrg){ + if(tstbc & P2P_BRG_CONTROL_ISA)Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_ISA_IO; + else Dev->Capab&=(~EFI_PCI_IO_ATTRIBUTE_ISA_IO); + + if(tstbc & P2P_BRG_CONTROL_VGA)Dev->Capab|=( EFI_PCI_IO_ATTRIBUTE_VGA_IO | + EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY|EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO); + else Dev->Capab&=(~(EFI_PCI_IO_ATTRIBUTE_VGA_IO | + EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY|EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)); + if(tstbc & P2P_BRG_CONTROL_VGA_16) Dev->Capab|=( EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | + EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16); + else Dev->Capab&=(~(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)); + + //bridge should support IDE attributes + Dev->Capab|=(EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO); + } else { + //Some special atributes could be supported by PCI devices based on class code + switch (Dev->Class.BaseClassCode){ + case PCI_CL_OLD : + if (Dev->Class.SubClassCode==PCI_CL_OLD_SCL_VGA) + Dev->Capab|=(EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO); + else + Dev->Capab&=(~(EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO)); + break; + case PCI_CL_DISPLAY: + if (Dev->Class.SubClassCode==PCI_CL_DISPLAY_SCL_VGA) + Dev->Capab|=(EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO); + else + Dev->Capab&=(~(EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO)); + + if (Dev->Class.SubClassCode==PCI_CL_DISPLAY_SCL_OTHER) //GFX device can snoop pallete + Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + else Dev->Capab&=(~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO); + break; + case PCI_CL_MASS_STOR : + if(Dev->Class.SubClassCode==PCI_CL_MASS_STOR_SCL_IDE){ + UINT8 pib=Dev->Class.ProgInterface, pif=0; + //--------------- + Dev->Capab|=(EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO|EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO); + //Now if device is IDE controller check PI on order determine how it was programmed + //Just in case overwrite bus master capab if IDE device sets bit 7 in PI Reg + if(Dev->Class.ProgInterface & 0x80) Dev->Capab|=EFI_PCI_IO_ATTRIBUTE_BUS_MASTER; + + //primary Controller in LEGACY mode? + if( !(Dev->Class.ProgInterface & 0x01)){ + if(Dev->HostData->PriIde==NULL){ + //Set the current PCI Device attributes to LEGACY + Dev->Attrib|=EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO; + Dev->HostData->PriIde=Dev; + } else { + //set native mode bit since this Legacy IO space has been taken already + pif++; + pib |= 0x01; + } + } + + //secondary Controller in LEGACY mode? + if( !(Dev->Class.ProgInterface & 0x04) ){ + if(Dev->HostData->SecIde==NULL){ + //Set the current PCI Device attributes to LEGACY + Dev->Attrib|=EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO; + Dev->HostData->SecIde=Dev; + } else { + //set native mode bit since this Legacy IO space has been taken already + pif++; + pib |= 0x04; + } + } + if(pif){ + Status=SetIdeDevMode(Dev, 0,0, &pib); + if(!EFI_ERROR(Status)) Dev->Class.ProgInterface = pib; + } + } else Dev->Capab&=(~(EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO|EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO)); + + break; + }//switch; + } + + //device caps should not exsceed parent; + if(Dev->Capab & EFI_PCI_IO_ATTRIBUTE_IO) + Dev->Capab|=(EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO | EFI_PCI_IO_ATTRIBUTE_ISA_IO); + else + Dev->Capab&=(~(EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO | EFI_PCI_IO_ATTRIBUTE_ISA_IO)); + + pBS->RestoreTPL(OldTpl); + PCI_TRACE((TRACE_PCI, "Supported Attributes -> 0x%lX\n", Dev->Capab)); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindFirstBit(UINT64 Value, BOOLEAN Set, BOOLEAN Right2Left) +// +// Description: This function will find first bit Set or Reset +// going Left to Right. +// +// Input: +// UINT64 Value Value to scan. +// BOOLEAN Set What condition to test +// Output: +// UINT8 First bit set/reset +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 FindFirstBit(UINT64 Value, BOOLEAN Set){ + UINT64 msk=1, iv=~Value; + UINT8 bit; +//--------------------- + for(bit=0;bit<64;bit++){ + msk=Shl64(1,bit); + if(Set) { + if( (Value & msk) == msk ) break; + } else { + if(( iv & msk ) == msk ) break; + } + } + if(bit==64) bit=0xFF; + return bit; +} + +/////////////////////////////////////////////////////////////// +// Capability pointers operation Including PCI Express... +/////////////////////////////////////////////////////////////// + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetPciCapPtrs() +// +// Description: This function will collect information about PCI "Device" +// Capability Headers (Including PCI Express, Hot Plug and PCI-X/X2) and +// record them. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When Device not present in the system. +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When some of the parameters - invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetPciCapPtrs(PCI_DEV_INFO *Device) +{ + PCI_CFG_ADDR devaddr; + EFI_STATUS Status=0; + EFI_PCI_CAPABILITY_HDR cp; + UINT16 sr; +//------------------------------- + devaddr.ADDR=Device->Address.ADDR; + devaddr.Addr.Register=0x06; //Status Register; + //bit 4 in status register is set if device supports capabilities pointer + Status=PciCfg16(Device->RbIo,devaddr,FALSE,&sr); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + if(!(sr&0x10)) return Status; //no reason to continue - capabilities is not supported! + + //if device Supports Capabilityes + cp.CAP_HDR=0; + if(Device->Type==tPci2CrdBrg) devaddr.Addr.Register=EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR; + else devaddr.Addr.Register=EFI_PCI_CAPABILITY_PTR; + + Status=PciCfg8(Device->RbIo,devaddr,FALSE,&cp.NextItemPtr); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //we got something here. + while(cp.NextItemPtr) + { + devaddr.Addr.Register=cp.NextItemPtr; + + Status=PciCfg16(Device->RbIo,devaddr,FALSE,&cp.CAP_HDR); + ASSERT_EFI_ERROR(Status); + if(cp.CapabilityID==PCI_CAP_ID_PMI) Device->PmiCapOffs=devaddr.Addr.Register; + +//Enables PCI Express Handling only if PCI Express Base is Defined and !=0 +#if PCI_EXPRESS_SUPPORT + + if(cp.CapabilityID==PCI_CAP_ID_PCIEXP){ + Device->PciExpress=MallocZ(sizeof(PCIE_DATA)); + ASSERT(Device->PciExpress); + if(!Device->PciExpress) return EFI_OUT_OF_RESOURCES; + + //Save Current Offset of PCIE Std Compatibility Registers Block + Device->PciExpress->PcieOffs=devaddr.Addr.Register; + Device->PciExpress->Owner=Device; + } +#endif + +#if HOTPLUG_SUPPORT + if(cp.CapabilityID==PCI_CAP_ID_HOTPLUG){ + //we may process this controller as root HPC so check that. + if(!Device->HotPlug){ + Device->HotPlug=MallocZ(sizeof(PCI_HPC_INFO)); + ASSERT(Device->HotPlug); + if(!Device->HotPlug) return EFI_OUT_OF_RESOURCES; + + //Save Current Offset of PCIE Std Compatibility Registers Block + Device->HotPlug->HpcLocation->HpcDevicePath=Device->DevicePath; + Device->HotPlug->HpcLocation->HpcDevicePath=Device->DevicePath; + Device->HotPlug->HpcPciAddr.ADDR=Device->Address.ADDR; + Device->HotPlug->HpbBridge=Device; + Device->HotPlug->BusFound=TRUE; + //For SHPC it must be initialized and enabled by hardware + Device->HotPlug->HpcState=EFI_HPC_STATE_INITIALIZED|EFI_HPC_STATE_ENABLED; + Device->HotPlug->HpcOffs=devaddr.Addr.Register; + Device->HotPlug->Owner=Device; + } + } +#endif + +//this is for feautufe use if we will support BootTime hotplug events +#if PCI_X_SUPPORT + if(cp.CapabilityID==PCI_CAP_ID_PCIX){ + + Device->PciX=MallocZ(sizeof(PCIX_DATA)); + ASSERT(Device->PciX); + if(!Device->PciX) return EFI_OUT_OF_RESOURCES; + + //fill out fields within PciX structure + devaddr.Addr.Register=Device->PciX->PcixOffs+PCIX_DEV_STA_OFFSET; + Status=PciCfg32(Device->RbIo, devaddr, FALSE, &Device->PciX->PcixDevStatus.DEV_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + devaddr.Addr.Register=Device->PciX->PcixOffs+PCIX_SEC_STA_OFFSET; + Status=PciCfg16(Device->RbIo, devaddr, FALSE, &Device->PciX->PcixSecStatus.SEC_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + Device->PciX->PcixOffs=devaddr.Addr.Register; + Device->PciX->Owner=Device; + + } +#endif + } + return Status; +} + +//---------------------------------------------------------------------------- +//Enable PCI Express Handling only if PCI Express Base is Defined and !=0 +#if PCI_EXPRESS_SUPPORT +////////////////////////////////////////////////////////////////////////////// +//---------------------------------------------------------------------------- +// PCI Express Helper Functions +//---------------------------------------------------------------------------- +////////////////////////////////////////////////////////////////////////////// +EFI_STATUS PcieDoubleCheckCard(PCI_DEV_INFO *Brg, PCI_CFG_ADDR *DevAddr, UINT32 *VenDevId){ + EFI_STATUS Status; + PCI_CFG_ADDR addr; + PCIE_SLT_STA_REG slts; +// PCIE_LNK_STA_REG lnks; +// PCIE_DEV_STA_REG devs; +//------------------------ + + + //Read PCIe.DEV_STA_REG; + addr.ADDR=Brg->Address.ADDR; +/* + addr.Addr.Register=Brg->PciExpress->PcieOffs+PCIE_DEV_STA_OFFSET; + Status=PciCfg16(Brg->RbIo, addr, FALSE, &devs.DEV_STA); + ASSERT_EFI_ERROR(Status); + + //Read PCIe.LNK_STA_REG; + addr.Addr.Register=Brg->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + Status=PciCfg16(Brg->RbIo, addr, FALSE, &lnks.LNK_STA); + ASSERT_EFI_ERROR(Status); +*/ + //Read PCIe.SLT_STA_REG; + addr.Addr.Register=Brg->PciExpress->PcieOffs+PCIE_SLT_STA_OFFSET; + Status=PciCfg16(Brg->RbIo, addr, FALSE, &slts.SLT_STA); + ASSERT_EFI_ERROR(Status); + +/* + TRACE((-1, "\n!!!!!!DEV_STA[ 0x%X ].TrasactPend(5)=%d;\n",devs.DEV_STA, devs.TrasactPend)); + TRACE((-1, "!!!!!!LNK_STA[0x%X].LnkTraining(11)=%d;\n",lnks.LNK_STA, lnks.LnkTraining)); + TRACE((-1, "!!!!!!SLT_STA[%X].CardPresent(6)=%d;\n",slts.SLT_STA, slts.CardPresent)); + TRACE((-1, "!!!!!!for the BRIDGE @ [B%X|D%X|F%X];\n",Brg->Address.Addr.Bus,Brg->Address.Addr.Device, Brg->Address.Addr.Function)); + TRACE((-1, "!!!!!!VID/DID=%X of [B%X|D0|F0]\n",*VenDevId, addr.Addr.Bus)); +*/ + + //if we are here that means card did not come up first time... + //so try to read it one more time, before taking some invasive actions. + addr.ADDR = DevAddr->ADDR; + addr.Addr.Register=0; + + //SOMETHING present there, but need some time to completely come up + if(slts.CardPresent != 0 || slts.PresenceDet !=0 ){ + UINTN i; + //--------- + for(i=0; i<=gPciSetupData->LnkTrRetry; i++){ + + Status=PciCfg32(Brg->RbIo, addr, FALSE, VenDevId); + ASSERT_EFI_ERROR(Status); + if( (*VenDevId) != 0xFFFFFFFF ) break; + + //Use same setup value for retry timeut and number + pBS->Stall(gPciSetupData->LnkTrTimeout*100); + } +// TRACE((-1, "!!!!!!VID/DID=%X after %d retry (timeout=%d) \n",*VenDevId, i+1, gPciSetupData->LnkTrTimeout*100)); + } + + //If nothing workeded just exit... + return Status; +} + +/////////////////////////////////////////////////////////////////////////////// +//Exclude support fot PCIe GEN2 to save space in projects w/o PCIE_GEN2 +#if PCI_EXPRESS_GEN2_SUPPORT + + +/////////////////////////////////////////////////////////////////////////////// +//Exclude support fot PCIe GEN3 to save space in projects w/o PCIE_GEN3 +#if PCI_EXPRESS_GEN3_SUPPORT //GEN3 support is a subset of GEN2 support!!! + +EFI_STATUS Pcie3EqualizeLink(PCI_DEV_INFO *Device, BOOLEAN *LnkRetrain){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_CFG_ADDR addr; + PCIE_LNK_CNT3_REG LnkCnt3; + PCIE_LNK_STA2_REG LnkSta2; +//----------------------------- + + //If device don't have GEN 3 Cap Hdr, or link is operating on lell then 8.0 GT/s speed - just exit... + if(Device->PciExpress->Pcie3==NULL) return EFI_SUCCESS; + + //Get LNK_STA2 regiser + addr.ADDR=Device->Address.ADDR; + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_STA2_OFFSET; + Status=PciCfg16(Device->RbIo, addr, FALSE,&LnkSta2.LNK_STA2); + ASSERT_EFI_ERROR(Status); + + //Display Content of the LNK_STA2 register. + PCI_TRACE((TRACE_PCI," LNK_STA2-> [R=%X|EqReq=%X|EqP3=%X|EqP2=%X|EqP1=%X|EqCompl=%X|SelDeEmp=%X]\n", + LnkSta2.Reserved, + LnkSta2.EqRequest, + LnkSta2.EqPhase3Ok, + LnkSta2.EqPhase2Ok, + LnkSta2.EqPhase1Ok, + LnkSta2.EqComplete, + LnkSta2.SelDeEmphasis)); + + //Check if equalization was requested or we are about to enter lLNK training session... + if(LnkSta2.EqRequest || *LnkRetrain){ + + PCI_TRACE((TRACE_PCI," PciE3: Equalization for Device @ [B%X|D%X|F%X] LnkRetrain=%X Before\n", + addr.Addr.Bus,addr.Addr.Device,addr.Addr.Function, *LnkRetrain)); + //read Lnk Control 3 register in Sec PCIe Ext Cap Header. + addr.Addr.ExtendedRegister=Device->PciExpress->Pcie3->SecPcieCapOffs+PCIE_LNK_CNT3_OFFSET; + Status=PciCfg32(Device->RbIo, addr, FALSE,&LnkCnt3.LNK_CNT3); + ASSERT_EFI_ERROR(Status); + + //Set Prform Equalization bit and disable Equalization Request Interrupt, just in case. + LnkCnt3.LnkEqReqIntEn=0; + LnkCnt3.PerformEqualiz=1; + + //Write it back into LNK_CNT3 register. + Status=PciCfg32(Device->RbIo, addr, TRUE, &LnkCnt3.LNK_CNT3); + ASSERT_EFI_ERROR(Status); + + *LnkRetrain=TRUE; + + //Display Content of the LNK_CNT3 register. + PCI_TRACE((TRACE_PCI," LNK_CNT3-> [R=%X|LnkEqReqIntEn=%X|DoEq=%X] LnkRetrain=%X After\n", + LnkCnt3.Reserved, + LnkCnt3.LnkEqReqIntEn, + LnkCnt3.PerformEqualiz, + *LnkRetrain)); + + } + return Status; +} + + +EFI_STATUS Pcie3GetEqualizationStatus(PCI_DEV_INFO *Device){ + PCI_CFG_ADDR addr; + PCIE_LNK_STA2_REG LnkSta2; + EFI_STATUS Status=EFI_SUCCESS; +//----------------------------- + + //If device don't have GEN 3 Cap Hdr, or link is operating on lell then 8.0 GT/s speed - just exit... + if(Device->PciExpress->Pcie3==NULL) return EFI_SUCCESS; + + //Get LNK_STA2 regiser + addr.ADDR=Device->Address.ADDR; + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_STA2_OFFSET; + Status=PciCfg16(Device->RbIo, addr, FALSE,&LnkSta2.LNK_STA2); + ASSERT_EFI_ERROR(Status); + + //Display Content of the LNK_STA2 register. + PCI_TRACE((TRACE_PCI,"Pcie3-> Checking Equalization Status...\n LNK_STA2-> [R=%X|EqReq=%X|EqP3=%X|EqP2=%X|EqP1=%X|EqCompl=%X|SelDeEmp=%X]\n", + LnkSta2.Reserved, + LnkSta2.EqRequest, + LnkSta2.EqPhase3Ok, + LnkSta2.EqPhase2Ok, + LnkSta2.EqPhase1Ok, + LnkSta2.EqComplete, + LnkSta2.SelDeEmphasis)); + + //Check equalization sesults... + if (LnkSta2.EqComplete) return EFI_SUCCESS; + + //Check if any of the equalization phases were completed... + if(LnkSta2.LNK_STA2 & 0x1C) return EFI_NOT_AVAILABLE_YET; + + return EFI_DEVICE_ERROR; +} + +#endif //GEN3 + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Pcie2GetGen2Info() +// +// Description: This function will collect information about PCIE GEN2 Device +// and initialize PCIE2_DATA structure based on information collected. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS Pcie2GetGen2Info(PCI_DEV_INFO *Device){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_CFG_ADDR addr; +//----------------------------- + addr.ADDR=Device->Address.ADDR; + //PCI_TRACE((TRACE_PCI," PciE2: Device @ [B%X|D%X|F%X] is PCIE GEN2 Device:\n", + // addr.Addr.Bus,addr.Addr.Device,addr.Addr.Function)); + + //Get PCI Express Device CAP2 - 32 bit + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_DEV_CAP2_OFFSET; + Status=PciCfg32(Device->RbIo, addr, FALSE,&Device->PciExpress->Pcie2->DeviceCap2.DEV_CAP2); + ASSERT_EFI_ERROR(Status); + + PCI_TRACE((TRACE_PCI," DEV_CAP2-> [R2=%X|MEEP=%X|EETP=%X|EFF=%X|R1=%X|TPH=%X|LTR=%X|NRP=%X|C128=%X|AtC64=%X|AtC32=%X|AtR=%X|Ari=%d|CTD=%X|CmTO=%X]\n", + Device->PciExpress->Pcie2->DeviceCap2.Reserved2, + Device->PciExpress->Pcie2->DeviceCap2.MaxEndEndPrefix, + Device->PciExpress->Pcie2->DeviceCap2.EndEndTlpPrefix, + Device->PciExpress->Pcie2->DeviceCap2.ExtFmtField, + Device->PciExpress->Pcie2->DeviceCap2.Reserved1, + Device->PciExpress->Pcie2->DeviceCap2.TphCompleter, + Device->PciExpress->Pcie2->DeviceCap2.LtrMechanism, + Device->PciExpress->Pcie2->DeviceCap2.NoRoPrPrPassing, + Device->PciExpress->Pcie2->DeviceCap2.Cas128Completer, + Device->PciExpress->Pcie2->DeviceCap2.AtomicOpCompl64, + Device->PciExpress->Pcie2->DeviceCap2.AtomicOpCompl32, + Device->PciExpress->Pcie2->DeviceCap2.AtomicOpRouting, + Device->PciExpress->Pcie2->DeviceCap2.AriForwarding, + Device->PciExpress->Pcie2->DeviceCap2.ComplToutDisable, + Device->PciExpress->Pcie2->DeviceCap2.ComplToutRanges)); + + //Get PCI Express Link CAP2 - 32 bit + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CAP2_OFFSET; + Status=PciCfg32(Device->RbIo, addr, FALSE,&Device->PciExpress->Pcie2->LinkCap2.LNK_CAP2); + ASSERT_EFI_ERROR(Status); + + if(Device->PciExpress->PcieCap.SlotImpl){ + //Get PCI Express Link SLOT2 - 32 bit + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_SLT_CAP2_OFFSET; + Status=PciCfg32(Device->RbIo, addr, FALSE,&Device->PciExpress->Pcie2->SlotCap2.SLT_CAP2); + ASSERT_EFI_ERROR(Status); + } + +#if PCI_EXPRESS_GEN3_SUPPORT + //Do some additional checks if device has GEN 3 Secondary PCIe Cap Header. + //At that point if we have discovered Sec PCIe Cap HDR Defice->PciExpress->Pcie3 must be initializad. + if(Device->PciExpress->Pcie3 != NULL){ + + + //Update Speed encoding it is defined differently for devices Supporting V3.0 spec. + + Device->PciExpress->Pcie3->MaxLanesCount=Device->PciExpress->LinkCap.MaxLnkWidth; + + //Display first LNK_CAP2_REG + PCI_TRACE((TRACE_PCI,"PCIe3 -> Device is PCIe v3.0 Compliant!!! LNK_CAP2 present!!! \n LNK_CAP2-> [R2=%X|CrossL=%X|SuppLnkSpeedVect=%X|R1=%X]; LANE_ERR_STA->[%X]; MaxLanes=%X\n", + Device->PciExpress->Pcie2->LinkCap2.Reserved2, + Device->PciExpress->Pcie2->LinkCap2.CrossLnk, + Device->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds, + Device->PciExpress->Pcie2->LinkCap2.Reserved1, + Device->PciExpress->Pcie3->LaneErrSts, + Device->PciExpress->Pcie3->MaxLanesCount)); + + } +#endif + + Device->PciExpress->Pcie2->Owner=Device; + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Pcie2EnableAri() +// +// Description: This function will Enable ARI Forwarding in DownSream Port of +// the device passed if +// 1.Device referenced is an ARI device; +// 2.Parenting Bridge supports ARI Forwarding. +// 3.ARI Firvarding Setup Question Set to "Enabled" +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When Device or Parenting Bridge does not support ARI +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS Pcie2EnableAri(PCI_DEV_INFO *Device){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_DEV_INFO *brg; + PCI_CFG_ADDR addr; + PCIE_DEV_CNT2_REG dcnt2; +//----------------------------------- + //Setup Don't have it enabled + if(gPciSetupData->AriFwd == 0) { + PCI_TRACE((TRACE_PCI," -> Setup=%d", gPciSetupData->AriFwd)); + return EFI_UNSUPPORTED; + } + + if(Device->Type != tPciDevice) { + PCI_TRACE((TRACE_PCI," -> not tDevice Type", gPciSetupData->AriFwd)); + return EFI_UNSUPPORTED; + } + + if(Device->PciExpress == NULL) { + PCI_TRACE((TRACE_PCI," -> not PCIe Device", gPciSetupData->AriFwd)); + return EFI_UNSUPPORTED; + } + + //Device don't have ARI Ext Cap + if(Device->PciExpress->AriData==NULL){ + PCI_TRACE((TRACE_PCI," -> non-ARI Device")); + return EFI_UNSUPPORTED; + } + //If we are here - device is an ARI Device. Now check if Parenting Bridge can do it... + brg=Device->ParentBrg; + //Check if Parenting Brg is Gen 2 device + if(brg->PciExpress->Pcie2==NULL){ + PCI_TRACE((TRACE_PCI," -> ParentBrg non-GEN2")); + return EFI_UNSUPPORTED; + } + + //Check if bridge can do ARI Forvarding + if(brg->PciExpress->Pcie2->DeviceCap2.AriForwarding==0){ + PCI_TRACE((TRACE_PCI," -> ParentBrg.Cap.AriFwd=0")); + return EFI_UNSUPPORTED; + } + + //Now check if this bridge has ARI Forwarding Enabled allready + if(brg->PciExpress->Pcie2->AriEnabled==TRUE){ + //Set Device ARI Falg + Device->PciExpress->Pcie2->AriEnabled=brg->PciExpress->Pcie2->AriEnabled; + PCI_TRACE((TRACE_PCI," -> Parent Bridge AriEnabled=1")); + return EFI_SUCCESS; + } + + //At that Point we must enable ARI. + addr.ADDR=brg->Address.ADDR; + addr.Addr.Register=brg->PciExpress->PcieOffs+PCIE_DEV_CNT2_OFFSET; + Status=PciCfg16(brg->RbIo, addr, FALSE,&dcnt2.DEV_CNT2); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + + dcnt2.AriForwarding=TRUE; + PCI_TRACE((TRACE_PCI," ARI -> Enabling ARI for Parent Bridge!")); + Status=PciCfg16(Device->RbIo, addr, TRUE,&dcnt2.DEV_CNT2); + ASSERT_EFI_ERROR(Status); + + + if(EFI_ERROR(Status)) return Status; + + Device->PciExpress->Pcie2->AriEnabled=(BOOLEAN)dcnt2.AriForwarding; + brg->PciExpress->Pcie2->AriEnabled=(BOOLEAN)dcnt2.AriForwarding; + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Pcie2CheckAri() +// +// Description: This function will Enable ARI Forwarding in DownSream Port of +// the device passed if +// 1.Device referenced is an ARI device; +// 2.Parenting Bridge supports ARI Forwarding. +// 3.ARI Firvarding Setup Question Set to "Enabled" +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// BOOLEAN *MultiFunc Pointer to a Flag to modify if Device is MF Device +// BOOLEAN *AriEnabled Pointer to a Flag to modify if this function was able to ENABLE ARI. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS Pcie2CheckAri(PCI_DEV_INFO *Device, BOOLEAN *MultiFunc, BOOLEAN *AriEnabled){ + EFI_STATUS Status; +//-------------------- + PCI_TRACE((TRACE_PCI," PciE2: Checking ARI @ [B%X|D%X|F%X]:", + Device->Address.Addr.Bus,Device->Address.Addr.Device,Device->Address.Addr.Function)); + + Status=Pcie2EnableAri(Device); + PCI_TRACE((TRACE_PCI," Status=%r\n",Status)); + + if((!EFI_ERROR(Status)) && + (Device->PciExpress->AriData!=NULL) && + (Device->PciExpress->Pcie2->AriEnabled==TRUE)) + { + *MultiFunc=TRUE; + *AriEnabled=TRUE; + } else { + if(Status==EFI_UNSUPPORTED){ + *AriEnabled=FALSE; + Status=EFI_SUCCESS; + } + } + + //PCI_TRACE((TRACE_PCI," AriEn=%d %r\n\n",*AriEnabled, Status)); + + return Status; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Pcie2SetLnkProperties() +// +// Description: This function will Select values for Link Control2 register on +// both sides of the LINK based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *DnStreamPort Pointer to PCI Device Private Data of Downstream Port of the link. +// PCIE_LNK_CNT2_REG *DnLnkCnt2 Pointer to the LNK_CNT2 Reg of the Downstream Port of the link. +// PCI_DEV_INFO *UpStreamPort Pointer to PCI Device Private Data of Upwnstream Port of the link. +// PCIE_LNK_CNT2_REG *UpLnkCnt2 Pointer to the LNK_CNT2 Reg of the Downstream Port of the link. +// BOOLEAN *LinkHotResetRequired Flag to modify if Link will need HOT RESET after programming. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS Pcie2SetLnkProperties(PCI_DEV_INFO *DnStreamPort, + PCIE_LNK_CNT2_REG *DnLnkCnt2, + PCI_DEV_INFO *UpStreamPort, + PCIE_LNK_CNT2_REG *UpLnkCnt2, + BOOLEAN *LinkHotResetRequired, + BOOLEAN *LinkRetrainRequired ) +{ + EFI_STATUS Status; + PCIE_LNK_STA_REG dnls, upls; //link status reg content of up and down side of the link + PCI_CFG_ADDR addr; + UINT16 ls, maxls, curls;//link speed variables +//------------------------------ + + PCI_TRACE((TRACE_PCI,"PciE2: Pcie2SetLnkProperties() ENTRY:\n")); + + //Get DownStream Port Properties + addr.ADDR=DnStreamPort->Address.ADDR; + + PCI_TRACE((TRACE_PCI," DN STREAM PORT -> [B%X|D%X|F%X] <--> [B%X|D%X|F%X] <- UP STREAM PORT\n", + DnStreamPort->Address.Addr.Bus,DnStreamPort->Address.Addr.Device, DnStreamPort->Address.Addr.Function, + UpStreamPort->Address.Addr.Bus,UpStreamPort->Address.Addr.Device, UpStreamPort->Address.Addr.Function)); + + addr.Addr.Register=DnStreamPort->PciExpress->PcieOffs+PCIE_LNK_CNT2_OFFSET; + Status=PciCfg16(DnStreamPort->RbIo,addr,FALSE, &DnLnkCnt2->LNK_CNT2); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI," LNK_CNT2-> [CmDe=%X|CmSOS=%X|ECm=%X|TrM=%X|SlDe=%X|AuSp=%X|EnCm=%X|TLS=%X]\n", + DnLnkCnt2->ComplDeEmphasis, + DnLnkCnt2->ComplianceSos, + DnLnkCnt2->EnterModCompl, + DnLnkCnt2->TrsMargin, + DnLnkCnt2->SelDeEmphasis, + DnLnkCnt2->HwAutoSpeedDis, + DnLnkCnt2->EnterCompliance, + DnLnkCnt2->TargetLnkSpeed)); + + + addr.Addr.Register=DnStreamPort->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + Status=PciCfg16(DnStreamPort->RbIo,addr,FALSE, &dnls.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Get UpStream Stream Port Properties + addr.ADDR=UpStreamPort->Address.ADDR; + + //PCI_TRACE((TRACE_PCI," UP STREAM PORT @ [B%X|D%X|F%X]:\n", + // addr.Addr.Bus,addr.Addr.Device, addr.Addr.Function)); + + addr.Addr.Register=UpStreamPort->PciExpress->PcieOffs+PCIE_LNK_CNT2_OFFSET; + Status=PciCfg16(UpStreamPort->RbIo,addr,FALSE, &UpLnkCnt2->LNK_CNT2); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI," LNK_CNT2-> [CmDe=%X|CmSOS=%X|ECm=%X|TrM=%X|SlDe=%X|AuSp=%X|EnCm=%X|TLS=%X]\n ....... UPDATINNG .......\n", + UpLnkCnt2->ComplDeEmphasis, + UpLnkCnt2->ComplianceSos, + UpLnkCnt2->EnterModCompl, + UpLnkCnt2->TrsMargin, + UpLnkCnt2->SelDeEmphasis, + UpLnkCnt2->HwAutoSpeedDis, + UpLnkCnt2->EnterCompliance, + UpLnkCnt2->TargetLnkSpeed)); + + //Get Lnk Status Content... + addr.Addr.Register=UpStreamPort->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + Status=PciCfg16(UpStreamPort->RbIo,addr,FALSE, &upls.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + + //Check link Speed selected in Setup and calculate applcable Link speed... + //get max possible link speed + maxls=DnStreamPort->PciExpress->LinkCap.MaxLnkSpeed; + if(maxls>UpStreamPort->PciExpress->LinkCap.MaxLnkSpeed) maxls=UpStreamPort->PciExpress->LinkCap.MaxLnkSpeed; + + //get the current speed of the link... + curls=DnStreamPort->PciExpress->CurrLnkSpeed; + //must be the same on both sides of the link + ASSERT(curls==UpStreamPort->PciExpress->CurrLnkSpeed); + + if(maxls>=PCIE_LINK_SPEED_80G){ + if(DnStreamPort->PciExpress->Pcie3==NULL || UpStreamPort->PciExpress->Pcie3==NULL) + maxls=PCIE_LINK_SPEED_50G; + } + + //Check Link Speed setup options... + //AUTO==55 + ls=curls; + if(gPciSetupData->LnkSpeed==55)ls=maxls; + + //Force 5.0GT/s == 2 + if(gPciSetupData->LnkSpeed==2){ + //check if it is supported + if(DnStreamPort->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds!=0){ + //if device is compatible with V3.0 spec it must report supported speeds + if(DnStreamPort->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds & PCIE_LINK_SPEED_VECT_50G) ls=PCIE_LINK_SPEED_50G; + } else { + //for devices compliand to spec v 2.1 check maxls value + if(maxls>=PCIE_LINK_SPEED_50G) ls=PCIE_LINK_SPEED_50G; + } + } + + //Force 2.5GT/s == 1 + if(gPciSetupData->LnkSpeed==1){ + //check if it is supported + if(DnStreamPort->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds!=0){ + //if device is compatible with V3.0 spec it must report supported speeds + if(DnStreamPort->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds & PCIE_LINK_SPEED_VECT_25G)ls=PCIE_LINK_SPEED_25G; + } else { + //for devices compliand to spec v 2.1 check maxls value + if(maxls>=PCIE_LINK_SPEED_25G) ls=PCIE_LINK_SPEED_25G; + } + } + + PCI_TRACE((TRACE_PCI," LNK SPEED SETTINGS: MaxLS=%X; CurrentLS=%X; SelectedLS=%X; Setup=%d\n", + maxls,curls,ls, gPciSetupData->LnkSpeed )); + + //Call porting hook to override link speed settings. + Status=PciPortOemSetLnkSpeed(DnStreamPort, (UINT8*)&ls, (UINT8)DnStreamPort->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds); + //one more time for Upstreamport + Status=PciPortOemSetLnkSpeed(UpStreamPort, (UINT8*)&ls, (UINT8)UpStreamPort->PciExpress->Pcie2->LinkCap2.SuppLnkSpeeds); + + //now check if curls different from ls + if(ls<curls){ +// DnLnkCnt2->EnterCompliance=TRUE; +// UpLnkCnt2->EnterCompliance=TRUE; +// *LinkHotResetRequired=TRUE; + *LinkRetrainRequired=TRUE; + } + + if(ls>curls){ + *LinkRetrainRequired=TRUE; +// *LinkHotResetRequired=TRUE; + } + + //Set selected speed on both sides of the link + DnLnkCnt2->TargetLnkSpeed=ls; + UpLnkCnt2->TargetLnkSpeed=ls; + + //Check; HwAutoSpeedDis; HwAutoWidth settings + DnLnkCnt2->HwAutoSpeedDis=gPciSetupData->HwAutoSpeed; + UpLnkCnt2->HwAutoSpeedDis=gPciSetupData->HwAutoSpeed; + + PCI_TRACE((TRACE_PCI," LNK_CNT2-> [CmDe=%X|CmSOS=%X|ECm=%X|TrM=%X|SlDe=%X|AuSp=%X|EnCm=%X|TLS=%X]\n", + DnLnkCnt2->ComplDeEmphasis, + DnLnkCnt2->ComplianceSos, + DnLnkCnt2->EnterModCompl, + DnLnkCnt2->TrsMargin, + DnLnkCnt2->SelDeEmphasis, + DnLnkCnt2->HwAutoSpeedDis, + DnLnkCnt2->EnterCompliance, + DnLnkCnt2->TargetLnkSpeed)); + + PCI_TRACE((TRACE_PCI," LNK_CNT2-> [CmDe=%X|CmSOS=%X|ECm=%X|TrM=%X|SlDe=%X|AuSp=%X|EnCm=%X|TLS=%X]\n\n", + UpLnkCnt2->ComplDeEmphasis, + UpLnkCnt2->ComplianceSos, + UpLnkCnt2->EnterModCompl, + UpLnkCnt2->TrsMargin, + UpLnkCnt2->SelDeEmphasis, + UpLnkCnt2->HwAutoSpeedDis, + UpLnkCnt2->EnterCompliance, + UpLnkCnt2->TargetLnkSpeed)); + + +#if PCI_EXPRESS_GEN3_SUPPORT + if(DnStreamPort->PciExpress->Pcie3!=NULL && UpStreamPort->PciExpress->Pcie3!=NULL){ + + if(ls >=PCIE_LINK_SPEED_80G) { + Status=Pcie3EqualizeLink(DnStreamPort, LinkRetrainRequired); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + //Equalize link must be set for Upstream Port if it has closslink + if(UpStreamPort->PciExpress->Pcie2->LinkCap2.CrossLnk){ + Status=Pcie3EqualizeLink(UpStreamPort, LinkRetrainRequired); + ASSERT_EFI_ERROR(Status); + } + } + } +#endif + + return Status; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Pcie2SelectComplTimeOut() +// +// Description: This function will select appropriate Completion Timeout range +// from supported by the device. +// +// Input: +// UINT32 Support Supported by Device Completion Timeout ranges. +// BOOLEAN Short A Flag to Indicate wahat type of ranges to select Biggest or Smallest +// +// Output: UINT16 +// Value to be programmed in DEV_CNT2 Register. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT16 Pcie2SelectComplTimeOut(UINT32 Support, BOOLEAN Short){ + //Completion Timeout Programability is not supported by HW. + if(Support==0) return 0; + + if(Short){ + //It is strongly recommended that the Completion Timeout + //mechanism not expire in less than 10 ms + + //Values available if Range A (50 mks to 10 ms) programmability range is supported: + // 0001b 50 mks to 100 mks; 0010b; 1 ms to 10 ms + if(Support & PCIE_CAP2_RANGE_A) return 0x2; + + //Values available if Range B (10 ms to 250 ms) programmability range is supported: + // 0101b 16 ms to 55 ms; 0110b 65 ms to 210 ms + if(Support & PCIE_CAP2_RANGE_B) return 0x5; + + //Values available if Range C (250 ms to 4 s) programmability range is supported: + // 1001b 260 ms to 900 ms; 1010b 1 s to 3.5 s + if(Support & PCIE_CAP2_RANGE_C) return 0x9; + + //Values available if the Range D (4 s to 64 s) programmability range is supported: + // 1101b 4 s to 13 s; 1110b 17 s to 64 s + if(Support & PCIE_CAP2_RANGE_D) return 0xD; + + } else { + //Values available if the Range D (4 s to 64 s) programmability range is supported: + // 1101b 4 s to 13 s; 1110b 17 s to 64 s + if(Support & PCIE_CAP2_RANGE_D) return 0xE; + + //Values available if Range C (250 ms to 4 s) programmability range is supported: + // 1001b 260 ms to 900 ms; 1010b 1 s to 3.5 s + if(Support & PCIE_CAP2_RANGE_C) return 0xA; + + //Values available if Range B (10 ms to 250 ms) programmability range is supported: + // 0101b 16 ms to 55 ms; 0110b 65 ms to 210 ms + if(Support & PCIE_CAP2_RANGE_B) return 0x6; + + //Values available if Range A (50 mks to 10 ms) programmability range is supported: + // 0001b 50 mks to 100 mks; 0010b; 1 ms to 10 ms + if(Support & PCIE_CAP2_RANGE_A) return 0x2; + } + return 0; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Pcie2SetDevProperties() +// +// Description: This function will Select values for DEVICE CCONTROL2 register +// based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *DnStreamPort Pointer to PCI Device Private Data of Downstream Port of the link. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS Pcie2SetDevProperties(PCI_DEV_INFO *Device){ + EFI_STATUS Status; + PCI_CFG_ADDR addr; + PCIE_DEV_CNT2_REG dcnt2; +//------------------------------ + + //Get Device Properties + addr.ADDR=Device->Address.ADDR; + + PCI_TRACE((TRACE_PCI,"PciE2: Pcie2SetDevProperties() Device @ [B%X|D%X|F%X] ENTRY:\n", + addr.Addr.Bus,addr.Addr.Device, addr.Addr.Function)); + + if (Device->PciExpress == NULL) + return EFI_SUCCESS; + + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_DEV_CNT2_OFFSET; + Status=PciCfg16(Device->RbIo,addr, FALSE, &dcnt2.DEV_CNT2); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI," DEV_CNT2-> [EEPrB=%X|R=%X|LTR=%X|IDOCm=%X|IDORq=%X|AtEgB=%X|AtRq=%X|ARI=%X|CToD=%X|CTo=%X]\n ....... UPDATINNG .......\n", + dcnt2.EndEndTlpBlk, + dcnt2.Reserved, + dcnt2.LtrEn, + dcnt2.IdoComplEn, + dcnt2.IdoRequestEn, + dcnt2.AtomicOpEgresBlk, + dcnt2.AtomicOpRequer, + dcnt2.AriForwarding, + dcnt2.ComplToutDisable, + dcnt2.ComplToutRanges)); + + //Now check setup settingds and apply it. But do't touch ARI Forwarding it was updated earlier. + dcnt2.EndEndTlpBlk=gPciSetupData->E2ETlpPrBlk; + dcnt2.LtrEn=gPciSetupData->LtrReport; + dcnt2.IdoComplEn=gPciSetupData->IDOCompl; + dcnt2.IdoRequestEn=gPciSetupData->IDOReq; + dcnt2.AtomicOpEgresBlk=gPciSetupData->AtomOpEgressBlk; + dcnt2.AtomicOpRequer=gPciSetupData->AtomOpReq; + + //Now check what ompletion Timeout ranges to select? + dcnt2.ComplToutDisable=FALSE; + dcnt2.ComplToutRanges=0; //set to default + + //In Setup 0=Disable;0x55=SHORT; 0xAA=LONG; 0xFF=DEFAULT + if(gPciSetupData->ComplTimeOut == 0) dcnt2.ComplToutDisable=TRUE; + else { + if(gPciSetupData->ComplTimeOut == 0xFF) dcnt2.ComplToutRanges=0; + else{ + //use SHORT timeout srom supported ranges option. + if(gPciSetupData->ComplTimeOut == 0x55) + dcnt2.ComplToutRanges=Pcie2SelectComplTimeOut(Device->PciExpress->Pcie2->DeviceCap2.ComplToutRanges, TRUE); + //use LONG timeout srom supported ranges option. + else + dcnt2.ComplToutRanges=Pcie2SelectComplTimeOut(Device->PciExpress->Pcie2->DeviceCap2.ComplToutRanges, FALSE); + } + } + + + Status=PciCfg16(Device->RbIo,addr, TRUE, &dcnt2.DEV_CNT2); + + PCI_TRACE((TRACE_PCI," DEV_CNT2-> [EEPrB=%X|R=%X|LTR=%X|IDOCm=%X|IDORq=%X|AtEgB=%X|AtRq=%X|ARI=%X|CToD=%X|CTo=%X]\n\n", + dcnt2.EndEndTlpBlk, + dcnt2.Reserved, + dcnt2.LtrEn, + dcnt2.IdoComplEn, + dcnt2.IdoRequestEn, + dcnt2.AtomicOpEgresBlk, + dcnt2.AtomicOpRequer, + dcnt2.AriForwarding, + dcnt2.ComplToutDisable, + dcnt2.ComplToutRanges)); +// PCI_TRACE((TRACE_PCI,"Status = %r.\n",Status)); + + ASSERT_EFI_ERROR(Status); + return Status; +} + + + + + + + + + + +#endif +//GEN 2 Helper Functions END +/////////////////////////////////////////////////////////////////////////////// + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieUpdateClockPm() +// +// Description: This function will update Device's referenced as "Func0" +// Clock Power Management based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *Func0 Pointer to PCI Device Private Data structure. +// CNT_REG *LnkCnt Pointer to the Device's LNK_CNT register data. +// +// Output: NOTHING +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID PcieUpdateClockPm(PCI_DEV_INFO *Func0, PCIE_LNK_CNT_REG *LnkCnt){ + UINTN i; + PCI_DEV_INFO *dev; +//------------------------ + //Check if Clock PM was set for F0 than we need not to scam caps of the other devices. + if(LnkCnt->ClockPm == FALSE) return; + //we will come here if we get a multifunction NON-ARI device and Device Points @ Function 0 + //"LnkCnt" has parameters filled in calculated for Func0 of a MF device. + //Func0->DevFunc[] includes all other functions except Func 0; + for(i=0; i<Func0->FuncCount; i++){ + dev=Func0->DevFunc[i]; + //For a non-ARI multi-Function device, power-managementconfiguration + //software must only Set this bit if all Functions of + //the multi-Function device indicate a 1b in the Clock Power + //Management bit of the Link Capabilities register. The + //component is permitted to use the CLKREQ# signal to power + //manage Link clock only if this bit is Set for all Functions. + + //For ARI Devices, Clock Power Management is enabled solely by + //the setting in Function 0. The settings in the other Functions + //always return whatever value software programmed for each, + //but otherwise are ignored by the component. + if(dev->PciExpress->LinkCap.ClockPm == FALSE) { + LnkCnt->ClockPm=FALSE; + return; + } + } +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieDisableLink() +// +// Description: This function will Disable Link of DNSTREAM port referenced as +// "Device" based on Setup Settings and hardware STATUS. Used to disable "EMPTY" +// links to save some POWER or "Force" LINK to Disable state if Link can not be +// trained correctly. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// BOOLEAN Force Flag to indicate to disable link unconditionally. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieDisableLink(PCI_DEV_INFO *Device, BOOLEAN Force){ + EFI_STATUS Status=0; + PCI_CFG_ADDR addr; + PCIE_LNK_CNT_REG lcnt; + BOOLEAN val; +//------------------------------------------ + + //Get Device Link Control Register + addr.ADDR=Device->Address.ADDR; + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + + Status=PciCfg16(Device->RbIo, addr, FALSE, &lcnt.LNK_CNT); + ASSERT_EFI_ERROR(Status); + + if(Force)val=TRUE; + else val=gPciSetupData->LnkDisable; + + //Program Link only if it different from what we have. + if((UINT8)lcnt.LnkDisable!=val){ + lcnt.LnkDisable=val; + Status=PciCfg16(Device->RbIo, addr, TRUE, &lcnt.LNK_CNT); + ASSERT_EFI_ERROR(Status); + } + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieProgramLink() +// +// Description: This function will Program Link with provided VALUEs +// trained correctly. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// UINT16 Data Value to put in LNK_CNT register +// BOOLEAN Reg2 Flag to select LNK_CNT or LNK_CNT2 register. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS PcieProgramLink(PCI_DEV_INFO *Device, UINT16 Data, BOOLEAN Reg2){ + EFI_STATUS Status=0; + PCI_CFG_ADDR addr; +//------------------------------------------ + + //Get DownStream Port Properties + addr.ADDR=Device->Address.ADDR; + if(Reg2)addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CNT2_OFFSET; + else addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + + Status=PciCfg16(Device->RbIo, addr, TRUE, &Data); + ASSERT_EFI_ERROR(Status); + + return Status; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieResetLink() +// +// Description: This function will issue HOT RESET on a LINK referenced by "Device". +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieResetLink(PCI_DEV_INFO *Device, UINT8 LnkSpeed){ + EFI_STATUS Status=0; + PCI_CFG_ADDR addr; + PCI_BRG_CNT_REG bcnt; + BOOLEAN lnkrst=TRUE; +//-------------------------------- + //For any Root or Switch Downstream Port, setting the Secondary Bus Reset bit of the Bridge + //Control register associated with the Port must cause a hot reset to be sent (see Section 4.2.4.7). + + PCI_TRACE((TRACE_PCI," Link RESETING (LnkSpeed=0x%X)... ",LnkSpeed)); + addr.ADDR=Device->Address.ADDR; + addr.Addr.Register=PCI_BRIDGE_CNTL; + +#if PCI_EXPRESS_GEN3_SUPPORT + if(LnkSpeed>=PCIE_LINK_SPEED_80G){ + Status=Pcie3EqualizeLink(Device, &lnkrst); + ASSERT_EFI_ERROR(Status); + } +#endif + + //Read BRG_CNT_REG + Status=PciCfg16(Device->RbIo, addr, FALSE, &bcnt.BRG_CNT_REG); + ASSERT_EFI_ERROR(Status); + + //ASSERT reset Signal + bcnt.SecBusReset=TRUE; + Status=PciCfg16(Device->RbIo, addr, TRUE, &bcnt.BRG_CNT_REG); + ASSERT_EFI_ERROR(Status); + pBS->Stall(PCI_T_RST); + + //DE-ASSERT reset Signal + bcnt.SecBusReset=FALSE; + Status=PciCfg16(Device->RbIo, addr, TRUE, &bcnt.BRG_CNT_REG); + ASSERT_EFI_ERROR(Status); + PCI_TRACE((TRACE_PCI,"Status = %r.\n",Status)); + pBS->Stall(PCI_T_RST_RECOVERY); + + return Status; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieRetrainLink() +// +// Description: This function will initiate LINK training of the +// Down Stream Port referenced as "Device". +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// UINT16 Data Value to put in LNK_CNT register +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieRetrainLink(PCI_DEV_INFO *Device, UINT16 Data, UINT8 LnkSpeed){ + EFI_STATUS Status=0; + PCI_CFG_ADDR staa, cnta; + PCIE_LNK_STA_REG sta; + PCIE_LNK_CNT_REG cnt; + UINTN i=0, j=0; + BOOLEAN ltok, lnkrt=TRUE; +//------------------------------------- + + PCI_TRACE((TRACE_PCI," Link RETRAINING...(LnkSpeed=0x%X); # of retry %d ",LnkSpeed, gPciSetupData->LnkTrRetry)); + + staa.ADDR=Device->Address.ADDR; + cnta.ADDR=Device->Address.ADDR; + cnta.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + staa.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + + Status=PciCfg16(Device->RbIo, cnta, FALSE, &cnt.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + +#if PCI_EXPRESS_GEN3_SUPPORT + if(LnkSpeed>=PCIE_LINK_SPEED_80G){ + Status=Pcie3EqualizeLink(Device, &lnkrt); + ASSERT_EFI_ERROR(Status); + } +#endif + + //The above algorithm guarantees that Link training will be based on the Link control parameter + //settings that software intends. + for(i=0, ltok=FALSE; i<=gPciSetupData->LnkTrRetry; i++){ + //1. Software sets the relevant Link control parameters to the desired settings without writing a 1b to + // the Retrain Link bit. (Was done before in PcieProgramLink routine)... + + //2. Software polls the Link Training bit in the Link Status register until the value returned is 0b. + Status=PciCfg16(Device->RbIo, staa, FALSE, &sta.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto rEXIT; + + if(sta.LnkTraining!=0){ + for(j=0; j<=gPciSetupData->LnkTrRetry; j++){ + Status=PciCfg16(Device->RbIo, staa, FALSE, &sta.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(sta.LnkTraining==0) break; + pBS->Stall(gPciSetupData->LnkTrTimeout); + } + } + + //if stll link did not come from Recovery State + if(sta.LnkTraining!=0 && i>=gPciSetupData->LnkTrRetry){ + PCI_TRACE((TRACE_PCI,"PciE: TRAINING FAILURE! Link can't exit Recovery State. Disabling Link!\n")); + Status=PcieDisableLink(Device, TRUE); + Status=EFI_DEVICE_ERROR; + ASSERT_EFI_ERROR(Status); + goto rEXIT; + } else PCI_TRACE((TRACE_PCI,"%d, ",i)); + + + //3. Software writes a 1b to the Retrain Link bit without changing any other fields in the Link + // Control register. + cnt.RetrainLnk=TRUE; + + Status=PciCfg16(Device->RbIo, cnta, TRUE, &cnt.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Workaround for devices which having Link Retrain bit "sticky" + //Spec says it always reads as "0". + Status=PciCfg16(Device->RbIo, cnta, FALSE, &cnt.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + if(cnt.RetrainLnk==TRUE){ + cnt.RetrainLnk=FALSE; + Status=PciCfg16(Device->RbIo, cnta, TRUE, &cnt.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + + //Pool link Status back again to make sure it trained well. + Status=PciCfg16(Device->RbIo, staa, FALSE, &sta.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto rEXIT; + + if(sta.LnkTraining!=0){ + for(j=0; j<gPciSetupData->LnkTrRetry; j++){ + Status=PciCfg16(Device->RbIo, staa, FALSE, &sta.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(sta.LnkTraining==0) { + ltok=TRUE; + break; + } + pBS->Stall(gPciSetupData->LnkTrTimeout); + } + } else ltok=TRUE; + + + if(ltok) break; + } + +#if PCI_EXPRESS_GEN3_SUPPORT + if(LnkSpeed>=PCIE_LINK_SPEED_80G){ + Status=Pcie3GetEqualizationStatus(Device); + if(EFI_ERROR(Status)){ + //if equalization did not went trough retry it + if(Status==EFI_DEVICE_ERROR) { + PCI_TRACE((TRACE_PCI," EQ_STS=%r; ", Status)); + } + Status=EFI_SUCCESS; + } + } +#endif + +rEXIT: + PCI_TRACE((TRACE_PCI," %r\n", Status)); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieSetSlotProperties() +// +// Description: This function will Initialize SLT_CNT and SLT_STA registers +// of the "Device". +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieSetSlotProperties(PCI_DEV_INFO *Device){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_CFG_ADDR addr; + PCIE_SLT_CNT_REG sltc; + PCIE_SLT_STA_REG slts; +//-------------------------------- + + PCI_TRACE((TRACE_PCI," PciE: PcieSetSlotProperties() SlotImpl=%d -> ",Device->PciExpress->PcieCap.SlotImpl)); + + if(Device->PciExpress->PcieCap.SlotImpl==TRUE){ + addr.ADDR=Device->Address.ADDR; + + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_SLT_CNT_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&sltc.SLT_CNT); + ASSERT_EFI_ERROR(Status); + + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_SLT_STA_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&slts.SLT_STA); + ASSERT_EFI_ERROR(Status); + + sltc.AttnBtnPress=0; + sltc.PowerFaul=0; + sltc.MrlSensor=0; + sltc.PresenceDet=0; + sltc.CmdCompleted=0; + sltc.HpIntEnable=0; + sltc.DllStatChEn=0; + + + //Clear all RW1C bits in status reg... + slts.AttnBtnPress=1; + slts.PowerFaul=1; + slts.MrlSensor=1; + slts.PresenceDet=1; + slts.CmdCompleted=1; + slts.DllStateChg=1; + + + //Power Up slot and set all possible indication on... + if(Device->PciExpress->SlotCap.AttnInd) sltc.AttnIndCnt=PCIE_SLT_INDICATOR_ON; + if(Device->PciExpress->SlotCap.PowerInd)sltc.PowerIndCnt=PCIE_SLT_INDICATOR_ON; + if(Device->PciExpress->SlotCap.PwrCntler)sltc.PowerOff=PCIE_SLT_PWR_ON; + + Status=PciCfg16(Device->RbIo,addr,TRUE,&slts.SLT_STA); + + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_SLT_CNT_OFFSET; + Status=PciCfg16(Device->RbIo,addr,TRUE,&sltc.SLT_CNT); + } + PCI_TRACE((TRACE_PCI,"%r\n", Status)); + ASSERT_EFI_ERROR(Status); + + return Status; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieGetCaps() +// +// Description: This function will Collect PCI Express Capabilities Data +// of the "Device". +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieGetCaps(PCI_DEV_INFO *Device){ + EFI_STATUS Status=0; + PCI_CFG_ADDR addr; +//------------------------------- + addr.ADDR=Device->Address.ADDR; + + PCI_TRACE((TRACE_PCI,"\n PciE: Collecting CAPs for [B%X|D%X|F%X]\n", + Device->Address.Addr.Bus,Device->Address.Addr.Device,Device->Address.Addr.Function)); + + PCI_TRACE((TRACE_PCI," PCIE_CAP-> [R=%X|IntMsgNo=%X|SlotImpl=%X|PortType=%X|CapVer=%X]\n", + Device->PciExpress->PcieCap.Reserved, + Device->PciExpress->PcieCap.IntMsgNo, + Device->PciExpress->PcieCap.SlotImpl, + Device->PciExpress->PcieCap.PortType, + Device->PciExpress->PcieCap.CapVersion + )); + + //Get PCI Express Device CAPs - 32 bit after setting clock configuration + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_DEV_CAP_OFFSET; + Status=PciCfg32(Device->RbIo,addr,FALSE,&Device->PciExpress->DeviceCap.DEV_CAP); + ASSERT_EFI_ERROR(Status); + + + //Print Content of DEV_CAP and DEV_CNT register.. + PCI_TRACE((TRACE_PCI," DEV_CAP -> [R2=%X|FR=%X|PwrS=%X|PwrV=%X|R1=%X|RBE=%X|PI=%X|AI=%X|AB=%X|EpL1=%X|EpL0=%X|ExT=%X|PhF=%X|MPL=%X]\n", + Device->PciExpress->DeviceCap.Reserved2, + //Added in PCIe Base V2.0 + Device->PciExpress->DeviceCap.FuncResetCap, + Device->PciExpress->DeviceCap.SlotPwrLimS, + Device->PciExpress->DeviceCap.SlotPwrLimV, + Device->PciExpress->DeviceCap.Reserved1, + //Added in PCIe Base V2.0 + Device->PciExpress->DeviceCap.RoleBasedErr, + Device->PciExpress->DeviceCap.PowerInd, + Device->PciExpress->DeviceCap.AttnInd, + Device->PciExpress->DeviceCap.AttnBtn, + Device->PciExpress->DeviceCap.EpL1Latency, + Device->PciExpress->DeviceCap.EpL0Latency, + Device->PciExpress->DeviceCap.ExtTagFld, + Device->PciExpress->DeviceCap.PhantomFunc, + Device->PciExpress->DeviceCap.MaxPayload + )); + + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CAP_OFFSET; + Status=PciCfg32(Device->RbIo,addr,FALSE,&Device->PciExpress->LinkCap.LNK_CAP); + ASSERT_EFI_ERROR(Status); + + PCI_TRACE((TRACE_PCI," LNK_CAP -> [P#=%X|R=%X|BwN=%X|DllL=%X|SDE=%X|ClkPM=%X|L1=%X|L0=%X|ASPM=%X|MaxW=%X|MaxS=%X]\n", + Device->PciExpress->LinkCap.PortNum, + Device->PciExpress->LinkCap.Reserved, + //Added in PCIe Base V2.0 + Device->PciExpress->LinkCap.BandwNotify, + Device->PciExpress->LinkCap.DllLnkActive, + Device->PciExpress->LinkCap.SurpDownErr, + Device->PciExpress->LinkCap.ClockPm, + //--------------------------------- + Device->PciExpress->LinkCap.ExL1Latency, + Device->PciExpress->LinkCap.ExL0Latency, + Device->PciExpress->LinkCap.AspmSupport, + Device->PciExpress->LinkCap.MaxLnkWidth, + Device->PciExpress->LinkCap.MaxLnkSpeed + )); + + //Get PCI Express Slot CAPs - 32 bit it is valid only for Ports Switches and Bridges + if((Device->Type==tPci2PciBrg || Device->Type==tPci2CrdBrg) && + Device->PciExpress->PcieCap.SlotImpl ) + { + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_SLT_CAP_OFFSET; + Status=PciCfg32(Device->RbIo,addr,FALSE,&Device->PciExpress->SlotCap.SLT_CAP); + ASSERT_EFI_ERROR(Status); + + PCI_TRACE((TRACE_PCI," SLT_CAP -> [S#=%X|NoCmdC=%X|EmLck=%X|PwrS=%X|PwrV=%X|HpC=%X|HpS=%X|PI=%X|AI=%X|MrlS=%X|PwC=%X|AB=%X]\n", + Device->PciExpress->SlotCap.PhisSlotNum, + //Added in PCIe Base V2.0 + Device->PciExpress->SlotCap.NoCmdCompl, + Device->PciExpress->SlotCap.EmInterlock, + //---------------------------- + Device->PciExpress->SlotCap.PwrLimScale, + Device->PciExpress->SlotCap.PwrLimVal, + Device->PciExpress->SlotCap.HpCapable, + Device->PciExpress->SlotCap.HpSurprise, + Device->PciExpress->SlotCap.PowerInd, + Device->PciExpress->SlotCap.AttnInd, + Device->PciExpress->SlotCap.MrlSensor, + Device->PciExpress->SlotCap.PwrCntler, + Device->PciExpress->SlotCap.AttnBtn + )); + + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieSetLnkProperties() +// +// Description: This function will Select values for Link Control2 register on +// both sides of the LINK based on Setup Settiongs and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *DnStreamPort Pointer to PCI Device Private Data of Downstream Port of the link. +// PCIE_LNK_CNT2_REG *DnLnkCnt Pointer to the LNK_CNT Reg of the Downstream Port of the link. +// PCI_DEV_INFO *UpStreamPort Pointer to PCI Device Private Data of Upwnstream Port of the link. +// PCIE_LNK_CNT2_REG *UpLnkCnt Pointer to the LNK_CNT Reg of the Downstream Port of the link. +// BOOLEAN *LinkTrainingRequired Flag to modify if Link will need RETRAINING after programming. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieSetLnkProperties( PCI_DEV_INFO *DnStreamPort, + PCIE_LNK_CNT_REG *DnLnkCnt, + PCI_DEV_INFO *UpStreamPort, + PCIE_LNK_CNT_REG *UpLnkCnt, + BOOLEAN *LinkTrainingRequired) +{ + EFI_STATUS Status=EFI_SUCCESS; + PCIE_LNK_STA_REG dnls, upls; //link status reg content of up and down side of the link + PCI_CFG_ADDR addr; + BOOLEAN cc=FALSE; +//------------------------------ + + PCI_TRACE((TRACE_PCI,"PciE: PcieSetLnkProperties() ENTRY:\n")); + + PCI_TRACE((TRACE_PCI," DN STREAM PORT -> [B%X|D%X|F%X] <--> [B%X|D%X|F%X] <- UP STREAM PORT\n", + DnStreamPort->Address.Addr.Bus,DnStreamPort->Address.Addr.Device, DnStreamPort->Address.Addr.Function, + UpStreamPort->Address.Addr.Bus,UpStreamPort->Address.Addr.Device, UpStreamPort->Address.Addr.Function)); + + //Get DownStream Port Properties + addr.ADDR=DnStreamPort->Address.ADDR; + addr.Addr.Register=DnStreamPort->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + Status=PciCfg16(DnStreamPort->RbIo,addr,FALSE, &DnLnkCnt->LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI," LNK_CNT -> [BwI=%X|BwMI=%X|AuWi=%X|CkPM=%X|ExS=%X|CCk=%X|Rtr=%X|LDis=%X|RCB=%X|ASPM=%X]\n", + DnLnkCnt->AutoBandwInt, + DnLnkCnt->BandwMgmtInt, + DnLnkCnt->HwAutoWdtDis, + DnLnkCnt->ClockPm, + DnLnkCnt->ExtSynch, + DnLnkCnt->CommonClk, + DnLnkCnt->RetrainLnk, + DnLnkCnt->LnkDisable, + DnLnkCnt->RdComplBound, + DnLnkCnt->AspmControl)); + + + + addr.Addr.Register=DnStreamPort->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + Status=PciCfg16(DnStreamPort->RbIo,addr,FALSE, &dnls.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Get UpStream Stream Port Properties + addr.ADDR=UpStreamPort->Address.ADDR; + + addr.Addr.Register=UpStreamPort->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + Status=PciCfg16(UpStreamPort->RbIo,addr,FALSE, &UpLnkCnt->LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI," LNK_CNT -> [BwI=%X|BwMI=%X|AuWi=%X|CkPM=%X|ExS=%X|CCk=%X|Rtr=%X|LDis=%X|RCB=%X|ASPM=%X]\n ....... UPDATINNG .......\n", + UpLnkCnt->AutoBandwInt, + UpLnkCnt->BandwMgmtInt, + UpLnkCnt->HwAutoWdtDis, + UpLnkCnt->ClockPm, + UpLnkCnt->ExtSynch, + UpLnkCnt->CommonClk, + UpLnkCnt->RetrainLnk, + UpLnkCnt->LnkDisable, + UpLnkCnt->RdComplBound, + UpLnkCnt->AspmControl)); + + //Get Lnk Status Content... from DownSteam and UpStream Ports + addr.Addr.Register=UpStreamPort->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + Status=PciCfg16(UpStreamPort->RbIo,addr,FALSE, &upls.LNK_STA); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //1.Disable ASPM for now we will set it later starting from Endpoints! + DnLnkCnt->AspmControl=0; + UpLnkCnt->AspmControl=0; + + //2. Check Clock Config + //Check if Lnk Clk config programmed correctly by CSP Code. + //see if both sides can use Common Clock (Power up Default == 0) + if(dnls.CommonClk && upls.CommonClk) cc=TRUE; + + //Verify if ClkConfig is set correctly and detect if link training is needed + if((DnLnkCnt->CommonClk != cc) || (UpLnkCnt->CommonClk!=cc)) *LinkTrainingRequired=TRUE; + DnLnkCnt->CommonClk=cc; + UpLnkCnt->CommonClk=cc; + + //3.Extended Sinch + DnLnkCnt->ExtSynch=gPciSetupData->ExtendedSynch; + UpLnkCnt->ExtSynch=gPciSetupData->ExtendedSynch; + + //4. Clock PM +#if PCI_EXPRESS_GEN2_SUPPORT + if((UpStreamPort->PciExpress->LinkCap.ClockPm) && (gPciSetupData->ClockPm)) + { + DnLnkCnt->ClockPm=TRUE; + UpLnkCnt->ClockPm=TRUE; + } else { + DnLnkCnt->ClockPm=FALSE; + UpLnkCnt->ClockPm=FALSE; + } +#endif + //5. Clear Some interupt related bits. + DnLnkCnt->BandwMgmtInt=FALSE; + DnLnkCnt->AutoBandwInt=FALSE; + + PCI_TRACE((TRACE_PCI," LNK_CNT -> [BwI=%X|BwMI=%X|AuWi=%X|CkPM=%X|ExS=%X|CCk=%X|Rtr=%X|LDis=%X|RCB=%X|ASPM=%X]\n", + DnLnkCnt->AutoBandwInt, + DnLnkCnt->BandwMgmtInt, + DnLnkCnt->HwAutoWdtDis, + DnLnkCnt->ClockPm, + DnLnkCnt->ExtSynch, + DnLnkCnt->CommonClk, + DnLnkCnt->RetrainLnk, + DnLnkCnt->LnkDisable, + DnLnkCnt->RdComplBound, + DnLnkCnt->AspmControl)); + + PCI_TRACE((TRACE_PCI," LNK_CNT -> [BwI=%X|BwMI=%X|AuWi=%X|CkPM=%X|ExS=%X|CCk=%X|Rtr=%X|LDis=%X|RCB=%X|ASPM=%X]\n\n", + UpLnkCnt->AutoBandwInt, + UpLnkCnt->BandwMgmtInt, + UpLnkCnt->HwAutoWdtDis, + UpLnkCnt->ClockPm, + UpLnkCnt->ExtSynch, + UpLnkCnt->CommonClk, + UpLnkCnt->RetrainLnk, + UpLnkCnt->LnkDisable, + UpLnkCnt->RdComplBound, + UpLnkCnt->AspmControl)); + + return Status; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieIsDownStreamPort() +// +// Description: This function will check if *PCI_DEV_INFO passed belongs to +// PCI Express DOWNSTREAM PORT: +// - RootPort of PCIe Root Complex; +// - DownStream Port of PCIe Switch; +// - PCI/PCI-X to PCIe Bridge. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// +// Output: BOOLEAN +// TRUE When PCI_DEV_INFO passed belongs to DOWNSTREAM PORT +// FALSE All other cases... +// +// NOTE: Must be called only for PCI Express devices (Device->PciExpress!=NULL) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN PcieIsDownStreamPort(PCI_DEV_INFO *Device){ + + if((Device->PciExpress->PcieCap.PortType == PCIE_TYPE_ROOTPORT) || + (Device->PciExpress->PcieCap.PortType == PCIE_TYPE_DNS_PORT) || + (Device->PciExpress->PcieCap.PortType == PCIE_TYPE_PCI_PCIE)) + return TRUE; + else + return FALSE; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieSetSlotPower() +// +// Description: This function will power ON or OFF PCI Express Slot +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// BOOLEAN PwrOn Tells to turn slot power ON or OFF +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieSetSlotPower(PCI_DEV_INFO* Device, BOOLEAN PwrOn){ + PCI_CFG_ADDR addr; + PCIE_SLT_CNT_REG sltc; + EFI_STATUS Status=0; + UINT16 pwr=PCIE_SLT_PWR_OFF; +//-------------------------------------------- + if(!Device->PciExpress) return EFI_SUCCESS; + + if(Device->PciExpress->SlotCap.PwrCntler){ + addr.ADDR=Device->Address.ADDR; + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_SLT_CNT_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&sltc.SLT_CNT); + ASSERT_EFI_ERROR(Status); + if(PwrOn){ + if(Device->PciExpress->SlotCap.PowerInd) sltc.PowerIndCnt=PCIE_SLT_INDICATOR_ON; + sltc.PowerOff=PCIE_SLT_PWR_ON; + } else { + if(Device->PciExpress->SlotCap.PowerInd) sltc.PowerIndCnt=PCIE_SLT_INDICATOR_OFF; + sltc.PowerOff=PCIE_SLT_PWR_OFF; + } + Status=PciCfg16(Device->RbIo,addr,TRUE,&sltc.SLT_CNT); + ASSERT_EFI_ERROR(Status); + } + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: RestoreBridgeBuses() +// +// Description: This function will Reprogram Primary Secondary and Subordinate +// bus numbers for the downsteram bridges after SEC BUS reset signal assertion. +// +// Input: +// PCI_DEV_INFO *DnPort Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS RestoreBridgeBuses(PCI_DEV_INFO *DnPort){ + UINTN i; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(DnPort+1); + PCI_DEV_INFO *dev; + EFI_STATUS Status=EFI_SUCCESS; +//--------------------- + for(i=0; i< ext->ChildCount; i++){ + dev=ext->ChildList[i]; + if(dev->Type==tPci2PciBrg){ + Status=MapBridgeBuses(dev); + if(EFI_ERROR(Status)) return Status; + //call recoursively to cover all hierarchy + Status=RestoreBridgeBuses(dev); + if(EFI_ERROR(Status)) return Status; + } + } + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieInitLink() +// +// Description: This function will Initialize Pcie Link on both sides starting +// fronm DownStream Port. +// +// Input: +// PCI_DEV_INFO *DnPort Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieInitLink(PCI_DEV_INFO *DnPort){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_DEV_INFO *dn, *up, *f0; + PCI_BRG_EXT *ext; + PCIE_LNK_CNT_REG dnlc, uplc; + BOOLEAN lr=FALSE,lt=FALSE, pe2=FALSE, mf=FALSE; + UINT16 mpl, l0, l1;//calculated link speed + UINTN i=0,r=1; + T_ITEM_LIST *chldlst=NULL; + UINT8 lnkspeed=0; +#if PCI_EXPRESS_GEN2_SUPPORT + PCIE_LNK_CNT2_REG dnlc2, uplc2; +#endif +//------------------------------- + + if(DnPort->PciExpress==NULL) return EFI_SUCCESS; + + //Going from DOWN STREAM PORT to EP + dn=DnPort; + ext=(PCI_BRG_EXT*)(dn+1); + + + PCI_TRACE((TRACE_PCI,"\n PciE: InitLink DNSP @ [B%X|D%X|F%X] has 0x%X Childs", + dn->Address.Addr.Bus,dn->Address.Addr.Device,dn->Address.Addr.Function, ext->ChildCount)); + if(ext->ChildCount==0){ + Status=PcieDisableLink(dn, FALSE); + PCI_TRACE((TRACE_PCI," - Disabe Inactive Link=%d: %r\n", gPciSetupData->LnkDisable, Status)); + ASSERT_EFI_ERROR(Status); + return Status; + } + + //Check if we need to initialize Pcie2 features as well + //it will happened if both sides of the link supports PcieGen2 spec +#if PCI_EXPRESS_GEN2_SUPPORT + if(dn->PciExpress->Pcie2!=NULL)pe2=TRUE; + else pe2=FALSE; +#endif + + if(pe2)PCI_TRACE((TRACE_PCI," ARI=%d; ",dn->PciExpress->Pcie2->AriEnabled)); + else PCI_TRACE((TRACE_PCI," ARI=0; ")); + + Status=CpyItemLst((T_ITEM_LIST*)&ext->InitialCount, &chldlst); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Went trough Bridge's Childs and... + for(i=0,f0=NULL; i<chldlst->ItemCount; i++){ + up=(PCI_DEV_INFO*)chldlst->Items[i]; + + if(up->PciExpress==NULL)return EFI_SUCCESS; + + if(IsFunc0(up)){ + f0=up; + mf=IsFunc0OfMfDev(up); +#if PCI_EXPRESS_GEN2_SUPPORT + //Set PCIe GEN2 Properties first it ia applicable only for Func0 + //if both sides of the link supports it... + if((up->PciExpress->Pcie2!=NULL) && (pe2==TRUE)){ + PCI_TRACE((TRACE_PCI,"GEN2=%d.\n",pe2)); + Status=Pcie2SetLnkProperties(dn, &dnlc2, up, &uplc2, &lr, <); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } else pe2 = FALSE; +#endif + if(pe2==FALSE)PCI_TRACE((TRACE_PCI,"GEN2=%d.\n",pe2)); + + //Now Set PCIe GEN1 properties. + Status=PcieSetLnkProperties(dn, &dnlc, up, &uplc, <); + + //Now remove pointer to the func 0 from DOWN STREAM PORT Child's List + Status=DeleteItemLst(chldlst, i, FALSE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + break; + } + } + + //It must be a Child with Function == 0 there... + ASSERT(f0!=NULL); + + //now we are here and have prepared content of LNK_CNT and LNK_CNT2 for programming. + //there are some rules for link initialization that differes for ARI devices and regular ones. + //1. If device is ARI devise (has ARI compatibility header) all programming is applicable for Function0 only. + // all other Link control Register bits are reserved for the functions other than 0. + //2. If Device is NON-ARI than: + // a) all functions must report same value in capabilities except ClockPM bit - + // it is independent but will work only if all Functions of the device reports same capability. + // b) all functions mus have same values in LNK_CNT for feature to work. + // except same old ClockPM - it can be set only if all functions support it. + + //Check some condition which suppose to be true for PCI Express Devices. + ASSERT(chldlst->ItemCount == f0->FuncCount); //it must be the same number as FuncCount of Func0 device + + //If device id NON-ARI we must programm all functions to the same values + if((f0!=NULL) && (f0->PciExpress->AriData == NULL) && (mf==TRUE)){ + + PcieUpdateClockPm(f0,&uplc); + //Apply Settings for each child if device is MF + for(i=0; i<f0->FuncCount; i++){ + up=f0->DevFunc[i]; + + if(up->PciExpress==NULL) continue; + + Status=PcieProgramLink(up,uplc.LNK_CNT, FALSE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + +#if PCI_EXPRESS_GEN2_SUPPORT + if(pe2){ + Status=PcieProgramLink(up,uplc2.LNK_CNT2,TRUE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } +#endif + + } + } + + //Now Program the link .... + //Func 0 of Upstrem port... + Status=PcieProgramLink(f0,uplc.LNK_CNT, FALSE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + +#if PCI_EXPRESS_GEN2_SUPPORT + if(pe2){ + Status=PcieProgramLink(f0,uplc2.LNK_CNT2, TRUE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } +#endif + + //Downstream port... + Status=PcieProgramLink(dn,dnlc.LNK_CNT, FALSE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + +#if PCI_EXPRESS_GEN2_SUPPORT + if(pe2){ + Status=PcieProgramLink(dn,dnlc2.LNK_CNT2, TRUE); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + //All soft instances of PCIe registers updated + //now check update lnkspeed variable + if(pe2)lnkspeed=(UINT8)(dnlc2.TargetLnkSpeed); + else lnkspeed=1; +#else + lnkspeed=1; +#endif + + //And now see do we need to Retrain link or issue a Hot Reset. + //If Link Speed was changed we need to do a Hot Reset of a Link. + //When Hot Reset issued with New Link Parameters link will be retrained anyway. + if(lr){ + Status=PcieResetLink(dn, lnkspeed); + Status=RestoreBridgeBuses(dn); + } + + if(lt) Status=PcieRetrainLink(dn,dnlc.LNK_CNT, lnkspeed); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Update Internal Data now once we have applied all link settings + //It might affect some capablities of the PCIe Device. +#if PCI_EXPRESS_GEN2_SUPPORT + if(pe2){ + dn->PciExpress->Pcie2->LnkSpeed=(UINT8)dnlc2.TargetLnkSpeed; + f0->PciExpress->Pcie2->LnkSpeed=(UINT8)uplc2.TargetLnkSpeed; + } +#endif + + //Set Flag that link was progranmmed! + dn->PciExpress->LinkSet=TRUE; + f0->PciExpress->LinkSet=TRUE; + + + //If link was reseted or retrained update link capabilities + //since it might change besause of clock config and speed change. + if(lt || lr ){ + PCI_TRACE((TRACE_PCI,"Pcie: Refresh CAPs for DNSTREAM; UPSTREAM + ALL FUNC\n")); + Status=PcieGetCaps(dn); + ASSERT_EFI_ERROR(Status); + + Status=PcieGetCaps(f0); + ASSERT_EFI_ERROR(Status); + } + + //For all devices interfacing with DownStream port + //update MaxPayLoad and L0s L1 exit Latencies once we are already here. + //We will use it later to Program Pcie Device Chain + mpl=dn->PciExpress->DeviceCap.MaxPayload; + + //value of 0xFFFE indicates corresponded Lx state is not supported) + //value of 0xFFFF indicates corresponded Lx latency was not calculated yet. + if(dn->PciExpress->LinkCap.AspmSupport & PCIE_ASPM_L0_ENABLE) l0=dn->PciExpress->LinkCap.ExL0Latency; + if(dn->PciExpress->LinkCap.AspmSupport & PCIE_ASPM_L1_ENABLE) l1=dn->PciExpress->LinkCap.ExL1Latency; + + if(mpl > f0->PciExpress->DeviceCap.MaxPayload)mpl=f0->PciExpress->DeviceCap.MaxPayload; + //It is stated in spec "Multi-Function devices associated with an Upstream Port must + //report the same value in this field for all Functions" + if(l0!=0xFFFF && (l0 < f0->PciExpress->LinkCap.ExL0Latency)) l0=f0->PciExpress->LinkCap.ExL0Latency; + if(l1 < f0->PciExpress->LinkCap.ExL1Latency) l1=f0->PciExpress->LinkCap.ExL1Latency; + + for(i=0; i<f0->FuncCount; i++){ + up=f0->DevFunc[i]; + + if(up->PciExpress==NULL)continue; + + up->PciExpress->LinkSet=TRUE; +#if PCI_EXPRESS_GEN2_SUPPORT + if(pe2) up->PciExpress->Pcie2->LnkSpeed=(UINT8)uplc2.TargetLnkSpeed; +#endif + //Link Retraining or Hot Reset might change Latency values... + if(lt || lr ){ + Status=PcieGetCaps(up); + ASSERT_EFI_ERROR(Status); + } + + //Update MaxPL for all other functions,....spec says + // "The Functions of a multi-Function device are permitted to + // report different values for this field." + if(mpl>up->PciExpress->DeviceCap.MaxPayload)mpl=up->PciExpress->DeviceCap.MaxPayload; + up->PciExpress->MaxL0Lat=l0; + up->PciExpress->MaxL1Lat=l1; + } + + //found smallest one and record it in MaxPayload field of DOWNSTREAM PORT and UPSTREAM PORT's F0; + f0->PciExpress->MaxPayload=mpl; + f0->PciExpress->MaxL0Lat=l0; + f0->PciExpress->MaxL1Lat=l1; + + dn->PciExpress->MaxPayload=mpl; + dn->PciExpress->MaxL0Lat=l0; + dn->PciExpress->MaxL1Lat=l1; + + //some house keeping; + ClearItemLst(chldlst, FALSE); + if(chldlst)pBS->FreePool(chldlst); + + return Status; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CollectDeviceExtCap() +// +// Description: This function will Fill out structure of PciE Ext Cap data +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CollectDeviceExtCap(PCI_DEV_INFO *Device, VOID **DataPtr, UINTN DataSize, UINT32 CapHdrOffset, BOOLEAN Cap16, UINTN OffsetFromCapHdr){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_CFG_ADDR addr; + PCIE_EXT_DATA_HDR *dhdr; +//--------------------------------------- + + //Pointer must be empty at the beginning. + if(*DataPtr!=NULL) { + ASSERT_EFI_ERROR(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; + } + + *DataPtr=MallocZ(DataSize); + + if(*DataPtr==NULL) { + ASSERT_EFI_ERROR(EFI_OUT_OF_RESOURCES); + return EFI_OUT_OF_RESOURCES; + } + + dhdr=(PCIE_EXT_DATA_HDR*)(*DataPtr); + + dhdr->CapHdrOffset=CapHdrOffset; + + addr.ADDR=Device->Address.ADDR; + addr.Addr.ExtendedRegister=CapHdrOffset+(sizeof(PCIE_EXT_CAP_HDR))+(UINT32)OffsetFromCapHdr; + + if(Cap16)Status=PciCfg16(Device->RbIo, addr, FALSE,(UINT16*)&dhdr->CapReg); + else Status=PciCfg32(Device->RbIo, addr, FALSE,(UINT32*)&dhdr->CapReg); + + ASSERT_EFI_ERROR(Status); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieProgramPayloadUp() +// +// Description: This function will reprogram Max Payload and Read Request Size +// in upstream link if initialization code founds that one of Nodes down stream +// has lesser Max Pay load size than currently programmed +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// UINT32 Payload Reduced Max Payload Value. +// UINT32 ReadRequest Reduced Read Request Value. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Notes: +// RootPortComplex<=>Switch0...<=>...SwitchN<=>EndPoint +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieProgramPayloadUp(PCI_DEV_INFO *Device, UINT16 MaxPayload, UINT16 MaxReadReq){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_DEV_INFO *dev=Device; +//------------------------- + + //It has to be PCIE Switch device so it must have PCI2PCI Bridge Header structure. + if(dev->Type!=tPci2PciBrg) return EFI_DEVICE_ERROR; + + //We are cominng here if Payload and MaxReadRequest been set for the device and + //Device is NOT ENDPOINT Device. Means we hit switch here and it handling more then + //one ENDPOINT Devices. So check if MPL and MRRS is Bigger or Equal then passed Payload parameter. + if(dev->PciExpress->MaxPayload > MaxPayload){ + UINTN i; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(dev+1); + PCI_CFG_ADDR addr; + PCIE_DEV_CNT_REG devc; + //------------- + //if condition met: one or some of the upstream device(s) are capable and programmed + //to generate TLP bigger than current proposed programming stored in "mrr" and "mpl". + + //Select Device Control Register + addr.ADDR= dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_DEV_CNT_OFFSET; + //Read what we have there + Status=PciCfg16(dev->RbIo,addr,FALSE,&devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + + PCI_TRACE((TRACE_PCI,"PciE: Going UP @ [B%X|D%X|F%X] Updating: MPL %X to %X\n", + Device->Address.Addr.Bus,Device->Address.Addr.Device, Device->Address.Addr.Function, + devc.MaxPayload, MaxPayload)); + + for(i=0;i<ext->ChildCount; i++){ + dev=(PCI_DEV_INFO*)ext->ChildList[i]; + if(dev->PciExpress!=NULL){ + //Reprogram only devices we have programmed already. + if(dev->PciExpress->DevSet){ + //If we have other switches in upstream link call this function recursively. + if(dev->Type==tPci2PciBrg) { + PcieProgramPayloadUp(dev, MaxPayload, MaxReadReq); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + //Select Device Control Register + addr.ADDR = dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_DEV_CNT_OFFSET; + //Read what we have there + Status=PciCfg16(dev->RbIo,addr,FALSE,&devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI,"PciE: Reprogram Payload @ [B%X|D%X|F%X] Updating: MPL %X to %X\n", + dev->Address.Addr.Bus,dev->Address.Addr.Device, dev->Address.Addr.Function, + devc.MaxPayload, MaxPayload)); + + devc.MaxPayload=MaxPayload; + //Leave CHIPSET INIT value if AUTO selected. + if(MaxReadReq != 55) devc.MaxReadReq=MaxReadReq; + + Status=PciCfg16(dev->RbIo,addr,TRUE, &devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + dev->PciExpress->MaxPayload=MaxPayload; + + } + } else { + //Such condition MUST NOT happened, since Parent is UPSTREAM PORT and childs must be a PciE only! + PCI_TRACE((TRACE_PCI, "PciE: ERROR! PciE Data Uninitialized! Child#=%d. TotalChlds=%d.\n", i, ext->ChildCount)); + return EFI_DEVICE_ERROR; + } + } + } else { + PCI_TRACE((TRACE_PCI,"PciE: NOT Going UP @ [B%X|D%X|F%X] Device's Link MPL %X <= New MPL %X\n", + Device->Address.Addr.Bus,Device->Address.Addr.Device, Device->Address.Addr.Function, + dev->PciExpress->MaxPayload, MaxPayload)); + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieConvertLatency() +// +// Description: This function will convert Latency value from Values read from. +// PPCIe.LNK_CNT_REG to Nanoseconds and opposite. +// +// Input: +// UINTN Latency Latency Value to convert +// BOOLEAN L0s Tells if L0s or L1 Exit latency +// BOOLEAN ToNs Tells how to convert: +// TRUE - to the units of nano Seconds; +// FALSE - to the LNK_CNT_REG.LxExitLat register value +// +// Output: EFI_STATUS +// UINTN Converted Value (-1) - means Invalid Value passed; +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +//Return value in nS of Max L0s, L1 Exit latency . +UINTN PcieConvertLatency(UINTN Latency, BOOLEAN L0s, BOOLEAN ToNs){ + UINTN l0s[]={64,128,256,512,1000,2000,4000,8000}; + UINTN l1[]= {1000, 2000, 4000, 8000, 16000,32000,64000,128000}; + UINTN *a, max,i=0; +//--------------------- + //Init stuff + if(L0s) a=&l0s[0]; + else a=&l1[0]; + + if (ToNs) max=7; + else{ + if(L0s) max=8000; + else max=128000; + } + + //Check parameters; + if (Latency > max){ + return max; + } + + if(ToNs) return a[Latency]; + else { + while(i<8){ + if(a[i]<Latency)i++; + else break; + } + if(i==8) i=7; + + return i; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieRemoveEpFromLst() +// +// Description: This function will removed Device referencesd as EndPoint from +// the gPcieEpLst data structure used as a database of available EndPoint devices. +// +// Input: +// PCI_DEV_INFO *EndPoint Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND EndPoint not in the gPcieEpLst. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieRemoveEpFromLst(PCI_DEV_INFO *EndPoint){ + PCI_DEV_INFO *dev; + UINTN i; +//------------------------- + for(i=0; i<gPcieEpList.ItemCount; i++){ + dev=(PCI_DEV_INFO*)gPcieEpList.Items[i]; + + if(dev==EndPoint){ + DeleteItemLst(&gPcieEpList, i, FALSE); + PCI_TRACE((TRACE_PCI,"PciE: Removing Device [B%X|D%X|F%X] from gPcieEpList[%d]\n", + EndPoint->Address.Addr.Bus,EndPoint->Address.Addr.Device, EndPoint->Address.Addr.Function, i)); + return EFI_SUCCESS; + } + } + PCI_TRACE((TRACE_PCI,"PciE: Can't find device [B%X|D%X|F%X] in gPcieEpList[%d]\n", + EndPoint->Address.Addr.Bus,EndPoint->Address.Addr.Device, EndPoint->Address.Addr.Function, gPcieEpList.ItemCount)); + + return EFI_NOT_FOUND; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieCalcMaxPayLoad() +// +// Description: This function will calculate MAX PayLoad Size needed to work +// correctly. +// +// Input: +// PCI_DEV_INFO *EndPoint Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT16 PcieCalcMaxPayLoad(PCI_DEV_INFO *EndPoint){ + UINT16 tmpl=0xFFFF, lmpl; + PCI_DEV_INFO *dn, *up; + BOOLEAN progup; +#if EFI_DEBUG == 1 //debug + UINTN i=1; +#endif +//-------------------- + up=EndPoint; + PCI_TRACE((TRACE_PCI," Calculate MPL :\n")); + //Down steam port and F0 holds optimal MPL for all elements on this link + do{ + if(up==NULL || up->ParentBrg==NULL)break; + progup=FALSE; + + if(!IsFunc0(up)) up=up->Func0; + //Init this link mpl var (dn<->up) + lmpl=up->PciExpress->MaxPayload; + + dn=up->ParentBrg; + if(dn->PciExpress->MaxPayload<lmpl){ + //if UP link has bigger MPL value then DN link + //Update UP link recoded value... + lmpl=dn->PciExpress->MaxPayload; + + //set the Flag that we have to reprogramm MPL since downstream MPL has been reduced + progup=TRUE; + } + + //Here lmpl holds smallest value of the link check if accomulated MPL exceeds MPL of this link... + if(tmpl!=lmpl) progup=TRUE; + if(tmpl>lmpl) tmpl=lmpl; + + //PcieProgramPayloadUp has double check if MPL needs to be programmed + if(progup && up->PciExpress->PcieCap.PortType==PCIE_TYPE_UPS_PORT && up->PciExpress->DevSet){ + if(gPciSetupData->MaxReadRequest!=55) PcieProgramPayloadUp(up, tmpl,gPciSetupData->MaxReadRequest); + else PcieProgramPayloadUp(up, tmpl, PCIE_MAXPL_512B); + } + + up->PciExpress->MaxPayload=tmpl; + +#if EFI_DEBUG == 1 //debug + PCI_TRACE((TRACE_PCI," Link # %d, Link MPL=%X; Total MPL=%X dn->[B%X|D%X|F%X]<->[B%X|D%X|F%X]<-up;\n", i,lmpl, tmpl, + dn->Address.Addr.Bus,dn->Address.Addr.Device, dn->Address.Addr.Function, + up->Address.Addr.Bus,up->Address.Addr.Device, up->Address.Addr.Function )); + i++; +#endif + up=dn->ParentBrg; + } while (up->ParentBrg->PciExpress!=NULL && up->ParentBrg->Type!=tPciRootBrg); //(EIP49743) + + PCI_TRACE((TRACE_PCI," Calculated MPL %X\n\n", tmpl)); + + return tmpl; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieCalcLatency() +// +// Description: This function will calculate MAX Latency needed to exit from +// ome of the ASPM Sattes L0s or L1. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// BOOLEAN L0s Tells which ASPM state Latency we are calculating +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINTN PcieCalcLatency(PCI_DEV_INFO *EndPoint, BOOLEAN L0s){ + PCI_DEV_INFO *dn, *up; + UINT16 *ll; + UINTN i=0, tmp=0, lat=0; +//-------------------- + up=EndPoint; + PCI_TRACE((TRACE_PCI," Calculate ")); + if(L0s)PCI_TRACE((TRACE_PCI,"L0s:\n")); + else PCI_TRACE((TRACE_PCI,"L1 :\n")); + //Down steam port and F0 holds optimal MPL for all elements on this link + do{ + if(!IsFunc0(up)) up=up->Func0; + dn=up->ParentBrg; + if(L0s)ll=&dn->PciExpress->MaxL0Lat; + else ll=&dn->PciExpress->MaxL1Lat; + + //if PciExpress->MaxL0Lat==0xFFFF means Link does not support ASPM + if(*ll!=0xFFFF ) { + if(L0s) { + tmp=PcieConvertLatency(dn->PciExpress->MaxL0Lat, L0s, TRUE); + lat+=tmp; + } else { + tmp=PcieConvertLatency(dn->PciExpress->MaxL1Lat, L0s, TRUE); + if(tmp>lat) lat=tmp; + } + } + + PCI_TRACE((TRACE_PCI," Link# %d Lat=%d(nS) dn->[B%X|D%X|F%X]<->[B%X|D%X|F%X]<-up;\n", i, tmp, + dn->Address.Addr.Bus,dn->Address.Addr.Device, dn->Address.Addr.Function, + up->Address.Addr.Bus,up->Address.Addr.Device, up->Address.Addr.Function )); + i++; + + //Advance to the next link. + up=dn->ParentBrg; + } while (dn->ParentBrg->PciExpress!=NULL && dn->ParentBrg->Type!=tPciRootBrg);//(EIP49743) + + //Internal delay on each Upstream Port (per spec.) MUST BE NO MORE than 1uS. + //so next UPSTREAM Link will start transition from L1 to L0 state in 1uS (worst case) + // to calculate L1 exit Latency we will use (MAX lat + 1000nS * (i-1)) where i number of links on the packet path. + if(!L0s && i>0) lat+=1000*(i-1); + + PCI_TRACE((TRACE_PCI," Total Calclulated latency: %d (nS)\n", lat )); + + return lat; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieInitVc() +// +// Description: This function will Initialize "Device"'s Virtual Channel properties +// based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieInitVc(PCI_DEV_INFO *Device){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_CFG_ADDR addr; + VC_RES_DATA *vcrd; + PCIE_VC_RESCNT_REG vcrc; + UINTN c; +//------------------------- + //Program VC configuration + //Limit VC TC to TC0 mapped trough VC0 and Disable all Extended VC resources on the way of the LINK. + //This is a device driver responcibility to allow different TCs and enable Extended VCs if link has it. + + addr.ADDR=Device->Address.ADDR; + //Arbitration Table has to be loaded by the Chipset specific code + //in NBDxe.c or SBDxe.c or by device specific driver. So don't bother + for(c=0; c<Device->PciExpress->VcData->VcCount; c++){ + vcrd=Device->PciExpress->VcData->VcResData[c]; + + //Locate VC Resource CNT reg + addr.Addr.ExtendedRegister=vcrd->VcResOffset+4; + Status=PciCfg32(Device->RbIo,addr,FALSE,&vcrc.VC_RESCNT); + ASSERT_EFI_ERROR(Status); + + //Disable VC and TC mapping except default mapping TC0 VC0 + if(c){ + vcrc.Tc_VcMap=0; + vcrc.VcEnable=0; + } else { + //for Channel0(Default VC this bits must be RO but who knows...) + vcrc.Tc_VcMap=1; + vcrc.VcEnable=1; + } + vcrc.VcId=(UINT8)c; + + //write it back + Status=PciCfg32(Device->RbIo,addr,TRUE,&vcrc.VC_RESCNT); + ASSERT_EFI_ERROR(Status); + } + + return Status; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieSetDevProperties() +// +// Description: This function will Select values for DEVICE CONTROL register +// based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data. +// UINT16 *MaxPayload Pointer to the MaxPayload value. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieSetDevProperties(PCI_DEV_INFO *Device, UINT16 MaxPayload){ + EFI_STATUS Status; + PCI_CFG_ADDR addr; + PCI_DEV_INFO *dev=Device; + PCIE_DEV_CNT_REG devc; +//------------------------- + + addr.ADDR=Device->Address.ADDR; + + PCI_TRACE((TRACE_PCI,"PciE: PcieSetDevProperties() Device @ [B%X|D%X|F%X] ENTRY:\n", + addr.Addr.Bus,addr.Addr.Device, addr.Addr.Function)); + + if (Device->PciExpress == NULL) + return EFI_SUCCESS; + + //Select Device Control Register + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_DEV_CNT_OFFSET; + //Read what we have there + Status=PciCfg16(dev->RbIo,addr,FALSE,&devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + PCI_TRACE((TRACE_PCI," DEV_CNT -> [FrBr=%X|MRR=%X|NS=%X|APPM=%X|PhF=%X|ETg=%X|MPL=%X|RO=%X|UpRR=%X|FtEr=%X|NfEr=%X|CEr=%X]\n ....... UPDATINNG .......\n", + devc.FnRstBrgRtry, + devc.MaxReadReq, + devc.NoSnoop, + devc.AuxPwrPm, + devc.PhantomFunc, + devc.ExtTagFld, + devc.MaxPayload, + devc.RelaxOrder, + devc.UsupReqRep, + devc.FatalErrRep, + devc.NfErrRep, + devc.CorrErrRep)); + + //Set some bits: + //1.Get Maximum PayLoad Size + //Don't allow overwrite if it is more than supported + if(gPciSetupData->MaxPayload!=55 && gPciSetupData->MaxPayload < MaxPayload) devc.MaxPayload=gPciSetupData->MaxPayload; + else devc.MaxPayload=MaxPayload; + + //2.Get Max Read Request Size + if(gPciSetupData->MaxReadRequest!=55) devc.MaxReadReq=gPciSetupData->MaxReadRequest; + //if "AUTO" selected use value already sitting there... +// else devc.MaxReadReq=PCIE_MAXPL_512B; + + //3.Enable/Disable extended tagfld per Setup Option + devc.ExtTagFld=0; //use 5 bit tag. + if(dev->PciExpress->DeviceCap.ExtTagFld)devc.ExtTagFld=gPciSetupData->ExtTagField; + + //4. Set No Snoop bit per Setup Option + devc.RelaxOrder=gPciSetupData->RelaxedOrdering; + devc.NoSnoop=gPciSetupData->NoSnoop; + + //Write it back + Status=PciCfg16(dev->RbIo,addr,TRUE,&devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + + //Init device's VC + //if we have a virtual channel capability + if(Device->PciExpress->VcData) Status=PcieInitVc(Device); + + +/* + //Print Content of DEV_CAP and DEV_CNT register.. + PCI_TRACE((TRACE_PCI," DEV_CAP -> [R2=%X|FR=%X|PwrS=%X|PwrV=%X|R1=%X|RBE=%X|PI=%X|AI=%X|AB=%X|EpL1=%X|EpL0=%X|ExT=%X|PhF=%X|MPL=%X]\n", + dev->PciExpress->DeviceCap.Reserved2, + //Added in PCIe Base V2.0 + dev->PciExpress->DeviceCap.FuncResetCap, + dev->PciExpress->DeviceCap.SlotPwrLimS, + dev->PciExpress->DeviceCap.SlotPwrLimV, + dev->PciExpress->DeviceCap.Reserved1, + //Added in PCIe Base V2.0 + dev->PciExpress->DeviceCap.RoleBasedErr, + dev->PciExpress->DeviceCap.PowerInd, + dev->PciExpress->DeviceCap.AttnInd, + dev->PciExpress->DeviceCap.AttnBtn, + dev->PciExpress->DeviceCap.EpL1Latency, + dev->PciExpress->DeviceCap.EpL0Latency, + dev->PciExpress->DeviceCap.ExtTagFld, + dev->PciExpress->DeviceCap.PhantomFunc, + dev->PciExpress->DeviceCap.MaxPayload + )); +*/ + PCI_TRACE((TRACE_PCI," DEV_CNT -> [FrBr=%X|MRR=%X|NS=%X|APPM=%X|PhF=%X|ETg=%X|MPL=%X|RO=%X|UpRR=%X|FtEr=%X|NfEr=%X|CEr=%X]\n\n", + devc.FnRstBrgRtry, + devc.MaxReadReq, + devc.NoSnoop, + devc.AuxPwrPm, + devc.PhantomFunc, + devc.ExtTagFld, + devc.MaxPayload, + devc.RelaxOrder, + devc.UsupReqRep, + devc.FatalErrRep, + devc.NfErrRep, + devc.CorrErrRep)); + +/* + PCI_TRACE((TRACE_PCI," LNK_CAP -> [P#=%X|R=%X|BwN=%X|DllL=%X|SDE=%X|ClkPM=%X|L1=%X|L0=%X|ASPM=%X|MaxW=%X|MaxS=%X]\n", + dev->PciExpress->LinkCap.PortNum, + dev->PciExpress->LinkCap.Reserved, + //Added in PCIe Base V2.0 + dev->PciExpress->LinkCap.BandwNotify, + dev->PciExpress->LinkCap.DllLnkActive, + dev->PciExpress->LinkCap.SurpDownErr, + dev->PciExpress->LinkCap.ClockPm, + //--------------------------------- + dev->PciExpress->LinkCap.ExL1Latency, + dev->PciExpress->LinkCap.ExL0Latency, + dev->PciExpress->LinkCap.AspmSupport, + dev->PciExpress->LinkCap.MaxLnkWidth, + dev->PciExpress->LinkCap.MaxLnkSpeed + )); + +#if EFI_DEBUG + if (Device->PciExpress->PcieCap.SlotImpl){ + + PCI_TRACE((TRACE_PCI," SLT_CAP -> [S#=%X|NoCmdC=%X|EmLck=%X|PwrS=%X|PwrV=%X|HpC=%X|HpS=%X|PI=%X|AI=%X|MrlS=%X|PwC=%X|AB=%X]\n", + dev->PciExpress->SlotCap.PhisSlotNum, + //Added in PCIe Base V2.0 + dev->PciExpress->SlotCap.NoCmdCompl, + dev->PciExpress->SlotCap.EmInterlock, + //---------------------------- + dev->PciExpress->SlotCap.PwrLimScale, + dev->PciExpress->SlotCap.PwrLimVal, + dev->PciExpress->SlotCap.HpCapable, + dev->PciExpress->SlotCap.HpSurprise, + dev->PciExpress->SlotCap.PowerInd, + dev->PciExpress->SlotCap.AttnInd, + dev->PciExpress->SlotCap.MrlSensor, + dev->PciExpress->SlotCap.PwrCntler, + dev->PciExpress->SlotCap.AttnBtn + )); + } +#endif +*/ + return Status; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieSetAspm() +// +// Description: This function will Select values for Link Control2 register on +// both sides of the LINK based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *DnPort Pointer to PCI Device Private Data of Downstream Port of the link. +// PCI_DEV_INFO *UpPort Pointer to PCI Device Private Data of Upwnstream Port of the link. +// UINT16 Aspm ASPM value to programm. +// BOOLEAN *LinkHotResetRequired Flag to modify if Link will need HOT RESET after programming. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieSetAspm(PCI_DEV_INFO *DnPort,PCI_DEV_INFO *UpPort,UINT16 Aspm){ + EFI_STATUS Status; + PCIE_LNK_CNT_REG lnkc; + PCI_CFG_ADDR addr; + UINT16 aspm=0, dnaspm, upaspm; +//------------------------- + + + PCI_TRACE((TRACE_PCI,"\n Setting ASPM for Link...\n UP STREAM PORT -> [B%X|D%X|F%X] <--> [B%X|D%X|F%X] <- DN STREAM PORT\n", + UpPort->Address.Addr.Bus,UpPort->Address.Addr.Device, UpPort->Address.Addr.Function, + DnPort->Address.Addr.Bus,DnPort->Address.Addr.Device, DnPort->Address.Addr.Function )); + + //We are coming here with UpPort as Function 0 already. + addr.ADDR=UpPort->Address.ADDR; + + //Select lnk Control Register + addr.Addr.Register=UpPort->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + //Read what we have there + Status=PciCfg16(UpPort->RbIo,addr,FALSE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Spec tells: "ASPM L1 must be enabled by software in the Upstream + //component on a Link prior to enabling ASPM L1 in the + //Downstream component on that Link. When disabling ASPM + //L1, software must disable ASPM L1 in the Downstream + //component on a Link prior to disabling ASPM L1 in the + //Upstream component on that Link. ASPM L1 must only be + //enabled on the Downstream component if both components on + //a Link support ASPM L1." + + //We have recorded in MaxLxLat field of the PciExpres Data Structure + //Link capability to support certain Lx states. + //value of 0xFFFF indicates corresponded Lx state is not supported. + //It must be the same on both sides of the link! + ASSERT(DnPort->PciExpress->MaxL0Lat == UpPort->PciExpress->MaxL0Lat); + ASSERT(DnPort->PciExpress->MaxL1Lat == UpPort->PciExpress->MaxL1Lat); + //If some links on the Pcie Packet Path does not support certain Lx states, + //they will remain in L0 state all the time. Mean while ones that supports, + //will transition to Lx power saving state. + if( (UpPort->PciExpress->MaxL0Lat == 0xFFFF) || + !(UpPort->PciExpress->LinkCap.AspmSupport & PCIE_ASPM_L0_ENABLE) || + !(DnPort->PciExpress->LinkCap.AspmSupport & PCIE_ASPM_L0_ENABLE) ) Aspm &=(~PCIE_ASPM_L0_ENABLE); + if( (UpPort->PciExpress->MaxL1Lat == 0xFFFF) || + !(UpPort->PciExpress->LinkCap.AspmSupport & PCIE_ASPM_L1_ENABLE) || + !(DnPort->PciExpress->LinkCap.AspmSupport & PCIE_ASPM_L1_ENABLE) ) Aspm &=(~PCIE_ASPM_L1_ENABLE); + + aspm=Aspm; + + //Check Setup settings "Force to L0s" must clear calculated PCIE_ASPM_L1_ENABLE; + //But should not affect OVERWRITE capabilities. + //[Disable]==0\ Auto==55 \ Force L0s==1 + if(gPciSetupData->AspmMode == 1) aspm &= (~PCIE_ASPM_L1_ENABLE); + if(gPciSetupData->AspmMode == 0) aspm = 0; + //Now "Aspm" has calculated MAX supported ASPM value + //and "aspm" has Updated accordingly to setup + dnaspm=aspm; + Status=PciPortOemSetAspm(DnPort, &dnaspm); + PCI_TRACE((TRACE_PCI," Getting Overwr Aspm Settings for DNSTREAM PORT: Calc ASPM = %X ... Setup ASPM = %X \n",Aspm, aspm)); + + upaspm=aspm; + Status=PciPortOemSetAspm(UpPort, &upaspm); + PCI_TRACE((TRACE_PCI," Getting Overwr Aspm Settings for UPSTREAM PORT: Calc ASPM = %X ... Setup ASPM = %X \n",Aspm, aspm)); + + //check UP and DN STREAM ASPM override settings. + //and pick smallest one... + if(dnaspm<upaspm) aspm=dnaspm; + else aspm=upaspm; + PCI_TRACE((TRACE_PCI," Status = %r : Calc ASPM = %X ... Overwr ASPM = %X \n",Status,Aspm, aspm)); + + //Check if ASPM settings were correctly overwritten + //It can't be more than calculated... otherwice system might hung! + if (aspm>Aspm){ + PCI_TRACE((TRACE_PCI," !![Calc ASPM = %X] LESSER THAN [Ovr ASPM = %X] - System Might HUNG. Reset to Calculated!!\n", Aspm, aspm)); + aspm=Aspm; + } + + PCI_TRACE((TRACE_PCI,"\n")); + + if(aspm) { + lnkc.AspmControl=aspm; + + //Set ASPM in UpStream Port First for Function 0 + Status=PciCfg16(UpPort->RbIo,addr,TRUE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //It is recommended to programm all functions even in + //case of ARI device Func0 is in charge for link behavior. + if(IsFunc0OfMfDev(UpPort)){ + UINTN i; + PCI_DEV_INFO *dev; + //-------------------------- + for(i=0; i<UpPort->FuncCount; i++){ + dev=UpPort->DevFunc[i]; + + if(dev->PciExpress==NULL) continue; + + addr.ADDR=dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + //Read what we have there + Status=PciCfg16(dev->RbIo,addr,FALSE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + lnkc.AspmControl=aspm; + + Status=PciCfg16(dev->RbIo,addr,TRUE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + + } + + //Select lnk Control Register of Down Stream port + addr.ADDR=DnPort->Address.ADDR; + addr.Addr.Register=DnPort->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + //Read what we have there + Status=PciCfg16(DnPort->RbIo,addr,FALSE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Set ASPM for Downstream Port + lnkc.AspmControl=aspm; + + //Write Back + Status=PciCfg16(DnPort->RbIo,addr,TRUE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + }//if(Aspm) + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieApplyDevSettings() +// +// Description: This function will Select values for DEVICE CONTROL register +// based on Setup Settings and hardware capabilities. +// +// Input: +// PCI_DEV_INFO *EndPoint Pointer to PCI Device Private Data. +// UINT16 MaxPayload MaxPayload value. +// UINT16 LatencyL0s Latency L0s value. +// UINT16 LatencyL1 Latency L1 value. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieApplyDevSettings(PCI_DEV_INFO *EndPoint, UINT16 MaxPayLoad, UINT16 LatencyL0s, UINT16 LatencyL1){ + EFI_STATUS Status=EFI_SUCCESS; + PCI_DEV_INFO *dn, *up, *f0=NULL; + UINTN i; + UINT16 aspmc=0, mpl=0; +#if PCI_EXPRESS_GEN2_SUPPORT == 1 + BOOLEAN pe2=FALSE; +#endif +//-------------------- + up=EndPoint; + if(!IsFunc0(up)) up=up->Func0; + + if(up->PciExpress->DeviceCap.EpL0Latency >= LatencyL0s) aspmc |= PCIE_ASPM_L0_ENABLE; + if(up->PciExpress->DeviceCap.EpL1Latency >= LatencyL1) aspmc |= PCIE_ASPM_L1_ENABLE; + + + PCI_TRACE((TRACE_PCI,"\nPciE: PcieApplyDevSettings() -> Starting with Device [B%X|D%X|F%X]\n", + up->Address.Addr.Bus,up->Address.Addr.Device, up->Address.Addr.Function)); + + + //Check if we need to initialize Pcie2 features as well + //it will happened if both sides of the link supports PcieGen2 spec +#if PCI_EXPRESS_GEN2_SUPPORT + if((up->ParentBrg->PciExpress->Pcie2!=NULL)&&(up->PciExpress->Pcie2!=NULL))pe2=TRUE; +#endif + + do{ + if(up==NULL || up->ParentBrg==NULL)break; + f0=NULL; + dn=up->ParentBrg; + //optimal MPL calculated and passed here; + mpl=MaxPayLoad; + + //Set fetures selected in SETUP + PCI_TRACE((TRACE_PCI,"#---> EndPoint/UPSTREAM @ [B%X|D%X|F%X] ASPM=%X; MPL=%X;\n", + up->Address.Addr.Bus,up->Address.Addr.Device, up->Address.Addr.Function, aspmc, mpl)); + +#if PCI_EXPRESS_GEN2_SUPPORT == 1 + if(pe2){ + //If applicable + //Set Device fetures for GEN2 devices + Status=Pcie2SetDevProperties(up); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } +#endif + + Status=PcieSetDevProperties(up, mpl); + + //SetFlag DevProgrammed FLAG.. + up->PciExpress->DevSet=TRUE; + + //Remove processed entrie from EndPoint Database... + Status=PcieRemoveEpFromLst(up); + + + //If we got an EndPoint and it is a Multy Func device - go and update all it's functions... + if(up->PciExpress->PcieCap.PortType == PCIE_TYPE_ENDPOINT || + up->PciExpress->PcieCap.PortType == PCIE_TYPE_PCIE_PCI || + up->PciExpress->PcieCap.PortType == PCIE_TYPE_LEGACYEP || + up->PciExpress->PcieCap.PortType == PCIE_TYPE_UPS_PORT ) + { + f0=up; + for (i=0; i<f0->FuncCount; i++){ + up=f0->DevFunc[i]; + + PCI_TRACE((TRACE_PCI,"#---> EndPoint/UPSTREAM Function @ [B%X|D%X|F%X] ASPM=%X; MPL=%X;\n", + up->Address.Addr.Bus,up->Address.Addr.Device, up->Address.Addr.Function, aspmc, mpl)); + + if(up->PciExpress==NULL) continue; + +#if PCI_EXPRESS_GEN2_SUPPORT == 1 + if(pe2){ + //If applicable + //Set Device fetures for GEN2 devices + Status=Pcie2SetDevProperties(up); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } +#endif + + //Set fetures selected in SETUP + Status=PcieSetDevProperties(up, mpl); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //SetFlag DevProgrammed FLAG.. + up->PciExpress->DevSet=TRUE; + + //Remove processed entrie from EndPoint Database... + Status=PcieRemoveEpFromLst(up); + } //for + }//if Mf endpoint + + //Restore "up" var + if(f0!=NULL) up=f0; + + PCI_TRACE((TRACE_PCI,"<---# RootComp/DNSTREAM @ [B%X|D%X|F%X] ASPM=%X; MPL=%X;\n", + dn->Address.Addr.Bus,dn->Address.Addr.Device, dn->Address.Addr.Function, aspmc, mpl)); + + //now do the DownStream Port... it always ONLY one device! +#if PCI_EXPRESS_GEN2_SUPPORT == 1 + if(pe2){ + //If applicable + //Set Device fetures for GEN2 devices + Status=Pcie2SetDevProperties(dn); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } +#endif + Status=PcieSetDevProperties(dn,mpl); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + + //Aspm is off at that point. + //We should turn it on first in UPSTREAM PORT, than IN DOWNSTREAM port. + //Since we can owerwrite Settings + Status=PcieSetAspm(dn,up,aspmc); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //SetFlag DevProgrammed FLAG.. + dn->PciExpress->DevSet=TRUE; + + //Remove processed entrie from EndPoint Database... + //Status=PcieRemoveEpFromLst(dn); + + //Go to the next link if any... + up=dn->ParentBrg; + } while (up!=NULL && up->ParentBrg!=NULL && up->ParentBrg->Type!=tPciRootBrg && up->ParentBrg->PciExpress!=NULL); //(EIP49743) + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieInitDevChain() +// +// Description: This function will detect optimal settings and programm - +// MaxPayLoadSize, ReadRequestSize, ASPM settings and Virtual Channels +// for all devices in the PCIE Links Chain. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Notes: +// RootPortComplex<=>Switch0...<=>...SwitchN<=>EndPoint +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieInitDevChain(PCI_DEV_INFO* Device ){ + EFI_STATUS Status=0; + UINT16 mpl=-1,mrr=-1; + UINTN lt0=0,lt1=0; //Latency in Nano Seconds. + UINT16 reg_lt0=0,reg_lt1=0;//Latency to be written into Register. +#if EFI_DEBUG == 1 //debug +//------------------------------ + PCIE_PCIE_CAP_REG pciecap; + PCIE_DEV_CAP_REG devcap; + PCIE_LNK_CAP_REG lnkcap; + PCIE_SLT_CAP_REG sltcap; + +#if PCI_EXPRESS_GEN2_SUPPORT == 1 + PCIE_DEV_CAP2_REG devcap2; + PCIE_LNK_CAP2_REG lnkcap2; +#endif +//----------------------------- +#endif //debug +//----------------------- + + //Now we will programm clock config when exiting from the bridge + //Collect Min Supported feature at the length of the PCIE Devices Chain +#if EFI_DEBUG == 1 //debug + pciecap.PCIE_CAP=Device->PciExpress->PcieCap.PCIE_CAP; + devcap.DEV_CAP=Device->PciExpress->DeviceCap.DEV_CAP; + lnkcap.LNK_CAP=Device->PciExpress->LinkCap.LNK_CAP; + sltcap.SLT_CAP=Device->PciExpress->SlotCap.SLT_CAP; +#if PCI_EXPRESS_GEN2_SUPPORT == 1 + devcap2.DEV_CAP2=Device->PciExpress->Pcie2->DeviceCap2.DEV_CAP2; + lnkcap2.LNK_CAP2=Device->PciExpress->Pcie2->LinkCap2.LNK_CAP2; +#endif +#endif//debug + + //Get MaxPayLoad + mpl=PcieCalcMaxPayLoad(Device); + + //After PcieCalcMaxPayLoad() Payload has to be adjusted DOWN STREAM already (towards EP Device)... + //When We come here ASPM already disabled by PcieProbeDevice() function. + //Since we are going to use Porting Hook to overwrite ASPM settings Calculate Latency OLWAYS + //and Enable it only if Setup says so...- will be done in PcieSetAspm() + + + //Get L0s L1 exit Latencies if needed... +// if(gPciSetupData->AspmMode!=0){ + + lt0=PcieCalcLatency(Device,TRUE); + + //now we should add CIPSET internal L0s Exit Latency to the total value + //For NB if any + if( (NbDmiAspmSupport & PCIE_ASPM_L0_ENABLE ) && (SbDmiAspmSupport & PCIE_ASPM_L0_ENABLE )){ + if(NbDmiL0ExitLatency > SbDmiL0ExitLatency) lt0 += NbDmiL0ExitLatency; + else lt0 += SbDmiL0ExitLatency; + } + //and SB if any + reg_lt0+=(UINT16) PcieConvertLatency(lt0, TRUE, FALSE); + +// if(gPciSetupData->AspmMode > 1){ + lt1=PcieCalcLatency(Device,FALSE); + + //now we should add CIPSET L1 Exit Latency to the total value + if( (NbDmiAspmSupport & PCIE_ASPM_L1_ENABLE ) && (SbDmiAspmSupport & PCIE_ASPM_L1_ENABLE )){ + if(NbDmiL1ExitLatency > SbDmiL1ExitLatency) lt1 += NbDmiL1ExitLatency; + else lt1 += SbDmiL1ExitLatency; + } + //and SB + lt1+=SbInternalDelay; + reg_lt1+=(UINT16) PcieConvertLatency(lt1, FALSE, FALSE); + +// } else reg_lt1=0xFFFF; +// } else reg_lt0=0xFFFF; + + //Apply collected values to the devices + Status=PcieApplyDevSettings(Device, mpl, reg_lt0, reg_lt1); + + return Status; +} + +#if SRIOV_SUPPORT +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ProbeSriovDevice() +// +// Description: This function will collect information about SRIOV PCIE Device +// and initialize it based on information collected. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ProbeSriovDevice(PCI_DEV_INFO *Device, UINT32 SriovCapBaseOffset){ + EFI_STATUS Status; + PCIE_SRIOV_CNT_REG SrIoVControl; + UINT32 PageSize, i=0, incr, maxbar; + UINT16 InitialFv; + UINT16 FirstVfOffset; + UINT16 VfStride; + UINT16 RoutingId; + UINT8 VfMaxBus; + + PCI_BAR *Bar; + PCI_CFG_ADDR addr; + + addr.ADDR=Device->Address.ADDR; + addr.Addr.ExtendedRegister = SriovCapBaseOffset; + PCI_TRACE((TRACE_PCI,"PciBus: Found SRIOV Device @ B%X|D%X|F%X; ", addr.Addr.Bus, addr.Addr.Device, addr.Addr.Function)); + +// Device->PciExpress->SriovData = MallocZ(sizeof(PCIE_SRIOV_DATA)); +// ASSERT(Device->PciExpress->SriovData!=NULL); + + //Disable VFs before any further manipulations + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_CNT_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&SrIoVControl.SRIOV_CNT); + ASSERT_EFI_ERROR(Status); + SrIoVControl.VfEnable = 0; + SrIoVControl.VfMse = 0; + Status=PciCfg16(Device->RbIo,addr,TRUE,&SrIoVControl.SRIOV_CNT); + ASSERT_EFI_ERROR(Status); + + //Initislize System Page Size + //get supported page sizes + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_SUPPORTED_PAGE_SIZES_OFFSET; + Status=PciCfg32(Device->RbIo,addr,FALSE,&PageSize); + ASSERT_EFI_ERROR(Status); + PCI_TRACE((TRACE_PCI,"PageSize: Sup=0x%X; ", PageSize)); + if(PageSize){ + //find the leftmost non-zero bit + for(i=1; (PageSize&i)==0 && i!=0; i<<=1) ; + ASSERT(i!=0); + //set page size + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_SYSTEM_PAGE_SIZE_OFFSET; + Status=PciCfg32(Device->RbIo,addr,TRUE,&i); + ASSERT_EFI_ERROR(Status); + PageSize = 1<<(i+11); + } + PCI_TRACE((TRACE_PCI,"Progr=0x%X(0x%X); ", i, PageSize)); + + //Read InitialFv (number of initially associated VFs) + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_INITIAL_VF_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&InitialFv); + ASSERT_EFI_ERROR(Status); + PCI_TRACE((TRACE_PCI,"InitialFv=%X; ", InitialFv)); + + //Calculate number of buses conumed by VF + //Read FirstVfOffset + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_FIRST_VF_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&FirstVfOffset); + ASSERT_EFI_ERROR(Status); + PCI_TRACE((TRACE_PCI,"FirstVfOffset=%X; ", FirstVfOffset)); + //Read VfStride + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_VF_STRIDE_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&VfStride); + ASSERT_EFI_ERROR(Status); + PCI_TRACE((TRACE_PCI,"VfStride=%X; ", VfStride)); + //Calculate number of busses conusmed by all VF + RoutingId = //Request ID of PF + (addr.Addr.Bus << 8 ) + + (addr.Addr.Device << 3 ) + + addr.Addr.Function + + FirstVfOffset + (InitialFv-1)*VfStride; + VfMaxBus = (UINT8)(RoutingId>>8); + PCI_TRACE((TRACE_PCI,"VfMaxBus=%X; ", VfMaxBus)); + //reserve additional buses consumed by VF + mMaxBusFound=VfMaxBus; + + //Read VF BARs + addr.Addr.ExtendedRegister=SriovCapBaseOffset+PCIE_SRIOV_VF_BAR0_OFFSET; + incr=0; + Bar = &Device->PciExpress->SriovData->Bar[0]; + maxbar = PCI_MAX_BAR_NO; + for(i=0; i<maxbar; i++){ + UINT32 old32, val32; + UINT64 old64, val64; + Status=PciCfg32(Device->RbIo,addr,FALSE,&val32); + if(EFI_ERROR(Status)) return Status; + ASSERT((val32 & 1)==0) //VF BAR must be MMIO + switch (val32 & 0x0F) { + case 0x0 : + Bar[i].Type=tBarMmio32; + Bar[i].DiscoveredType=tBarMmio32; + incr=4; + break; + case 0x4 : + Bar[i].Type=tBarMmio64; + Bar[i].DiscoveredType=tBarMmio64; + incr=8; + maxbar--; + break; + case 0x8 : +#if PCI_AMI_COMBINE_MEM_PMEM32 == 1 + Bar[i].Type=tBarMmio32; +#else + Bar[i].Type=tBarMmio32pf; +#endif + Bar[i].DiscoveredType=tBarMmio32pf; + incr=4; + break; + case 0xc : + Bar[i].Type=tBarMmio64pf; + Bar[i].DiscoveredType=tBarMmio64pf; + incr=8; + maxbar--; + break; + default : return EFI_UNSUPPORTED; + } //switch + Bar[i].ExtOffset=addr.Addr.ExtendedRegister; + + val32=(~0); val64=(~0); + + switch (Bar[i].Type){ + + case tBarMmio64pf : + case tBarMmio64 : + Status=PciCfg64(Device->RbIo,addr,FALSE,&old64); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg64(Device->RbIo,addr,TRUE,&val64); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg64(Device->RbIo,addr,FALSE,&val64); + if(EFI_ERROR(Status)) return Status; + val64&=(~0x0F); //Mask don't care bits + if(val64){ + Bar[i].Gran=(UINTN)(~val64); + Bar[i].Length=Mul64((Bar[i].Gran+1),(UINT32)InitialFv); + } else { + Bar[i].Type=tBarUnused; + } + break; + + case tBarMmio32pf : + case tBarMmio32 : + Status=PciCfg32(Device->RbIo,addr,FALSE,&old32); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg32(Device->RbIo,addr,TRUE,&val32); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg32(Device->RbIo,addr,FALSE,&val32); + if(EFI_ERROR(Status)) return Status; + val32&=(~0x0F); + if(val32){ + Bar[i].Gran=(~val32); + Bar[i].Length=Mul64((Bar[i].Gran+1),(UINT32)InitialFv); + } else{ + Bar[i].Type=tBarUnused; + } + break; + + default : Bar[i].Type=tBarUnused; + }//switch + + //Restore Original Value value + if(Bar[i].Type!=tBarUnused){ + if(Bar[i].Type==tBarMmio64pf || Bar[i].Type==tBarMmio64) Status=PciCfg64(Device->RbIo,addr,TRUE,&old64); + else Status=PciCfg32(Device->RbIo,addr,TRUE,&old32); + if(EFI_ERROR(Status)) return Status; + } + Bar[i].Owner = Device; + addr.Addr.ExtendedRegister+=incr; + } // Bar enumeration loop + PCI_TRACE((TRACE_PCI,"\n")); + return EFI_SUCCESS; +} +#endif + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitDeviceVc() +// +// Description: This function will Init VC_DATA structure of the "Device". +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data. +// PCI_CFG_ADDR *DevAddr Pointer to Device Address value. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InitDeviceVc(PCI_DEV_INFO *Device, PCI_CFG_ADDR *DevAddr){ + EFI_STATUS Status; + VC_DATA *vcd=MallocZ(sizeof(VC_DATA)); + VC_RES_DATA *vcrd; + UINTN i; + PCI_CFG_ADDR addr; +//----------------- + addr.ADDR=DevAddr->ADDR; + if(!vcd) return EFI_OUT_OF_RESOURCES; + + Device->PciExpress->VcData=vcd; + vcd->VcOffset=addr.Addr.ExtendedRegister; + //Read and store VC Cap 1 reg + addr.Addr.ExtendedRegister=vcd->VcOffset+PCIE_PORTVC_CAP1_OFFSET; + Status=PciCfg32(Device->RbIo,addr,FALSE,&vcd->VcCap1.PORTVC_CAP1); + ASSERT_EFI_ERROR(Status); + + //Read and store VC Cap 2 reg + addr.Addr.ExtendedRegister=vcd->VcOffset+PCIE_PORTVC_CAP2_OFFSET; + Status=PciCfg32(Device->RbIo,addr,FALSE,&vcd->VcCap2.PORTVC_CAP2); + ASSERT_EFI_ERROR(Status); + + //Collect VC resource info... + for(i=0; i<vcd->VcCap1.ExtVcCnt+vcd->VcCap1.LPExtVcCnt+1; i++){ + vcrd=MallocZ(sizeof(VC_RES_DATA)); + if(!vcrd) return EFI_OUT_OF_RESOURCES; + addr.Addr.ExtendedRegister=(UINT32)(vcd->VcOffset+PCIE_VC_RES_CAP_OFFSET(i)); + //Record Offset of the VC resource capability register + vcrd->VcResOffset=addr.Addr.ExtendedRegister; + Status=PciCfg32(Device->RbIo,addr,FALSE,&vcrd->VcResCap.VC_RESCAP); + ASSERT_EFI_ERROR(Status); + + Status=AppendItemLst((T_ITEM_LIST*)&vcd->InitCnt, vcrd); + if(EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES; + } + return Status; +} + + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieProbeDevice() +// +// Description: This function will collect information about PCIE Device +// and initialize it based on information collected. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Notes: The function will do the following steps +// 1.disable ASPM if any; +// 2.disable PMI Generation if any; +// 3.power up PCIE Slot (if capable) if the slot has device behind it; +// 4.if nothing connected to slot, power it down to make it HOTPLUG READY; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PcieProbeDevice(PCI_DEV_INFO *Device){ + PCI_CFG_ADDR addr; + PCIE_DEV_CNT_REG devc; + PCIE_LNK_CNT_REG lnkc; + PCIE_EXT_CAP_HDR extcap; + PCIE_LNK_STA_REG lnks; + EFI_STATUS Status=0; +//------------------------------------- + + //init fields that not suppose to be 0 + Device->PciExpress->MaxL0Lat=0xFFFF; + Device->PciExpress->MaxL1Lat=0xFFFF; + + addr.ADDR=Device->Address.ADDR; + + //Get PCI Express CAPs - 16 bit + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_CAP_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&Device->PciExpress->PcieCap.PCIE_CAP); + ASSERT_EFI_ERROR(Status); + + Status=PcieGetCaps(Device); + ASSERT_EFI_ERROR(Status); + + //Get PCI Express Slot it is valid only for Ports Switches and Bridges + if((Device->Type==tPci2PciBrg) || (Device->Type==tPci2CrdBrg)) PcieSetSlotProperties(Device); + + //Disable Device Control Reg functions we'll not need now + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_DEV_CNT_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + //Set Default values + devc.CorrErrRep=0; //bit 0 + devc.NfErrRep=0; //bit 1 + devc.FatalErrRep=0; //bit 2 + devc.UsupReqRep=0; //bit 3 + devc.RelaxOrder=1; //bit 4 + devc.MaxPayload=PCIE_MAXPL_128B;//bit 5..7 + devc.ExtTagFld=0; //bit 8 + devc.PhantomFunc=0; //bit 9 + devc.NoSnoop=1; //bit 11 + //Don't touch MRR value it might be device dependent and may cause system hung + //devc.MaxReadReq=PCIE_MAXPL_512B;//bit 12..14 + + Status=PciCfg16(Device->RbIo,addr,TRUE,&devc.DEV_CNT); + ASSERT_EFI_ERROR(Status); + + //Get common Lnk Properties from LNK_STA reg.. + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_STA_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&lnks.LNK_STA); + ASSERT_EFI_ERROR(Status); + + //Update data + Device->PciExpress->CurrLnkSpeed=(UINT8)lnks.LnkSpeed; + Device->PciExpress->CurrLnkWidth=(UINT8)lnks.LnkWidth; + + //Disable ASPM + addr.Addr.Register=Device->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + Status=PciCfg16(Device->RbIo,addr,FALSE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + + lnkc.AspmControl=PCIE_ASPM_DISABLE; + lnkc.ExtSynch=0; + + Status=PciCfg16(Device->RbIo,addr,TRUE,&lnkc.LNK_CNT); + ASSERT_EFI_ERROR(Status); + + //Check Pci Express Extended Capability header + addr.Addr.ExtendedRegister=0x100; + //if something there advance trough EXT capabilities list to find VC Cap + while(addr.Addr.ExtendedRegister){ + Status=PciCfg32(Device->RbIo,addr,FALSE,&extcap.EXT_CAP_HDR); + ASSERT_EFI_ERROR(Status); + //Check if Extended PciExpress Config Space is assessible. + if(extcap.ExtCapId==0xFFFF) break; //(EIP19144+) + + //we've got VC Cap header + if(extcap.ExtCapId==PCIE_CAP_ID_VIRTUAL_CH){ + PCI_TRACE((TRACE_PCI,"PciE2: Found VIRTUAL_CHNL Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + Status=InitDeviceVc(Device, &addr); + ASSERT_EFI_ERROR(Status); + } +#if SRIOV_SUPPORT + if (extcap.ExtCapId==PCIE_CAP_ID_SRIOV){ + PCI_TRACE((TRACE_PCI,"PciE2: Found SRIOV Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + Status=CollectDeviceExtCap(Device, &Device->PciExpress->SriovData, sizeof(PCIE_SRIOV_DATA), + addr.Addr.ExtendedRegister, FALSE, 0); //32 bit cap register + ASSERT_EFI_ERROR(Status); + + Status=ProbeSriovDevice(Device, addr.Addr.ExtendedRegister); + ASSERT_EFI_ERROR(Status); + } +#endif +#if PCI_EXPRESS_GEN2_SUPPORT + //Check and collect capability (read only) data from devices + //1. Alternative Routing ID capabilities + if (extcap.ExtCapId==PCIE_CAP_ID_ARI){ + PCI_TRACE((TRACE_PCI,"PciE2: Found ARI Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + + Status=CollectDeviceExtCap(Device, &Device->PciExpress->AriData, sizeof(PCIE2_ARI_DATA), + addr.Addr.ExtendedRegister, TRUE, 0); // 16 bit cap reg + ASSERT_EFI_ERROR(Status); + } + + //2. Access Control Services + if (extcap.ExtCapId==PCIE_CAP_ID_ACS){ + PCI_TRACE((TRACE_PCI," PciE2: Found ACS Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + Status=CollectDeviceExtCap(Device, &Device->PciExpress->AcsData, sizeof(PCIE2_ACS_DATA), + addr.Addr.ExtendedRegister, TRUE, 0); // 16 bit cap reg + ASSERT_EFI_ERROR(Status); + } + + //3. Address Translation services + if (extcap.ExtCapId==PCIE_CAP_ID_ATS){ + PCI_TRACE((TRACE_PCI,"PciE2: Found ATS Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + Status=CollectDeviceExtCap(Device, &Device->PciExpress->AtsData, sizeof(PCIE2_ATS_DATA), + addr.Addr.ExtendedRegister, TRUE, 0); // 16 bit cap reg + ASSERT_EFI_ERROR(Status); + } + +#if PCI_EXPRESS_GEN3_SUPPORT + //check for Secondary PCIe Extended Capability header. + //must be implemented if device supports GEN 3 speed of 8.0 GT/s + if (extcap.ExtCapId==PCIE_CAP_ID_SEC_PCIE_CAP){ + PCI_TRACE((TRACE_PCI,"PciE3: Found SEC PCIe Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + Status=CollectDeviceExtCap(Device, &Device->PciExpress->Pcie3, sizeof(PCIE3_DATA), + addr.Addr.ExtendedRegister, FALSE, 4); // 32 bit cap reg + ASSERT_EFI_ERROR(Status); + } +#endif +#endif //gen2 support + //4. Internal RC Link + if (extcap.ExtCapId==PCIE_CAP_ID_RC_INT_LNK){ + PCI_TRACE((TRACE_PCI,"PciE2: Found INT_LINK Ext Cap Header @ offset 0x%X\n", addr.Addr.ExtendedRegister)); + Status=CollectDeviceExtCap(Device, &Device->PciExpress->RcLnkData, sizeof(PCIE_RCLNK_DATA), + addr.Addr.ExtendedRegister, FALSE, 0); // 32 bit cap reg + ASSERT_EFI_ERROR(Status); + } + + addr.Addr.ExtendedRegister=extcap.NextItemPtr; + } //while loop serching for ext caps + +#if PCI_EXPRESS_GEN2_SUPPORT + //if PciExpress Capability Reg if it supports PCIe 2.1 + if(Device->PciExpress->PcieCap.CapVersion>=PCIE_CAP_VER2){ + Device->PciExpress->Pcie2=MallocZ(sizeof(PCIE2_DATA)); + if(Device->PciExpress->Pcie2==NULL){ + ASSERT_EFI_ERROR(EFI_OUT_OF_RESOURCES); + return EFI_OUT_OF_RESOURCES; + } else Status=Pcie2GetGen2Info(Device);//Function Will update GEN 3 Properties as well... + } +#endif + + //If device is Upstream Port type add it to an EndPoint device list. + if(!PcieIsDownStreamPort(Device) && (Device->Type!= tPci2PciBrg) && + (Device->PciExpress->PcieCap.PortType!=PCIE_TYPE_RC_INTEGR_EP) && + (Device->PciExpress->PcieCap.PortType!=PCIE_TYPE_RC_EVT_COLLECT) && + (Device->ParentBrg->ParentBrg != NULL)) + { + Status=AppendItemLst(&gPcieEpList, Device); + PCI_TRACE((TRACE_PCI,"PciE: Adding Device [B%X|D%X|F%X] to gPcieEpList[%d]\n", + Device->Address.Addr.Bus,Device->Address.Addr.Device, Device->Address.Addr.Function, gPcieEpList.ItemCount)); + ASSERT_EFI_ERROR(Status); + } + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PcieRecordBootScript() +// +// Description: This function will create S3 Resume Boot Script +// for Device's Virtual Channels feature initialization if device +// supports Virtual Channels. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID PcieRecordBootScript(PCI_DEV_INFO *Brg){ + PCI_DEV_INFO *dev; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Brg+1); + UINTN i,c; + PCI_CFG_ADDR addr; + EFI_STATUS Status; + UINT64 v=0; +//------------------------------ + for(i=0; i<ext->ChildCount; i++){ + dev=ext->ChildList[i]; + if(!dev->PciExpress) continue; + //It could be the case when we have PCI 2 PCI bridges chain and behind + //them we will found PCI 2 PCIE bridge. So starting from ROOT we should not + //skip bridges without PCIE Capabilities but must go inside and check! + //if((dev->PciExpress==NULL) || (dev->Type!=tPci2PciBrg && dev->Type!=tPci2CrdBrg)) continue; + + addr.ADDR=dev->Address.ADDR; + addr.Addr.ExtendedRegister=0; + //if device is PciExpress check if it has VC + if(dev->Type==tPci2PciBrg || dev->Type==tPci2CrdBrg){ + //record Base bus Subordinste bus Secondary bus registers programming + //to have device visible on the bus + addr.Addr.Register=PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET; + + Status=PciCfg32(dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + //call the same function recoursively + PcieRecordBootScript(dev); + + } + if(dev->PciExpress->VcData){ + //if(dev->PciExpress!=NULL && dev->PciExpress->VcData!=NULL){ + for(c=0; c<dev->PciExpress->VcData->VcCount; c++){ + VC_RES_DATA *vcrd=dev->PciExpress->VcData->VcResData[c]; + //--------------------------------------- + addr.Addr.ExtendedRegister=vcrd->VcResOffset+4; + Status=PciCfg32(dev->RbIo,addr,FALSE,(UINT32*)&v); + + BOOT_SCRIPT_S3_MEM_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + PCIE_CFG_ADDR(addr.Addr.Bus,addr.Addr.Device,addr.Addr.Function,addr.Addr.ExtendedRegister), + 1,&v); //Data + } + } + + if (gPciSetupData->S3PciExpressScripts){ + addr.ADDR=dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_DEV_CNT_OFFSET; + Status=PciCfg16(dev->RbIo,addr,FALSE,(UINT16*)&v); + + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR, + 1,&v); //Data + + addr.ADDR=dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_LNK_CNT_OFFSET; + Status=PciCfg16(dev->RbIo,addr,FALSE,(UINT16*)&v); + + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR, + 1,&v); //Data + + if(dev->PciExpress->PcieCap.SlotImpl){ + addr.ADDR=dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_SLT_CNT_OFFSET; + Status=PciCfg16(dev->RbIo,addr,FALSE,(UINT16*)&v); + + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR, + 1,&v); //Data + } + if(dev->PciExpress->Pcie2){ + addr.ADDR=dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_DEV_CNT2_OFFSET; + Status=PciCfg16(dev->RbIo,addr,FALSE,(UINT16*)&v); + + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR, + 1,&v); //Data + + addr.ADDR=dev->Address.ADDR; + addr.Addr.Register=dev->PciExpress->PcieOffs+PCIE_LNK_CNT2_OFFSET; + Status=PciCfg16(dev->RbIo,addr,FALSE,(UINT16*)&v); + + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR, + 1,&v); //Data + } + } // if (gPciSetupData->S3PciExpressScripts) + }//for +} +//---------------------------------------------------------------------------- +//Enable PCI Express Handling only if PCI Express Base is Defined and !=0 +#endif //PCI_EXPRESS_SUPPORT +//---------------------------------------------------------------------------- + +#if S3_VIDEO_REPOST_SUPPORT == 1 +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SaveBars() +// +// Description: This function will create S3 Resume Boot Script +// for Device's BAR Registers. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// +// Output: +// Nothing. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SaveBars(PCI_DEV_INFO *Dev){ + UINTN i; + PCI_BAR *bar; + PCI_CFG_ADDR addr; + EFI_STATUS Status; + UINT64 v=0; + PCI_BRG_EXT *ext; +//---------------------------- + + for( i=0; i < PCI_MAX_BAR_NO+1; i++){ + bar=&Dev->Bar[i]; + addr.ADDR=Dev->Address.ADDR; + addr.Addr.ExtendedRegister=0; + + if( (bar->Type != tBarUnused) && (bar->Length != 0)){ + addr.Addr.Register=bar->Offset; + if( (Dev->Bar[0].DiscoveredType == tBarMmio64) || (Dev->Bar[0].DiscoveredType == tBarMmio64pf)){ + Status=PciCfg64(Dev->RbIo,addr,FALSE,&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint64, //Width + addr.ADDR,1,&v); //Address, Data + } else { + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + } + } + } //for + + //if device is p2p bridge + if( Dev->Type == tPci2PciBrg){ + //get bridge extension structure pointer + ext=(PCI_BRG_EXT*)(Dev+1); + + //For IO 16 Resources Decoded by the bridge + addr.Addr.Register = ext->Res[rtIo16].Offset; + Status=PciCfg16(Dev->RbIo,addr,FALSE,(UINT16*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR,1,&v); //Address, Data + //Upper 16bits for IO window + addr.Addr.Register = 0x30; + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + + //For MMIO Resources Decoded by the bridge + addr.Addr.Register = ext->Res[rtMmio32].Offset; + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + //For MMIO_PF + addr.Addr.Register = ext->Res[rtMmio32p].Offset; + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + //For MMIO_PF Upper 32 bit + addr.Addr.Register = 0x28; + Status=PciCfg64(Dev->RbIo,addr,FALSE,&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint64, //Width + addr.ADDR,1,&v); //Address, Data + } + + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SaveDevice() +// +// Description: This function will create S3 Resume Boot Script +// for Device's other than BAR Registers. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure. +// +// Output: +// Nothing. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SaveDevice(PCI_DEV_INFO *Dev){ + PCI_CFG_ADDR addr; + EFI_STATUS Status; + UINT64 v=0; +//---------------------------- + addr.ADDR=Dev->Address.ADDR; + addr.Addr.ExtendedRegister=0; + + //get Cache line size and Latency Timer + ProgInterface + addr.Addr.Register=PCI_CLS; + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + //Save content of BARs + SaveBars(Dev); + + //get IntLine; IntPin; MaxLat; MinGnt + addr.Addr.Register=PCI_INTLINE; + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + + + //if device is Pci2PciBrg + if( Dev->Type == tPci2PciBrg){ + + //get Base bus Subordinste bus Secondary bus registers + Secondary Latency Timer + addr.Addr.Register=PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET; + + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + + } else { + //Get Subsystem VID; DID Just In case... + addr.Addr.Register=PCI_SVID; + Status=PciCfg32(Dev->RbIo,addr,FALSE,(UINT32*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint32, //Width + addr.ADDR,1,&v); //Address, Data + + } + + //Now get Device Control Reg + addr.Addr.Register=PCI_COMMAND_REGISTER_OFFSET; + Status=PciCfg16(Dev->RbIo,addr,FALSE,(UINT16*)&v); + BOOT_SCRIPT_S3_PCI_CONFIG_WRITE_MACRO( + gBootScriptSave, //This + EfiBootScriptWidthUint16, //Width + addr.ADDR,1,&v); //Address, Data + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: RecordPriVgaBootScript() +// +// Description: This function will create S3 Resume Boot Script +// for Device's on the path of primary VGA Device inclusive. +// +// Input: +// Nothing +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID RecordPriVgaBootScript(IN EFI_EVENT Event, IN VOID *Context){ + PCI_DEV_INFO *vga=NULL; + PCI_DEV_INFO *dev; + PCI_HOST_INFO *hst=&gPciHost[0]; + PCI_BRG_EXT *ext; + T_ITEM_LIST VgaPath={0,0,NULL}; + INTN i; + UINTN j; + EFI_STATUS Status; +//------------------------------ + for( i=0; (UINTN)i<gHostCnt; i++){ + hst=&gPciHost[i]; + //There might be only one legacy VGA device in the system + if( hst->VgaDev!=0){ + vga=hst->VgaDev; + break;//there will be only one Primary VGA + } + } + + //If we can't find Primery VGA device just exit + //Most likely we are dealing here with headless system. + if( vga == NULL){ + return; + } + + dev = vga; + //Save Device pointers in Current Primary Vga Path + while (dev!=NULL){ + Status=AppendItemLst(&VgaPath,dev); + dev=dev->ParentBrg; + } + + //Now write the boot script in opposite order for the devices stored @ VgaPath object. + //So the script will go from Host Bridge down to the Pri VGA device + for(i=VgaPath.ItemCount-1; i>=0;i--){ + dev=(PCI_DEV_INFO*)VgaPath.Items[i]; + + //Save device content into BOOT SCRIPT + SaveDevice(dev); + + //Now check if device is a multifunction device + //if so it's other functions needs to be saved as well + if( ( dev->ParentBrg !=NULL) && ( dev->Type != tPci2PciBrg)){ + + ext = (PCI_BRG_EXT*)(dev->ParentBrg+1); + //check for devices with the same Dev# but different Function# among device's ParentBridge childs... + for(j=0; j<ext->ChildCount; j++){ + vga=ext->ChildList[j]; + //Since this is one bridge childs they have to have same bus + if(vga->Address.Addr.Device == dev->Address.Addr.Device && + vga->Address.Addr.Function != dev->Address.Addr.Function) { + SaveDevice(vga); + } + + }//for j + } + }//for i + + pBS->CloseEvent(Event); +} +#endif //S3_VIDEO_REPOST + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ResetDevicePm() +// +// Description: This function will turn off SMI generation on PCI PME +// and put device in to D0 state, if device has PM capability. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Device Private Data structure. +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID ResetDevicePm(PCI_DEV_INFO *Device) +{ + EFI_STATUS Status; + PCI_CFG_ADDR devaddr; + UINT16 pmcsrv=0x8000;//Turn off the PME assertion and set D0 PM State +//------------------------------- + + if(Device->PmiCapOffs){ + devaddr.ADDR=Device->Address.ADDR; + devaddr.Addr.Register=(UINT8)(Device->PmiCapOffs+4); // + Status=PciCfg16(Device->RbIo,devaddr,TRUE,&pmcsrv); + ASSERT_EFI_ERROR(Status); + } + return; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: QueryPciDevice() +// +// Description: This function will collect all possible data about PCI Device. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS QueryPciDevice(PCI_DEV_INFO *Device) +{ + EFI_STATUS Status=EFI_SUCCESS; + UINT8 maxbar, i, incr=0; + UINT64 buff=0xff, oldv; + PCI_CFG_ADDR devaddr; + UINT32 *b32=&(UINT32)buff, *o32=&(UINT32)oldv; +//------------------------------------------ + + //for accuracy + Device->Address.Addr.Register=0; + Device->Address.Addr.ExtendedRegister=0; + devaddr.ADDR=Device->Address.ADDR; + + PCI_TRACE((TRACE_PCI,"PciBus: Discovered PCI Device @ [B%X|D%X|F%X]; PCI_DEV_INFO.Type=%d.\n Device Data: -> ", + Device->Address.Addr.Bus, Device->Address.Addr.Device, + Device->Address.Addr.Function, Device->Type)); + + //Clear Interrupt line register + devaddr.Addr.Register=PCI_INTLINE; + //P2P Bridge Spec. v1.1 requires to set INT Line Register to 0xFF + //PCI spec 3.0 require to set it to 0xFF - means not connected for x86 architecture. + //Values of 0..0x0F indicating IRQ0..15 values 0x10..0xFE reserved. + Status=PciCfg8(Device->RbIo,devaddr,TRUE,(UINT8*)&buff); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //We must call Preprocess Controller + Status=DoPrepController(Device); + + Status=GetDeviceCapabilities(Device); + + Status=GetPciCapPtrs(Device); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + ResetDevicePm(Device); + + //Set Pci Latency Timer register according to the Setup settings; + devaddr.Addr.Register = 0x0d; + Status=PciCfg8(Device->RbIo,devaddr,TRUE,(UINT8*)&gPciSetupData->PciLatency); + if((Device->Type == tPci2PciBrg) || (Device->Type == tPci2CrdBrg)){ + devaddr.Addr.Register = 0x1b; + Status=PciCfg8(Device->RbIo,devaddr,TRUE,(UINT8*)&gPciSetupData->PciLatency); + } + +#if PCI_X_SUPPORT + //Set PCI-X Latency Timer register according to the Setup settings; + devaddr.Addr.Register = 0x0d; + Status=PciCfg8(Device->RbIo,devaddr,TRUE,(UINT8*)&gPciSetupData->PciXLatency); + if((Device->Type == tPci2PciBrg) || (Device->Type == tPci2CrdBrg)){ + devaddr.Addr.Register = 0x1b; + Status=PciCfg8(Device->RbIo,devaddr,TRUE,(UINT8*)&gPciSetupData->PciXLatency); + } +#endif + +//Enables PCI Express Handling only if PCI Express Base is Defined and !=0 +#if PCI_EXPRESS_SUPPORT + + if(Device->PciExpress) { + Status=PcieProbeDevice(Device); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; +/* + //If it is end point Device or PCIE 2 PCI bridge + if( + Device->PciExpress->PcieCap.PortType==PCIE_TYPE_LEGACYEP|| + Device->PciExpress->PcieCap.PortType==PCIE_TYPE_PCIE_PCI|| + Device->PciExpress->PcieCap.PortType==PCIE_TYPE_RC_INTEGR_EP || + Device->PciExpress->PcieCap.PortType==PCIE_TYPE_RC_EVT_COLLECT) + { + //Programm Common Clock it will affect ASPM latency of the devices + //So it has to be programmed first before collecting all the information about + //Device Max PLoad ant reqd request and ep Latency. + Status=PcieSetClockConfig(Device); + ASSERT_EFI_ERROR(Status); + + //Programm MaxPayLoad, ReadRequest ASPM settings + Status=PcieInitDevChain(Device); + ASSERT_EFI_ERROR(Status); + } +*/ + } +#endif + + if(CheckPciCompatibility(Device,NULL,tBarUnused))Device->Incompatible=TRUE; //(EIP41687) + switch (Device->Type){ + case tPci2PciBrg : + maxbar=2; + devaddr.Addr.Register=0x10; //first BAR starts here + break; + case tPciDevice : + case tPciHostDev: + maxbar=PCI_MAX_BAR_NO; + devaddr.Addr.Register=0x10; //first BAR starts here + break; + case tPci2CrdBrg : + maxbar=1; + devaddr.Addr.Register=0x10; //first BAR starts here + break; + default : return EFI_SUCCESS; //other devices not suppose to be examined???? + } + + for(i=0; i<maxbar; i++){ + buff=0; + oldv=0; + devaddr.Addr.Register=devaddr.Addr.Register+incr; + Status=PciCfg32(Device->RbIo,devaddr,FALSE,b32); + if(EFI_ERROR(Status)) return Status; + + //check if what it is... + if((*b32) & 1) { + Device->Bar[i].Type=tBarIo; + incr=4; + } else { + switch ((*b32) & 0x0F) { + case 0x0 : + Device->Bar[i].Type=tBarMmio32; + Device->Bar[i].DiscoveredType=tBarMmio32; + incr=4; + break; + case 0x4 : + Device->Bar[i].Type=tBarMmio64; + Device->Bar[i].DiscoveredType=tBarMmio64; + incr=8; + maxbar--; + break; + case 0x8 : +#if PCI_AMI_COMBINE_MEM_PMEM32 == 1 + Device->Bar[i].Type=tBarMmio32; +#else + Device->Bar[i].Type=tBarMmio32pf; +#endif + Device->Bar[i].DiscoveredType=tBarMmio32pf; + incr=4; + break; + case 0xc : + Device->Bar[i].Type=tBarMmio64pf; + Device->Bar[i].DiscoveredType=tBarMmio64pf; + incr=8; + maxbar--; + break; + default : return EFI_UNSUPPORTED; + } //switch + }// else for memory BAR + Device->Bar[i].Offset=devaddr.Addr.Register; + //Device->Bar[i].Owner=Device; + + buff=(~0ULL); + + switch (Device->Bar[i].Type){ + + case tBarMmio64pf : + case tBarMmio64 : + Status=PciCfg64(Device->RbIo,devaddr,FALSE,&oldv); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg64(Device->RbIo,devaddr,TRUE,&buff); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg64(Device->RbIo,devaddr,FALSE,&buff); + if(EFI_ERROR(Status)) return Status; + buff&=(~0x0F); //Mask don't care bits + if(buff){ + //This workaround done for PCI Compliance Test... + //It could be the BAR that clames - "I'm a 64bit BAR", + //but implemented as 32bit register. This BAR will not hold + //64bit address and must be converted to 32bit BAR. + if(buff<=0xFFFFFFFF) { + buff|=0xFFFFFFFF00000000; + Device->Bar[i].Type-=2; //reduce tBarType to 32 bit BAR + } + Device->Bar[i].Gran=(UINTN)(~buff); + if(Device->Incompatible) AdjustBarGra(&Device->Bar[i]); + if(Device->Bar[i].Type==tBarUnused) { + Status=PciCfg64(Device->RbIo,devaddr,TRUE,&oldv); + if(EFI_ERROR(Status)) return Status; + } + Device->Bar[i].Length=Device->Bar[i].Gran+1; + } else Device->Bar[i].Type=tBarUnused; + break; + + case tBarMmio32pf : + case tBarMmio32 : + case tBarIo : + Status=PciCfg32(Device->RbIo,devaddr,FALSE,o32); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg32(Device->RbIo,devaddr,TRUE,b32); + if(EFI_ERROR(Status)) return Status; + Status=PciCfg32(Device->RbIo,devaddr,FALSE,b32); + if(EFI_ERROR(Status)) return Status; + if(Device->Bar[i].Type==tBarIo){ + (*b32)&=(~0x03); + if(*b32){ + //We got something here try to determine is it 32 bit addressing IO + //of 16 bit addressing + if(*b32&0xFFFF0000) { + Device->Bar[i].Type=tBarIo32; + Device->Bar[i].DiscoveredType=tBarIo32; + } else { + (*b32)|=(0xffff0000); + Device->Bar[i].Type=tBarIo16; + Device->Bar[i].DiscoveredType=tBarIo16; + } + } + } else (*b32)&=(~0x0F); + if(*b32){ + Device->Bar[i].Gran=(~(*b32)); + if(Device->Incompatible) AdjustBarGra(&Device->Bar[i]); + if(Device->Bar[i].Type==tBarUnused) { + Status=PciCfg32(Device->RbIo,devaddr,TRUE,o32); + if(EFI_ERROR(Status)) return Status; + } + Device->Bar[i].Length=Device->Bar[i].Gran+1; + //Doing work around for resource requirements for I/O + //where request is lesser than 16 bytes. I'll just make it 16 + //it might be some compatibility issues if I/O resourtce alignment will be + // lesser than 8 byte + if((Device->Bar[i].Type==tBarIo32 || Device->Bar[i].Type==tBarIo16)&& + Device->Bar[i].Length<0x10) + { + Device->Bar[i].Length=0x10; + Device->Bar[i].Gran=0x0F; + } + + } else Device->Bar[i].Type=tBarUnused; + break; + + default : Device->Bar[i].Type=tBarUnused; + }//switch + + //Restore Original Value value + if(Device->Bar[i].Type!=tBarUnused){ + if(Device->Bar[i].Type==tBarMmio64pf || Device->Bar[i].Type==tBarMmio64) Status=PciCfg64(Device->RbIo,devaddr,TRUE,&oldv); + else Status=PciCfg32(Device->RbIo,devaddr,TRUE,o32); + if(EFI_ERROR(Status)) return Status; + } + +//Check that all MMIO is allocated in 4k aligned chanks IVT-d requirements +#if( (defined iVTd_SUPPORT && iVTd_SUPPORT == 1) || ( PCI_4K_RESOURCE_ALIGNMENT == 1 ) || (SRIOV_SUPPORT == 1) ) +//--------------------------------------------- + if((Device->Bar[i].Type==tBarMmio64pf || Device->Bar[i].Type==tBarMmio64 || + Device->Bar[i].Type==tBarMmio32pf || Device->Bar[i].Type==tBarMmio32) && + Device->Bar[i].Length<0x1000 ) { + Device->Bar[i].Length=0x1000; + Device->Bar[i].Gran=0xFFF; + } +//--------------------------------------------- +#endif + + } // Bar enumeration loop + + if(Device->Type==tPci2CrdBrg){ + //Clear Brg Control Reg bits 8 & 9 to signify that Mem Window 1&2 is not PF + devaddr.Addr.Register=PCI_BRIDGE_CONTROL_REGISTER_OFFSET; + Status=PciCfg16(Device->RbIo,devaddr,FALSE,(UINT16*)&buff); + ASSERT_EFI_ERROR(Status); + buff&=(~(BIT09 | BIT08)); //Memory Window 2 is nonPF + Status=PciCfg16(Device->RbIo,devaddr,TRUE,(UINT16*)&buff); + ASSERT_EFI_ERROR(Status); + } + + //now we're going to check if any Option ROM present + Status=OptionRom(Device); +#if EFI_DEBUG + for(i=0; i<=PCI_MAX_BAR_NO; i++){ + + if((Device->Bar[i].Type>0) && (Device->Bar[i].Length>0)) + { + PCI_TRACE((TRACE_PCI,"BAR Index=%d;\tType=%d;\tGRA=0x%lX;\tLEN=0x%lX;\tOffset=0x%X;\n", + i, Device->Bar[i].Type, Device->Bar[i].Gran, + Device->Bar[i].Length, Device->Bar[i].Offset)); + } + } + PCI_TRACE((TRACE_PCI,"\n")); +#endif + + Device->Discovered=TRUE; + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ApplyCrdPadding() +// +// Description: This function applys default Card Bus Bridge Padding. +// +// Input: +// PCI_DEV_INFO *Device Pointer to PCI Device Private Data structure. +// MRES_TYPE ResType Type of resource padding is applied. +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID ApplyCrdPadding(PCI_DEV_INFO *Device, MRES_TYPE ResType){ + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Device+1); + PCI_BAR *bbar=&ext->Res[ResType]; +//--------------- + + bbar->Type=ResType+1; + switch(ResType){ + case rtIo16: + bbar->Length+=0x1000; + if(bbar->Gran < 0xFFF) bbar->Gran=0xFFF; + break; + + case rtIo32: + if(CPU_MAX_IO_SIZE <= 0x10000) { + bbar->Type=tBarUnused; + bbar=&ext->Res[ResType-1]; + } + bbar->Length+=0x1000; + if(bbar->Gran < 0xFFF) bbar->Gran=0xFFF; + break; + + case rtMmio32: + bbar->Length+=0x1400000; + if(bbar->Gran < 0xFFFFF) bbar->Gran=0xFFFFF; + break; + + case rtMmio32p: + if (gAllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) { + bbar->Type=tBarUnused; + bbar=&ext->Res[ResType-1]; + } + bbar->Length+=0x1400000; + if(bbar->Gran < 0xFFFFF) bbar->Gran=0xFFFFF; + break; + case rtMmio64: + case rtMmio64p: + bbar->Type=tBarUnused; + break; + } + + ext->Padded=TRUE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Cmp128Int() +// +// Description: This function compares 2 128 bit integers. +// +// Input: +// VOID* pDestination *Pointer to the 128bit Integer to compare. +// VOID* pSource *Pointer to the 128bit Integer to compare. +// +// Output: INTN +// == 0 Destination and are Source equal; +// > 0 Destination is bigger than Source; +// < 0 Destination is lesser than Source; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +INTN Cmp128Int(VOID* pDestination, VOID* pSource){ + INT64 r; + UINT64 *d=(UINT64*)pDestination; + UINT64 *s=(UINT64*)pSource; +//---------------------------------- + r = d[1] - s[1]; + if( r == 0){ + r = d[0] - s[0]; + } + return (r>0) ? 1 : (r<0) ? -1 : 0; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Cmp128IntRR() +// +// Description: This function compares 2 128 bit integers with respect to EFI +// Database Engine Record to Record comparation Routine. +// When position of record gets determined. +// +// Input: +// VOID* pContext Pointer to the DBE_OFFSET_KEY_CONTEXT structure +// VOID* pRecord1 Pointer to the 128bit Integer to compare. +// VOID* pRecord2 Pointer to the 128bit Integer to compare. +// +// Output: INTN +// == 0 pRecord1 and are pRecord2 equal; +// > 0 pRecord1 is bigger than pRecord2; +// < 0 pRecord2 is lesser than pRecord2; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +INTN Cmp128IntRR(IN VOID *pContext, VOID *pRecord1, VOID *pRecord2) +{ + DBE_OFFSET_KEY_CONTEXT *pOffsetKey = (DBE_OFFSET_KEY_CONTEXT*)pContext; +//-------------------------- + return Cmp128Int((VOID*)((INT8*)pRecord1+pOffsetKey->Offset),(VOID*)((INT8*)pRecord2+pOffsetKey->Offset)); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: Cmp128IntKR() +// +// Description: This function compares 2 128 bit integers with respect to EFI +// Database Engine Key to Record comparation Routine. +// When search for record is conducted. +// +// Input: +// VOID* pContext Pointer to the DBE_OFFSET_KEY_CONTEXT structure +// VOID* pRecord1 Pointer to the 128bit Integer to compare. +// VOID* pRecord2 Pointer to the 128bit Integer to compare. +// +// Output: INTN +// == 0 pRecord1 and are pRecord2 equal; +// > 0 pRecord1 is bigger than pRecord2; +// < 0 pRecord2 is lesser than pRecord2; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +INTN Cmp128IntKR(IN DBE_OFFSET_KEY_CONTEXT *pContext, VOID *pKey, VOID *pRecord) +{ + DBE_OFFSET_KEY_CONTEXT *pOffsetKey = (DBE_OFFSET_KEY_CONTEXT*)pContext; +//------------------------------ + return Cmp128Int((VOID*)pKey,(VOID*)((INT8*)pRecord+pOffsetKey->Offset)); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FreeResDb() +// +// Description: This function suppore to free memory allocated for index array +// pool of the EFI Database Engine DATABASE. +// +// Input: +// DBE_DATABASE* Db Pointer to the EFI Database Engine DATABASE. +// +// Output: EFI_STATUS +// EFI_SUCCESS if everything OK; +// an EFI_ERROR if an ERROR +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS FreeResDb(DBE_DATABASE *Db){ + if(Db->IndexArray!=NULL)return pBS->FreePool(Db->IndexArray); + else return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitResDb() +// +// Description: This function suppore to initialize EFI Database Engine DATABASE +// with PCI_BAR pointers in decending order. +// +// Input: +// DBE_DATABASE* Db Pointer to the EFI Database Engine DATABASE. +// PCI_DEV_INFO* Brg, Bridge whose BARs must be stuffed in DATABASE. +// MRES_TYPE ResType Resource type of the BARs. +// BOOLEAN Dev We are filling DATABASE with Bridges or Devices. +// +// Output: EFI_STATUS +// EFI_SUCCESS if everything OK; +// an EFI_ERROR if an ERROR +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InitResDb(DBE_DATABASE *Db, PCI_DEV_INFO *Brg, MRES_TYPE ResType, BOOLEAN Dev){ + EFI_STATUS Status=0; + PCI_DEV_INFO *dev; + PCI_BRG_EXT *Ext=(PCI_BRG_EXT*)(Brg+1); + UINTN i,j; +//------------------------------------ + + //Initialize Optimization Database + Db->KeyCount=1; + Db->KeyField=&gBarKey; + Db->MemoryType=EfiBootServicesData; + Db->RecordCount=0; + + if(Dev)Db->InitialCount=0x30; //least likely it would be more than 48 BARs of the same type + else Db->InitialCount=0x10; //same 16 for the bridges, but anyway it would be realocated... + + Status=pBS->AllocatePool(Db->MemoryType,sizeof(VOID*)*Db->InitialCount,&Db->IndexArray); + if(EFI_ERROR(Status)) return Status; + + //Now we will stuff the database with resource requirements sorted in assending order + for(i=0; i<Ext->ChildCount; i++){ + dev=Ext->ChildList[i]; + + if(dev->OutOfResRemove) continue; + + if(Dev){ + for( j=0; j<PCI_MAX_BAR_NO+1; j++){ + //Use ResType+1 Since CountBars() takes diferent type of parameter - + //PCI_BAR_TYPE. It mapps to MRES_TYPE as MRES_TYPE+1 + if ((dev->Bar[j].Type==ResType+1) && dev->Bar[j].Length){ + Status=DbeInsert(Db,&dev->Bar[j]); + if(EFI_ERROR(Status)) return Status; + } + }//bar loop +#if SRIOV_SUPPORT + if (dev->PciExpress!=NULL && dev->PciExpress->SriovData!=NULL){ + PCI_BAR *VfBar = &dev->PciExpress->SriovData->Bar[0]; + for( j=0; j<PCI_MAX_BAR_NO; j++){ + //Use ResType+1 Since CountBars() takes diferent type of parameter - + //PCI_BAR_TYPE. It mapps to MRES_TYPE as MRES_TYPE+1 + if ((VfBar[j].Type==ResType+1) && VfBar[j].Length){ + Status=DbeInsert(Db,&VfBar[j]); + if(EFI_ERROR(Status)) return Status; + } + }//bar loop + } +#endif + } else { + //take care of the bridge + if(dev->Type==tPci2PciBrg || dev->Type==tPci2CrdBrg){ + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(dev+1); + //----------------------- + //Don't add empry bridge BARs + if((ext->Res[ResType].Type==ResType+1) && ext->Res[ResType].Length ){ + Status=DbeInsert(Db,&ext->Res[ResType]); + if(EFI_ERROR(Status)) Status; + } + } + } + } //child loop + +// if(!Db->RecordCount)Status=EFI_NOT_FOUND; + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AppendBarOrder() +// +// Description: This function suppore to fill array of BAR ORDER with actual +// order of PCI_BARs behind the Bridge and remove added BAR structure from +// the BAR DATABASE. +// +// Input: +// DBE_DATABASE* Db Pointer to the EFI Database Engine DATABASE. +// BRG_RES_ORDER* BrgResOrder Pointer to the Bridge Resource order structure. +// PCI_BAR Bar Pointer to the BAR structure to be added. +// +// Output: EFI_STATUS +// EFI_SUCCESS if everything OK; +// an EFI_ERROR if an ERROR +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AppendBarOrder(DBE_DATABASE *Db, BRG_RES_ORDER *BrgResOrder, PCI_BAR *Bar){ + EFI_STATUS Status; +//-------------------------- + Status=AppendItemLst((T_ITEM_LIST*)BrgResOrder, Bar); + if(EFI_ERROR(Status))return Status; + + //Remove copied record from Database it not suppose to clear the *bar variable; + Status=DbeDelete(Db,Bar,FALSE); + + PCI_TRACE((TRACE_PCI," BAR: Len=0x%lX;\t Gra=0x%lX;\t Ofs=0x%X; Owner->[B%X|D%X|F%X] DEV_TYPE=%d\n", + Bar->Length, Bar->Gran, Bar->Offset, Bar->Owner->Address.Addr.Bus, + Bar->Owner->Address.Addr.Device, Bar->Owner->Address.Addr.Function, Bar->Owner->Type)); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: OptimizeBrgResource() +// +// Description: This function arrange Bridge resource request in a way it will +// consume a optimal amount of resources. +// +// Input: +// PCI_DEV_INFO* Brg, Bridge whose BARs must be stuffed in DATABASE. +// MRES_TYPE ResType Resource type we are doing optimization for. +// +// Output: EFI_STATUS +// EFI_SUCCESS if everything OK; +// an EFI_ERROR if an ERROR +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS OptimizeBrgResource(PCI_DEV_INFO *Brg, MRES_TYPE ResType){ + EFI_STATUS Status=0; + PCI_DEV_INFO *dev; //Device Dtata used for iteration, + PCI_DEV_INFO *brg; //Bridge Device used to identify Bridge resources with uneven Granularity. + PCI_BRG_EXT *Ext=(PCI_BRG_EXT*)(Brg+1),*ext; //This Bridge Bridge Extension Data. + UINTN i; + PCI_BAR *bar,*bbar,*nbbar,*nextbar; //temp BAR used in iterations, This Bridge child who is the bridge. + BRG_ALIGN_INFO *balign; + PCI_BAR *ebar; + BRG_RES_ORDER *ResOrd=&Ext->BarOrder[ResType]; //This Bridge this bridge Resource Alignment information + DBE_DATABASE DevDb={0,0,0,0,NULL,NULL},BrgDb={0,0,0,0,NULL,NULL}; + INT8 v; + UINT64 val; + UINT8 bit; +//------------------------------------ + + //No childs behind the bridge, no optimization... + if(!Ext->ChildCount)return EFI_SUCCESS; + PCI_TRACE((TRACE_PCI,"PciBus: OptimizeBrgRes() Bridge->[B%X|D%X|F%X] PCI_BRG_EXT.Res[%d] :\n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device, Brg->Address.Addr.Function, ResType)); + + + //Start the optimization + //1. Create Assending Sorted Database of all PCI Devices BARs behind the Brg of ResType. + Status=InitResDb(&DevDb, Brg, ResType, TRUE); + if(EFI_ERROR(Status)) goto ExitLbl; + + Status=InitResDb(&BrgDb, Brg, ResType, FALSE); + if(EFI_ERROR(Status)) goto ExitLbl; + + PCI_TRACE((TRACE_PCI," BAR(s) Order for %d Device BAR(s); %d Bridge BAR(s) of BAR_TYPE=%d\n", + DevDb.RecordCount, BrgDb.RecordCount, ResType+1)); + + //2. Start Populating Resource Array Brg->BarOrder[ResType] + while(DevDb.RecordCount || BrgDb.RecordCount){ + + if(BrgDb.RecordCount){ + Status=DbeGoToIndex(&BrgDb,0,BrgDb.RecordCount-1,&bbar); + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + } else bbar=NULL; + + if(DevDb.RecordCount){ + Status=DbeGoToIndex(&DevDb,0,DevDb.RecordCount-1,&bar); + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + } else bar=NULL; + + //Check if THIS Bridge has a bridge childs + if((bar!=NULL) && (bbar!=NULL)){ + //This case when we have bridge resourses among regular device resources + brg=bbar->Owner; + dev=bar->Owner; + ext=(PCI_BRG_EXT*)(brg+1); + balign=&ext->Align[ResType]; + + //1. Check first if Biggest resource in "BrgDb" - "bbar" has the same or lesser + //Alignment Requirements as a Biggest one in "DevDb" - "bar". balign->MaxGran + if(bar->Gran >= balign->MaxGran){ + Status=AppendBarOrder(&DevDb,ResOrd, bar); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto ExitLbl; + } else { + //This is the case when we should use PCI_BRG_EXT.ExtraRes[ResType] information to accomodate + //resources with lower granularity to utilize spase used to adjust uneven bridge granularity + Status=AppendBarOrder(&BrgDb,ResOrd, bbar); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto ExitLbl; + + //Determine how much Extra resources we will use here + ebar=&balign->ExtraRes; + if(bbar->Length & bbar->Gran){ + //Here we have add the biggest bridge resource to the BarOrdedr DB. + //We have yet Biggrest Dev Resource. Let's see if there are any Bridge resources left + if(BrgDb.RecordCount){ + Status=DbeGoToIndex(&BrgDb,0,BrgDb.RecordCount-1,&nbbar); + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + } else nbbar=NULL; + //Now see which bar (nbbar-NextBridgeBar) if any, or bar-DeviceBar will be the next + //member in BarOrder Database. + if(nbbar!=NULL){ + if(bar->Gran>=nbbar->Gran)nextbar=bar; + else nextbar=nbbar; + } else nextbar=bar; + + //Determine how much Extra resources we will use here + //if we got here - the Bridge resource request, we just added to the BarOrder DB, has uneven alignment + //Here we have: + //bbar - already added to the BarOrder DB; + //nextbar - biggest resource following by the bbar; + //bar - biggest Device Bar evenly aligned ; + if(nextbar->Gran <= balign->ResGran) { + //if next biggest bar has Alignment requirements lesser or equal to the bbar just added + //GREAT! We will just add it and forget it; + if(nextbar==bar)Status=AppendBarOrder(&DevDb,ResOrd, nextbar); + else Status=AppendBarOrder(&BrgDb,ResOrd, nextbar); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto ExitLbl; + + } else { + ebar->Length=(( bbar->Length | nextbar->Gran )+1)-bbar->Length; + bit=FindFirstBit(ebar->Length-1,FALSE); + ebar->Gran=Shr64((~0ULL),64 - bit); + } + } + + //bar->Gran here < "bbar" MaxGran, so "bar" holds next biggest Gran after the bridge + //we will try to adjust Extra Space requested by the bridge, analizing bar->Gran information + if(ebar->Length) { + while( ebar->Length >= (ebar->Gran+1) ){ + VOID* p; + //----------------------- + + if(!DevDb.RecordCount)break; + + bar=NULL; + val=ebar->Gran+1; + Status=DbeLocateKey(&DevDb,0,&val,&p,&v, &i); + + + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF) || (Status==EFI_NOT_FOUND))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + + Status=DbeGoToIndex(&DevDb,0,i,&bar); + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + + //if DevDb (who has even sizes) has resource that smaller or equal + //we will try to fill Extra Gap... + if((v == -1) && (bar!=NULL)){ + //Database sorted in ascending order. DbeLocateKey() function, parameter "v" tells how close the result is. + //if DBE couldn't find exact match, it will return pointer at first element bigger than Parameter Passed. + //There fore, if this is the case, we need to go down one index to get a smaller element than Parameter Passed. + if(i>0){ + bar=NULL; + Status=DbeGoToIndex(&DevDb,0,i-1,&bar); + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + } else break; //this will break "while(DevDb.RecordCount || BrgDb.RecordCount)" loop + } //if(v==-1 && bar!=NULL) + + if(bar!=NULL && bar->Gran<=ebar->Gran){ + Status=AppendBarOrder(&DevDb,ResOrd,bar); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto ExitLbl; + + //Adjust ebar->Length and Gran since we have filled out some extra space... + ebar->Length-=bar->Length; + if(ebar->Length!=0){ + bit=FindFirstBit(ebar->Length-1,FALSE); + ebar->Gran=Shr64((~0ULL),64-bit); + } else break; //this will break "while( ebar->Length >= (ebar->Gran+1) )" loop + } else break; //this will break "while( ebar->Length >= (ebar->Gran+1) )" loop + + } //while( ebar->Length >= (ebar->Gran+1) + + //if after all efforts we still have extra resources left + //Mark ebar->Offset as 0xFF to notify routine which will programm the BARs + //Not to toughch this one, but just add ebar->Length before next valid BAR. + + PCI_TRACE((TRACE_PCI," EBAR: Len=0x%lX;\t Gra=0x%lX;\t Ofs=0x%X; Owner [B%X|D%X|F%X] Type=%d\n", + ebar->Length, ebar->Gran, ebar->Offset, ebar->Owner->Address.Addr.Bus, + ebar->Owner->Address.Addr.Device, ebar->Owner->Address.Addr.Function, ebar->Owner->Type)); + if(ebar->Length!=0){ + ebar->Offset=0xFF; + ebar->Type=ResType+1; + ebar->DiscoveredType=ebar->Type; + + Status=AppendItemLst((T_ITEM_LIST*)ResOrd, ebar); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto ExitLbl; + } + }//if(ebar->Length) + }//else of "if(bar->Gran >= balign->MaxGran)" + } else { //"if((bar!=NULL) && (bbar!=NULL))" + //This case when we have only one type of resources most likely it would be regular device resources + //But just in case do the check + if(bbar==NULL) Status=AppendBarOrder(&DevDb,ResOrd,bar); + else { + ebar=NULL; + //If we got only bridges (more than one) behind parent bridge we might got uneven alignment! + //So we have to check if Granuilarity requirements satisfactory for them and padd resources if needed. + if(BrgDb.RecordCount>1){ + UINT64 resgran; + //--------------------- + PCI_TRACE((TRACE_PCI," Bridges ONLY found!!! \n")); + brg=bbar->Owner; + ext=(PCI_BRG_EXT*)(brg+1); + balign=&ext->Align[ResType]; + + bit=FindFirstBit(bbar->Length-1,FALSE); + resgran=Shr64((~0ULL),64-bit); + + if(bbar->Gran>resgran){ + //get next record + Status=DbeGoToIndex(&BrgDb,0,BrgDb.RecordCount-2,&nextbar); + if(EFI_ERROR(Status)){ + if(!((Status==EFI_DBE_EOF) || (Status==EFI_DBE_BOF))){ + ASSERT_EFI_ERROR(Status); + goto ExitLbl; + } + } + //determine extra resource size... + ebar=&ext->Align[ResType].ExtraRes; + ebar->Length=(( bbar->Length | nextbar->Gran )+1)-bbar->Length; + if(ebar->Length!=0){ + bit=FindFirstBit(ebar->Length-1,FALSE); + ebar->Gran=Shr64((~0ULL),64-bit); + } + }//if(balign->MaxGran>balign->ResGran) + }//if(BrgDb.RecordCount>1) + Status=AppendBarOrder(&BrgDb,ResOrd,bbar); + if(ebar!=NULL && ebar->Length){ + ebar->Offset=0xFF; + ebar->Type=ResType+1; + ebar->DiscoveredType=ebar->Type; + PCI_TRACE((TRACE_PCI," EBAR: Len=0x%lX;\t Gra=0x%lX;\t Ofs=0x%X; Owner [B%X|D%X|F%X] Type=%d\n", + ebar->Length, ebar->Gran, ebar->Offset, ebar->Owner->Address.Addr.Bus, + ebar->Owner->Address.Addr.Device, ebar->Owner->Address.Addr.Function, ebar->Owner->Type)); + + Status=AppendItemLst((T_ITEM_LIST*)ResOrd, ebar); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto ExitLbl; + } + + ASSERT_EFI_ERROR(Status); + } + if(EFI_ERROR(Status)) goto ExitLbl; + } + + }//while(DevDb.RecordCount || BrgDb.RecordCount) + +ExitLbl: + //Free Memory allocated... + FreeResDb(&DevDb); + FreeResDb(&BrgDb); + + //if there was an ERROR clear Bridge Resource Ortder Array. + if(EFI_ERROR(Status)){ + ClearItemLst((T_ITEM_LIST*)ResOrd,FALSE); + PCI_TRACE((TRACE_PCI,"PciBus: OptimizeBrgResource() returning ERROR=%r\n", Status)); + } + + return Status; + +} + +VOID ClearBrgResources(PCI_DEV_INFO *Brg){ + EFI_STATUS Status=0; + PCI_DEV_INFO *dev; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Brg+1); + UINTN i; +//------------------------------- + + for (i=0; i<ext->ChildCount; i++){ + dev=ext->ChildList[i]; + + if((dev->Type==tPci2PciBrg || dev->Type==tPci2CrdBrg) ) + ClearBrgResources(dev); + } //child loop + + //Once here that means all recourcive calls are done and + //all BridgeChilds Bridges - clean.... + //Clear ThisBridge Res[], Pad[], Align[]... + for(i=rtIo16; i<rtMaxRes; i++) { + PCI_DEV_INFO *owner; + //---------------------- + owner=ext->Res[i].Owner; + pBS->SetMem(&ext->Res[i], sizeof(PCI_BAR),0); + ext->Res[i].Owner=owner; + + owner=ext->Align[i].ExtraRes.Owner; + pBS->SetMem(&ext->Align[i], sizeof(BRG_ALIGN_INFO),0); + ext->Align[i].ExtraRes.Owner=owner; +#if HOTPLUG_SUPPORT + owner=ext->Pad[i].Owner; + pBS->SetMem(&ext->Pad[i], sizeof(PCI_BAR),0); + ext->Pad[i].Owner=owner; +#endif + if(ext->BarOrder[i].BarCount) ClearItemLst((T_ITEM_LIST*)&ext->BarOrder[i], FALSE); + } +} + + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CalculateBrgResources() +// +// Description: The objective of this routine is to select the biggest +// possible Granularity/Alignment for the Bridge by adding all Child's +// resources of the same type together. +// +// Input: +// PCI_DEV_INFO *Brg Pointer to PCI Device Private Data structure. +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID CalculateBrgResources(PCI_DEV_INFO *Brg) +{ + EFI_STATUS Status=0; + PCI_DEV_INFO *dev; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Brg+1); + UINTN i,j,k; + PCI_BAR *bar, *bbar; + UINT8 bit; + BRG_RES_ORDER *resord; +#if HOTPLUG_SUPPORT + PCI_BAR *pbar; +#endif + BRG_ALIGN_INFO *balign; + BOOLEAN paddingappl; + MRES_TYPE LowResType=rtMaxRes; +//----------------------------------------------- + //Tell what we are doing + PCI_TRACE((TRACE_PCI,"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + PCI_TRACE((TRACE_PCI,"PciBus: ")); + if(gPciOutOfRes) PCI_TRACE((TRACE_PCI," RE_")); + PCI_TRACE((TRACE_PCI,"CalculateBrgResources() Bridge->[B%X|D%X|F%X] ---> BEGIN \n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device, Brg->Address.Addr.Function)); + PCI_TRACE((TRACE_PCI,"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + + //Init initial Alignment fields for the special Bridge BARs + //every P2P brg has 4k IO and 1M MMMIO alignment + //Init Initial Granularity array + if(Brg->Type==tPciRootBrg){ + //in case of Host Bridge Granularity Values should be provided by Root Brg + for(i=1; i<rtMaxRes; i++) ext->Align[i].MinGran=1; //just don't care now + } else { + //in case of P2P Brg use default settings + ext->Align[1].MinGran=P2P_BRG_IO_GRA; + ext->Align[2].MinGran=P2P_BRG_IO_GRA; + ext->Align[3].MinGran=P2P_BRG_MEM_GRA; + ext->Align[4].MinGran=P2P_BRG_MEM_GRA; + ext->Align[5].MinGran=P2P_BRG_MEM_GRA; + ext->Align[6].MinGran=P2P_BRG_MEM_GRA; + } + + //Initialize fields in Bridge info Structure + ext->Res[rtIo16].Gran=P2P_BRG_IO_GRA; + ext->Res[rtIo32].Gran=P2P_BRG_IO_GRA; + ext->Res[rtMmio32].Gran=P2P_BRG_MEM_GRA; + ext->Res[rtMmio32p].Gran=P2P_BRG_MEM_GRA; + ext->Res[rtMmio64].Gran=P2P_BRG_MEM_GRA; + ext->Res[rtMmio64p].Gran=P2P_BRG_MEM_GRA; + + //Init Bridge Bar offset fields + if(Brg->Type==tPci2PciBrg){ + //For IO 16 Resources Decoded by the bridge + ext->Res[rtIo16].Offset=0x1C; + //For IO 32 Resources Decoded by the bridge + ext->Res[rtIo32].Offset=0x1C; + //For MMIO32 + ext->Res[rtMmio32].Offset=0x20; + //For MMIO32 PF + ext->Res[rtMmio32p].Offset=0x24; + //For MMIO64 + ext->Res[rtMmio64].Offset=0x20; //P2PBridge doesnot have any MMIO64 + //For MMIO64 PF + ext->Res[rtMmio64p].Offset=0x24; + } + + //Init Card Bus Bridge Bar offset fields + if(Brg->Type==tPci2CrdBrg){ + //For IO 16 Resources Decoded by the bridge + ext->Res[rtIo16].Offset=0x2C; + //For IO 32 Resources Decoded by the bridge + ext->Res[rtIo32].Offset=0x34; + //For MMIO32 + ext->Res[rtMmio32].Offset=0x1C; + //For MMIO32 PF + ext->Res[rtMmio32p].Offset=0x24; + //For MMIO64 + ext->Res[rtMmio64].Offset=0x1C; //P2Crd Bridge doesnot have any MMIO64 + //For MMIO64 PF + ext->Res[rtMmio64p].Offset=0x24;//P2Crd Bridge doesnot have any MMIO64PF + } + + if(gPciOutOfRes){ +//OUT_OF_RES!! + //Get AmiOutOfResVar (suppose to be created by ROOT BRG Generic code or Custom HbCspAllocateResources()) + Status=AmiPciOutOfRes(&gPciOutOfResData, TRUE); + ASSERT_EFI_ERROR(Status); //should not fail at that point! + + //gPciOutOfResData.Resource.Type can't be ASLRV_SPC_TYPE_BUS + //Update resource type + if(gPciOutOfResData.Resource.Type==ASLRV_SPC_TYPE_IO) LowResType=rtIo16; + + if(gPciOutOfResData.Resource.Type==ASLRV_SPC_TYPE_MEM){ + if(gPciOutOfResData.Resource._GRA==32){ + LowResType=rtMmio32; + if(gPciOutOfResData.Resource.TFlags.MEM_FLAGS._MEM!=ASLRV_MEM_UC)LowResType=rtMmio32p; + } + if(gPciOutOfResData.Resource._GRA==64){ + LowResType=rtMmio64; + if(gPciOutOfResData.Resource.TFlags.MEM_FLAGS._MEM!=ASLRV_MEM_UC)LowResType=rtMmio64p; + } + } + } + + //Start adding resources for all childs behind that bridge + for (i=0; i<ext->ChildCount; i++){ + dev=ext->ChildList[i]; + + //if we got Out Of resources condition call Platforn function to determine + //priority list for devices Platform wants to IGNORE. + //Pick just ONe device at a time. + if(gPciOutOfRes && !gPciOutOfResHit && !dev->OutOfResRemove){ + Status=PciPortOutOfResourcesRemoveDevice(dev, gPciOutOfResData.Count, LowResType); + if(!EFI_ERROR(Status)){ + gPciOutOfResHit=TRUE; + dev->OutOfResRemove=TRUE; + + PCI_TRACE((TRACE_PCI,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")); + PCI_TRACE((TRACE_PCI,"\nPciBus: OutOfRes Hit #%d!!! Removing Device [B%X|D%X|F%X]->", + gPciOutOfResData.Count, dev->Address.Addr.Bus, dev->Address.Addr.Device, dev->Address.Addr.Function)); + + if(dev->PicIrqEntry!=NULL) PCI_TRACE((TRACE_PCI,"Slt #%d\n", dev->PicIrqEntry->SlotNum)); + else PCI_TRACE((TRACE_PCI,"Slt N/A\n")); + PCI_TRACE((TRACE_PCI,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")); + + //We must remove all it's functions also since f0 defines persence of the rest. + if(IsFunc0OfMfDev(dev)&& dev->Type!=tPci2PciBrg) { + PCI_TRACE((TRACE_PCI," AND ALL IT's %d FUNCTIONS!!!\n",dev->FuncCount)); + for(j=0;j<dev->FuncCount;j++){ + dev->DevFunc[j]->OutOfResRemove=TRUE; + DisableDeviceDecoding(dev->DevFunc[j], stDisableAll); + } + } + //if we hit device from remove list - shut it down... + DisableDeviceDecoding(dev, stDisableAll); + if(dev->Type==tPci2PciBrg) DisableBridgeDecoding((PCI_BRG_INFO*)dev); + + //save OUT_OF_RES_VAR + Status=AmiPciOutOfRes(&gPciOutOfResData, FALSE); + + } + } + + if(dev->OutOfResRemove) continue; + //here we have to check if the Child device is P2P brg - + //it requires a special handling + if(dev->Type==tPci2PciBrg || dev->Type==tPci2CrdBrg) + CalculateBrgResources(dev); + } //child loop + + PCI_TRACE((TRACE_PCI,"=>>>Resource Requirements for Bridge->[B%X|D%X|F%X] :<<<=\n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device, Brg->Address.Addr.Function)); + PCI_TRACE((TRACE_PCI,"ResType: 1=rtIo16; 2=rtIo32; 3=rtMmio32; 4=rtMmio32p; 5=rtMmio64; 6=rtMmio64p\n\n")); + + + for(j=rtIo16; j<rtMaxRes; j++){ + //Init variables. + paddingappl=FALSE; + bbar=&ext->Res[j]; + balign=&ext->Align[j]; + resord=&ext->BarOrder[j]; + balign->MaxGran=bbar->Gran; + + Status=OptimizeBrgResource(Brg, j); + ASSERT_EFI_ERROR(Status); + + for(k=0; k<resord->BarCount; k++){ + bar=resord->BarList[k]; + //add children's resources to the bridge decoding + if(bbar->Gran < bar->Gran)bbar->Gran=bar->Gran; + bbar->Length+=bar->Length; + bbar->Type=bar->Type; + } + +#if HOTPLUG_SUPPORT + pbar=&ext->Pad[j]; + //if this is the bridge with hotplug capabilities it might supports Resource Padding + //Apply padding and padding alignment if it is bigger than this bridge is currently requesting + if(pbar->Length){ + if(pbar->Length > bbar->Length) bbar->Length = pbar->Length; + if(bbar->Gran < pbar->Gran) bbar->Gran=pbar->Gran; + bbar->Type=pbar->Type; + paddingappl=TRUE; + } +#endif + //if we have a card bus brg and hotplug is disabled we will APPLY default padding + if(Brg->Type==tPci2CrdBrg && !paddingappl) { + PCI_TRACE((TRACE_PCI,"->>>Applying CRD BUS Default Padding for Pci2CrdBrg [B%X|D%X|F%X]\n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device, Brg->Address.Addr.Function)); + ApplyCrdPadding(Brg, j); + } + + //if Brg have resource request + balign->MaxGran=bbar->Gran; + if(bbar->Length){ + if( (bbar->Length < (balign->MinGran + 1)) || ((bbar->Length & balign->MinGran)) ) + bbar->Length=(bbar->Length | balign->MinGran)+1; + //Figure out Resource Delivered Granularity + bit=FindFirstBit(bbar->Length-1,FALSE); + balign->ResGran=Shr64((~0ULL),64-bit); + } + //Report Bridge Parameters + PCI_TRACE((TRACE_PCI,"->ResType=%X; Len=%lX; Gran=%lX; MaxGran=%lX; ResGran=%lX; MinGran=%lX\n\n", + j, bbar->Length, bbar->Gran, balign->MaxGran, balign->ResGran, balign->MinGran)); + PCI_TRACE((TRACE_PCI,"------------------------------------------------------------------------\n")); + + } //for(j=rtIo16; j<rtMaxRes; j++).. + + //Tell what we are doing + PCI_TRACE((TRACE_PCI,"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n")); + PCI_TRACE((TRACE_PCI,"PciBus: CalculateBrgResources() Bridge->[B%X|D%X|F%X] ---> END \n", + Brg->Address.Addr.Bus, Brg->Address.Addr.Device, Brg->Address.Addr.Function)); + PCI_TRACE((TRACE_PCI,"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n")); + + //We did it ... EXIT! +} + +//================================================ +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: NewDevice() +// +// Description: Allocats Space nedded for New PCI_Device Instance and inits +// some of it's Fields +// +// Input: +// BOOLEAN BrgDevice Indicator that New Device is a BRIDGE Device. +// PCI_CFG_ADDR *DevArrd Device Address on PCI Bus. +// +// Output: PCI_DEV_INFO* +// Pointer to the Created PCI Device Private Data structure. +// NULL, if there was an ERROR. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +PCI_DEV_INFO* NewDevice(BOOLEAN BrgDevice, PCI_CFG_ADDR *DevAddr) +{ + UINTN i; + PCI_DEV_INFO *dev; + PCI_BRG_EXT *ext; +//------------------------------------ + PCI_TRACE((TRACE_PCI,"\n==========================================================================\n")); + if(BrgDevice)i=sizeof(PCI_BRG_INFO); + else i=sizeof(PCI_DEV_INFO); + + dev=MallocZ(i); + if(!dev) return dev; + + //Specify Owner for BusSpecific Override Protocol + dev->BusOvrData.Owner=dev; +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + dev->LoadFileData.Owner=dev; +#endif + dev->Signature=AMI_PCI_SIG; + dev->MajorVersion = PCI_BUS_MAJOR_VER; + dev->MinorVersion = PCI_BUS_MINOR_VER; + dev->Revision = PCI_BUS_REVISION; + + //init some fields which must not be ZERO + for(i=0; i<PCI_MAX_BAR_NO+1; i++)dev->Bar[i].Owner=dev; + if(DevAddr){ + dev->Address.ADDR=DevAddr->ADDR; + dev->Address.Addr.Register=0; + } else dev->Address.ADDR=0; + + //Initialize some static fields + if(BrgDevice){ + dev->Type=tPci2PciBrg; + ext=(PCI_BRG_EXT*)(dev+1); + for(i=0; i<rtMaxRes; i++) { + ext->Res[i].Owner=dev; + ext->Align[i].ExtraRes.Owner=dev; + } + } else dev->Type=tPciDevice; + + return dev; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: BridgeAddChild() +// +// Description: Adds Pointer at the child PCI Device to the "Bridge" +// T_ITEM_LIST Child List Structure of the BRG_EXT. +// some of it's Fields +// +// Input: +// PCI_DEV_INFO *Brgidge Pointer to PCI Device Private Data structure +// of the Parent Bridge. +// PCI_DEV_INFO *Child Pointer to PCI Device Private Data structure. +// of the Child Device. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS BridgeAddChild(PCI_DEV_INFO *Bridge,PCI_DEV_INFO *Child) +{ + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(Bridge+1); +//------------------------------------------------- + return AppendItemLst((T_ITEM_LIST*)&ext->InitialCount,Child); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitDeviceData() +// +// Description: Initializes missing fields in PCI_DEV_INFO structure. +// +// Input: +// PCI_DEV_INFO *Dev Pointer to PCI Device Private Data structure +// to initialize. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InitDevData(PCI_DEV_INFO *Dev, PCI_DEV_INFO *Parent, UINT32 VenDevId, UINT32 ClassCodes, PCI_DEV_INFO *Func0){ + EFI_STATUS Status; + PCI_CFG_ADDR addr; +//------------------------- + //Get CMD Register's safe value per UEFI 2.1 spec + addr.ADDR=Dev->Address.ADDR; + + Dev->ParentBrg=Parent; + Dev->DevVenId.DEV_VEN_ID=VenDevId; + Dev->Class.DEV_CLASS=ClassCodes; + Dev->HostData=Parent->HostData; + Dev->RbIo=Parent->RbIo; + Dev->Func0=Func0; + + //If (Func0==NULL && FuncCount==0) function is a single function device, following fields are not used and reserved; + //If (Func0!=NULL && FuncCount==0) function is one of the Func1..Func7 of multi-func device, Func0 points on DevFunc0; + //If (Func0!=NULL && (FuncCount!=0 || FuncInitCnt!=0)) function is Func0 of multyfunc device DevFunc holds pointers at all other Func1..7 found yet + + //If (Func0==NULL && FuncCount!=0) Illehgal combination - reserved! + if(Func0!=NULL){ + if (Func0!=Dev){ + //This is func 1..7 of the device... add it to the list. + Status=AppendItemLst((T_ITEM_LIST*)&Func0->FuncInitCnt,Dev); + ASSERT_EFI_ERROR(Status) + if(EFI_ERROR(Status)) return Status; + } else { + //This is Func 0 if the device.. init Func0->FuncInitCnt with 8 + Func0->FuncInitCnt=8; + } + } + + addr.Addr.Register=PCI_CMD; + Status=PciCfg16( Dev->RbIo, addr, FALSE, &Dev->CmdReg.CMD_REG); + ASSERT_EFI_ERROR(Status) + if(EFI_ERROR(Status)) return Status; + + Status=MakePciDevicePath(Dev); + if(EFI_ERROR(Status)) return Status; + + Status=PciPortSkipThisDevice(Dev); + if(!EFI_ERROR(Status)){ + PCI_TRACE((TRACE_PCI,"PciBus: Device @ [B%X|D%X|F%X], VID=%X, DID=%X SKIPPED from enumeration.\n\n", + Dev->Address.Addr.Bus, Dev->Address.Addr.Device, Dev->Address.Addr.Function, + Dev->DevVenId.VenId, Dev->DevVenId.DevId)); + Dev->SkipDevice=TRUE; + }else Status=EFI_SUCCESS; + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: EnumerateBus() +// +// Description: Enumerate the PCI BUSes behind the "ParentBrg" and determine +// how much resources nedded for all its Child devices. +// +// Input: +// PCI_DEV_INFO *ParentBrg Pointer to PCI Device Private Data structure +// of the Parent Bridge. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EnumerateBus(PCI_DEV_INFO *ParentBrg) +{ + EFI_STATUS Status, Status1=EFI_NOT_FOUND; + PCI_CFG_ADDR pcidev; + BOOLEAN mf,ari; //multi-function flag; ARI Flag + UINT32 id, cc; //Device ID Vendor ID reg + UINT8 ht; //Header type reg + PCI_BRG_EXT *ext, *parext; + PCI_DEV_INFO *dev, *func0; + UINT8 omb=0; +#if PCI_DEV_REVERSE_SCAN_ORDER + UINT8 DevBuff; +#endif +//---------------------------------- + PROGRESS_CODE(DXE_PCI_BUS_ENUM); + //Root Bridges Will have Same Number for Primary and Secondary bus + pcidev.ADDR=PCI_VID; + parext=(PCI_BRG_EXT*)(ParentBrg+1); + pcidev.Addr.Bus=(UINT8)parext->Res[rtBus].Base; + func0=NULL; + ari=FALSE; + + for(pcidev.Addr.Device=0; pcidev.Addr.Device<=PCI_MAX_DEVICE; pcidev.Addr.Device++){ +#if PCI_DEV_REVERSE_SCAN_ORDER + DevBuff = pcidev.Addr.Device; + pcidev.Addr.Device = PCI_MAX_DEVICE - pcidev.Addr.Device; +#endif + //if ARI Detected and Enabled we should scan all devices and functions + //but in ARI Mode Dev0..31 and Func0..7 will be translted for PCIe as Dev0 Func 0...255 + //So Func0 must be the same as we have detected when started from Actual Function 0 + //And we should not reset MF flag for ARI device when we reach Func 7 of the device. + if(ari == FALSE){ + mf=FALSE; + func0=NULL; + } + + for(pcidev.Addr.Function=0; pcidev.Addr.Function<=PCI_MAX_FUNC; pcidev.Addr.Function++){ + //read devid-vendid register pare, + id=0; + pcidev.Addr.Register=PCI_VID; + + /// + /// A config write is required in order for the device to re-capture the Bus number, + /// according to PCI Express Base Specification, 2.2.6.2 + /// Write to a read-only register VendorID to not cause any side effects. + /// + Status=PciCfg32(ParentBrg->RbIo,pcidev,TRUE,&id); + + Status=PciCfg32(ParentBrg->RbIo,pcidev,FALSE,&id); + if(EFI_ERROR(Status)) return Status; //Error happend - can't continue + //Check if all Ones +#if PCI_EXPRESS_SUPPORT + if( (id == 0xFFFFFFFF)&& //oinly if first attemt of CFG read did not find anything + (ParentBrg->PciExpress!=NULL) && //and device is PCIe capable +#if PCI_DEV_REVERSE_SCAN_ORDER + (DevBuff==0) && (pcidev.Addr.Function==0) && //for PCIe dev0 func0 is only option +#else + (pcidev.Addr.Device==0) && (pcidev.Addr.Function==0) && //for PCIe dev0 func0 is only option +#endif + (ParentBrg->PciExpress->PcieCap.SlotImpl)) //and we have a slot there... + { + //Some cards does not reply on configuration transactions + //for some time after opening config space behind the bridge. + //If slot is implemented behind the bridge - + //doiblecheck if card present using PCIe facilities (SLOT_STATUS reg) + //we will save time on skipping DEV 1..31 though + Status=PcieDoubleCheckCard(ParentBrg,&pcidev,&id); + ASSERT_EFI_ERROR(Status); + } +#endif + if(id == 0xFFFFFFFF || id==0){ + if (!mf)break; //devX.fun0.reg=0 returns 0xFFFFFFFF nothing is there + else continue; //if device was identified as multifunc keep scanning + } + //here we got something alive there + Status1=EFI_SUCCESS; + ht=0; + //read the HeaderType Reg + pcidev.Addr.Register=EFI_FIELD_OFFSET(PCI_COMMON_REG,HeaderType); + Status=PciCfg8(ParentBrg->RbIo,pcidev,FALSE,&ht); + if(EFI_ERROR(Status)) return Status; //Error happend cant continue + + if(ari==FALSE){ + if(pcidev.Addr.Function==0) { + if(ht & HDR_TYPE_MULTIFUNC)mf=TRUE; //this is multifunc device + } + } + + ht&=3; + + //Get the class code and revision Id + pcidev.Addr.Register=PCI_RID; //Rev ID and Class Code + Status=PciCfg32(ParentBrg->RbIo,pcidev,FALSE,&cc); + if(EFI_ERROR(Status)) return Status; //Error happend can't continue + + switch (ht){ + case HDR_TYPE_DEVICE : + //Allocate Space to accomodate found device + dev=NewDevice(FALSE,&pcidev); + if(!dev) return EFI_OUT_OF_RESOURCES; + + if((ari==FALSE) && (mf) && (pcidev.Addr.Function==0))func0=dev; + Status=InitDevData(dev, ParentBrg, id, cc, func0); + if(EFI_ERROR(Status)) goto EEXIT; + //Test the class code to mark host brg device + if( dev->Class.SubClassCode==0 && + dev->Class.BaseClassCode==6 && + dev->Class.ProgInterface==0 ) + { + dev->Type=tPciHostDev; + } + //Check if we got a debug port here +#if EFI_DEBUG || USB_DEBUG_TRANSPORT + if( + (gDbgPortHob && ( + (gDbgPortInfo.DebugPortType==USB2_EHCI) || + (gDbgPortInfo.DebugPortType==USB2_UHCI) || + (gDbgPortInfo.DebugPortType==USB2_OHCI) ) + ) && ( + (pcidev.Addr.Function==gDbgPortInfo.Address.Addr.Function) && + (pcidev.Addr.Device==gDbgPortInfo.Address.Addr.Device) && + (pcidev.Addr.Bus==gDbgPortInfo.Address.Addr.Bus) + ) + ) + { + dev->Bar[gDbgPortInfo.BarIndex].Length =gDbgPortInfo.Length; + dev->Bar[gDbgPortInfo.BarIndex].Gran =gDbgPortInfo.Length-1; + dev->Bar[gDbgPortInfo.BarIndex].Offset =gDbgPortInfo.BarOffset; + dev->Bar[gDbgPortInfo.BarIndex].Type =gDbgPortInfo.BarType; + dev->DebugPort=TRUE; + dev->Enumerated=TRUE; + dev->Discovered=TRUE; + } + else +#endif + { + if(dev->SkipDevice){ + //if porting hook tells us to skip this device. + //We will just start it + dev->Assigned=TRUE; + dev->Discovered=TRUE; + dev->Enumerated=TRUE; + dev->Incompatible=TRUE; + } else { + //Vars we need here + UINTN i; + UINT64 tl32, tl64, tlIO; + //------------- + //make sure - Device is disabled + Status=DisableDeviceDecoding(dev, stMemIoSpace); + if(EFI_ERROR(Status)) goto EEXIT; + + //Try to determine how mutch resources Device consumes + Status=QueryPciDevice(dev); + if(EFI_ERROR(Status)) goto EEXIT; + + //Find IRQ Routing Entry for discovered device + Status = FindDevIrqEntry(dev); + + //This workaround done for PCI Compliance Test... + //32 bit, 64bit and IO resource request excides certain length. + for(i=0,tlIO=0,tl32=0,tl64=0; i<PCI_MAX_BAR_NO+1; i++){ + if((dev->Bar[i].Type!=tBarUnused) && (dev->Bar[i].Length!=0) ){ + switch (dev->Bar[i].Type){ + case tBarIo16: + case tBarIo32: + tlIO+=dev->Bar[i].Length; + break; + case tBarMmio32: + case tBarMmio32pf: + tl32+=dev->Bar[i].Length; + break; + case tBarMmio64: + case tBarMmio64pf: + tl64+=dev->Bar[i].Length; + }//switch + }//if not empty + } //for + + //Check if Calculated total resource request falls in acceptable range + if( (tlIO>=PCI_DEVICE_IO_RESOURCE_THRESHOLD) || + (tl32>=PCI_DEVICE_32BIT_RESOURCE_THRESHOLD) || + (tl64>=PCI_DEVICE_64BIT_RESOURCE_THRESHOLD) + ) + { + //Zero out all BARs and ROM BAR. + for(i=PCI_BAR0, id=0; i<PCI_CAPP; i+=4){ + pcidev.Addr.Register=(UINT8)i; + Status=PciCfg32(ParentBrg->RbIo,pcidev,TRUE,&id); + if(EFI_ERROR(Status)) goto EEXIT; + } + //Clear CMD_REG + pcidev.Addr.Register=(UINT8)PCI_CMD; + Status=PciCfg16(ParentBrg->RbIo,pcidev,TRUE,(UINT16*)(&id)); + if(EFI_ERROR(Status)) goto EEXIT; + + //Clear All collected resource information for that device + //to avoid them to be added to the system's resource request. + for(i=0; i<PCI_MAX_BAR_NO+1; i++){ + dev->Bar[i].Type=tBarUnused; + dev->Bar[i].DiscoveredType=tBarUnused; + dev->Bar[i].Length=0; + dev->Bar[i].Gran=0; + } + //Setting Flags telling not to install PciIo protocol instance + //on this device and don't touch device at all! + dev->Started=TRUE; + dev->Assigned=TRUE; + dev->Discovered=TRUE; + dev->Enumerated=TRUE; + dev->RomBarError=TRUE; + dev->Incompatible=TRUE; + } //if .. Device requests too much resources. + +#if PCI_EXPRESS_GEN2_SUPPORT + //Check if we have to enable ARI here. + if(IsFunc0(dev)){ + Status=Pcie2CheckAri(dev,&mf,&ari); + if(EFI_ERROR(Status)) goto EEXIT; + } +#endif + dev->Enumerated=TRUE; + + } + } + break; + + case HDR_TYPE_P2P_BRG : + case HDR_TYPE_P2C_BRG : + //Allocate space for new bridge struct + dev=NewDevice(TRUE,&pcidev); + if(!dev) return EFI_OUT_OF_RESOURCES; + + ext=(PCI_BRG_EXT*)(dev+1); + if(ht==HDR_TYPE_P2C_BRG)dev->Type=tPci2CrdBrg; + + //Record some properties of the discovered device + if(pcidev.Addr.Function==0 && mf)func0=dev; + Status=InitDevData(dev, ParentBrg, id, cc, func0); + if(EFI_ERROR(Status)) goto EEXIT; + + if(dev->SkipDevice){ + //if porting hook tells us to skip this device. + //We will just start it + dev->Assigned=TRUE; + dev->Discovered=TRUE; + dev->Enumerated=TRUE; + dev->Incompatible=TRUE; + } else { + //make sure - Device is disabled + if(dev->Type == tPci2PciBrg) DisableBridgeDecoding((PCI_BRG_INFO*)dev); + Status=DisableDeviceDecoding(dev, stMemIoSpace); + if(EFI_ERROR(Status)) goto EEXIT; + + //Try to determine how mutch resources Device consumes + Status=QueryPciDevice(dev); + //this call must fill Bar[0..1] + if(EFI_ERROR(Status)) goto EEXIT; + } + +#if PCI_EXPRESS_GEN2_SUPPORT + //Check if we have to enable Ari in case of + if((dev->PciExpress!=0) && (PcieIsDownStreamPort(dev)==FALSE)){ + +#if PCI_BUS_SKIP_BRG_RECURSIVELY + if(dev->SkipDevice==0){ +#endif + Status=Pcie2CheckAri(dev,&mf,&ari); + if(EFI_ERROR(Status)) goto EEXIT; + +#if PCI_BUS_SKIP_BRG_RECURSIVELY + } +#endif + } +#endif + + //Find PCI Bus Xlat entry corresponded to this bridge + Status=FindBridgeXlatEntry(dev, ext); + //Find IRQ Routing Entry for discovered device + Status = FindDevIrqEntry(dev); + + //KeepUpdating NewBrg + //Programm Primary and Secondary I/F Bus Numbers + //To store Bridge SecondaryBusNo and SubordinateBusNo we will use PCI_BAR structure + //Device.Address.Addr.Bus will have PrimaryBusNo + //Bar.Base will be used for SecondaryBusNo and + //Bar.Base +Bar.Length-1 will give us SubordinateBusNo. + //So Record the Secondary Bus we will use for this Bridge.. + + //Set Bridge Bus register Proprties + ext->Res[rtBus].Type=tBarBus; + ext->Res[rtBus].Offset=PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET; //SecondaryBusOffset + + //If fixed bus assignment we should handle situation differenty + if( FixedBusAssign && ext->XlatTblEntry != NULL ){ + //get sceondary bus number from BusXlat Table + mMaxBusFound = ext->XlatTblEntry->BusBuild; + } else { + //Bridge has been found just increase bus counter + mMaxBusFound++; + } + + ext->Res[rtBus].Base = mMaxBusFound; + //Set Sub Bus # for this bridge to max # available + ext->Res[rtBus].Length=mMaxBusScan-ext->Res[rtBus].Base; + if(ext->XlatTblEntry){ + ext->XlatTblEntry->BusRun=mMaxBusFound; + } + + if(mMaxBusReport < mMaxBusFound) mMaxBusReport=mMaxBusFound; + +#if PCI_BUS_SKIP_BRG_RECURSIVELY + if(dev->SkipDevice==0){ +#endif + Status=MapBridgeBuses(dev); +#if PCI_BUS_SKIP_BRG_RECURSIVELY + } +#endif + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto EEXIT; + +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + omb=mMaxBusFound; //save the old number of buses found only in case of hotplug + //this will try to init Root HPC siting behind this bridge if any... +#if PCI_BUS_SKIP_BRG_RECURSIVELY + if(dev->SkipDevice==0){ +#endif + Status=CheckRootHotplug(dev); +#if PCI_BUS_SKIP_BRG_RECURSIVELY + } +#endif + ASSERT_EFI_ERROR(Status); + //if root hpc init fail for any reason we just must keep going +#endif + + //Enter a Recursive call in both cases + //Only in case Device is identifyes itself as Bridge + if(dev->Class.BaseClassCode == PCI_CL_BRIDGE){ +#if PCI_BUS_SKIP_BRG_RECURSIVELY + if(dev->SkipDevice==0){ +#endif + Status = EnumerateBus(dev); +#if PCI_BUS_SKIP_BRG_RECURSIVELY + } +#endif + + if(Status!=EFI_NOT_FOUND){ + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto EEXIT; + } else Status=EFI_SUCCESS; + //After we come back from enumeration update all IRQ Tables entries + //From BusBuild to BusRun (actual bus number) + if(ext->XlatTblEntry){ + UpdateIrqTables(ext->XlatTblEntry); + PCI_TRACE((TRACE_PCI,"PciBus: Update Bus# for Brg [B%X|D%X|F%X] - Bld %X -> Run %X\n", + dev->Address.Addr.Bus,dev->Address.Addr.Device,dev->Address.Addr.Function, + ext->XlatTblEntry->BusBuild,ext->XlatTblEntry->BusRun)); + } + } + +//------------------------------------------------------------------------- +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + //here if this is the bridge who has hotplugable slots + //we must appy resource padding to it + if(dev->HotPlug){ +#if PCI_BUS_SKIP_BRG_RECURSIVELY + if(dev->SkipDevice==0){ +#endif + Status=GetHpbResPadding(dev); + + //Here we come with information about resources padding + //dev->Hotplug->Padd[rtBus].Length will have Bus numbers needed to pad for this bridge + //mMaxBusFound will have number of buses actualy present behind this bridge + //take care of buses now the rest of resources will be taken care of when + //CalculateBridge resources will be called + if(ext->PaddAttr==EfiPaddingPciBus){ + //EIP 19106 If 1 Bus set to padding in Setup it did not do the padding. + if(ext->Pad[rtBus].Length && ext->Pad[rtBus].Length>mMaxBusFound-ext->Res[rtBus].Base){ + mMaxBusFound=omb+(UINT8)ext->Pad[rtBus].Length; + } + } +#if PCI_BUS_SKIP_BRG_RECURSIVELY + } +#endif + + } +#endif +//------------------------------------------------------------------------- + //when we come back from EnumerateBus and have applyed padding for Bus Resources + // - mMaxBusFound will effectively reflect subordinate bus number for this Bridge so... + + //If fixed bus assignment we should handle situation differenty + if( FixedBusAssign && + (ext->XlatTblEntry != NULL) && + (ext->ItemNumber < gPciBusDb.ItemCount-1)) + { + UINT8 busnum; + //------------------------- + busnum=FindNextSameLevelBrgXlatEntry(ext); + + if( mMaxBusFound <= busnum )mMaxBusFound = busnum; + else { + //With Fixed Bus allocation this condition signifies an error if we here + //that means that we have found more buses than allowed buy fixed bus layout + //So scream about it. + PCI_TRACE((TRACE_PCI,"PciBus: Can't apply Fixed Buses for the Bridge @ [B%X|D%X|F%X]:\n Actual MAX Bus Discovered =%X; Proposed MAX Bus in BusXlatTbl = %X\n", + dev->Address.Addr.Bus, dev->Address.Addr.Device, dev->Address.Addr.Function, + mMaxBusFound, busnum)); + ASSERT(FALSE); + } + + } + ext->Res[rtBus].Length=mMaxBusFound-ext->Res[rtBus].Base+1; + + if(mMaxBusReport < mMaxBusFound) mMaxBusReport=mMaxBusFound; + +#if PCI_BUS_SKIP_BRG_RECURSIVELY + if(dev->SkipDevice==0){ +#endif + Status=SetSubBus(dev,mMaxBusFound); +#if PCI_BUS_SKIP_BRG_RECURSIVELY + } +#endif + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto EEXIT; + +//------------------------------------------------------------------------- +//Enables PCI Express Handling only if PCI Express Base is Defined and !=0 +#if PCI_EXPRESS_SUPPORT + //Now when we come back we can power off PCIExpress Empty slot to make it + //cpable for Hot Plugging + if(dev->PciExpress!=NULL){ + //Check if we hit a DOWN STREAM type device, + //and Initialize PciE link properties if so. + if(PcieIsDownStreamPort(dev)){ + Status=PcieInitLink(dev); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto EEXIT; + } else { + //Add to the gPcieEpLst Orphan Upstream Ports of Switches and PCIe2PCI bridgers. + if((dev->PciExpress->PcieCap.PortType==PCIE_TYPE_UPS_PORT) || + (dev->PciExpress->PcieCap.PortType==PCIE_TYPE_PCIE_PCI)){ + + Status=AppendItemLst(&gPcieEpList, dev); + PCI_TRACE((TRACE_PCI,"PciE: Adding Device [B%X|D%X|F%X] to gPcieEpList[%d]\n", + dev->Address.Addr.Bus,dev->Address.Addr.Device, dev->Address.Addr.Function, gPcieEpList.ItemCount)); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) goto EEXIT; + } + } + } +#endif +//------------------------------------------------------------------------- + //Finally we got here this bridge is done for now!!! we will use + //information collected, when we will programm the resources + dev->Enumerated=TRUE; + break; + + default : + Status=EFI_UNSUPPORTED; + ASSERT_EFI_ERROR(Status); + return Status; + } //switch; + //Now update ParentBridge ChildList and Count + Status=BridgeAddChild(ParentBrg,dev); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) goto EEXIT; + //and so on + if( !mf ) break; + } //function loop +#if PCI_DEV_REVERSE_SCAN_ORDER + pcidev.Addr.Device=DevBuff; +#endif + } //device loop + return Status1; +/////////////////////////////////////////// +//Emergency Exit Label +EEXIT: + if(dev){ + if(dev->PciExpress){ + if(dev->PciExpress->Pcie2) pBS->FreePool(dev->PciExpress->Pcie2); + if(dev->PciExpress->VcData) { + if(dev->PciExpress->VcData->VcCount)ClearItemLst((T_ITEM_LIST*)&dev->PciExpress->VcData->InitCnt, TRUE); + pBS->FreePool(dev->PciExpress->VcData); + } + if(dev->PciExpress->SriovData) pBS->FreePool(dev->PciExpress->SriovData); + if(dev->PciExpress->AriData) pBS->FreePool(dev->PciExpress->AriData); + if(dev->PciExpress->AcsData) pBS->FreePool(dev->PciExpress->AcsData); + if(dev->PciExpress->AtsData) pBS->FreePool(dev->PciExpress->AtsData); + if(dev->PciExpress->RcLnkData) pBS->FreePool(dev->PciExpress->RcLnkData); + if(dev->PciExpress->Pcie3) pBS->FreePool(dev->PciExpress->Pcie3); + + pBS->FreePool(dev->PciExpress); + } + + if(dev->PciX) pBS->FreePool(dev->PciX); + if(dev->HotPlug)pBS->FreePool(dev->HotPlug); + pBS->FreePool(dev); + } + return Status; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ProgramBar() +// +// Description: Programm PCI BAR Register with the Resource Address +// provided by the "bar" parameter. +// +// Input: +// PCI_BAR *bar Pointer at PCI BAR register information +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ProgramBar(PCI_BAR *bar) +{ + EFI_STATUS Status=0; + PCI_CFG_ADDR addr; + PCI_DEV_INFO *owner=bar->Owner; +//------------------------------------ + addr.ADDR=bar->Owner->Address.ADDR; + addr.Addr.Register=bar->Offset; + addr.Addr.ExtendedRegister=bar->ExtOffset; + +#if EFI_DEBUG || USB_DEBUG_TRANSPORT + if(owner->DebugPort){ + gDbgPortInfo.BaseAddress=bar->Base; + Status=gDbgPortHob->SetDebugPortResources(gDbgPortHob, pBS, &gDbgPortInfo); + ASSERT_EFI_ERROR(Status); + owner->Assigned=TRUE; + return Status; + } +#endif + + PCI_TRACE((TRACE_PCI,"PciBus: Device [B%X|D%X|F%X] Type=%X Bar.Offs=%Xh, Bar.Type=%d \n Assigned Base=%lX, Size=%lX \n", + owner->Address.Addr.Bus, owner->Address.Addr.Device, + owner->Address.Addr.Function, owner->Type, + ((bar->ExtOffset==0) ? bar->Offset : bar->ExtOffset), + bar->Type, bar->Base, bar->Length)); + //EIP 26787 + + //Forgot to exclude P2P Bridge ROM BAR, it belongs to primary interface! + //if(owner->Type==tPci2PciBrg && (bar->Offset > 0x14 ){ + if(owner->Type==tPci2PciBrg && ( (bar->Offset > PCI_BAR1) && (bar->Offset < PCI_EROM) ) ){ + //EIP 26787 - + + //we got special P2P bridge BAR + switch (bar->Type){ + case tBarIo16 : + case tBarIo32 : + Status=EnableBridgeIoDecoding(owner, (UINT64)bar->Base, (UINT64)bar->Length); + //if(EFI_ERROR(Status)) return Status; + break; + + case tBarMmio32: + case tBarMmio64: + Status=EnableBridgeMmioDecoding(owner, (UINT64)bar->Base, (UINT64)bar->Length); + //if(EFI_ERROR(Status)) return Status; + break; + + case tBarMmio32pf: + case tBarMmio64pf: + Status=EnableBridgePfmmDecoding(owner, (UINT64)bar->Base, (UINT64)bar->Length); + //if(EFI_ERROR(Status)) return Status; + break; + }//switch + + } else { + if(owner->Type==tPci2CrdBrg && bar->Offset > PCI_BAR0 ){ + //here goes special Memory and IO windows of CardBus Bridge + UINT32 buffer=(UINT32)bar->Base; + //-------------------- + Status=PciCfg32(owner->RbIo,addr,TRUE,(UINT32*)&buffer); //Base + + addr.Addr.Register+=4; //Limit + buffer=(UINT32)(bar->Base+bar->Length-1); + Status=PciCfg32(owner->RbIo,addr,TRUE,(UINT32*)&buffer); + + //Program Brg Control Reg to notify that Bridge Mem Window is PF + if(bar->Type==tBarMmio32pf || bar->Type==tBarMmio64pf){ + + addr.Addr.Register=PCI_BRIDGE_CONTROL_REGISTER_OFFSET; + Status=PciCfg16(owner->RbIo,addr,FALSE,(UINT16*)&buffer); + + if(bar->Offset==0x1C) buffer|=BIT08; //Memory Window 1 is PF + if(bar->Offset==0x24) buffer|=BIT09; //Memory Window 2 is PF + + Status=PciCfg16(owner->RbIo,addr,TRUE,(UINT16*)&buffer); + } + } else { + //do regular device BAR programming + UINT64 buffer=bar->Base; + //-------------------- + if(bar->DiscoveredType == tBarMmio64 || bar->DiscoveredType == tBarMmio64pf) + Status=PciCfg64(owner->RbIo,addr,TRUE,&buffer); + else Status=PciCfg32(owner->RbIo,addr,TRUE,(UINT32*)&buffer); + } + } + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AssignBridgeResources() +// +// Description: Sorts, Aligns, and Programms Resources requested by devices +// residing behind its Parent PCI Bridge - "Brg". +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Device Private Data structure +// of the Parent Bridge. +// MRES_TYPE rt Type of PCI Bus resources to work with. +// See definition of MRES_TYPE for detail. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AssignBridgeResources(PCI_BRG_INFO *Brg, MRES_TYPE rt) +{ + EFI_STATUS Status=EFI_NOT_FOUND; + UINT64 min=Brg->Bridge.Res[rt].Base; + UINT64 max=(min+Brg->Bridge.Res[rt].Length); + PCI_BAR *bar=NULL; + BRG_RES_ORDER *ord=&Brg->Bridge.BarOrder[rt]; + UINTN i;//,j; +//--------------------------------------- + + if(ord->BarCount == 0) return EFI_SUCCESS; + + //Assign Io resources to all of Bridge childs + for(i=0; i<ord->BarCount; i++){ + if(min>=max) { + Status=EFI_UNSUPPORTED; + PCI_TRACE((TRACE_PCI,"PciBus: ERROR Assign Res: MIN_ADDR(0x%lX) >= MAX_ADDR(0x%lX)\n", min, max)); + break; + } + bar=ord->BarList[i]; +//(EIP45278)> +#if PCI_MMIO_RES_TOP_ALLIGN == 1 + if(rt==rtIo16) +#endif + bar->Base=min; +#if PCI_MMIO_RES_TOP_ALLIGN == 1 + else + bar->Base=max-bar->Length; +#endif +//<(EIP45278) + if(bar->Offset!=0xFF){ + Status=ProgramBar(bar); + if(EFI_ERROR(Status)) break; + } +//(EIP45278)> +#if PCI_MMIO_RES_TOP_ALLIGN == 1 + if(rt==rtIo16) +#endif + min+=(bar->Length); +#if PCI_MMIO_RES_TOP_ALLIGN == 1 + else + max-=(bar->Length); +#endif +//<(EIP45278) + } + + if(EFI_ERROR(Status)&& bar!=NULL){ + PCI_TRACE((TRACE_PCI,"PciBus: ERROR Assign Res for BAR(T=%X O=%X) @ [ B%X|D%X|F%X ]", + bar->Type, bar->Offset, bar->Owner->Address.Addr.Bus, + bar->Owner->Address.Addr.Device,bar->Owner->Address.Addr.Function)); + ASSERT_EFI_ERROR(Status); + } + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ClearBar() +// +// Description: Clears/zeros contents of PCI_BAR structure. +// +// Input: +// PCI_BAR *Bar Pointer to PCI_BAR structure to clear. +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID ClearBar(PCI_BAR *Bar) +{ + Bar->Type=tBarUnused; + Bar->Gran=0; + Bar->Length=0; + Bar->Base=0; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindBarByType() +// +// Description: Checks if PCI BAR register of a particular "BarType" present +// behind the PCI Bridge. +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Device Private Data structure +// of the Parent Bridge. +// PCI_BAR_TYPE BarType Bar Type to search for. +// +// Output: BOOLEAN +// TRUE if BAR of "BarType" present Behind the "Brg". +// FALSE if otherwice. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN FindBarByType(PCI_BRG_INFO* Brg, PCI_BAR_TYPE BarType) +{ + UINTN i,j; + BOOLEAN res; + PCI_DEV_INFO *dev; +//--------------------- + for(i=0; i<Brg->Bridge.ChildCount; i++){ + dev=Brg->Bridge.ChildList[i]; + if(dev->Type<tPciHostDev && dev->Type>=tPciRootBrg){ + //go inside the bridge... + res=FindBarByType((PCI_BRG_INFO*)dev,BarType); + if(res) return res; + } + + for(j=0; j<PCI_MAX_BAR_NO+1; j++) if(dev->Bar[j].Type==BarType) return TRUE; +#if SRIOV_SUPPORT +//SRIOV Support adds some more bars ito the picture + if( (dev->PciExpress != NULL) && (dev->PciExpress->SriovData != NULL)){ + for(j=0; j<PCI_MAX_BAR_NO; j++) if(dev->PciExpress->SriovData->Bar[j].Type==BarType) return TRUE; + } +#endif + } + return FALSE; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ConvertResources() +// +// Description: Converts Resources Requested by the Devices behind the +// PCI Bridge of "ResType" using "ConvType" method of conversion +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Device Private Data structure +// of the Parent Bridge. +// PCI_BAR_TYPE ResType Resource Type to convert. Accepted values are +// tBarIo, tBarMem, tBarMemPf, +// all other values are invalid. +// RES_CONV_TYPE ConvType Type of Conversion to be performed. +// +// Output: Nothing +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID ConvertResources(PCI_BRG_INFO *Brg, PCI_BAR_TYPE ResType, RES_CONV_TYPE ConvType, BOOLEAN CombineMemPmem) +{ + PCI_BRG_EXT *ext=&Brg->Bridge; + PCI_DEV_INFO *dev; + UINTN i,j; + BOOLEAN cnv=FALSE; + PCI_BAR_TYPE nt, wt; + RES_CONV_TYPE p2pct; +//---------------------------- + + //Pick Brg Bars to convert + switch (ResType) { + case tBarIo: + nt=tBarIo16; + wt=tBarIo32; + p2pct=rcOneOf; + if(Brg->Common.Type==tPci2CrdBrg)p2pct=rcBoth; + break; + + case tBarMem: + nt=tBarMmio32; + wt=tBarMmio64; + p2pct=rcNarrow; + if(Brg->Common.Type==tPci2CrdBrg)p2pct=rcNarrow; + break; + + case tBarMemPf: + nt=tBarMmio32pf; + wt=tBarMmio64pf; + p2pct=rcOneOf; + if(Brg->Common.Type==tPci2CrdBrg)p2pct=rcNarrow; + break; + + default : return; //no other combinations supported + }//switch + + switch (ConvType){ + case rcNone: + cnv=TRUE; + break; + case rcOneOf: + cnv=FindBarByType(Brg,nt); + break; + case rcNarrow: + cnv=FindBarByType(Brg,wt); + break; + case rcBoth: cnv=FALSE; + }//switch + + //Take care about Padding behind the bridge if CombineMemPmem Attribute is set + if(ext->Pad[rtMmio32p].Length && CombineMemPmem){ + ext->Pad[rtMmio32].Length+=ext->Pad[rtMmio32p].Length; + ext->Pad[rtMmio32p].Length=0; + } + if(ext->Pad[rtMmio64p].Length && CombineMemPmem){ + ext->Pad[rtMmio64].Length+=ext->Pad[rtMmio64p].Length; + ext->Pad[rtMmio64p].Length=0; + } + + for(i=0; i<ext->ChildCount; i++) { + dev=ext->ChildList[i]; + for(j=0; j<PCI_MAX_BAR_NO; j++){ + if(cnv){ + switch(ConvType){ + case rcNone: + if(dev->Bar[j].Type==wt) ClearBar(&dev->Bar[j]); + break; + case rcOneOf: + case rcNarrow: + if(dev->Bar[j].Type==wt) dev->Bar[j].Type=nt; + break; + } + } //if cnv + if(CombineMemPmem){ + if( dev->Bar[j].Type==tBarMmio32pf ) dev->Bar[j].Type=tBarMmio32; + if( dev->Bar[j].Type==tBarMmio64pf ) dev->Bar[j].Type=tBarMmio64; + } + }//for j + +#if SRIOV_SUPPORT +//SRIOV Support adds some more bars ito the picture + if( (dev->PciExpress != NULL) && (dev->PciExpress->SriovData != NULL)){ + for(j=0; j<PCI_MAX_BAR_NO; j++){ + if(cnv){ + switch(ConvType){ + case rcNone: + if(dev->PciExpress->SriovData->Bar[j].Type==wt){ + ClearBar(&dev->PciExpress->SriovData->Bar[j]); + } + break; + case rcOneOf: + case rcNarrow: + if(dev->PciExpress->SriovData->Bar[j].Type==wt){ + dev->PciExpress->SriovData->Bar[j].Type=nt; + } + break; + }//switch + } //if cnv + if(CombineMemPmem){ + if( dev->PciExpress->SriovData->Bar[j].Type==tBarMmio32pf ) + dev->PciExpress->SriovData->Bar[j].Type=tBarMmio32; + if( dev->PciExpress->SriovData->Bar[j].Type==tBarMmio64pf ) + dev->PciExpress->SriovData->Bar[j].Type=tBarMmio64; + } + }//for j + } +#endif + + //recoursively call to convert child resources behind other brg + if(dev->Type==tPci2PciBrg || dev->Type==tPci2CrdBrg){ + if(cnv){ + //Unconditionally convert all resources to narrow because parent requested resource conversion + if(ConvType)ConvertResources((PCI_BRG_INFO*)dev, ResType, rcNarrow, CombineMemPmem); + else ConvertResources((PCI_BRG_INFO*)dev, ResType, ConvType, CombineMemPmem); + } else ConvertResources((PCI_BRG_INFO*)dev, ResType, p2pct, CombineMemPmem); + } + } //Child loop + //we did it!!! +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AssignBusResources() +// +// Description: Sorts, Aligns, and Programms Resources requested by devices +// on the PCI Bus created by the PCI Bridge - "Brg". +// +// Input: +// PCI_BRG_INFO *Brg Pointer to PCI Device Private Data structure +// of the Bridge who creates the bus. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Notes: +// Assigns Resources by filling Device Bar structure +// and programm all Bridge Childs Bars +// and Enables Bridge devices to decode their resources +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AssignBusResources(PCI_BRG_INFO *Brg) +{ + EFI_STATUS Status=0; + UINT8 i; + PCI_DEV_INFO *dev; +//---------------------------------- + //First Check if Resources Assigned don't do it multiple times + if(Brg->Common.Assigned) return EFI_SUCCESS; + + if(Brg->Common.Type == tPci2PciBrg || Brg->Common.Type == tPci2CrdBrg){ + Status=DisableDeviceDecoding(&Brg->Common,stDisableAll); + Brg->Common.Attrib=0; + } + + //Start with IO + if (Brg->Bridge.Res[rtIo32].Length) Status=AssignBridgeResources(Brg,rtIo32); + if(EFI_ERROR(Status)) return Status; + + if (Brg->Bridge.Res[rtIo16].Length) Status=AssignBridgeResources(Brg,rtIo16); + if(EFI_ERROR(Status)) return Status; + + + //Now MMIO 64 PF + if(Brg->Bridge.Res[rtMmio64p].Length)Status=AssignBridgeResources(Brg,rtMmio64p); + if(EFI_ERROR(Status)) return Status; + + //Now MMIO 64 + if(Brg->Bridge.Res[rtMmio64].Length)Status=AssignBridgeResources(Brg, rtMmio64); + if(EFI_ERROR(Status)) return Status; + + //Now MMIO 32 PF + if(Brg->Bridge.Res[rtMmio32p].Length)Status=AssignBridgeResources(Brg,rtMmio32p); + if(EFI_ERROR(Status)) return Status; + + //And MMIO 32 + if(Brg->Bridge.Res[rtMmio32].Length)Status=AssignBridgeResources(Brg, rtMmio32); + if(EFI_ERROR(Status)) return Status; + + + //So far so good - resources has been assigned on this Bridge level + //now check if we have any p2p brg among this brg childs... + //if so we will call this function recoursively... + for(i=0; i<Brg->Bridge.ChildCount; i++ ){ + PCI_CFG_ADDR a; + PCI_CMD_REG cmdreg; + //----------------- + Status=EFI_SUCCESS; + + dev=Brg->Bridge.ChildList[i]; + a.ADDR=dev->Address.ADDR; + + //Now take care of CacheLine Size register + if(dev->Capab&MY_PCI_IO_ATTRIBUTE_MEM_WR_INVALIDATE){ + a.Addr.Register=PCI_CLS; // Cache Line Size + + Status=PciCfg8(dev->RbIo,a,TRUE,&gPciCaheLineSize); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + + + if(dev->Type==tPci2PciBrg ||dev->Type==tPci2CrdBrg) Status=AssignBusResources((PCI_BRG_INFO*)dev); + + //disable decoding fo the PCI devices unles PciPortSkipThisDevice() + //says to Skip it. The Device Specific driver should enable it using Attributes() function. + if(!dev->SkipDevice){ + Status=DisableDeviceDecoding(dev,stDisableAll); + dev->Attrib=0; + } + + if (EFI_ERROR(Status)) return Status; + dev->Assigned=TRUE; + //UEFI 2.1 - we must leave BRIDGES open (decoding it's ranges) + if(dev->Type==tPci2PciBrg ||dev->Type==tPci2CrdBrg){ + PCI_BRG_CNT_REG bc; + //--------------------------- + Status=DeviceAttributes(dev, dev->Capab & (EFI_PCI_DEVICE_ENABLE), TRUE); + ASSERT_EFI_ERROR(Status); + + a.Addr.Register=PCI_BRIDGE_CNTL; //Bridge Control Reg + + Status=PciCfg16(dev->RbIo,a,FALSE,&bc.BRG_CNT_REG); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Set VGA16 enable to avoid forwarding ISA VGA Aliases + bc.Vga16Enable=1; + + //Programm device's BRG_CTL_REG to forward #SERR and #PERR to the primary Interface. + if(gPciSetupData->SerrEnable) bc.SerrEnable=1; + else bc.SerrEnable=0; + + if(gPciSetupData->PerrEnable) bc.PerrEnable=1; + else bc.PerrEnable=0; + + + Status=PciCfg16(dev->RbIo,a,TRUE,&bc.BRG_CNT_REG); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + + //Programm device's PCI_CMD_REG to generate #SERR and #PERR according to Setup. + a.Addr.Register=PCI_CMD; //PCI Command Reg + + Status=PciCfg16(dev->RbIo,a,FALSE,&cmdreg.CMD_REG); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + if(gPciSetupData->SerrEnable) cmdreg.SerrEnable=1; + else cmdreg.SerrEnable=0; + + if(gPciSetupData->PerrEnable) cmdreg.ParityErrorResp=1; + else cmdreg.ParityErrorResp=0; + + Status=PciCfg16(dev->RbIo,a,TRUE,&cmdreg.CMD_REG); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + } //for + Brg->Common.Assigned=TRUE; + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CreateRootResDsc() +// +// Description: Creates an ACPI QWORD Resource Descriptors set to reflect +// this "RootBrg" resource request +// +// Input: +// PCI_BRG_INFO *RootBrg Pointer to PCI Device Private Data structure +// of the Bridge who creates the bus. +// IN OUT VOID* *ResDsc ACPI QWORD Resource Descriptors set. +// See definition of ASLR_QWORD_ASD for details. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// +// Notes: +// Meaning of QWORD Resource Descriptor Fields for this function +// _LEN => Set to the size of the aperture that is requested. +// _GRA => Used to differentiate between a 32-bit memory request and a +// 64-bit memory request. For a 32-bit memory request, +// this field should be set to 32. For a 64-bit memory request, +// this field should be set to 64. All other values result in +// this function returning the error code of EFI_INVALID_PARAMETER. +// _MAX => Used to specify the alignment requirement. +// All other fields are ignored. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CreateRootResDsc(PCI_DEV_INFO *RootBrg, VOID **ResDsc){ + UINTN i, rc=0; + ASLR_QWORD_ASD *rd; + PCI_BRG_EXT *ext=(PCI_BRG_EXT*)(RootBrg+1); +//----------------------------------------------------- + //First count how many rd suppose to be + for(i=rtIo16; i<rtMaxRes; i++){ + if(ext->Res[i].Type && ext->Res[i].Length) rc++; + } + + //If RB don't have any resource requests fill out END_TAG_DESCRIPTOR and return. + if(!rc){ + rd=MallocZ(sizeof(ASLR_EndTag)); + rd->Hdr.HDR=ASLV_END_TAG_HDR; + *ResDsc=rd; + return EFI_SUCCESS; + } + + //get some memory + rd=MallocZ(sizeof(ASLR_QWORD_ASD)*rc+sizeof(ASLR_EndTag)); + ASSERT(rd); + if(!rd) return EFI_OUT_OF_RESOURCES; + + *ResDsc=rd; + for(i=rtIo16; i<rtMaxRes; i++){ + if(!(ext->Res[i].Type && ext->Res[i].Length)) continue ; + switch(ext->Res[i].Type){ + case tBarIo16: + rd->Type=ASLRV_SPC_TYPE_IO; + rd->_GRA=16; + break; + case tBarIo32: + rd->Type=ASLRV_SPC_TYPE_IO; + rd->_GRA=32; + break; + case tBarMmio32pf: + rd->TFlags.MEM_FLAGS._MEM=ASLRV_MEM_CEPF; + //no break intentionally!! DON'T CHANGE + case tBarMmio32: + rd->Type=ASLRV_SPC_TYPE_MEM; + rd->_GRA=32; + rd->TFlags.MEM_FLAGS._RW=1; + break; + case tBarMmio64pf: + rd->TFlags.MEM_FLAGS._MEM=ASLRV_MEM_CEPF; + //no break intentionally!! DON'T CHANGE + case tBarMmio64: + rd->Type=ASLRV_SPC_TYPE_MEM; + rd->_GRA=64; + rd->TFlags.MEM_FLAGS._RW=1; + break; + default : continue; + } + rd->Hdr.HDR=0x8A; + rd->GFlags.GFLAGS=0x0C; //Means _MIN and _MAX is fixed + rd->Hdr.Length=0x2B; + rd->_MAX=ext->Res[i].Gran; + rd->_LEN=ext->Res[i].Length + ext->Align[i].ExtraRes.Length; + + if(rd->Type==ASLRV_SPC_TYPE_MEM){ + //Check to Memory Resource Size Align on 4K + if(rd->_LEN & (EFI_PAGE_SIZE-1))rd->_LEN=(rd->_LEN | (EFI_PAGE_SIZE-1))+1; + } + + PCI_TRACE((TRACE_PCI,"CreateRD QWD: T=%X; GF=%X; TF=%X; _MN=%lX; _MX=%lX; _LN=%lX;_GR=%lX;\n", + rd->Type, rd->GFlags.GFLAGS, rd->TFlags.TFLAGS, rd->_MIN, rd->_MAX, rd->_LEN, rd->_GRA)); + + rd++; + } + rd->Hdr.HDR=ASLV_END_TAG_HDR; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ConvertResources() +// +// Description: Converts Resource information from QWORD ACPI ResDesc +// to internal format and store it within PCI_DEV_INFO structure. +// +// Input: +// PCI_BRG_EXT *RbExt Pointer to PCI Device Private Data structure +// of the Root Bridge. (PCI_BRG_EXT part) +// ASLR_QWORD_ASD *Resources Pointer to the set + +// RES_CONV_TYPE ConvType Type of Conversion to be prformed. +// +// Output: Nothing +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID ApplyAcpiResources(PCI_BRG_EXT *RbExt, ASLR_QWORD_ASD *Resources){ + ASLR_QWORD_ASD *res=Resources; + PCI_BAR *bar; + UINTN i, s, e; +//------------------------------------ + while(res->Hdr.HDR!=ASLV_END_TAG_HDR) { + bar=NULL; + PCI_TRACE((TRACE_PCI,"ApplyRD QWD: T=%X; GF=%X; TF=%X; _MN=%lX; _MX=%lX; _LN=%lX;_GR=%lX;\n", + res->Type, res->GFlags.GFLAGS, res->TFlags.TFLAGS, res->_MIN, res->_MAX, res->_LEN, res->_GRA)); + + if(res->Type==ASLRV_SPC_TYPE_IO){ + s=rtIo16; + e=rtMmio32; + } else { + if(res->Type==ASLRV_SPC_TYPE_MEM){ + s=rtMmio32; + e=rtMaxRes; + } else { + res++; + continue; + } + } + + for(i=s; i<e; i++){ + UINT64 len; + //-------------------- + bar=&RbExt->Res[i]; + len=bar->Length+RbExt->Align[i].ExtraRes.Length; + + if( (res->Type==ASLRV_SPC_TYPE_MEM) && (len&(EFI_PAGE_SIZE-1)) ) + len=(len|(EFI_PAGE_SIZE-1))+1; + + //It might be an empty descriptor (i.e. System has MMIO32, but does not have MMIO32PF) + //This might cause to break early. w/o searching through 64bit resources + //take care of this condition by adding check (bar->Length != 0) + if((bar->Base == 0) && (bar->Length != 0) && (len <= res->_LEN)) break; + else bar=NULL; + } + + if(bar)bar->Base=res->_MIN; + res++; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitPciDb() +// +// Description: Creates all anckor structures and Initialize PCI Database. +// +// Input: +// EFI_HANDLE Controller Controller Handle passed to the PCI Bus Driver +// Start Function. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InitPciDb(EFI_HANDLE Controller){ + EFI_STATUS Status; + EFI_HANDLE *hBuff, htmp=NULL; + EFI_DEVICE_PATH_PROTOCOL *rbdp; + UINTN i, cnt=0; + PCI_DEV_INFO *rb; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *rbio; + +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + UINTN ghpccnt=0, j; + EFI_HPC_LOCATION *ghpclst=NULL; +#endif + +//------------------------ + Status=PopulateBusDb(); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return EFI_DEVICE_ERROR; + + Status=pBS->HandleProtocol(Controller,&gPciRootBridgeIoProtocolGuid,&rbio); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return EFI_INVALID_PARAMETER; + if(gPciHost && gPciHost[0].Updated) return EFI_SUCCESS; + + + //Try to figure out how many instances of PCI HostBridge Resource Allocation Protocol + //exists, this will give us an idea how many PCI_ROOT_INFO instances to create... + Status=pBS->LocateHandleBuffer( + ByProtocol, // SearchType, + &gEfiPciHostBrgResAllocProtocolGuid, //*Protocol OPTIONAL, + NULL, //*SearchKey OPTIONAL, + &gHostCnt, //*NoHandles, + &hBuff); //**Buffer + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Now we know how many Host Bridges the System has + gPciHost=MallocZ(sizeof(PCI_HOST_INFO)*gHostCnt); + + //record Host Bridge Properties + for(i=0; i<gHostCnt; i++){ + gPciHost[i].HostHandle=hBuff[i]; + //Get Resource Alloc Protocol and Record It + Status=pBS->HandleProtocol(hBuff[i],&gEfiPciHostBrgResAllocProtocolGuid,&gPciHost[i].ResAllocProt); + //it has to be there or plaform is not Framework compliant + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + //now will locate some optional protocols which must be used if present during PCI enumeration + //as per spec - only one instance of this protocols should be present + if(i==0){ +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + pBS->LocateProtocol(&gEfiPciHotPlugInitProtocolGuid, NULL, &gPciHost[i].HpInitProt); +#endif + pBS->LocateProtocol(&gEfiPciPlatformProtocolGuid, NULL, &gPciHost[i].PlatformProt); + pBS->LocateProtocol(&gEfiIncompatiblePciDeviceProtocolGuid, NULL, &gPciHost[i].IncompDevProt); + } else { +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + gPciHost[i].HpInitProt=gPciHost[0].HpInitProt; +#endif + gPciHost[i].PlatformProt=gPciHost[0].PlatformProt; + gPciHost[i].IncompDevProt=gPciHost[0].IncompDevProt; + } + gPciHost[i].Updated=TRUE; + } + +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + + //If HpInitProtocol Exists get RootHpcList + if(gPciHost[0].HpInitProt ){ + Status=gPciHost[0].HpInitProt->GetRootHpcList(gPciHost[0].HpInitProt,&ghpccnt,&ghpclst); + ASSERT_EFI_ERROR(Status); + } +#endif + + //Now get all RbIo Protocol Handlers and find the right place for it Protocol Instance. + Status=pBS->HandleProtocol(Controller,&gPciRootBridgeIoProtocolGuid,&rbio); + //RBIoProtocol has to be installed on Controller Handle + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //Select Right Host Brg for this RootBrg Io Protocol Handler + for(i=0; i<gHostCnt; i++){ + //if(gPciHost[i].HostHandle==rbio->ParentHandle) gCurHost=i; + + htmp=NULL; + //Now we will fill Pci Root infrastructure in the right order + while(!Status){ + //get Root Bridge Handle of this Host + Status=gPciHost[i].ResAllocProt->GetNextRootBridge(gPciHost[i].ResAllocProt, &htmp); + if(EFI_ERROR(Status)) break; + + + //Create New PCI_BRG_INFO structure; + rb=NewDevice(TRUE,NULL); + if(!rb) return EFI_OUT_OF_RESOURCES; + + //Get the Resource Allocation Attributes + //Status=gPciHost[i].ResAllocProt->GetAllocAttributes(gPciHost[i].ResAllocProt, htmp, &rb->Attrib); + //if(EFI_ERROR(Status)) break; + + + //Add it to the Root Bridge Item List + Status=AppendItemLst((T_ITEM_LIST*)&gPciHost[i].RbInitCnt, rb); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //now I'll get DevicePath and RootBridgeIo protocols Associated with this Handle + //Status=pBS->HandleProtocol(htmp,&gPciRootBridgeIoProtocolGuid,&rb->RbIo); + //This Protocol will remain opened untill PciBusStop is Called. + Status=pBS->OpenProtocol(htmp, + &gPciRootBridgeIoProtocolGuid,(VOID **)&rb->RbIo, + gPciBusDriverBinding.DriverBindingHandle,htmp, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + ASSERT_EFI_ERROR(Status); //it MUST have this + if(EFI_ERROR(Status)) return Status; + + Status=pBS->HandleProtocol(htmp,&gDevicePathProtocolGuid,&rbdp); + ASSERT_EFI_ERROR(Status); //it MUST have this + if(EFI_ERROR(Status)) return Status; + + //Fill out some missing and incorrectly filled fields + rb->DevicePath=DPCopy(rbdp); + rb->Type=tPciRootBrg; + rb->HostData=&gPciHost[i]; + rb->Handle=htmp; + rb->ParentBrg=NULL; + +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + + //sort out Root Hot Plug Controlers list items to where they belongs + PCI_TRACE((TRACE_PCI,"PciBus: Get Location - HpcLocCount=%d; RbDp=[HID(%X)UID(%X)]\n", + ghpccnt,((ACPI_HID_DEVICE_PATH*)rbdp)->HID,((ACPI_HID_DEVICE_PATH*)rbdp)->UID)); + PCI_TRACE((TRACE_PCI,"-------------------------------------------------\n")); + + for (j=0; j<ghpccnt; j++){ + + if( !MemCmp(rbdp, ghpclst[j].HpcDevicePath, sizeof(ACPI_HID_DEVICE_PATH)) ){ + PCI_HPC_INFO *rhpc; + //----------------------------- + rhpc=MallocZ(sizeof(PCI_HPC_INFO)); + ASSERT(rhpc); + if(!rhpc) return EFI_OUT_OF_RESOURCES; + //Init PCI_ROOT_HPC structure + rhpc->Root=TRUE; + rhpc->HpcLocation=&ghpclst[j]; + + PCI_TRACE((TRACE_PCI,"HpcDP=[HID(%X)UID(%X)]; HpbDP[HID(%X)UID(%X)]\n", + ((ACPI_HID_DEVICE_PATH*)rhpc->HpcLocation->HpcDevicePath)->HID,((ACPI_HID_DEVICE_PATH*)rhpc->HpcLocation->HpcDevicePath)->UID, + ((ACPI_HID_DEVICE_PATH*)rhpc->HpcLocation->HpbDevicePath)->HID,((ACPI_HID_DEVICE_PATH*)rhpc->HpcLocation->HpbDevicePath)->UID)); + + Status=AppendItemLst((T_ITEM_LIST*)&rb->HostData->RhpcInitCnt,rhpc); + ASSERT_EFI_ERROR(Status); //it MUST have this + if(EFI_ERROR(Status)) return Status; + } + } + PCI_TRACE((TRACE_PCI,"-------------------------------------------------\n")); +#endif + + } + if(Status!=EFI_NOT_FOUND) return Status; + } + + //Don't forget to free handle Buffer; + pBS->FreePool(hBuff); + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: EnumerateAll() +// +// Description: This is Main function to start PCI Bus Enumeration Process. +// +// Input: +// EFI_HANDLE Controller Controller Handle passed to the PCI Bus Driver +// Start Function. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS EnumerateAll(EFI_HANDLE Controller){ + EFI_STATUS Status=EFI_SUCCESS; + UINTN i, j; + UINT8 StartBus, EndBus; + RES_CONV_TYPE ct; + PCI_HOST_INFO *lhst; + PCI_DEV_INFO *rb; + PCI_BRG_EXT *ext; + ASLR_QWORD_ASD *rres; +//------------------------------- + //Init Pci Local Data if it wasn't initialized yet + if(gPciHost==NULL){ + Status=InitPciDb(Controller); + ASSERT_EFI_ERROR(Status); + } + //Check if we have enumerated VERY FIRST ROOT we done. + //That means all roots were enumerated alredy, don't spend eny more time here... + if(gPciHost[0].Enumerated) return EFI_SUCCESS; + + //We will do enumeration for all PCI infrastructure, as soon as we got very first + //Root Bridge Handle. and then will start only devices belonging to the RootBridge + //who's handle we have received as a Controller Handle. + mMaxBusFound=0; + mMaxBusReport=0; + + for(j=0; j<gHostCnt; j++){ + lhst=&gPciHost[j]; //init local host pointer + + //will circle trough Root bridges system has starting from _UID=0 + for(i=0; i<lhst->RbCount; i++){ + rb=lhst->RootBridges[i]; + ext=(PCI_BRG_EXT*)(rb+1); + +#if BoardPciRes_SUPPORT + gPciOutOfRes=FALSE; +#endif + //check if we have this Root Bridge Enumerated already + if(rb->Enumerated) continue; +// ClearItemLst(&res, TRUE); + + //6. Notify the host bridge driver that PCI enumeration is about to begin by calling + //NotifyPhase (EfiPciHostBridgeBeginEnumeration). This member function + //must be the first one that gets called. PCI enumeration has two steps: bus enumeration and + //resource enumeration. + Status=DoPciNotify(lhst, EfiPciHostBridgeBeginEnumeration); + ASSERT_EFI_ERROR(Status); + + //7. Notify the host bridge driver that bus enumeration is about to begin by calling + //NotifyPhase (EfiPciHostBridgeBeginBusAllocation). + Status=DoPciNotify(lhst, EfiPciHostBridgeBeginBusAllocation); + ASSERT_EFI_ERROR(Status); + + //8. Do the following for every PCI root bridge handle: + // a. Call StartBusEnumeration (This,RootBridgeHandle). + Status=lhst->ResAllocProt->StartBusEnumeration(lhst->ResAllocProt, rb->Handle, &rres); + ASSERT_EFI_ERROR(Status); + + //Check if it is NULL descriptor.. + if(rres->_MIN==0 && rres->_MAX==0 && rres->_LEN==0) { + Status=DoPciNotify(lhst, EfiPciHostBridgeEndBusAllocation); + Status=DoPciNotify(lhst, EfiPciHostBridgeBeginResourceAllocation); + continue; + } + + //Check if we've received correct descriptors + if(!ValidateDescriptorBlock(rres,tResBus,FALSE)) { + ASSERT(0); + return EFI_DEVICE_ERROR; + } + + //we have reseived BUS configuration information in "rres" + //_MIN Bus# has to be Updated with respect of previous pass + StartBus=(UINT8)rres->_MIN; + mMaxBusFound=StartBus; + + rb->Address.Addr.Bus=StartBus; + mMaxBusScan=(UINTN)(StartBus+rres->_LEN-1); + //Maximum bus number must not exceed 0xFF buses! + if(mMaxBusScan > 0xFF) ASSERT_EFI_ERROR(EFI_DEVICE_ERROR); + //Match Busxlat Entry to the current Host Bridge + Status=FindBridgeXlatEntry(rb, ext); + //It's a seriouse error if it returns NOT_FOUND need to ASSERT here. + ASSERT_EFI_ERROR(Status); + + ext->Res[rtBus].Type=tBarBus; + ext->Res[rtBus].Base=StartBus; + ext->Res[rtBus].Length=rres->_LEN; + //Get Attributes to see what this RB could support + Status=rb->RbIo->GetAttributes(rb->RbIo,&rb->Capab,&rb->Attrib); + ASSERT_EFI_ERROR(Status); + +//Exclude Hotplug support +#if HOTPLUG_SUPPORT + //this will try to init Root HPC siting behind this bridge if any... + Status=CheckRootHotplug(rb); + ASSERT_EFI_ERROR(Status); + //if root hpc init fail for any reason we just must keep going +#endif + // b. Make sure each PCI root bridge handle supports the + // EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + // c. Allocate memory to hold resource requirements. These resources can be two resource trees: + // one to hold bus requirements and another to hold the I/O and memory requirements. + // + // e. Scan all the devices in the specified bus range and on the specified segment. If it is a PCIto- + // PCI bridge, update the bus numbers and program the bus number registers in the PCI-to- + // PCI bridge hardware. If it is an ordinary device, collect the resource request and add up all + // of these requests in multiple pools (e.g., I/O, 32-bit prefetchable memory). Combine + // different types of memory requests at an appropriate level based on the PCI root bridge + // attributes. Update the resource requirement information accordingly. On every PCI root + // bridge, reserve space to cover the largest expansion ROMs on that bus, which will allow + // the PCI bus driver to retrieve expansion ROMs from the PCI card or device without having + // to reprogram the PCI host bridge. Because the memory and I/O resource collection step + // does not call any member function of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL, + // it can be performed at a later time. + // f. Once the number of PCI buses under this PCI root bridge is known, call + // SetBusNumbers() with this information. + + //Go and do the job! + mMaxBusReport=StartBus; + PCI_TRACE((TRACE_PCI,"PciBus: Root#%d; ScanFullBusRange=%d; Scanning ",i, ScanFullBusRange)); + if(ScanFullBusRange) { + EndBus=(UINT8)(mMaxBusScan); + PCI_TRACE((TRACE_PCI,"Bus Range 0x%X...0x%X \n", StartBus, EndBus)); + } else { + EndBus=StartBus; + PCI_TRACE((TRACE_PCI,"Buses Starting from 0x%X \n", StartBus)); + } + + if(ext->XlatTblEntry) ext->XlatTblEntry->BusRun=StartBus; + + do{ + Status=EnumerateBus((PCI_DEV_INFO*)rb); + if(EFI_ERROR(Status)){ + if(Status != EFI_NOT_FOUND) return Status; + } else { + if(mMaxBusReport < rb->Address.Addr.Bus) mMaxBusReport = rb->Address.Addr.Bus; + rb->Address.Addr.Bus = mMaxBusReport; + ext->Res[rtBus].Base = mMaxBusReport; + } + + //Bus is UINT8 to avoid deadloop here check + //for condition to berak the loop. + if(rb->Address.Addr.Bus==0xFF) break; + rb->Address.Addr.Bus++; + ext->Res[rtBus].Base++; + } while (rb->Address.Addr.Bus <= EndBus); + +#if PCI_EXPRESS_SUPPORT + //We have collected all Upstream Ports information + //Now init it from EndPoint up to RootPort + while(gPcieEpList.ItemCount!=0){ + PCI_DEV_INFO *epdev; + //--------------------- + epdev=(PCI_DEV_INFO*)gPcieEpList.Items[0]; + + Status=PcieInitDevChain(epdev); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } +#endif + //Restore old values + rb->Address.Addr.Bus = StartBus; + ext->Res[rtBus].Base = StartBus; + if(ext->XlatTblEntry){ + UpdateIrqTables(ext->XlatTblEntry); + PCI_TRACE((TRACE_PCI,"PciBus: Update Bus# for RootBrg [B%X|D%X|F%X] - Bld %X -> Run %X\n", + rb->Address.Addr.Bus,rb->Address.Addr.Device,rb->Address.Addr.Function, + ext->XlatTblEntry->BusBuild,ext->XlatTblEntry->BusRun)); + } + + //we got lucky!!! finally we are here with information about all resources we need + //in the Root Bridge device the following fields will reflect ACPI Resource descriptor fields + // rb->Address.Bus = Primary Bus Number _MIN + // ext->Res[rtBus].Base = Subordinate Bus Number = _MAX + // ext->Res[rtBus].Len = _MAX+1 + ext->Res[rtBus].Base=mMaxBusReport; //that how much this root brg has buses + ext->Res[rtBus].Length=mMaxBusReport-StartBus+1; + + //Update discovered Bus Numbers and report Bus Resources to the HOST + rres->_LEN=ext->Res[rtBus].Length; + rres->_MAX=rres->_MIN+rres->_LEN-1; + Status=lhst->ResAllocProt->SetBusNumbers(lhst->ResAllocProt, rb->Handle, rres); + ASSERT_EFI_ERROR(Status); + //if everything OK free memory given by StartBusEnumeration function + pBS->FreePool(rres); + + + + //Here we have to convert some resourcers which we have discovered but RB doesn't supports + //Get Allocation Attributes for this Root Bridge it will let us know how to convert resources for this Root bridge +//??????????????????????????????????????????????????????????????????????????????????????????????????? +//Currently resource allocation attributes reflects only capability of RB to decode 64 bit address +//but still will not give any clue weathere it is single window or RB has a separate BAR to decode it. +//If the bar is single and it decodes eather 32 or 64 bit resources the "rcOneOf" must be selected +//??????????????????????????????????????????????????????????????????????????????????????????????????? + Status=lhst->ResAllocProt->GetAllocAttributes(lhst->ResAllocProt,rb->Handle,&gAllocationAttributes); + ASSERT_EFI_ERROR(Status); + + //Notify HB and CSP + Status=DoPciNotify(lhst, EfiPciHostBridgeEndBusAllocation); + ASSERT_EFI_ERROR(Status); + + PROGRESS_CODE(DXE_PCI_BUS_REQUEST_RESOURCES); + + //First do IO - Any PCI Root Bridge supports only Io16 + ConvertResources((PCI_BRG_INFO*)rb,tBarIo,rcNarrow,(BOOLEAN)(gAllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM)); + + //than do MMIO + if(gAllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE)ct=rcBoth; + else ct=rcNarrow; + ConvertResources((PCI_BRG_INFO*)rb,tBarMem,ct,(BOOLEAN)(gAllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM)); + + //than do pfMMIO + if(gAllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE)ct=rcBoth; + else ct=rcNarrow; + ConvertResources((PCI_BRG_INFO*)rb,tBarMemPf,ct,(BOOLEAN)(gAllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM)); + +//??????????????????????????????????????????????????????????????????????????????????????????????????? +// Attempt to boot with reduced number of PCI Cards if resources will be not enough +//??has to be called consequently +//??or create RecalculateBrgResources()... +////////////////////////////////////////////////////////////////// +//??????????????????????????????????????????????????????????????????????????????????????????????????? +#if BoardPciRes_SUPPORT + + do{ +//OUT_OF_RES!! + //Reset Flag to stop calling Platform function to select PCI device selected + // to be removed from enumeration for this pass. It will be SET in CalculateBrgResources(). + gPciOutOfResHit=FALSE; + ext=(PCI_BRG_EXT*)(rb+1); + if(gPciOutOfRes) ClearBrgResources(rb); +#endif + //Calculate resources Consumed by this Root bridge + CalculateBrgResources(rb); + rb->Discovered=TRUE; + + //Notify HB and CSP + Status=DoPciNotify(lhst, EfiPciHostBridgeBeginResourceAllocation); + ASSERT_EFI_ERROR(Status); + + //Status=AllocateRootResources(gPciRoot.RootBrg[i], &mRootRes); + //Create Resource information to report to the HOST BRG + Status=CreateRootResDsc(rb,&rres); + if(EFI_ERROR(Status)){ + PCI_TRACE((TRACE_PCI,"PciBus: CreateRootResDsc() returned %r \n ",Status)); + return Status; + } + + //Not Found Condition is Normal for RB it does not have enything behind it. + //Skip Calling SubmitResources() since nothing to Submit + Status=lhst->ResAllocProt->SubmitResources(lhst->ResAllocProt, rb->Handle, rres); + if(EFI_ERROR(Status)) { + VOID *Configuration; //This is a dummy parameter. +#if BoardPciRes_SUPPORT +#if PCI_OUT_OF_RESOURCE_SETUP_SUPPORT + //Declare Boot flow variable GUID... + EFI_GUID BootFlowVariableGuid = BOOT_FLOW_VARIABLE_GUID; + UINT32 BootFlow = BOOT_FLOW_CONDITION_PCI_OUT_OF_RESOURCE; + //------------------------------ + Status=pRS->SetVariable(L"BootFlow",&BootFlowVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS,sizeof(BootFlow),&BootFlow); +#endif + + //Give Platform Policy Driver to handle OUT_OF_RESOURCES situation + //by itself (it just might want to BEEP and HUNG the system) + gPciOutOfRes=TRUE; + +#endif + lhst->ResAllocProt->GetProposedResources( + lhst->ResAllocProt, + rb->Handle, + &Configuration); +#if BoardPciRes_SUPPORT +#else + ERROR_CODE(DXE_PCI_BUS_OUT_OF_RESOURCES,EFI_ERROR_MAJOR); + ASSERT_EFI_ERROR(Status); +#endif + pBS->FreePool(rres); +#if BoardPciRes_SUPPORT + } else gPciOutOfRes=FALSE; + } while(gPciOutOfRes); //while resources found +#else + return Status; + } +#endif + } //loop (i) on submiting resources +#if BoardPciRes_SUPPORT + //Check if we suppose to beep and report "OUT OF_RESOURCES" condition + Status=AmiPciOutOfRes(NULL, TRUE); + if(!EFI_ERROR(Status)) ERROR_CODE(DXE_PCI_BUS_OUT_OF_RESOURCES,EFI_ERROR_MAJOR); +#endif + //Notify HB and CSP + Status=DoPciNotify(lhst, EfiPciHostBridgeAllocateResources); + PROGRESS_CODE(DXE_PCI_BUS_ASSIGN_RESOURCES); + + + ASSERT_EFI_ERROR(Status); +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO +// if Allocate Resources Notify Phase returns an ERROR +// Here suppose to be the following logic : +// a. Make do with the smaller ranges. +// b. Call GetProposedResources() to retrieve the proposed settings and examine the +// differences. Prioritize various requests and drop lower-priority requests. Call +// NotifyPhase (EfiPciHostBridgeFreeResources) to undo the previous +// allocation. Go back to step 11 with reduced requirements, which includes resubmitting +// requests for all the root bridges. + + +// It easy to say, but hard to implement!!!!! +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO + + Status=DoPciNotify(lhst, EfiPciHostBridgeSetResources); + ASSERT_EFI_ERROR(Status); + + //now enter the loop where we will get resource windows selected by the Root Bridge + //and programm it in to PCI subsystem BARs + for(i=0; i<lhst->RbCount; i++){ + rb=lhst->RootBridges[i]; + ext=(PCI_BRG_EXT*)(rb+1); + + //Get Copy of updated resources to see if our call worked + Status=rb->RbIo->Configuration(rb->RbIo,(VOID**)&rres); + if (Status==EFI_NOT_AVAILABLE_YET) continue; + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + ApplyAcpiResources(ext, rres); + + //now we have to assign PCI bus resources, and PciRoot will be the special case. + //We should not touch the device which adressed as gPciRoot.RootBrg[i].Address + //because it is controlled by PciRootBridge Driver and we must not directly access it + //So AssignBusResources routine has a checking of such condition + Status=AssignBusResources((PCI_BRG_INFO*)rb); + if(EFI_ERROR(Status)) return Status; + +#if PCI_EXPRESS_SUPPORT + //Record PciEcpress Boot Script since not all OSs knows about it + PcieRecordBootScript(rb); +#endif + + //Set Started Flag for RootBridge device in order not to install PCI IO on it later + rb->Started=TRUE; + }//loop (i) for root bridge + Status=DoPciNotify(lhst, EfiPciHostBridgeEndResourceAllocation); + ASSERT_EFI_ERROR(Status); + + lhst->Enumerated=TRUE; + } //loop (j) +#if S3_VIDEO_REPOST_SUPPORT == 1 +// if( (gPciSetupData->S3ResumeVideoRepost==1) && S3VideoRepost ){ + // Register the event handling function to Record Primary VGA BootScript. + Status = CreateReadyToBootEvent ( + TPL_CALLBACK, + RecordPriVgaBootScript, + NULL, + &gVgaS3Event); +// } +#endif + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CheckPciDevicePath() +// +// Description: Checks if "DevicePath" is a PCI_DEVICE_PATH. +// +// Input: +// EFI_DEVICE_PATH_PROTOCOL *DevicePath Device Path Pointer. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When "DevicePath" is not a PCI_DEVICE_PATH. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CheckPciDevicePath(EFI_DEVICE_PATH_PROTOCOL *DevicePath) +{ + // Check if the RemainingDevicePath is valid + if (DevicePath->Type != HARDWARE_DEVICE_PATH || + DevicePath->SubType != HW_PCI_DP && + NODE_LENGTH(DevicePath) != sizeof (PCI_DEVICE_PATH)) + return EFI_UNSUPPORTED; + else return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DoubleCheckOpRom() +// +// Description: This function called when PciRomHdr->InitializationSize and +// Pcir->ImageSize has different values and Pcir->Indicator bit 7 is not set. +// It evaluets whch one is correct by Searching for 0x55AA signature that is +// must present in the beginning of next OptROM image. +// +// Input: +// LEGACY_OPT_ROM_HEADER *PciRomHdr Pointer to Legacy Option ROM Header(0x55AA). +// PCI_DATA_STRUCTURE *Pcir Pointer to PCI ROM header ("PCIR") +// +// Output: EFI_STATUS +// UINTN Size of the ROM in bytes; +// Note: PCIR and OptROM signatures assumed to be valid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINTN DoubleCheckOpRom(VOID *PciRomHdr, PCI_DATA_STRUCTURE *Pcir){ + UINT8 *p; + UINTN sz=0; + UINTN hsz=0; +//--------------------------------- + //EFI Compatible ROM headers have 16 bit Length field... + if( ((PCI_EFI_OPT_ROM_HEADER*)PciRomHdr)->EfiSignature == PCI_OPT_ROM_EFISIG) hsz=((PCI_EFI_OPT_ROM_HEADER*)PciRomHdr)->InitializationSize; //16 bit size + else hsz=((LEGACY_OPT_ROM_HEADER*)PciRomHdr)->Size512; + + if(hsz == Pcir->ImageLength ) return (hsz*512); + + p=(UINT8*)PciRomHdr; + + if(hsz < Pcir->ImageLength ) { + sz= Pcir->ImageLength*512; + if( ((LEGACY_OPT_ROM_HEADER*)(p+sz))->Signature==PCI_OPT_ROM_SIG) return sz; + if(Pcir->Indicator&0x80) return sz; //(EIP37774+) + } + + sz=hsz*512; + if( ((LEGACY_OPT_ROM_HEADER*)(p+sz))->Signature==PCI_OPT_ROM_SIG) return sz; + else { + if(Pcir->Indicator&0x80) return sz;//(EIP37774+) + if ( ((LEGACY_OPT_ROM_HEADER*)PciRomHdr)->Signature==PCI_OPT_ROM_SIG ) return sz; + return 512; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetOptRom() +// +// Description: Validate and copy PCI Option ROM Image From ADD ON CARD to +// the System Memory. +// +// Input: +// PCI_DEV_INFO *Dev Pointer PCI Devicse Private Data. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_DEVICE_ERROR When driver fails access PCI Bus. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetOptRom(PCI_DEV_INFO *Dev) +{ + EFI_STATUS Status=EFI_NOT_FOUND, ExitStatus=0; + PCI_BAR *rombar=&Dev->Bar[PCI_MAX_BAR_NO]; + //UINT8 RomBuff[20]; + UINTN OptRomSize = 0; + UINT32 trs=0; + PCI_DATA_STRUCTURE Pcir; + PCI_STD_OPT_ROM_HEADER PciRomHdr; + PCI_EFI_OPT_ROM_HEADER *EfiRomHdr=(PCI_EFI_OPT_ROM_HEADER*)&PciRomHdr; +#if CSM_SUPPORT + VOID *EmbRom; +#endif + BOOLEAN ff=TRUE; + UINT64 base=rombar->Base; + UINTN sz=0; +//------------------------------------- + //we got Opt ROM to check... + if(Dev->Bar[PCI_MAX_BAR_NO].Type!=tBarUnused){ + //Enable RomBar Decoding + //We will use PciIo->SetAttributes here to enable device Memory Space. + //If device sits behind some P2P brg Attributes will enable it all the way down + //Per UEFI 2.1 spec bridges must be open and decoding it's resources. + //Status=DeviceAttributes(Dev, EFI_PCI_IO_ATTRIBUTE_MEMORY, TRUE); + //if(EFI_ERROR(Status))return Status; + + Status=EnableDeviceDecoding(Dev,stOptRomSpace); + if(EFI_ERROR(Status))return Status; + + for(;;){ + if(base+trs+512 >= rombar->Base+rombar->Length) break; + + // Get the first 20 bytes of the ROM header + Status=Dev->RbIo->Mem.Read(Dev->RbIo, EfiPciWidthUint8, base+trs, + sizeof(PCI_STD_OPT_ROM_HEADER), &PciRomHdr); + if(EFI_ERROR(Status))goto ExitLbl; + + // Check the validity of the ROM + if ((PciRomHdr.Signature != PCI_OPT_ROM_SIG) || (PciRomHdr.PcirOffset == 0) ){ + if(ff) { + Status=EFI_NOT_FOUND; + goto ExitLbl; + } else { + //base+=512; + trs+=512; + continue; + } + } + ff=FALSE; + + Status=Dev->RbIo->Mem.Read(Dev->RbIo, EfiPciWidthUint8, base+trs+PciRomHdr.PcirOffset, + sizeof(PCI_DATA_STRUCTURE), &Pcir); + if(EFI_ERROR(Status))goto ExitLbl; + + if(Pcir.Signature!=PCI_PCIR_SIG){ + //Status=EFI_NOT_FOUND; + //goto ExitLbl; + continue; + } + + OptRomSize=trs; + + sz=DoubleCheckOpRom((VOID*)(base+trs), &Pcir); + OptRomSize+=sz; + +/* + //Figure out the size of image. Some of the cards has PCI_STD_OPT_ROM_HEADER.Size value + //bigger then in PCIR PCI_DATA_STRUCTURE.ImageLength field. + if(Pcir.CodeType == 0){ + if(PciRomHdr.Reserved[0] < Pcir.ImageLength) OptRomSize+=(Pcir.ImageLength*512); + else OptRomSize+=(PciRomHdr.Reserved[0]*512); + } + //Open Firmware Standard for PCI + if(Pcir.CodeType == 1){ + OptRomSize+=(Pcir.ImageLength*512); + } + + //In case of EFI Option ROM Header + if(Pcir.CodeType == 3) { + if(EfiRomHdr->InitializationSize < Pcir.ImageLength) OptRomSize+=(Pcir.ImageLength*512); + else OptRomSize+=(EfiRomHdr->InitializationSize*512); + } +*/ + trs=(UINT32)OptRomSize; + + if(Pcir.Indicator & 0x80) break; + }//for(;;) + + //Allocate Memory For Opt Rom Image Buffer + Dev->PciIo.RomImage=Malloc(OptRomSize); + if(Dev->PciIo.RomImage==NULL){ + Status=EFI_OUT_OF_RESOURCES; + goto ExitLbl; + } + + //Copy Rom image into memory +// Status=Dev->RbIo->Mem.Read(Dev->RbIo, EfiPciWidthUint8,rombar->Base, +// OptRomSize,Dev->PciIo.RomImage); +// if(EFI_ERROR(Status)) goto ExitLbl; + + MemCpy32(Dev->PciIo.RomImage, (VOID*)(rombar->Base), OptRomSize); + + //We didnot parse OPT ROM buffer yet so RomSize will have temp value + Dev->PciIo.RomSize=OptRomSize; + +ExitLbl: + //Disable decoding option rom again + //Per UEFI 2.1 spec bridges must be open and decoding it's resources. + //ExitStatus=DeviceAttributes(Dev, EFI_PCI_IO_ATTRIBUTE_MEMORY, FALSE); + ExitStatus=DisableDeviceDecoding(Dev,stOptRomSpace); + } //if(Dev->Bar[PCI_MAX_BAR_NO].Type!=tBarUnused) + //We tryed to Find PCI Off Board Card Option ROM because it's ROM BAR was valid. + //But Some On Board Devices Implements ROM BAR but It does not have a valid ROM + //So I will check for embeded Option ROM if Status==EFI_NOT_FOUND and ExitStatus==EFI_SUCCES +#if CSM_SUPPORT + if((Status==EFI_NOT_FOUND)&&(ExitStatus==EFI_SUCCESS)){ + //Here we'll try to locate Embeded rom For Onboard devices. + //we'll use CSM Ext Protocol to do so. + if(gLegacyBiosExt==NULL) Status=EFI_NOT_FOUND; + else { + //Got Protocol. Will try to use it. + Status=gLegacyBiosExt->GetEmbeddedRom(0x20,Dev->DevVenId.VenId, + Dev->DevVenId.DevId,&EmbRom, &OptRomSize); + if(EFI_ERROR(Status)) { + Dev->PciIo.RomImage=NULL; + Dev->PciIo.RomSize=0; + } else { + //Check if Embeded Op ROM is valid... + if(*((UINT16*)EmbRom)!=PCI_OPT_ROM_SIG) Status=EFI_NOT_FOUND; + else{ + //Allocate buffer for ROM Image. + Dev->PciIo.RomImage=Malloc(OptRomSize); + if(Dev->PciIo.RomImage==NULL) Status=EFI_OUT_OF_RESOURCES; + else { + MemCpy(Dev->PciIo.RomImage,EmbRom,OptRomSize); + Dev->PciIo.RomSize=OptRomSize; + Dev->Capab |= (EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE + EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM); + Dev->Attrib |= (EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE + EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM); + } + } + } + } + } +#endif + if(EFI_ERROR(ExitStatus)) return ExitStatus; +//(EIP42750+) + //Calling OEM Hook to override Option Rom content... + Status=PciPortOemGetOptRom(Dev, &Dev->PciIo.RomImage, &Dev->PciIo.RomSize); + //if porting hook not implemented, adjust Status, otherwice return whatever we got + if(Status==EFI_UNSUPPORTED) Status=EFI_SUCCESS; +//(EIP42750-) + return Status; +} + + +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) +EFI_STATUS LoadRomFile( IN EFI_LOAD_FILE2_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL) +{ + PCI_LOAD_FILE_DATA *lfdata=(PCI_LOAD_FILE_DATA*)This; + PCI_DEV_INFO *dev=lfdata->Owner; + EFI_STATUS Status; + UINTN i; + MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *dp=(MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH*)FilePath; + PCI_ROM_IMAGE_DATA *romdata; + BOOLEAN found=FALSE; + VOID *imgb=NULL; + UINT32 imgsz; +//--------------------- + + //Check input parameters first... + if( (dev->Signature != AMI_PCI_SIG) || + (FilePath==NULL) || (BufferSize==NULL) || + (dp->Header.Type!=MEDIA_DEVICE_PATH)|| + (dp->Header.Type!=MEDIA_RELATIVE_OFFSET_RANGE_DP)|| + (dev->EfiRomCount==0) ) return EFI_INVALID_PARAMETER; + + if(BootPolicy==TRUE) return EFI_UNSUPPORTED; + + for(i=0;i<dev->EfiRomCount; i++){ + romdata=dev->EfiRomImages[i]; + //verify that relative odffset corresponds to the images stored. + if(MemCmp(dp,&romdata->RomImageDP,sizeof(MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH))==0){ + found=TRUE; + break; + } + } + + if(!found) return EFI_NOT_FOUND; + + if((romdata->ActualSize<*BufferSize)||(Buffer==NULL)){ + *BufferSize=romdata->ActualSize; + if(Buffer==NULL)return EFI_SUCCESS; + else return EFI_BUFFER_TOO_SMALL; + } + + //here we have checked everything Time to read file ... + Status=ReadEfiRom(dev, romdata,&imgb,&imgsz); + if(EFI_ERROR(Status)) return Status; + + MemCpy(Buffer,imgb,imgsz); + + pBS->FreePool(imgb); + return Status; + +} +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: OvrGetDriver() +// +// Description: PCI Bus Specific Override Protocol Get Override Driver +// function implementation of the PCI Bus Driver. +// +// Input: +// EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL **This Pointer PCI Devicse's +// Bus Specific Override +// Protocol Interface. +// EFI_HANDLE IN OUT *DriverImageHandle Image Handle of the Option +// ROM EFI Driver. +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND When there are no more handles to override. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS OvrGetDriver(IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle ) +{ + PCI_BUS_OVERRIDE_DATA *ovr=(PCI_BUS_OVERRIDE_DATA*)This; + UINTN i; + EFI_HANDLE himg=NULL; + PCI_DEV_INFO *dev=ovr->Owner; + PCI_ROM_IMAGE_DATA *romdata; +//------------------------------------------------------------------ + + if((DriverImageHandle==NULL)||(dev->EfiRomCount==0))return EFI_INVALID_PARAMETER; + + //Here we know dev->EfiRomCount>0 + if(*DriverImageHandle==NULL) { + romdata=dev->EfiRomImages[0]; + himg=romdata->RomImgHandle; + } else { + for(i=0; i<dev->EfiRomCount; i++){ + romdata=dev->EfiRomImages[i]; + if(*DriverImageHandle==romdata->RomImgHandle)break; + } + + if(i==dev->EfiRomCount) return EFI_INVALID_PARAMETER; + + if(i<dev->EfiRomCount-1)himg=romdata->RomImgHandle; + else return EFI_NOT_FOUND; + } + + *DriverImageHandle=himg; + return EFI_SUCCESS; +} + +/* +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AddOvrHandle() +// +// Description: Adds EFI_HANDLE of the Addon Card Option ROM image to the +// PCI Bus Driver Private Data. +// +// Input: +// PCI_BUS_OVERRIDE_DATA *OvrData Pointer to the PCI Devicse's Bus +// Override data inside PCI_DEV_INFO +// EFI_HANDLE OvrHandle Handle to add. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AddOvrHandle( PCI_DEV_INFO *Device, EFI_HANDLE OvrHandle, UINTN StartOffset, UINTN EndOffset) +{ + PCI_ROM_IMAGE_DATA *romdata; +//------------------------------------------------- + if(Device->BusOvrData.BusOverride.GetDriver==NULL)Device->BusOvrData.BusOverride.GetDriver=OvrGetDriver; + + + //Get the space needed + romdata=MallocZ(sizeof(PCI_ROM_IMAGE_DATA)); + if (romdata==NULL) return EFI_OUT_OF_RESOURCES; + + romdata->RomImgHandle=OvrHandle; + romdata->RelOffsStart=StartOffset; + romdata->RelOffsEnd=EndOffset; + + return AppendItemLst((T_ITEM_LIST*)&Device->RomInitCnt, romdata); +} +*/ + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DecompressOptRom() +// +// Description: Decompresses Option ROM Image if it is Compressed. +// +// Input: +// VOID *Image Pointer at the compressed Option ROM Image. +// UINT32 ImageLength Length of the Compressed Image. +// OUT VOID **DecompImage Place holder to return pointer to the +// Decopressed Image. +// OUT UINT32 ImageLength Length of the Decompressed Image. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DecompressOptRom( VOID *Image, UINT32 ImageLength, VOID** DecompImage, UINT32 *DecompSize) +{ + EFI_STATUS Status; + EFI_DECOMPRESS_PROTOCOL *dcp; + UINT32 scrsz, imgsz; + VOID *imgb, *scrb; +//-------------------------------- + //Check for parameter first + if(!DecompImage) return EFI_INVALID_PARAMETER; + + Status = pBS->LocateProtocol(&gEfiDecompressProtocolGuid, NULL,(VOID**)&dcp); + if(EFI_ERROR(Status))return Status; + + Status = dcp->GetInfo(dcp,Image,ImageLength, &imgsz, &scrsz); + if (EFI_ERROR (Status)) return Status; + + Status=pBS->AllocatePool(EfiBootServicesData, imgsz,&imgb); + if(EFI_ERROR(Status)) return Status; + + Status=pBS->AllocatePool(EfiBootServicesData, scrsz,&scrb); + if(EFI_ERROR(Status)) return Status; + + Status=dcp->Decompress(dcp,Image,ImageLength,imgb,imgsz,scrb,scrsz); + pBS->FreePool(scrb); + + if(!EFI_ERROR(Status)){ + *DecompImage=imgb; + *DecompSize=imgsz; + } + + return Status; +} + + +EFI_STATUS ReadEfiRom(PCI_DEV_INFO *Dev, PCI_ROM_IMAGE_DATA *RomData, VOID **ImgBase, UINT32 *ImgSize){ + EFI_STATUS Status=EFI_SUCCESS; + VOID *imgb; + UINT32 imgsz; +//------------------- + + imgb=(VOID*)((UINTN)Dev->PciIo.RomImage+(UINTN)RomData->RomImageDP.StartingOffset); + imgsz=(UINT32)(RomData->RomImageDP.EndingOffset-RomData->RomImageDP.StartingOffset+1); + + if (RomData->RomHeader->CompressionType){ + Status=DecompressOptRom((UINT8*)RomData->RomHeader+RomData->RomHeader->EfiImageOffset,imgsz,&imgb,&imgsz); + } + + if(!(EFI_ERROR(Status))){ + *ImgBase=imgb; + *ImgSize=imgsz; + } + return Status; + +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InstallEfiOpRom() +// +// Description: Loads and Starts Native EFI PCI Option ROM. +// +// Input: +// PCI_DEV_INFO *Dev Pointer PCI Devicse Private Data. +// PCI_EFI_OPT_ROM_HEADER *RomHeader Pointer at PCI Option ROM Header +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InstallEfiOpRom( PCI_DEV_INFO *Dev, + PCI_EFI_OPT_ROM_HEADER *RomHeader, + PCI_DATA_STRUCTURE *Pcir) +{ + EFI_STATUS Status=0; + VOID *imgb; + UINT32 imgsz; + PCI_ROM_IMAGE_DATA *romdata; + EFI_DEVICE_PATH_PROTOCOL *romdp=NULL; + +//------------------------------------------- + + if ((RomHeader->EfiSubsystem != EFI_IMAGE_BS_DRIVER) && + (RomHeader->EfiSubsystem != EFI_IMAGE_RT_DRIVER)) + return EFI_NOT_FOUND; + + // decompress it if needed + if (RomHeader->CompressionType > 1) return EFI_INVALID_PARAMETER; + + //Get the space needed + romdata=MallocZ(sizeof(PCI_ROM_IMAGE_DATA)); + if (romdata==NULL) return EFI_OUT_OF_RESOURCES; + + //Fill RomData Parts + romdata->RomHeader=RomHeader; + //Init RELATIVE OFFS DP Header... + romdata->RomImageDP.Header.Type=MEDIA_DEVICE_PATH; + romdata->RomImageDP.Header.SubType=MEDIA_RELATIVE_OFFSET_RANGE_DP; + SET_NODE_LENGTH(&romdata->RomImageDP.Header, sizeof(MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)); + + //imgsz=RomHeader->InitializationSize*512-RomHeader->EfiImageOffset; + imgsz=(UINT32)DoubleCheckOpRom((VOID*)RomHeader, Pcir); + imgsz-=RomHeader->EfiImageOffset; + + //Get Start..End offsets of Rom File... + imgb=(VOID*)((UINT8*)RomHeader+RomHeader->EfiImageOffset); + romdata->RomImageDP.StartingOffset=(UINT64)((UINTN)imgb-(UINTN)Dev->PciIo.RomImage); + romdata->RomImageDP.EndingOffset=romdata->RomImageDP.StartingOffset+imgsz-1; + + Status=ReadEfiRom(Dev, romdata, &imgb, &imgsz); + if(EFI_ERROR(Status)) return Status; + + //update Actual File size.. + romdata->ActualSize=imgsz; + + //Form Rom Image Device Path from Dev->DevicePath + romdata->RomImgDP+DP_END... + romdp=DPAddNode((VOID*)Dev->DevicePath, (VOID*)&romdata->RomImageDP); + if(romdp==NULL) return EFI_OUT_OF_RESOURCES; + + //load image and start image + Status=pBS->LoadImage(FALSE,gPciBusDriverBinding.ImageHandle,romdp,imgb,imgsz,&romdata->RomImgHandle); + if (EFI_ERROR(Status)) return Status; + + Status=pBS->StartImage(romdata->RomImgHandle,NULL,NULL); + if (EFI_ERROR(Status)) return Status; + + //Add romdata to the EfiRomList... + Status=AppendItemLst((T_ITEM_LIST*)&Dev->RomInitCnt, romdata); + if(EFI_ERROR(Status)) return Status; + + //update BusOvr Data... + if(Dev->BusOvrData.BusOverride.GetDriver==NULL)Dev->BusOvrData.BusOverride.GetDriver=OvrGetDriver; + +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + //Update LoadFile Data + if(Dev->LoadFileData.LoadFile2.LoadFile==NULL)Dev->LoadFileData.LoadFile2.LoadFile=LoadRomFile; +#endif + + if(romdp!=NULL)pBS->FreePool(romdp); + return Status; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CheckPciRomDevId() +// +// Description: PCI Firmware Spec 3.0 defines some reserved field in PCIR +// Structure as Device List Pointer. This function checks additional Device IDs +// +// Input: +// PCI_DEV_INFO *Dev Pointer PCI Devicse Private Data. +// PCI_DATA_STRUCTURE *PciRomStruct Pointer at PCIR ROM Header +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_UNSUPPORTED When ROM is not compatible with device. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CheckPciRomDevId(PCI_DEV_INFO *Dev, PCI_DATA_STRUCTURE *PciRomStruct){ + UINT16 *did; +//-------------------------- + if(Dev->DevVenId.VenId != PciRomStruct->VendorId) return EFI_NOT_FOUND; + + if(Dev->DevVenId.DevId != PciRomStruct->DeviceId){ + //Dev->DevVenId.DevId ==0x0000 special case - (Service ROM like PXE, iSCIS boot agent) + if(Dev->DevVenId.DevId==0) return EFI_SUCCESS; + + //Check Device List if any... + if(PciRomStruct->Reserved0 == 0) return EFI_UNSUPPORTED; + + did=(UINT16*)((UINT8*)PciRomStruct + PciRomStruct->Reserved0); + + while(*did != 0){ + if(Dev->DevVenId.DevId==*did) return EFI_SUCCESS; + did++; // next device list entry + } + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ExecuteUefiRom() +// +// Description: This function decide to launch or not UEFI compatible +// Option ROM +// +// Input: +// UINT8 PciClass PCI Class Code Of the Device. +// +// Output: BOOLEAN +// TRUE Launch UEFI Option ROM +// FALSE NOT Launch UEFI Option ROM +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN ExecuteUefiRom(PCI_DEV_INFO *Dev) +{ + EFI_STATUS Status; + AMI_OPROM_POLICY_PROTOCOL *AmiOpromPolicyProtocol; + static EFI_GUID AmiOpromPolicyProtocolGuid = AMI_OPROM_POLICY_PROTOCOL_GUID; + + Status = pBS->LocateProtocol(&AmiOpromPolicyProtocolGuid, NULL, &AmiOpromPolicyProtocol); + if(EFI_ERROR(Status)) //if CSM OptOut is disabled we should always launch UEFI OpROM + return TRUE; + + Status = AmiOpromPolicyProtocol->CheckUefiOpromPolicy(AmiOpromPolicyProtocol, Dev->Handle); + return (EFI_ERROR(Status)) ? FALSE : TRUE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ActivateOptRom() +// +// Description: This function parses Option ROM Image to decide which +// Image to give control to and updates PciIO->OptioRom and +// PciIO->OptioRomSize with Correct values. +// +// Input: +// PCI_DEV_INFO *Dev Pointer PCI Devicse Private Data. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_NOT_FOUND When Device does not have any ROMs. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ActivateOptRom(PCI_DEV_INFO *Dev) +{ + UINT8 *cp; + UINTN roms=0; + UINTN romc; + PCI_EFI_OPT_ROM_HEADER *rh; + PCI_DATA_STRUCTURE *pcir; + BOOLEAN ff=TRUE;//, fnd=FALSE; + BOOLEAN efior=FALSE; + BOOLEAN notarom=FALSE; + UINTN sz=0; + INT64 rsz=(INT64)Dev->PciIo.RomSize; + EFI_STATUS Status=EFI_SUCCESS; + BOOLEAN RomMatch=FALSE; +//------------------------ + if (!Dev->PciIo.RomImage) return EFI_NOT_FOUND; + + cp=(UINT8*)Dev->PciIo.RomImage; + for(romc=0;;romc++){ + rsz-=sz; + if(rsz<=0)return Status; + cp=cp+sz; + + rh=(PCI_EFI_OPT_ROM_HEADER*)cp; + //Check if a valid signarture here + if(ff){//first time here + if(rh->Signature!=PCI_OPT_ROM_SIG){ + notarom=TRUE; + break; + } + roms=(UINTN)rh; + } else { + //here is the case when we can not find a valid signature for the next image + //withing the Option ROM + if(rh->Signature!=PCI_OPT_ROM_SIG){ + sz=512; + continue; + } + } + ff=FALSE; + + //Check if it is EFI Opt ROM + if(rh->EfiSignature==PCI_OPT_ROM_EFISIG) efior=TRUE; + else efior=FALSE; + + //we got what we were looking for... + pcir=(PCI_DATA_STRUCTURE*)(cp+rh->PcirOffset); + if(pcir->Signature!=PCI_PCIR_SIG) continue; + + //Here is some more conditions to check. + //some ROMs has Different Sizes filled in 0x55AA ROM Header and in PCIR structure. + //So check which size is right by looking one + + //PCI Firmware Spec 3.0 defines some reserved field in PCIR Structure as Device List Pointer + Status=CheckPciRomDevId(Dev, pcir); + if(EFI_ERROR(Status)) { + if(Status==EFI_NOT_FOUND){ + PCI_TRACE((TRACE_PCI," ROM Img #%d Dev.VID!=PCIR.VID ", romc)); + } else PCI_TRACE((TRACE_PCI," ROM Img #%d Dev.DID!=PCIR.DID ", romc)); + } else RomMatch=TRUE; + + //Check Setup option which Option ROM to post Legacy = 0 \[EFI Compatible = 1] + if( ExecuteUefiRom(Dev) ) { + //here we go...let's see what it is + //check conditions under which we must process EFI OptROM + if( efior && pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE && RomMatch) + { + PCI_TRACE((TRACE_PCI,"(Install EFI ROM=")); + Status=InstallEfiOpRom(Dev,rh, pcir); + PCI_TRACE((TRACE_PCI,"%r)", Status)); + } + } + + if(pcir->Indicator&0x80) { + break; + } + //else keep circling until we reach the end... + sz=DoubleCheckOpRom((VOID*)rh, pcir); + } + + if(notarom || !RomMatch){ + Status=pBS->FreePool(Dev->PciIo.RomImage); + Dev->PciIo.RomImage=NULL; + Dev->PciIo.RomSize=0; + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InstallPciDevice() +// +// Description: This function performs the following operations +// 1. Register Device with CORE by getting a brand new handle +// 2. Install PciIo Protocol Interface on This Device +// 3. Generates EFI_DEVICE_PPATH protocol instance for "Dev"ice +// 4. Installs DevicePath Protocol on Created Handle +// 5. If Device has Option ROM copy it to the Memory Buffer +// 6. If 5 is TRUE and if Opt ROM has EFI compliant Image +// installs Bus Override protocol. +// +// Input: +// EFI_HANDLE ControllerHandle Device's Controller Handle. +// PCI_DEV_INFO *Dev Pointer PCI Devicse Private Data. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS InstallPciDevice(EFI_HANDLE ControllerHandle, PCI_DEV_INFO *Dev) +{ + EFI_STATUS Status=0; + EFI_STATUS OpRomStatus = EFI_NOT_FOUND; + BOOLEAN ndp=FALSE;//NewDevicePath +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + VOID *buff[8]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +#else + VOID *buff[6]={NULL,NULL,NULL,NULL,NULL,NULL}; +#endif + UINTN offs=0; + BOOLEAN cr=TRUE; +//----------------------------------- + + PCI_TRACE((TRACE_PCI,"PciBus: Installing PCI IO for B%X|D%X|F%X; ->->->->\n", Dev->Address.Addr.Bus, + Dev->Address.Addr.Device,Dev->Address.Addr.Function)); + + //Check if Device Has Been already started + if(Dev->Started) { + Status=EFI_ALREADY_STARTED; + PCI_TRACE((TRACE_PCI," -> Dev.Started=1; -> %r\n",Status)); + return Status; + } + + if(Dev->Type==tPciRootBrg) ndp=FALSE; + else ndp=TRUE; + + if(Dev->PciIo.PollMem!=gPciIoInstance.PollMem){ + pBS->CopyMem(&Dev->PciIo, &gPciIoInstance, sizeof(EFI_PCI_IO_PROTOCOL)); + } else cr=FALSE; + buff[offs]=&gPciIoProtocolGuid; + buff[offs+1]=&Dev->PciIo; + offs+=2; + + //Install Device Path Protocol on newly created Handle + if(ndp){ + buff[offs]=&gDevicePathProtocolGuid; + buff[offs+1]=Dev->DevicePath; + offs+=2; + } + //Check if Device has Opton ROM ... + if(cr) + OpRomStatus=GetOptRom(Dev); + else if(Dev->PciIo.RomImage != NULL && Dev->PciIo.RomSize != 0) //OpROM was initialized earlier + OpRomStatus = EFI_SUCCESS; + + Status=pBS->InstallMultipleProtocolInterfaces( + &Dev->Handle, + buff[0],buff[1], //PciIO GUID - I/F pare + buff[2],buff[3], //DevPath GUID - I/F pare + NULL, NULL ); + PCI_TRACE((TRACE_PCI,"/nPciBus: Installing DP; PCIO Status=%r",Status)); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + //update offset it might be ==2 if ndp==FALSE, but we need it as 4 after this point. + offs=4; + + PCI_TRACE((TRACE_PCI,":GetRom=")); + + if(EFI_ERROR(OpRomStatus)){ + Dev->RomBarError=TRUE; + Dev->PciIo.RomImage=NULL; + Dev->PciIo.RomSize=0; + PCI_TRACE((TRACE_PCI,"%r\n", OpRomStatus)); + } else { + //Print Status from GetOptRom() + PCI_TRACE((TRACE_PCI,"%r :ActivateRom", OpRomStatus)); + if(cr) Status=ActivateOptRom(Dev); + PCI_TRACE((TRACE_PCI,"=%r\n", Status)); + if(EFI_ERROR(Status)){ + if(Status==EFI_NOT_FOUND) Status=EFI_SUCCESS; //just there are no any EFI Opt ROMs + else return Status; + } + + //Check if Override handle count gets changed.. + //then install Bus Override protocol interface + if(Dev->BusOvrData.BusOverride.GetDriver!=NULL){ + buff[offs]=&gBusSpecificDriverOverrideProtocolGuid; + buff[offs+1]=&Dev->BusOvrData.BusOverride; + } + +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + offs+=2; + if(Dev->LoadFileData.LoadFile2.LoadFile!=NULL){ + buff[offs]=&gEfiLoadFile2ProtocolGuid; + buff[offs+1]=&Dev->LoadFileData.LoadFile2; + } +#endif + + } + + + //Now Before installing Protocol Interface for THIS device. + //Call Porting Hook to do OEM Custom Programming of the device. + //PciIo and all the stuff been updated for this device. + //But NO notification yet for PciIO installation dispatchetd + Status=PciPortOemProgDevice(Dev); + + PCI_TRACE((TRACE_PCI,":PciBus: Calling PciPortOemProgDevice() >Status=%r\n", Status)); + + if(buff[5]!=NULL){ + Status=pBS->InstallMultipleProtocolInterfaces( + &Dev->Handle, + buff[4],buff[5], //PciIO GUID - I/F pare +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + buff[6],buff[7], //LoadFile2 GUID - I/F pare if present +#endif + NULL, NULL ); + + PCI_TRACE((TRACE_PCI," -> Installing BusOvr and LoadFile2 -> %r\n", Status)); + + if(EFI_ERROR(Status)) return Status; + } + + if(Dev->Type>tPciRootBrg){//Don't Open Rb Protocol for itself + Status=pBS->OpenProtocol( + ControllerHandle, &gPciRootBridgeIoProtocolGuid, + (VOID**)&Dev->RbIo, gPciBusDriverBinding.DriverBindingHandle, + Dev->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); + } + + //Set Started Flag... + Dev->Started=TRUE; + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: StartPciChildDevice() +// +// Description: Starts PCI Devices Behind the Bridge. (Called recoursively) +// This function performs the following operations +// 1. Register Device with CORE by getting a brand new handle +// 2. Install PciIo Protocol Interface on This Device +// 3. Generates EFI_DEVICE_PPATH protocol instance for "Dev"ice +// 4. Installs DevicePath Protocol on Created Handle +// 5. If Device has Option ROM copy it to the Memory Buffer +// 6. If 5 is TRUE and if Opt ROM has EFI compliant Image +// installs Bus Override protocol. +// +// Input: +// EFI_HANDLE ControllerHandle Device's Controller Handle. +// PCI_BRG_INFO *Brg Pointer at PCI Bridge Private Data. +// EFI_DEVICE_PATH_PROTOCOL *RemainingDp Pointer at PCI Device Path +// Protocol Instance or NULL. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS StartPciChildDevice(EFI_HANDLE ControllerHandle,PCI_BRG_INFO *Brg, PCI_DEVICE_PATH *RemainingDp) +{ + PCI_DEV_INFO *dev; + EFI_STATUS Status = EFI_NOT_FOUND; + UINTN i; + PCI_DEVICE_PATH *pcidp=RemainingDp; + BOOLEAN Started=FALSE, Success=FALSE; +//------------------------------- + + PCI_TRACE((TRACE_PCI, "PciBus: StartPciChildDevice -> Bridge has %d Child Devices \n",Brg->Bridge.ChildCount)); + + //Check if Device Path is a valid PCI Device Path + if (pcidp!=NULL){ + //Check if remaining device path is a valid PCI device path + if( EFI_ERROR(CheckPciDevicePath(&pcidp->Header)) ) return EFI_INVALID_PARAMETER; + //If remaining device path is provided, we must find the device. + } + + if(!Brg->Bridge.ChildCount) return Status; + + for(i=0; i<Brg->Bridge.ChildCount; i++){ + dev=Brg->Bridge.ChildList[i]; + if(dev->OutOfResRemove) continue; + //if Remaining Device Path provided start only specified device + if(pcidp) + { + if(pcidp->Device != dev->Address.Addr.Device || + pcidp->Function != dev->Address.Addr.Function + ) continue; + // The Device Path of this Device matches provided + Status=InstallPciDevice(ControllerHandle, dev); + if (EFI_ERROR(Status)){ + if(Status==EFI_ALREADY_STARTED) Started=TRUE; + else return Status; + } else Success=TRUE; + + //if Device is P2P bridge than BDS might like to start next DP node + //So recousively call this function to find desired Device + pcidp++; + if(dev->Type==tPci2PciBrg && !isEndNode(&pcidp->Header)) + Status=StartPciChildDevice(ControllerHandle,(PCI_BRG_INFO*)dev,pcidp); + + + //if(!EFI_ERROR(Status) && Status == EFI_NOT_FOUND){ + // if(Started && !Success) Status=EFI_ALREADY_STARTED; + //} + return Status; + } + else //if no Remaining Device Path provided start all devices + { + Status=InstallPciDevice(ControllerHandle, dev); + if (EFI_ERROR(Status)){ + if(Status==EFI_ALREADY_STARTED){ + Started=TRUE; + Status=EFI_SUCCESS; + } else return Status; + } else Success=TRUE; + + //if Device is P2P bridge recousively call this function + if(dev->Type==tPci2PciBrg){ + Status=StartPciChildDevice(ControllerHandle,(PCI_BRG_INFO*)dev,pcidp); + if(EFI_ERROR(Status)){ + //StartPciChildDevice() could return EFI_ALREADY_STARTED or EFI_NOT_FOUND + //this is if we have started this device already, of Bridge don't have any + //childs behind it. This is normal and we shouldn't break the loop. + //All other ERROR Statuses suppose to break the loop and raise an ERROR. + if(Status==EFI_ALREADY_STARTED || Status==EFI_NOT_FOUND){ + Started=TRUE; + Status=EFI_SUCCESS; + } else return Status; + } else Success=TRUE; + } + } + }//for + + if(!EFI_ERROR(Status)){ + if(Started && !Success) Status=EFI_ALREADY_STARTED; + } + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: StartPciDevices() +// +// Description: Installs PCI Io Protocol Instance on all or some PCI Devices +// in the System +// +// Input: +// EFI_HANDLE ControllerHandle Device's Controller Handle. +// EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath Pointer at PCI Device Path +// Protocol Instance or NULL. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS StartPciDevices(IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINTN i, j; + PCI_DEV_INFO *rbrg; + PCI_HOST_INFO *lhst; //local host + EFI_DEVICE_PATH_PROTOCOL *rdp=RemainingDevicePath; +//--------------------------------------------- + PCI_TRACE((TRACE_PCI, "\n====================================================================\n")); + PCI_TRACE((TRACE_PCI, "PciBus: StartPciDevices Called -> hCtrl=0x%X; RemainingDp=0x%X;\n",ControllerHandle,RemainingDevicePath)); + + //Check if RemainingDevicePath is valid + if(rdp!=NULL){ + + if (isEndNode(rdp)) { + PCI_TRACE((TRACE_PCI, "PciBus: RemainingDp==EndOfDpNode\n")); + return EFI_SUCCESS; + } else { + Status=CheckPciDevicePath(rdp); + PCI_TRACE((TRACE_PCI, "PciBus: START CheckPciDp -> %r\n",Status)); + if(EFI_ERROR(Status)) goto ExitLbl; + } + } + + //find Root Bridge first + for(j=0; j<gHostCnt; j++){ + lhst=&gPciHost[j]; + for(i=0; i<lhst->RbCount; i++){ + rbrg=lhst->RootBridges[i]; + + if(rbrg->Handle==ControllerHandle){ + + Status=pBS->OpenProtocol(rbrg->Handle, + &gPciRootBridgeIoProtocolGuid,(VOID **)&rbrg->RbIo, + gPciBusDriverBinding.DriverBindingHandle,rbrg->Handle, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + if(EFI_ERROR(Status)){ + if( Status!=EFI_ALREADY_STARTED ) return Status; + else Status=EFI_SUCCESS; + } + + Status=StartPciChildDevice(ControllerHandle,(PCI_BRG_INFO*)rbrg,(PCI_DEVICE_PATH*)rdp); + break; + } + } + } +ExitLbl: + + PCI_TRACE((TRACE_PCI, "PciBus: StartPciChildDevice -> %r\n",Status)); + PCI_TRACE((TRACE_PCI, "====================================================================\n")); + + return Status; +} + +EFI_STATUS LocateDevHandle(PCI_DEV_INFO *Dev, T_ITEM_LIST *PciHnd){ + UINTN i; + EFI_HANDLE h; +//------------------------ + for(i=0; i<PciHnd->ItemCount; i++){ + h=*(EFI_HANDLE*)(PciHnd->Items[i]); + if(Dev->Handle==h){ + DeleteItemLst(PciHnd, i, FALSE); + Dev->Handle=NULL; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: StopPciDevice() +// +// Description: Stops PCI Device referenced as "Dev". Called From +// StopPciDeviceBrg() function. +// +// Input: +// PCI_DEV_INFO *Dev Pointer PCI Devicse Private Data. +// EFI_HANDLE Controller Device's Controller Handle. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS StopPciDevice(PCI_DEV_INFO *Dev,EFI_HANDLE Controller, T_ITEM_LIST *HndDb) +{ + EFI_STATUS Status=EFI_SUCCESS; + UINTN offs=0; + BOOLEAN ndp; +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + VOID *buff[8]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +#else + VOID *buff[6]={NULL,NULL,NULL,NULL,NULL,NULL}; +#endif +//-------------------------------------------------------------------- + + //Check if Device Has been Stopped already... + if(Dev->Started==FALSE) return EFI_SUCCESS; + + if(Dev->Type==tPciRootBrg) { + Dev->Started=FALSE; + return EFI_SUCCESS; + } + + PCI_TRACE((TRACE_PCI,"\nPciBusStop: Hnd=%X [B%X|D%X|F%X]->",Dev->Handle, + Dev->Address.Addr.Bus,Dev->Address.Addr.Device, Dev->Address.Addr.Function)); + //Close Root Brg Protocol we've opened at the beginning. + //Avoid Closing Protocol for RootBridge Device - we didn't open it. + if(Dev->Handle!=Controller){ + Status=pBS->CloseProtocol(Controller,&gPciRootBridgeIoProtocolGuid, + gPciBusDriverBinding.DriverBindingHandle, Dev->Handle); + ndp=TRUE; + PCI_TRACE((TRACE_PCI,"Close(RbIo)=%r;\n",Status)); + } else { + ndp=FALSE; + } + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + + buff[offs]=&gPciIoProtocolGuid; + buff[offs+1]=&Dev->PciIo; + offs+=2; + + //Same for Device Path: we did'not create device path for RootBridge device + if(ndp){ + buff[offs]=&gDevicePathProtocolGuid; + buff[offs+1]=Dev->DevicePath; + offs+=2; + } + + //Now take care of BusSpecific Override Protocol + //If it was installed + if(Dev->BusOvrData.BusOverride.GetDriver!=NULL){ + buff[offs]=&gBusSpecificDriverOverrideProtocolGuid; + buff[offs+1]=&Dev->BusOvrData.BusOverride; + } + +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + //LoadFile2 Protocol + offs+=2; + if(Dev->LoadFileData.LoadFile2.LoadFile!=NULL){ + buff[offs]=&gEfiLoadFile2ProtocolGuid; + buff[offs+1]=&Dev->LoadFileData.LoadFile2; + } +#endif + Status=pBS->UninstallMultipleProtocolInterfaces( + Dev->Handle, + buff[0],buff[1], //PciIO GUID - I/F pare + buff[2],buff[3], //DevPath GUID - I/F pare + buff[4],buff[5], //BusOwerride GUID - I/F pare if present +#if ((defined EFI_SPECIFICATION_VERSION) && (EFI_SPECIFICATION_VERSION >= 0x2001F)) + buff[6],buff[7], //LoadFile2 GUID - I/F pare if present +#endif + NULL, NULL ); + + PCI_TRACE((TRACE_PCI,"\nPciBusStop: Hnd=%X [B%X|D%X|F%X]->",Dev->Handle, + Dev->Address.Addr.Bus,Dev->Address.Addr.Device, Dev->Address.Addr.Function)); + PCI_TRACE((TRACE_PCI,"Uninst(PciIo,DP,BusOvr)=%r;\n",Status)); +//DEBUG???? + if(!EFI_ERROR(Status)){ +//DEBUG???? + Dev->Started=FALSE; + if(HndDb!=NULL) Status=LocateDevHandle(Dev, HndDb); + Dev->Handle=NULL; +//DEBUG???? + } +//DEBUG???? + ASSERT_EFI_ERROR(Status); + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: StopPciDeviceBrg() +// +// Description: Stops - Uninstalls PCI Io Protocol Instance from PCI Devices +// behind the PCI Bridge referenced as "Brg" +// +// Input: +// PCI_BRG_INFO *Brg Pointer PCI Devicse Private Data. +// EFI_HANDLE Controller Device's Controller (Parent) Handle. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_OUT_OF_RESOURCES When system runs out of resources. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS StopPciDeviceBrg(PCI_BRG_INFO *Brg, EFI_HANDLE Controller, T_ITEM_LIST *HndDb) +{ + PCI_DEV_INFO *dev; + UINTN i; + EFI_STATUS Status; +//-------------------------------------------------------------------- + for(i=0; i<Brg->Bridge.ChildCount; i++){ + dev=Brg->Bridge.ChildList[i]; + //recoursive calling ourselfs + if(dev->Type==tPci2PciBrg) Status=StopPciDeviceBrg((PCI_BRG_INFO*)dev,Controller, HndDb); + else Status=StopPciDevice(dev, Controller, HndDb); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) return Status; + } + //After we done with the childs - Stop this Bridge itself + Status=StopPciDevice(&Brg->Common, Controller, HndDb); + ASSERT_EFI_ERROR(Status); + + return Status; +} + + +//============================================================================== +// +// EFI Drver Binding Protocol Functions +// +//============================================================================== + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciBusSupported() +// +// Description: Supported Function of the EFI_DRIVER_BINDING_PROTOCOL +// for PCI Bus Driver. +// +// Notes: +// See EFI Specification for detail description +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciBusSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_DEVICE_PATH_PROTOCOL *rdp=RemainingDevicePath; +//----------------------------------------------- + + + //Check if it is valid Device Path + if (rdp != NULL){ + if (isEndNode(rdp)) rdp=NULL; + else { + Status=CheckPciDevicePath(rdp); + if (EFI_ERROR (Status)) return Status; + } + } + + //Open the IO Abstraction(s) needed to perform the supported test + Status=pBS->OpenProtocol(Controller, + &gDevicePathProtocolGuid, + (VOID **)&ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + if (Status == EFI_ALREADY_STARTED)return EFI_SUCCESS; + if (EFI_ERROR (Status)) return Status; + + pBS->CloseProtocol(Controller,&gDevicePathProtocolGuid,This->DriverBindingHandle, + Controller); + + Status=pBS->OpenProtocol( Controller, + &gPciRootBridgeIoProtocolGuid, + (VOID **)&PciRootBridgeIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + if(Status==EFI_ALREADY_STARTED) return EFI_SUCCESS; + + pBS->CloseProtocol(Controller,&gPciRootBridgeIoProtocolGuid,This->DriverBindingHandle, + Controller); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciBusStart() +// +// Description: Start Function of the EFI_DRIVER_BINDING_PROTOCOL +// for PCI Bus Driver +// +// Notes: +// See EFI Specification for detail description +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciBusStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) +{ + EFI_STATUS Status; + BOOLEAN ft=FALSE; +//------------------------------------------------ + PROGRESS_CODE(DXE_PCI_BUS_BEGIN); + + PCI_TRACE((TRACE_PCI,"\n")); + + //Locate Boot Script protocol we will need it to record Extd PCIExpress Config Space Programing + if(gBootScriptSave==NULL){ + Status = pBS->LocateProtocol(&gEfiBootScriptSaveGuid, NULL, &gBootScriptSave); + if(EFI_ERROR(Status)) { + PCI_TRACE((TRACE_PCI,"PciBus: Unable to find EfiBootScriptSave Protocol! Status=%r EXITING!\n", Status)); + return EFI_DEVICE_ERROR; + } + } + +#if CSM_SUPPORT + //Locate Legacy BIOS Extended protocol, we will need it to record Extd PCIExpress Config Space Programing + if(gLegacyBiosExt==NULL){ + Status = pBS->LocateProtocol(&gEfiLegacyBiosExtProtocolGuid, NULL, &gLegacyBiosExt); + if(EFI_ERROR(Status)) { + PCI_TRACE((TRACE_PCI,"PciBus: Unable to find Legacy Bios Extension Protocol! Status=%r\n", Status)); + gLegacyBiosExt=NULL; + } + } +#endif + + //Locate Ami Board Info Protocol + if(gAmiBoardInfo==NULL){ + Status = pBS->LocateProtocol(&gAmiBoardInfoProtocolGuid, NULL, &gAmiBoardInfo); + if(EFI_ERROR(Status)) { + PCI_TRACE((TRACE_PCI,"PciBus: Unable to find AMI Board Info Protocol! Status=%r\n", Status)); + return Status; + } + ft=TRUE; + } + + //Create Pci Setup Data Buffer; + if(gPciSetupData==NULL){ + gPciSetupData=MallocZ(sizeof(PCI_SETUP_DATA)); + if (gPciSetupData==NULL) return EFI_OUT_OF_RESOURCES; + //Call Board Specific function from PciPort.c to fill PCI Setup data buffer + BrdGetPciSetupData(gPciSetupData); + } + + // Enumerate the entire host bridge + Status = EnumerateAll(Controller); + if(ft){ +#if EFI_DEBUG + //Print Bus Xlat table + UINTN i; + PCI_IRQ_PIC_ROUTE *ir; + PCI_IRQ_APIC_ROUTE *ar; + //----------- + PCI_TRACE((TRACE_PCI,"PciBus: Printing PIC $PIR table, %d entries \n", gAmiBoardInfo->PicRoutLength/sizeof(PCI_IRQ_PIC_ROUTE) )); + PCI_TRACE((TRACE_PCI,"============================================================\n")); + PCI_TRACE((TRACE_PCI," # Bus D|F PIRQ A PIRQ B PIRQ C PIRQ D Slt#\n")); + PCI_TRACE((TRACE_PCI,"------------------------------------------------------------\n")); + for(i=0; i<(gAmiBoardInfo->PicRoutLength/sizeof(PCI_IRQ_PIC_ROUTE));i++){ + ir=&gAmiBoardInfo->PicRoutTable[i]; + PCI_TRACE((TRACE_PCI,"%02d %02X %02X|%X %02X->%04X %02X->%04X %02X->%04X %02X->%04X %02X\n", i, + ir->PciBusNumber, ir->DevFun.Dev,ir->DevFun.Fun, + ir->PciIrq[0].ChipsetReg, ir->PciIrq[0].IrqMask, + ir->PciIrq[1].ChipsetReg, ir->PciIrq[1].IrqMask, + ir->PciIrq[2].ChipsetReg, ir->PciIrq[2].IrqMask, + ir->PciIrq[3].ChipsetReg, ir->PciIrq[3].IrqMask, + ir->SlotNum)); + } + PCI_TRACE((TRACE_PCI,"============================================================\n")); + PCI_TRACE((TRACE_PCI,"\nPciBus: Printing APIC table, %d entries \n", gAmiBoardInfo->ApicRoutLength/sizeof(PCI_IRQ_APIC_ROUTE) )); + PCI_TRACE((TRACE_PCI,"============================================================\n")); + PCI_TRACE((TRACE_PCI," # Bus Dev PIRQ A PIRQ B PIRQ C PIRQ D\n")); + PCI_TRACE((TRACE_PCI,"------------------------------------------------------------\n")); + for(i=0; i<(gAmiBoardInfo->ApicRoutLength/sizeof(PCI_IRQ_APIC_ROUTE));i++){ + ar=&gAmiBoardInfo->ApicRoutTable[i]; + PCI_TRACE((TRACE_PCI,"%02d %02X %02X %02X ID=%02X %02X ID=%02X %02X ID=%02X %02X ID=%02X\n", i, + ar->PciBusNumber, ar->DeviceNumber, + ar->Intn[0].IoApicItin, ar->Intn[0].IoApicId, + ar->Intn[1].IoApicItin, ar->Intn[1].IoApicId, + ar->Intn[2].IoApicItin, ar->Intn[2].IoApicId, + ar->Intn[3].IoApicItin, ar->Intn[3].IoApicId)); + } + PCI_TRACE((TRACE_PCI,"============================================================\n")); + +#endif + RemoveUnusedIrqEntries(); + gAmiBoardInfo->DataValid=TRUE; + } + + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) return Status; + + //If Enumeration is OK install Extended PCI BUS Protocol Interface NOW. + //Only if we have not done it before. It is only single instance on PciBusExt possible. + if(gAmiExtPciBusProtocol.PciExtHanle==NULL){ + Status=pBS->InstallMultipleProtocolInterfaces( &gAmiExtPciBusProtocol.PciExtHanle, + &gAmiExtPciBusProtocolGuid, &gAmiExtPciBusProtocol, NULL); + } + + if (EFI_ERROR (Status)){ + PCI_TRACE((TRACE_PCI,"PciBus: Unable to INSTALL Extended PCI Bus Protocol! Status=%r\n", Status)); + } + ASSERT_EFI_ERROR(Status); + + // Enable PCI device specified by remaining device path. BDS or other driver can call the + // start more than once. + Status=StartPciDevices (Controller, RemainingDevicePath); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciBusStop() +// +// Description: Stop Function of the EFI_DRIVER_BINDING_PROTOCOL +// for PCI Bus Driver. +// +// Notes: +// See EFI Specification for detail description +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciBusStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer) +{ + EFI_STATUS Status=0; + PCI_DEV_INFO *dev=NULL; + UINTN i; + T_ITEM_LIST PciHndDb={0,0,NULL}; + EFI_HANDLE hnd; +//------------------------------------------------ + PCI_TRACE((TRACE_PCI,"\nPciBusStop: NumberOfChildren=0x%X, Controller=0x%X\n",NumberOfChildren, Controller)); + + if (NumberOfChildren == 0) { + // Close the bus driver + //mST->BootServices->CloseProtocol(Controller,&gDevicePathProtocolGuid, + // This->DriverBindingHandle, Controller); + dev=FindPciDeviceByHandle(Controller); + if(dev) Status=StopPciDeviceBrg((PCI_BRG_INFO*)dev, Controller, NULL); + else Status=EFI_NOT_FOUND; + ASSERT_EFI_ERROR(Status); + //Close PCI Rooty Bridge Protocol we opened BY_DRIVER + pBS->CloseProtocol(Controller,&gPciRootBridgeIoProtocolGuid, + This->DriverBindingHandle,Controller); + } else { + //Populate PciHandle Database we need to stop. If we will enter recoursive + //call we need to rtemove stopped handles from DB inside recoursive call + //to avoid getting EFI_INVALID_PARAMETER trying to Stop already stopped devices. + for(i=0; i<NumberOfChildren; i++){ + AppendItemLst(&PciHndDb, &ChildHandleBuffer[i]); + PCI_TRACE((TRACE_PCI,"Hnd #%X: %X \n", i, ChildHandleBuffer[i])); + } + + //Stopping all the childs + while(PciHndDb.ItemCount){ + hnd=*(EFI_HANDLE*)(PciHndDb.Items[0]); + dev=FindPciDeviceByHandle(hnd); + if(dev){ + //If device a bridge stop all its childs first + if(dev->Type==tPci2PciBrg)Status=StopPciDeviceBrg((PCI_BRG_INFO*)dev,Controller, &PciHndDb); + else Status=StopPciDevice(dev,Controller,&PciHndDb); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status))return Status; + } else { + Status=EFI_NOT_FOUND; + break; + } + ASSERT_EFI_ERROR(Status); + }//while... + } + + if(gAmiExtPciBusProtocol.PciExtHanle!=NULL){ + Status=pBS->UninstallMultipleProtocolInterfaces( gAmiExtPciBusProtocol.PciExtHanle, + &gAmiExtPciBusProtocolGuid, &gAmiExtPciBusProtocol, NULL); + if (!EFI_ERROR(Status)) { + gAmiExtPciBusProtocol.PciExtHanle=NULL; + } + } + + //Cleanup used memory... + ClearItemLst(&PciHndDb, FALSE); + return Status; +} + + +////////////////////////////////////////////////////////////////////////////// +//---------------------------------------------------------------------------- +// PCI BUS Extended Protocol Function Implementation + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtGetDevice() +// +// Description: Locates PCI_DEV_INFO using passed PCI Device Handle or PciIo +// Protocol pointer. +// Input: +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// +// Output: +// PCI_DEV_INFO* When everything is going on fine! +// NULL If no such device exists. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +PCI_DEV_INFO* PciExtGetDevice(EFI_HANDLE PciDeviceHandle, EFI_PCI_IO_PROTOCOL *PciIo){ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + if(PciDeviceHandle == NULL){ + if(PciIo!=NULL){ + dev=(PCI_DEV_INFO*)PciIo; + if(dev->Signature != AMI_PCI_SIG) return NULL; + } else return NULL; + } else dev=FindPciDeviceByHandle(PciDeviceHandle); + + return dev; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtIsPciExpresss() +// +// Description: Checks if PciDeviceHandle, or PciIO passed belongs to +// PCI Express device. +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCIE_DATA** PciExpData Double Pointer to the PCIE_DATA Structure (OPTIONAL) +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If Device is not PCI Express device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +// **PciExpData if not needed must be NULL; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtIsPciExpresss( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCIE_DATA **PciExpData OPTIONAL +) +{ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev) { + if(dev->PciExpress != NULL){ + //if we have to update pointer + if(PciExpData != NULL){ + *PciExpData = dev->PciExpress; + } + return EFI_SUCCESS; + } else return EFI_NOT_FOUND; + } else return EFI_INVALID_PARAMETER; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtIsPciX() +// +// Description: Checks if PciDeviceHandle, or PciIO passed belongs to +// PCI Express device. +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCIX_DATA** PciXData Double Pointer to the PCIX_DATA Structure (OPTIONAL) +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If Device is not PCI X device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +// **PciXData if not needed must be NULL; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtIsPciX( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCIX_DATA **PciXData OPTIONAL +) +{ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev) { + if(dev->PciX != NULL){ + //if we have to update pointer + if(PciXData != NULL){ + *PciXData = dev->PciX; + } + return EFI_SUCCESS; + } else return EFI_NOT_FOUND; + } else return EFI_INVALID_PARAMETER; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtIsPciBrg() +// +// Description: Checks if PciDeviceHandle, or PciIO passed belongs to +// PCI 2 PCI Bridge device. +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCI_BRG_EXT** PciBrgExt Double Pointer to the PCI_BRG_EXT Structure (OPTIONAL) +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If Device is not PCI 2 PCI Bridge device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +// **PciBrgExt if not needed must be NULL; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtIsPciBrg( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_BRG_EXT **BrgData OPTIONAL +) +{ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev) { + if(dev->Type == tPci2PciBrg){ + //if we have to update pointer + if(BrgData != NULL){ + *BrgData = (PCI_BRG_EXT*)(dev+1); + } + return EFI_SUCCESS; + } else return EFI_NOT_FOUND; + } else return EFI_INVALID_PARAMETER; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtIsCrdBrg() +// +// Description: Checks if PciDeviceHandle, or PciIO passed belongs to +// PCI 2 Card Bridge device. +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCI_BRG_EXT** PciBrgExt Double Pointer to the PCI_BRG_EXT Structure (OPTIONAL) +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If Device is not PCI 2 Card Bridge device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +// **PciBrgExt if not needed must be NULL; +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtIsCrdBrg( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_BRG_EXT **BrgData OPTIONAL +) +{ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev) { + if(dev->Type == tPci2CrdBrg){ + //if we have to update pointer + if(BrgData != NULL){ + *BrgData = (PCI_BRG_EXT*)(dev+1); + } + return EFI_SUCCESS; + } else return EFI_NOT_FOUND; + } else return EFI_INVALID_PARAMETER; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtIsDevice() +// +// Description: Checks if PciDeviceHandle, or PciIO passed belongs to +// Regular PCI device. +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If Device is not Regular PCI device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtIsDevice( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL +) +{ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev){ + if(dev->Type == tPciDevice) return EFI_SUCCESS; + else return EFI_NOT_FOUND; + } else return EFI_INVALID_PARAMETER; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtClassCodes() +// +// Description: Returns device's Class code; Sub Class code; Programing Interface +// and Revision Id information. +// +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCI_DEV_CLASS* CassCodes Pointer to the PCI_DEV_CLASS to fill. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtClassCodes( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_DEV_CLASS *CassCodes +) +{ + PCI_DEV_INFO *dev=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev){ + *CassCodes=dev->Class; + return EFI_SUCCESS; + } else return EFI_INVALID_PARAMETER; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtPicIrqRout() +// +// Description: Returns device's corresponded PIC IRQ routing entry from OEMPIR.INC +// table created by the BUILD process. +// If function returns EFI_SUCCESS the "PicIrqTblEntry" updated with corresponded PIC +// IRQ Table entry pointer. "ParentDevices" == NULL and "EntryCount"==0 +// Function will return EFI_NOT_FOUND if there a no entry for the Device HANDLE passed. +// +// But it will return update the array of EFI_PCI_CONFIGURATION_ADDRESS structures with +// PCI Addresses of parenti +// +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCI_IRQ_PIC_ROUTE** PicIrqTblEntry Double pointer to the corresponded PCI_IRQ_PIC_ROUTE entry +// EFI_PCI_CONFIGURATION_ADDRESS** ParentDevices Pointer to an array of parent Devices +// for which was not found a valid PCI_IRQ_PIC_ROUTE entry. +// UINTN* EntryCount Number of elements in an array above. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If no PIRQ entry was found for this device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtPicIrqRout ( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_IRQ_PIC_ROUTE **PicIrqTblEntry, + OUT EFI_PCI_CONFIGURATION_ADDRESS **ParentDevices, + OUT UINTN *EntryCount ) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=NULL; + PCI_DEV_INFO *parent; + T_ITEM_LIST ParentLst={0,0,NULL}; + INTN i,j; + EFI_PCI_CONFIGURATION_ADDRESS *pa=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev != NULL ){ + if( dev->PicIrqEntry != NULL ){ + *PicIrqTblEntry = dev->PicIrqEntry; + ParentDevices = NULL; + EntryCount = 0; + return EFI_SUCCESS; + } else { + parent=dev; + do{ + parent=parent->ParentBrg; + Status=AppendItemLst(&ParentLst, parent); + }while( (parent->PicIrqEntry == NULL) || (parent->Type != tPciRootBrg)); + + if( parent->PicIrqEntry != NULL ){ + *PicIrqTblEntry=parent->PicIrqEntry; + //Create the array of addresses in order from Device which has IRQ endtry down to this Device parent + if(ParentLst.ItemCount){ + pa=Malloc(sizeof(EFI_PCI_CONFIGURATION_ADDRESS)*(ParentLst.ItemCount)); + for(i=(INTN)ParentLst.ItemCount-1, j=0; i<=0; i--,j++){ + parent = (PCI_DEV_INFO*)ParentLst.Items[i]; + pa[j] = parent->Address.Addr; + } + } + *ParentDevices=pa; + *EntryCount=ParentLst.ItemCount; + } else { + *PicIrqTblEntry=NULL; + ParentDevices=NULL; + EntryCount=0; + } + return EFI_NOT_FOUND; + } + } + else return EFI_INVALID_PARAMETER; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: PciExtApicIrqRout() +// +// Description: Returns device's corresponded APIC IRQ routing entry from MPPCIIRQ.INC +// table created by the BUILD process. +// If function returns EFI_SUCCESS the "ApicIrqTblEntry" updated with corresponded PIC +// IRQ Table entry pointer. "ParentDevices" == NULL and "EntryCount"==0 +// Function will return EFI_NOT_FOUND if there a no entry for the Device HANDLE passed. +// +// But it will return update the array of EFI_PCI_CONFIGURATION_ADDRESS structures with +// PCI Addresses of parenti +// +// Input: +// AMI_PCI_EXT_PROTOCOL* This Pointer to the PciBusExtended protocol. +// EFI_HANDLE PciDeviceHandle Handle of the PCI Device to check. +// EFI_PCI_IO_PROTOCOL* PciIo Pointer to the instance of PCI IO Protocol (OPTIONAL) +// PCI_IRQ_PIC_ROUTE** ApicIrqTblEntry Double pointer to the corresponded PCI_IRQ_PIC_ROUTE entry +// EFI_PCI_CONFIGURATION_ADDRESS** ParentDevices Pointer to an array of parent Devices +// for which was not found a valid PCI_IRQ_PIC_ROUTE entry. +// UINTN* EntryCount Number of elements in an array above. +// +// Output: EFI_STATUS +// EFI_SUCCESS When everything is going on fine! +// EFI_NOT_FOUND If no PIRQ entry was found for this device. +// EFI_INVALID_PARAMETER When Parameter passed is invalid. +// +// Note: +// If PciDeviceHandle == NULL, PciIo must be valid. +// If *PciIo == NULL PciDeviceHandle must be valid. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS PciExtApicIrqRout ( + IN AMI_PCI_EXT_PROTOCOL *This, + IN EFI_HANDLE PciDeviceHandle, + IN EFI_PCI_IO_PROTOCOL *PciIo OPTIONAL, + OUT PCI_IRQ_APIC_ROUTE **ApicIrqTblEntry, + OUT EFI_PCI_CONFIGURATION_ADDRESS **ParentDevices, + OUT UINTN *EntryCount ) +{ + EFI_STATUS Status; + PCI_DEV_INFO *dev=NULL; + PCI_DEV_INFO *parent; + T_ITEM_LIST ParentLst={0,0,NULL}; + INTN i,j; + EFI_PCI_CONFIGURATION_ADDRESS *pa=NULL; +//------------------------------------ + dev=PciExtGetDevice(PciDeviceHandle, PciIo); + + if(dev != NULL ){ + if( dev->ApicIrqEntry != NULL ){ + *ApicIrqTblEntry = dev->ApicIrqEntry; + ParentDevices = NULL; + EntryCount = 0; + return EFI_SUCCESS; + } else { + parent=dev; + do{ + parent=parent->ParentBrg; + Status=AppendItemLst(&ParentLst, parent); + }while( (parent->ApicIrqEntry == NULL) || (parent->Type != tPciRootBrg)); + + if( parent->ApicIrqEntry != NULL ){ + *ApicIrqTblEntry=parent->ApicIrqEntry; + //Create the array of addresses in order from Device which has IRQ endtry down to this Device parent + if(ParentLst.ItemCount){ + pa=Malloc(sizeof(EFI_PCI_CONFIGURATION_ADDRESS)*(ParentLst.ItemCount)); + for(i=(INTN)ParentLst.ItemCount-1, j=0; i<=0; i--,j++){ + parent = (PCI_DEV_INFO*)ParentLst.Items[i]; + pa[j] = parent->Address.Addr; + } + } + *ParentDevices=pa; + *EntryCount=ParentLst.ItemCount; + } else { + *ApicIrqTblEntry=NULL; + ParentDevices=NULL; + EntryCount=0; + } + return EFI_NOT_FOUND; + } + } + else return EFI_INVALID_PARAMETER; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2010, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |