From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM11-CO1-obe.outbound.protection.outlook.com (NAM11-CO1-obe.outbound.protection.outlook.com [40.107.220.121]) by mx.groups.io with SMTP id smtpd.web11.4686.1634883620762150075 for ; Thu, 21 Oct 2021 23:20:20 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@os.amperecomputing.com header.s=selector2 header.b=c6NrE4Qu; spf=pass (domain: os.amperecomputing.com, ip: 40.107.220.121, mailfrom: nhi@os.amperecomputing.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=i5nSyAQucO6bN7ZwEborKUa1ncn9KFmbragnMwCyLPGt72ZjtIOQrHpcOJG57wb+q/Wvwo/gDCrQYhMSkSy17D5Jb+LP/citBYtIVRRbH9fTR6zaISvwpyHOGUUScZziVnaidYcDuBu0pBjp/2M5SryeU9vUsnO00fKxtEPqieao7m6ZZYIRsfKBvkBNgnICHE2dd1o1BVhOOnG4/y2FaiV0IG06EZYJTXROCiUqc0VR3gxwN+I7T7m6zmbTF9eZn1OdoSMSVmrh5s6pS+YMiD9E8fzcHBxVoKXC/KyIJXbjf0eIRpQFQ9nToNfy+OPgpi+oKuldqA9+G1yvkLVSIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=LpvFW8/FTzi9ENPixUPU7iRpN+E82etFoYn9uoY9mQQ=; b=bwqQOTpmRb9zc1Rhp8zH+mKU+nphjc5f7liL2cdUjYe0EiAjrqSmU5Y1nNVQqZAaOtDq3fajn410fFjDmdwI/ZHN0S90VHSWbWbwj4nMePSkyG9vkkpDT6GjfgsFuf3r4aw4V6EcSE9lDxg7nWb7sk3alk1PyucrNKYJ5gkV3v1jeRJ8wGQACfJ6sbIKLX6Tk33VNA1L+nZY5rUSeCthoWOwfg6RQVH69oupmSJp9LMX2nK97WKHR99Ey172hItQvIpKxfM3XTNnX92aGvhCBZJV2jyrsL/MGQb1+XjvSjgWs4MuablgE7ozfHzmpp43tmk+QmG1of8AzJBdT+c1ww== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=LpvFW8/FTzi9ENPixUPU7iRpN+E82etFoYn9uoY9mQQ=; b=c6NrE4QurI6XIem4epR0IMJTRPAJL36nWfPqAgs36BzydGBc0g1nzS8K16alkddiRhb1GUJeBa+RMafcOe0GAh5d4iPyds2p4Ukjt/tfNPdhrKniu9V6DV8Guyqk1yAi8A+7YXyJ7EUduFG00rNT7PEGS06zxS78NBClPwD/3CQ= Authentication-Results: edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=none action=none header.from=os.amperecomputing.com; Received: from PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) by PH0PR01MB6325.prod.exchangelabs.com (2603:10b6:510:1e::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4628.18; Fri, 22 Oct 2021 06:20:18 +0000 Received: from PH0PR01MB7287.prod.exchangelabs.com ([fe80::254c:9533:7f35:aee]) by PH0PR01MB7287.prod.exchangelabs.com ([fe80::254c:9533:7f35:aee%4]) with mapi id 15.20.4628.016; Fri, 22 Oct 2021 06:20:18 +0000 From: "Nhi Pham" To: devel@edk2.groups.io CC: patches@amperecomputing.com, nhi@os.amperecomputing.com, vunguyen@os.amperecomputing.com, Thang Nguyen , Chuong Tran , Phong Vo , Leif Lindholm , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: [edk2-platforms][PATCH v4 16/31] AmpereAltraPkg: Add PciSegmentLib library instance Date: Fri, 22 Oct 2021 13:17:54 +0700 Message-ID: <20211022061809.31087-17-nhi@os.amperecomputing.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211022061809.31087-1-nhi@os.amperecomputing.com> References: <20211022061809.31087-1-nhi@os.amperecomputing.com> X-ClientProxiedBy: HK2PR02CA0168.apcprd02.prod.outlook.com (2603:1096:201:1f::28) To PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) Return-Path: nhi@os.amperecomputing.com MIME-Version: 1.0 Received: from sw004.amperecomputing.com (118.69.219.201) by HK2PR02CA0168.apcprd02.prod.outlook.com (2603:1096:201:1f::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4628.16 via Frontend Transport; Fri, 22 Oct 2021 06:20:15 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 177adcfd-6617-45b4-5ec2-08d995240478 X-MS-TrafficTypeDiagnostic: PH0PR01MB6325: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:10000; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: qFJXsneo/c5vdk0uFW3Py0Fx0fju0h4Vlvy1mTYjq6HekiueuVwvEONDHwuk2r6AM/gYfDwtSe8pj3KhWV4x975nbCAdUN6VkzExWicMfrSL1axgutF/hFr4P3v+B5+ddcqHs+4l5yppBQ0jUVlFAs8UmVRysUpHm5zqLeM8Vt9/EdE1yB/zbuFSz+1izphBa0SZcyFo7sfMB/9psoA63IeLwF0YHtCNTLdpOiJi3Jvv+Sc5r3jgoXdGQmi5kCfcF7tuubDCRoajAl8vcsDJteR0MQW4fn1IARuoLjbuX3FFKunf6DqcM/JgTRSwhUmXyG13Xk5DcL55Vdidx5BYyLJZ+p24cJcTaIGveS8GNljc9OGwfofa+466tGnbYoF5vcBqPH4soevuZjARxpA4GHhL9wZd4cDnZFyUN1V0oJ7W2fNmGknCODKrPAMBxFxF3vBcN+UK27uUPGVwOpLaCcFkNl7iQ+JgYBMg/V+2LFo2JsczXJqET8O9WK0FSJl3M8pCunuNJGOPyHc1CeaqYcyGReDlswC8dmxFmuGkMYHQ0CWq5fNUl7Bo3DgKvcbLCydjV483mtQvVxXroxVQz0MIuTl+09OkFuxb2UDwGp9wgH70NW4NRC+jNk+ZVS0qmo/joQt8Ge44D/H99rYritMl+bRQJSSK5CSAsJgSpAz1t6Ah5bXTiGG2iSvy7DqBQ+kteumqOPJPpv1G8IpwxQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PH0PR01MB7287.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(4636009)(366004)(6506007)(5660300002)(6666004)(8936002)(19627235002)(38100700002)(38350700002)(6486002)(186003)(26005)(508600001)(1076003)(316002)(8676002)(54906003)(6916009)(66476007)(66556008)(6512007)(66946007)(83380400001)(86362001)(956004)(4326008)(30864003)(2616005)(52116002)(2906002)(559001)(579004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?LmOdwZ+Z0Y43333sScNUaLeEm64gR3BdKBmRwE6LFpYHXTclY1YZ7YGEcS5U?= =?us-ascii?Q?NVRp0m07PafQtZ+BJhn73/jY5Gcv2/msvyh2c3Xwaf9kYEoGDjSnQQAzrKJW?= =?us-ascii?Q?cM0jKcnqzQXcfD/pJfDp6QOgHlYg/aKo/sgYUiaL82G+g0u/UHhItISnermX?= =?us-ascii?Q?wSjYT42eGizCiwCUGvoOT4bH9hnabudbGS3XfV66MOCACu3Hkmv6N++3j8n1?= =?us-ascii?Q?yIGYPwC7YKP8+LY/yO67qBezJIvIRcG+Us89SAXR1zPIKhkFEjuSvgGGj4tK?= =?us-ascii?Q?ExxpKHscN364sCiny1Kr7oNoSzJ3XGECjD1ApYHgb7ZFwu6ui9w3MBdAb5+q?= =?us-ascii?Q?D+rjBtqOmp3HzLgUUZvONxOQmDM55/F1aGHEeIqiFk8NJrvOkLYGF0oyyiOv?= =?us-ascii?Q?4Zkiqc9ZbHlZJH4otREoZw0o+pSYypccrKPKvXEO3bP9F4yPxBMT7oDopx2/?= =?us-ascii?Q?FjabB+kEO9Qr9fsd9D6v6Vg7mlGaK/8g8cExSBd4ryg0DjiaS2JK+0mYv6RY?= =?us-ascii?Q?AMa2FeNtXq0ywEYD/TcATdOMvliHQLdUO8t0pwFBIMTWzxPFdP9B6KEYsp/n?= =?us-ascii?Q?ehsDxMGmWZkVj1m6sWuT6WzwhkRmmY2cug1xtSRB2elab7yiUCgKr97UE529?= =?us-ascii?Q?ro+bpRWR1TdxdlwppiETfiz0CYK48kAzMLpaIuN5GdX/r8hfneFG5hw3lpwz?= =?us-ascii?Q?UjkgY1ZNYNmUrUn7yCEQp6kKykp8mkhczrcWKeg5uo8SMUZK7Dak9nfqOpAw?= =?us-ascii?Q?F7ieo1bSpGM9qsv66JgYBk1okGHWugDOLZwEV6qcm6JBRWecCZSmzsDq3Rr7?= =?us-ascii?Q?LHj3wjKXvvXgL/6108lVnwom/GovqagWgQULgWJRxp8lHEAw3qWkS7su6qw2?= =?us-ascii?Q?ucSZOP03LZKAbtkEhfdyMjCrzb8/AL4RWk1FBSFCVVR2Wo/upYsRUggFq3FE?= =?us-ascii?Q?LaNA5WRxJylat6R2wcXkbGB27dKcV9ZZW1hJo9wBsYUd7utRM3XTnAJf3LIi?= =?us-ascii?Q?GhmS2il/9QTAWzLebQ4fad0fCeydBfnUtfO7q9Q5sOVDpu+cKNT2LGB0sU9g?= =?us-ascii?Q?vcGCdXetAPhDgzYU7Z0zcgUQdk+bE5K6ytlnTcPFSXpLoUy1FaSDY4svso+K?= =?us-ascii?Q?r0VnZTvLQudCYwG/Zjp8Z3vt41QMlXZiK/IGu2g1Yd9/2/Wh+c6vMUNrnlxK?= =?us-ascii?Q?Y4m9RtCBLSKRDr0XzUB+FJhdU8BbZ7qx4f4E/Nest0OJM6kZM+mAhyk/WsW2?= =?us-ascii?Q?lWYPnUAqBMDlEzIW7xKMa7E/xjhvXrIEOysKSMuPNS69FG9pg5ER1QCN2YsC?= =?us-ascii?Q?wCvgRHvSxjmB3LZYLckp5PVruj4UlXiIHTwdNi49fYpx31hPnr4p+FNG6czG?= =?us-ascii?Q?F+6EIR5XaWDXtHNVv67Z4tqmw8G047ELCOEXGsSDADX9fGMf8itHQovxMHbQ?= =?us-ascii?Q?+8U2SCAhGoVer+63M50iydjKOdBD4tr300h1Peo5mDUYHj9gerBzLA=3D=3D?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: 177adcfd-6617-45b4-5ec2-08d995240478 X-MS-Exchange-CrossTenant-AuthSource: PH0PR01MB7287.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Oct 2021 06:20:17.9389 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: nhi@amperemail.onmicrosoft.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR01MB6325 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain From: Vu Nguyen Provides functions to handle the PCIe configuration requests. The target Root Complex is selected based on the segment number parsed from the input address. Cc: Thang Nguyen Cc: Chuong Tran Cc: Phong Vo Cc: Leif Lindholm Cc: Michael D Kinney Cc: Ard Biesheuvel Cc: Nate DeSimone Signed-off-by: Nhi Pham --- Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc = | 1 + Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibPci.in= f | 32 + Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.c = | 1573 ++++++++++++++++++++ 3 files changed, 1606 insertions(+) diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon= /Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc index 3b576df24073..1dee436f97b4 100644 --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc @@ -226,6 +226,7 @@ [LibraryClasses.common.DXE_DRIVER] PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.= inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll= ocationLib.inf PciHostBridgeLib|Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/= PciHostBridgeLib.inf + PciSegmentLib|Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/Pci= SegmentLibPci.inf =20 [LibraryClasses.common.UEFI_APPLICATION] UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCust= omDecompressLib.inf diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegm= entLibPci.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciS= egmentLibPci.inf new file mode 100644 index 000000000000..ca564997e609 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLibP= ci.inf @@ -0,0 +1,32 @@ +## @file +# +# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D PciSegmentLibPci + FILE_GUID =3D 0AF5E76D-D31E-492B-AE69-A7B441FF62D9 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D PciSegmentLib + +[Sources] + PciSegmentLib.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + HobLib + IoLib + +[Guids] + gRootComplexInfoHobGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegm= entLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmen= tLib.c new file mode 100644 index 000000000000..854f50f953be --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.= c @@ -0,0 +1,1573 @@ +/** @file + + Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define GET_SEG_NUM(Address) (((Address) >> 32) & 0xFFFF) +#define GET_BUS_NUM(Address) (((Address) >> 20) & 0x7F) +#define GET_DEV_NUM(Address) (((Address) >> 15) & 0x1F) +#define GET_FUNC_NUM(Address) (((Address) >> 12) & 0x07) +#define GET_REG_NUM(Address) ((Address) & 0xFFF) + +/** + Assert the validity of a PCI Segment address. + A valid PCI Segment address should not contain 1's in bits 28..31 and 48= ..63. + + @param A The address to validate. + @param M Additional bits to assert to be zero. + +**/ +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A,M) \ + ASSERT (((A) & (0xffff0000f0000000ULL | (M))) =3D=3D 0) + +/** + Convert the PCI Segment library address to PCI library address. + + @param A The address to convert. +**/ +#define PCI_SEGMENT_TO_PCI_ADDRESS(A) ((UINTN)(UINT32)A) + +/** + Get the MCFG Base from input Address. +**/ +UINTN +GetMmcfgBase ( + IN UINTN Address + ) +{ + AC01_ROOT_COMPLEX *RootComplexList; + UINTN Idx; + VOID *Hob; + + Hob =3D GetFirstGuidHob (&gRootComplexInfoHobGuid); + if (Hob =3D=3D NULL) { + return 0; + } + + RootComplexList =3D (AC01_ROOT_COMPLEX *)GET_GUID_HOB_DATA (Hob); + + for (Idx =3D 0; Idx < AC01_PCIE_MAX_ROOT_COMPLEX; Idx++) { + if (RootComplexList[Idx].Logical =3D=3D GET_SEG_NUM (Address)) { + return RootComplexList[Idx].MmcfgBase; + } + } + + return 0; +} + +/** + Register a PCI device so PCI configuration registers may be accessed aft= er + SetVirtualAddressMap(). + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + + @retval RETURN_SUCCESS The PCI device was registered for runti= me access. + @retval RETURN_UNSUPPORTED An attempt was made to call this functi= on + after ExitBootServices(). + @retval RETURN_UNSUPPORTED The resources required to access the PC= I device + at runtime could not be mapped. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources availabl= e to + complete the registration. + +**/ +RETURN_STATUS +EFIAPI +PciSegmentRegisterForRuntimeAccess ( + IN UINTN Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + return RETURN_UNSUPPORTED; +} + +/** + Reads an 8-bit PCI configuration register. + + Reads and returns the 8-bit PCI configuration register specified by Addr= ess. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + + @return The 8-bit PCI configuration register specified by Address. + +**/ +UINT8 +EFIAPI +PciSegmentRead8 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + UINTN CfgBase; + UINT8 Value; + + CfgBase =3D GetMmcfgBase (Address) + (Address & 0x0FFFFFFF); + + UINT64 AlignedAddr =3D CfgBase & ~0x3; + UINT32 Val32 =3D MmioRead32 (AlignedAddr); + switch (CfgBase & 0x3) { + case 3: + Value =3D Val32 >> 24; + break; + + case 2: + Value =3D Val32 >> 16; + break; + + case 1: + Value =3D Val32 >> 8; + break; + + case 0: + default: + Value =3D Val32; + break; + } + DEBUG (( + DEBUG_INFO, + "PCIE CFG RD8: 0x%p value: 0x%02X (0x%08llX 0x%08X)\n", + CfgBase, + Value, + AlignedAddr, + Val32 + )); + + return Value; +} + +/** + Writes an 8-bit PCI configuration register. + + Writes the 8-bit PCI configuration register specified by Address with th= e value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, F= unction, and Register. + @param Value The value to write. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentWrite8 ( + IN UINT64 Address, + IN UINT8 Value + ) +{ + UINT32 Val32; + UINT64 AlignedAddr; + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + CfgBase =3D GetMmcfgBase (Address) + (Address & 0x0FFFFFFF); + + AlignedAddr =3D CfgBase & ~0x3; + Val32 =3D MmioRead32 (AlignedAddr); + + switch (CfgBase & 0x3) { + case 0: + Val32 &=3D ~0xFF; + Val32 |=3D Value; + break; + + case 1: + Val32 &=3D ~0xFF00; + Val32 |=3D (UINT32)Value << 8; + break; + + case 2: + Val32 &=3D ~0xFF0000; + Val32 |=3D (UINT32)Value << 16; + break; + + case 3: + default: + Val32 &=3D ~0xFF000000; + Val32 |=3D (UINT32)Value << 24; + break; + } + MmioWrite32 (AlignedAddr, Val32); + DEBUG (( + DEBUG_INFO, + "PCIE CFG WR8: 0x%p value: 0x%04X (0x%08llX 0x%08X)\n", + CfgBase, + Value, + AlignedAddr, + MmioRead32 ((UINT64)AlignedAddr) + )); + + return Value; +} + +/** + Performs a bitwise OR of an 8-bit PCI configuration register with an 8-b= it value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentOr8 ( + IN UINT64 Address, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), (UINT8)(P= ciSegmentRead8 (Address) | OrData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-= bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + If any reserved bits in Address are set, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAnd8 ( + IN UINT64 Address, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & An= dData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-= bit value, + followed a bitwise OR with another 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAndThenOr8 ( + IN UINT64 Address, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & A= ndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in an 8-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldRead8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 8-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param Value New value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldWrite8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 Value + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Va= lue) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, = and + writes the result back to the bit field in the 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 8-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrDat= a) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration register, performs a bit= wise + AND, and writes the result back to the bit field in the 8-bit register. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise AND between the read result and the value specified by AndData, = and + writes the result to the 8-bit PCI configuration register specified by + Address. The value written to the PCI configuration register is returned= . + This function must guarantee that all PCI read and write operations are + serialized. Extra left bits in AndData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAnd8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndD= ata) + ); +} + +/** + Reads a bit field in an 8-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the 8-bit por= t. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 8-bit PCI + configuration register specified by Address. The value written to the PC= I + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAndThenOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit= , AndData, OrData) + ); +} + +/** + Reads a 16-bit PCI configuration register. + + Reads and returns the 16-bit PCI configuration register specified by Add= ress. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + + @return The 16-bit PCI configuration register specified by Address. + +**/ +UINT16 +EFIAPI +PciSegmentRead16 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + UINTN CfgBase; + UINT16 Value; + + CfgBase =3D GetMmcfgBase (Address) + (Address & 0x0FFFFFFE); + UINT64 AlignedAddr =3D CfgBase & ~0x3; + UINT32 RegC, Reg18; + UINT8 MfHt, Primary =3D 0, Sec =3D 0, Sub =3D 0; + UINT32 Val32; + + if ((GET_BUS_NUM (CfgBase) > 0) && (GET_DEV_NUM (CfgBase) > 0) && (GET_R= EG_NUM (CfgBase) =3D=3D 0)) { + Value =3D MmioRead32 (CfgBase); + DEBUG (( + DEBUG_INFO, + "PCIE CFG16 RD: B%X|D%X 0x%p value: 0x%08X\n", + GET_BUS_NUM (CfgBase), + GET_DEV_NUM (CfgBase), + CfgBase, + Value + )); + + if (Value !=3D 0xffff) { + RegC =3D MmioRead32 (CfgBase + 0xC); + DEBUG ((DEBUG_INFO, " Peek PCIE MfHt RD: 0x%p value: 0x%08X\n", Cfg= Base + 0xc, RegC)); + MfHt =3D RegC >> 16; + DEBUG ((DEBUG_INFO, " Peek RD8 MfHt=3D0x%02X\n", MfHt)); + + if ((MfHt & 0x7F)!=3D 0) { /* Type 1 header */ + Reg18 =3D MmioRead32 (CfgBase + 0x18); + Primary =3D Reg18; Sec =3D Reg18 >> 8; Sub =3D Reg18 >> 16; + DEBUG (( + DEBUG_INFO, + " Bus Peek PCIE Sub:%01X Sec:%01X Primary:%01X RD: 0x%p value:= 0x%08X\n", + Sub, + Sec, + Primary, + CfgBase + 0x18, + Reg18 + )); + } + + if ((MfHt =3D=3D 0) || (Primary !=3D 0)) { /* QS RPs Primary Bus is = 0b */ + Value =3D 0xffff; + DEBUG (( + DEBUG_INFO, + " Skip RD16 B%X|D%X PCIE CFG RD: 0x%p return 0xffff\n", + GET_BUS_NUM (CfgBase), + GET_DEV_NUM (CfgBase), + CfgBase + )); + return 0; + } + } + } + + Val32 =3D MmioRead32 (AlignedAddr); + switch (CfgBase & 0x3) { + case 2: + Value =3D Val32 >> 16; + break; + + case 0: + default: + Value =3D Val32; + break; + } + DEBUG (( + DEBUG_INFO, + "PCIE CFG RD16: 0x%p value: 0x%04X (0x%08llX 0x%08X)\n", + CfgBase, + Value, + AlignedAddr, + Val32 + )); + + if (GET_REG_NUM (Address) =3D=3D 0xAE && Value =3D=3D 0xFFFF) { + DEBUG ((DEBUG_ERROR, "PANIC due to PCIE link issue - Addr 0x%llx\n", A= ddress)); + // Loop forever waiting for failsafe/watch dog time out + CpuDeadLoop (); + } + + return Value; +} + +/** + Writes a 16-bit PCI configuration register. + + Writes the 16-bit PCI configuration register specified by Address with t= he value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, F= unction, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +PciSegmentWrite16 ( + IN UINT64 Address, + IN UINT16 Value + ) +{ + UINT32 Val32; + UINT64 AlignedAddr; + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + CfgBase =3D GetMmcfgBase (Address) + (Address & 0x0FFFFFFE); + + AlignedAddr =3D CfgBase & ~0x3; + Val32 =3D MmioRead32 (AlignedAddr); + + switch (CfgBase & 0x3) { + case 2: + Val32 &=3D ~0xFFFF0000; + Val32 |=3D (UINT32)Value << 16; + break; + + case 0: + default: + Val32 &=3D ~0xFFFF; + Val32 |=3D Value; + break; + } + MmioWrite32 (AlignedAddr, Val32); + DEBUG (( + DEBUG_INFO, + "PCIE CFG WR16: 0x%p value: 0x%04X (0x%08llX 0x%08X)\n", + CfgBase, + Value, + AlignedAddr, + MmioRead32 (AlignedAddr) + )); + + return Value; +} + +/** + Performs a bitwise OR of a 16-bit PCI configuration register with + a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by OrData, an= d + writes the result to the 16-bit PCI configuration register specified by = Address. + The value written to the PCI configuration register is returned. This fu= nction + must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Funct= ion and + Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentOr16 ( + IN UINT64 Address, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) = | OrData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-= bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAnd16 ( + IN UINT64 Address, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) = & AndData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-= bit value, + followed a bitwise OR with another 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAndThenOr16 ( + IN UINT64 Address, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) ((PciSegmentRead16 (Address)= & AndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 16-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldRead16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 16-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param Value New value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldWrite16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 Value + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, = Value) + ); +} + +/** + Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, = writes + the result back to the bit field in the 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 16-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrD= ata) + ); +} + +/** + Reads a bit field in a 16-bit PCI configuration register, performs a bit= wise + AND, writes the result back to the bit field in the 16-bit register. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND between the read result and the value specified by AndData, = and + writes the result to the 16-bit PCI configuration register specified by + Address. The value written to the PCI configuration register is returned= . + This function must guarantee that all PCI read and write operations are + serialized. Extra left bits in AndData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAnd16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, An= dData) + ); +} + +/** + Reads a bit field in a 16-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 16-bit PCI + configuration register specified by Address. The value written to the PC= I + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAndThenOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndB= it, AndData, OrData) + ); +} + +/** + Reads a 32-bit PCI configuration register. + + Reads and returns the 32-bit PCI configuration register specified by Add= ress. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + + @return The 32-bit PCI configuration register specified by Address. + +**/ +UINT32 +EFIAPI +PciSegmentRead32 ( + IN UINT64 Address + ) +{ + UINT32 RegC, Reg18; + UINT32 Value; + UINT8 MfHt, Ht, Primary =3D 0, Sec =3D 0, Sub =3D 0; + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + CfgBase =3D GetMmcfgBase (Address) + (Address & 0x0FFFFFFC); + + if ((GET_BUS_NUM (CfgBase) > 0) && (GET_DEV_NUM (CfgBase) > 0) && (GET_R= EG_NUM (CfgBase) =3D=3D 0)) { + Value =3D MmioRead32 (CfgBase); + DEBUG (( + DEBUG_INFO, + "PCIE CFG RD32: B%X|D%X 0x%p value: 0x%08X\n", + GET_BUS_NUM (CfgBase), + GET_DEV_NUM (CfgBase), + CfgBase, + Value + )); + + if (Value !=3D 0xffffffff) { + RegC =3D MmioRead32 (CfgBase + 0xC); + DEBUG ((DEBUG_INFO, "Peek PCIE MfHt RD32: 0x%p value: 0x%08X\n", Cfg= Base + 0xc, RegC)); + MfHt =3D RegC >> 16; + DEBUG ((DEBUG_INFO, " Peek RD8 MfHt=3D0x%02X\n", MfHt)); + + Ht =3D MfHt & 0x7F; + if (Ht !=3D 0) { /* Type 1 header */ + Reg18 =3D MmioRead32 (CfgBase + 0x18); + Primary =3D Reg18; Sec =3D Reg18 >> 8; Sub =3D Reg18 >> 16; + DEBUG (( + DEBUG_INFO, + " Bus Peek PCIE Sub:%01X Sec:%01X Primary:%01X RD32: 0x%p valu= e: 0x%08X\n", + Sub, + Sec, + Primary, + CfgBase + 0x18, + Reg18 + )); + } + if ((Ht =3D=3D 0) || (Primary !=3D 0)) { /* Ampere Altra RPs Primary= Bus is 0b */ + Value =3D 0xffffffff; + DEBUG (( + DEBUG_INFO, + " Skip RD32 B%X|D%X PCIE CFG RD32: 0x%p return 0xffffffff\n", + GET_BUS_NUM (CfgBase), + GET_DEV_NUM (CfgBase), + CfgBase + )); + } + } + } else { + Value =3D MmioRead32 (CfgBase); + } + + DEBUG ((DEBUG_INFO, "PCIE CFG RD32: 0x%p value: 0x%08X\n", CfgBase, Valu= e)); + + return Value; +} + +/** + Writes a 32-bit PCI configuration register. + + Writes the 32-bit PCI configuration register specified by Address with t= he value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, F= unction, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT32 +EFIAPI +PciSegmentWrite32 ( + IN UINT64 Address, + IN UINT32 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + UINTN CfgBase; + + CfgBase =3D GetMmcfgBase (Address) + (Address & 0x0FFFFFFC); + MmioWrite32 (CfgBase, Value); + DEBUG (( + DEBUG_INFO, + "PCIE CFG WR32: 0x%p value: 0x%08X (0x%08X)\n", + CfgBase, + Value, + MmioRead32 (CfgBase) + )); + + return Value; +} + +/** + Performs a bitwise OR of a 32-bit PCI configuration register with a 32-b= it value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentOr32 ( + IN UINT64 Address, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-= bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAnd32 ( + IN UINT64 Address, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData)= ; +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-= bit value, + followed a bitwise OR with another 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAndThenOr32 ( + IN UINT64 Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData= ) | OrData); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 32-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldRead32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 32-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param Value New value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldWrite32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 Value + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, = Value) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, = and + writes the result back to the bit field in the 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 32-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrD= ata) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration register, performs a bit= wise + AND, and writes the result back to the bit field in the 32-bit register. + + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a bitwise + AND between the read result and the value specified by AndData, and writ= es the result + to the 32-bit PCI configuration register specified by Address. The value= written to + the PCI configuration register is returned. This function must guarante= e that all PCI + read and write operations are serialized. Extra left bits in AndData ar= e stripped. + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address Address that encodes the PCI Segment, Bus, Device, Fun= ction, and Register. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAnd32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, An= dData) + ); +} + +/** + Reads a bit field in a 32-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 32-bit PCI + configuration register specified by Address. The value written to the PC= I + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAndThenOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndB= it, AndData, OrData) + ); +} + +/** + Reads a range of PCI configuration registers into a caller supplied buff= er. + + Reads the range of PCI configuration registers specified by StartAddress= and + Size into the buffer specified by Buffer. This function only allows the = PCI + configuration registers from a single PCI function to be read. Size is + returned. When possible 32-bit PCI configuration read cycles are used to= read + from StartAddress to StartAddress + Size. Due to alignment restrictions,= 8-bit + and 16-bit PCI configuration read cycles may be used at the beginning an= d the + end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress Starting address that encodes the PCI Segment, Bus= , Device, + Function and Register. + @param Size Size in bytes of the transfer. + @param Buffer Pointer to a buffer receiving the data read. + + @return Size + +**/ +UINTN +EFIAPI +PciSegmentReadBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <=3D SIZE_4KB); + + if (Size =3D=3D 0) { + return Size; + } + + ASSERT (Buffer !=3D NULL); + + // + // Save Size for return + // + ReturnValue =3D Size; + + if ((StartAddress & BIT0) !=3D 0) { + // + // Read a byte if StartAddress is byte aligned + // + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); + StartAddress +=3D sizeof (UINT8); + Size -=3D sizeof (UINT8); + Buffer =3D (UINT8 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16) && (StartAddress & BIT1) !=3D 0) { + // + // Read a word if StartAddress is word aligned + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + while (Size >=3D sizeof (UINT32)) { + // + // Read as many double words as possible + // + WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress)); + StartAddress +=3D sizeof (UINT32); + Size -=3D sizeof (UINT32); + Buffer =3D (UINT32 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16)) { + // + // Read the last remaining word if exist + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT8)) { + // + // Read the last remaining byte if exist + // + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); + } + + return ReturnValue; +} + +/** + Copies the data in a caller supplied buffer to a specified range of PCI + configuration space. + + Writes the range of PCI configuration registers specified by StartAddres= s and + Size from the buffer specified by Buffer. This function only allows the = PCI + configuration registers from a single PCI function to be written. Size i= s + returned. When possible 32-bit PCI configuration write cycles are used t= o + write from StartAddress to StartAddress + Size. Due to alignment restric= tions, + 8-bit and 16-bit PCI configuration write cycles may be used at the begin= ning + and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress Starting address that encodes the PCI Segment, Bus= , Device, + Function and Register. + @param Size Size in bytes of the transfer. + @param Buffer Pointer to a buffer containing the data to write. + + @return The parameter of Size. + +**/ +UINTN +EFIAPI +PciSegmentWriteBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + IN VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <=3D SIZE_4KB); + + if (Size =3D=3D 0) { + return Size; + } + + ASSERT (Buffer !=3D NULL); + + // + // Save Size for return + // + ReturnValue =3D Size; + + if ((StartAddress & BIT0) !=3D 0) { + // + // Write a byte if StartAddress is byte aligned + // + PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer); + StartAddress +=3D sizeof (UINT8); + Size -=3D sizeof (UINT8); + Buffer =3D (UINT8 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16) && (StartAddress & BIT1) !=3D 0) { + // + // Write a word if StartAddress is word aligned + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + while (Size >=3D sizeof (UINT32)) { + // + // Write as many double words as possible + // + PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer)); + StartAddress +=3D sizeof (UINT32); + Size -=3D sizeof (UINT32); + Buffer =3D (UINT32 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16)) { + // + // Write the last remaining word if exist + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT8)) { + // + // Write the last remaining byte if exist + // + PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer); + } + + return ReturnValue; +} --=20 2.17.1