From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM12-MW2-obe.outbound.protection.outlook.com (NAM12-MW2-obe.outbound.protection.outlook.com [40.107.244.93]) by mx.groups.io with SMTP id smtpd.web10.9748.1637167827820064282 for ; Wed, 17 Nov 2021 08:50:28 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@os.amperecomputing.com header.s=selector2 header.b=Z+J4yfFD; spf=pass (domain: os.amperecomputing.com, ip: 40.107.244.93, mailfrom: nhi@os.amperecomputing.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=AeMiCUUoKfnGfgK4un8CE0mqWgz6ddQcNF6mv2SFL/Xt/NOH4uYbZRrYJ5ece8L2OL53tz/NU2DGdYrlrGjSBGdBSSeaiWUULxv2VUE4jxCKTPqmgY5kMh2PDz5mlY1hQjDZ2ee/GoS3SCbO2qwJ0km44iM39tdbIiXJln0OTEy47Qovui5/VQee/6KoEDUDQ+cwbfj9g1gL4Zng97uiIuM8Erd8ye77DYKzW9dMgOzEycfz4xC53C+jL3er/76M9ZiL3tJgCNG4FU3oRo5WnZ/e/r0TOAta80fMjD4ydUsFHd7nkjzDHcXNGOSnC2zgWBLzdBoeLma/21KENUnLSQ== 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=7B1uWOPBevX8og4VJOf9o68eV6NoOdRHmhnqsVYQtkM=; b=VG1vII18QWSoaChmjTfdaxRjownsr5/GzWD0XX9NjZ8crnvYnNwGke4NH5JMdjIbP9PCLhC9lmajpPvhIablCdZXLk2+yeMavUFBKE0aN2oSZM6V7OwB+FKIPLGX6E52E4R4DCTJMJ4n4y/DBR7P11v9H/fMBJGOe3FVWJfJoLYy//ltny9dxZgEsuT86c7BU9svlqZZUXox8dFoO1K3zpdm/TlhejJmWS6P/CYx5uyAR8jwvomAe9na80q2xcsLyMMk7pisuS9+0/f+ggcHY9n9n17qfnmdPLjz/DEnIfgXg85PfAcKV7xn8qANK5tcGGT8LGmY9uci4elEIyyeuQ== 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=7B1uWOPBevX8og4VJOf9o68eV6NoOdRHmhnqsVYQtkM=; b=Z+J4yfFDD1vXV8jg51nE4vdDW+Hj8wyeLUmmEbJlF0cZTbJ6uB+34NX51TpfiPT4DE+Z5yTNhSbKC/MhVh+BMncLBdfcviOpswGSqkqae9awTsIa9F63zHvQWaifrPQd9L6plFbYYwfl3WtKNgTK7ukn0F+Z/KWR9GJPLGLyPU8= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=os.amperecomputing.com; Received: from PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) by PH0PR01MB7521.prod.exchangelabs.com (2603:10b6:510:f4::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.19; Wed, 17 Nov 2021 16:50:23 +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.4713.019; Wed, 17 Nov 2021 16:50:23 +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 v5 15/30] AmpereAltraPkg: Add PciSegmentLib library instance Date: Wed, 17 Nov 2021 23:47:12 +0700 Message-ID: <20211117164727.10922-16-nhi@os.amperecomputing.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211117164727.10922-1-nhi@os.amperecomputing.com> References: <20211117164727.10922-1-nhi@os.amperecomputing.com> X-ClientProxiedBy: HKAPR04CA0001.apcprd04.prod.outlook.com (2603:1096:203:d0::11) 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 HKAPR04CA0001.apcprd04.prod.outlook.com (2603:1096:203:d0::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.21 via Frontend Transport; Wed, 17 Nov 2021 16:50:20 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: cbd18228-7d3a-4890-60d5-08d9a9ea593f X-MS-TrafficTypeDiagnostic: PH0PR01MB7521: 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: 6Si4nsPt0PokZHZ0zAYEusIorpIjgd+gOqohNPRT9qaZRjhwZ94/jo8B+rRvUe0gMUUEC+82c1Xn4TgYhsDvfRlyCKnB35FCg+kcNtnipU4OKn0A7f/Wrl7E/Wph+Xo/mE0j3rdngcTNWuo34JMo4QgyOyqJe+VYHqfTzUqBV+8AbnpVLLoeVblZmw+nEKxcEBbIjGy9fh9ng6scl/FK+kkgd8M6qEke75wiHXDPhurDG2rbB9KeuHGGGqU2CMfSH3G+dqMOxYm7MUl+4fySctO+9KTji9Oc6aqQVgpGYBJvHU0wedvoKQCccDEyy6UxaPLY8kF5H6jIi1pkmZtUaABJI2BoMO53ASyq1Vpyrlq7iOJ4P/9fuVJKv2TcOg2RDYzb6yjshrw5tPwusEQAQtQZwNS0qiFaoJTUwsRznbOqw7FhiPNoMnrtkov8+SMseWzGtUkDGZ52KfBcdC2ATnkN7hkpi5ZmKW7xGYpGkz0ReJdaj4rWx3LwYrP8iTdKs720hEWvQ9hFfFAsB5ElKLtbnjv8sbNftWBtICs2zJ9fBGG2H2gbBCO1thTVWL1Vfgo6XmQyiAFqQlsEs/pr2+1DlukuvWh3Rxdauv8dW5DXUoVV7U+/T50U2/tSEMv7gHxgkBDrRJR/itSDBKSZKeSwV2mPf2IVmk+YoJIJQ2RWsUlA9PjLMqW6Rv79IGHy2uGZBDnBIjOiP0KM0Tw3Gg== 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)(54906003)(316002)(1076003)(8676002)(6506007)(4326008)(52116002)(86362001)(186003)(6512007)(6916009)(66556008)(2906002)(83380400001)(66476007)(956004)(38100700002)(8936002)(19627235002)(2616005)(38350700002)(6666004)(5660300002)(66946007)(30864003)(6486002)(508600001)(26005)(559001)(579004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?yiSvqPzKdtZwny5w7PoiavVP1WWLl6tRQeR9rQZRThG4Z+2QAO5NFMf6KvA6?= =?us-ascii?Q?mUTo0RYy76ewt/+nMHQPcQXTVmdpa1zF0Hm4LqiYUc/+SuYUfuqZwql+FZBB?= =?us-ascii?Q?LXO1Y+/I5iKPgzZ8vVig0HSSRKUhmomdYwRWYDf6oFLr44mhFsJMl0qcvNe7?= =?us-ascii?Q?VAk5sJriw6XqFTIWp7FKvlzw73XtIs4RGY+EQ4KSDCmNvtoxanTsOqvNyw6q?= =?us-ascii?Q?lEWbSweaF0riM8Vuitt9iUvyCIhazWw0ZVcH0YdEuoqY38ezPO7BTBHAf+Sz?= =?us-ascii?Q?8djQnI7Jk8RLalmGsCVqsJTePp9ydhcjLzv1f5ms2RauLfH7tchIVFVKXO2K?= =?us-ascii?Q?CsB2lwWoSnzF3NZBqU8PvttPPQjN6an4iKPrJTgPhqePzxH0Us5mpOhJdOps?= =?us-ascii?Q?8hXaBs5PqJxBgtTlz6tb06QeM5mf7LbbCjoY4/4psYE8mZhYtlxeFg5SW4XP?= =?us-ascii?Q?IaDCEKnB2GFjEoK+hmVx/lM5eW3RaY48Z1hKaV0I/V6yGbPu5fg1KbyRHHPW?= =?us-ascii?Q?dKNPQEoCb7grApOggr4eWY8EGM6kagL1wpJhda6AiqybGHpbvs2kBJP6P/+M?= =?us-ascii?Q?QWE4ihbNEgwwqoXYBnCmV3cY48ZIY1lUaJhkTGT5Q0lpEBP38IvUORvRqzNN?= =?us-ascii?Q?1xgUYCfSrK/ckeZCytF/tqNZVzlviizClwdukjnmNvcg81WRXQ4S4u8yW6Dx?= =?us-ascii?Q?0Si69gHU/oc/QJeiFd49r4IawcKsQwcO/gAZ9XGUoJlnWs1CqnTNBUfh7SB8?= =?us-ascii?Q?4CR7zAGpxL4x4CDyWFVM4/xh6OlNP4qqiPxMZZQ+umjWIxLXPH3GFoPUhj4O?= =?us-ascii?Q?rrH7KhclQVL3nR9/J7J09bUKeWvG3L+5bui8HQjmMWOilSEPJVzcmjaRsB9q?= =?us-ascii?Q?DzwW1ETLZQmhCuynZkOgc2hciKF7LXMTcmho/loUu+5CcmAFKqSxpy2IfB5U?= =?us-ascii?Q?wQ8cHHR8jH+cNYu5w8N9KS3pHUisehJGxcKYfJICTJjaywyI6PYvbywn+SlU?= =?us-ascii?Q?vuTscP8vyS//uEqRSSQNf8h/WidZOn7Rqx4IG3A5sO9OlwSRd1YDDYFsFL80?= =?us-ascii?Q?fOtWIRn8Ka61gD4WBGh1Y9Yqes8tTmjNxSlaw97jZvWdkAybAhTx4vQv2fMI?= =?us-ascii?Q?fXIz7ynHqjvKrunppjnNV3yJrwp4wROb191Pckv/GK+TuTH5dNfq2kjy6fqf?= =?us-ascii?Q?OwUmy/5alQPlaEVThvnbRsTLAmeT/qeFICcoYZqMh0/7YxbvHYQdErQS7AOS?= =?us-ascii?Q?IrLUb6W13xmckeKlB409QN4NnrURCUKAjYzKg02R2gF1Uza5sQSc4pdTFqjK?= =?us-ascii?Q?KZ2ExIUXB81kx4qYpFMrtx0Wm/G4oLr9wQvD0kyyy71ytv3YXI2PtgFrqxAg?= =?us-ascii?Q?IO5y+ZNyKBH0RzXJJsMChtkBaV+z3LUwLIwbtoRH4lhfVUvuC2i9WI9HdQmF?= =?us-ascii?Q?P5dimbD1vF8JX2rEtTowcTZ6Lr0hVi07/cOcjKUJt4FIIRoFsJEwgvGvpSpz?= =?us-ascii?Q?eIHYRhQpH0sKzFK/9hBFMG6KXi9aCLEHE/BU2+0+31hptfIivnj7zLyty7ZS?= =?us-ascii?Q?+6hzr6rrDcI/pUo3G1DEx9xeXjIVy6LIbUe7hVHvnggNN1I5dOHm2EE2YEBw?= =?us-ascii?Q?pEd//xgXtkF6Es6ubc8rGqLht+OcDyeyCVCbcmT+Co2gLo/oXS2EA/kUKK+H?= =?us-ascii?Q?8COVdRO3we/G+07mVs6Dulmnns0=3D?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: cbd18228-7d3a-4890-60d5-08d9a9ea593f X-MS-Exchange-CrossTenant-AuthSource: PH0PR01MB7287.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Nov 2021 16:50:23.7668 (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: N7rHON6p72Icp+wcd7qKVQNFtns3itfgISqaRmzxumToSwxP0Dt9GgC1wJPg2hS88cPHV1sX7Immn2F6tAsADWBfSP/180eJJ9eonqf4MOY= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR01MB7521 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 = | 1523 ++++++++++++++++++++ 3 files changed, 1556 insertions(+) diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon= /Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc index e13777934173..cea1ff6b26ef 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..898558db8d3b --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLibPci/PciSegmentLib.= c @@ -0,0 +1,1523 @@ +/** @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) + +#define WORD_ALIGN_MASK 0x3 +#define WORD_GET_BYTE(Word, ByteOffset) (((Word) >> ((Byte= Offset) * 8)) & 0xFF) +#define WORD_SET_BYTE(Word, Byte, ByteOffset) \ + (((Word) & ~(0xFF << ((ByteOffset) * 8))) | ((UINT32)(Byte) << ((ByteOff= set) * 8))) + +#define WORD_GET_HALF_WORD(Word, ByteOffset) (((Word) >> ((Byte= Offset) * 8)) & 0xFFFF) +#define WORD_SET_HALF_WORD(Word, HalfWord, ByteOffset) \ + (((Word) & ~(0xFFFF << ((ByteOffset) * 8))) | ((UINT32)(HalfWord) << ((B= yteOffset) * 8))) + +#define HEADER_TYPE_REG 0x0C +#define GET_HEADER_TYPE(x) (((x) >> 16) & 0x7F) +#define PRIMARY_BUS_NUMBER_REG 0x18 + +/** + 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 address from the segment number. +**/ +UINTN +GetMmcfgBase ( + IN UINT16 SegmentNumber + ) +{ + 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 SegmentNumber) { + 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 + ) +{ + UINT32 Val32; + UINT64 AlignedAddr; + UINT8 Value; + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + CfgBase =3D GetMmcfgBase (GET_SEG_NUM (Address)) + (Address & 0x0FFFFFFF= ); + AlignedAddr =3D CfgBase & ~WORD_ALIGN_MASK; + + Val32 =3D MmioRead32 (AlignedAddr); + Value =3D WORD_GET_BYTE (Val32, CfgBase & WORD_ALIGN_MASK); + + 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 (GET_SEG_NUM (Address)) + (Address & 0x0FFFFFFF= ); + AlignedAddr =3D CfgBase & ~WORD_ALIGN_MASK; + + Val32 =3D MmioRead32 (AlignedAddr); + Val32 =3D WORD_SET_BYTE (Val32, Value, CfgBase & WORD_ALIGN_MASK); + + MmioWrite32 (AlignedAddr, Val32); + + DEBUG (( + DEBUG_INFO, + "PCIe CFG WR8: 0x%p value: 0x%02X (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 + ) +{ + UINT16 Value; + UINT32 Val32; + UINT64 AlignedAddr; + UINT8 HeaderType; + UINT8 PrimaryBus; + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + PrimaryBus =3D 0; + CfgBase =3D GetMmcfgBase (GET_SEG_NUM (Address)) + (Address & 0x0FFFFFFE= ); + AlignedAddr =3D CfgBase & ~WORD_ALIGN_MASK; + + 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 RD16: B%X|D%X 0x%p value: 0x%08X\n", + GET_BUS_NUM (CfgBase), + GET_DEV_NUM (CfgBase), + CfgBase, + Value + )); + + if (Value !=3D 0xFFFF) { + Val32 =3D MmioRead32 (CfgBase + HEADER_TYPE_REG); + + HeaderType =3D GET_HEADER_TYPE (Val32); + DEBUG ((DEBUG_INFO, " Peek RD: HeaderType=3D0x%02X\n", HeaderType))= ; + + // Type 1 Configuration Space Header + if (HeaderType !=3D 0) { + PrimaryBus =3D MmioRead32 (CfgBase + PRIMARY_BUS_NUMBER_REG); + DEBUG ((DEBUG_INFO, " Peek RD: PrimaryBus=3D0x%02X\n", PrimaryBus= )); + } + + if ((HeaderType =3D=3D 0) || (PrimaryBus !=3D 0)) { + 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 Value; + } + } + } + + Val32 =3D MmioRead32 (AlignedAddr); + Value =3D WORD_GET_HALF_WORD (Val32, CfgBase & WORD_ALIGN_MASK); + + 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 (GET_SEG_NUM (Address)) + (Address & 0x0FFFFFFE= ); + AlignedAddr =3D CfgBase & ~WORD_ALIGN_MASK; + + Val32 =3D MmioRead32 (AlignedAddr); + Val32 =3D WORD_SET_HALF_WORD (Val32, Value, CfgBase & WORD_ALIGN_MASK); + + 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 Val32; + UINT32 Value; + UINT8 HeaderType; + UINT8 PrimaryBus; + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + PrimaryBus =3D 0; + CfgBase =3D GetMmcfgBase (GET_SEG_NUM (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) { + Val32 =3D MmioRead32 (CfgBase + HEADER_TYPE_REG); + + HeaderType =3D GET_HEADER_TYPE (Val32); + DEBUG ((DEBUG_INFO, " Peek RD: HeaderType=3D0x%02X\n", HeaderType))= ; + + // Type 1 Configuration Space Header + if (HeaderType !=3D 0) { + PrimaryBus =3D MmioRead32 (CfgBase + PRIMARY_BUS_NUMBER_REG); + DEBUG ((DEBUG_INFO, " Peek RD: PrimaryBus=3D0x%02X\n", PrimaryBus= )); + } + + if ((HeaderType =3D=3D 0) || (PrimaryBus !=3D 0)) { + Value =3D 0xFFFFFFFF; + DEBUG (( + DEBUG_INFO, + " Skip RD32 B%X|D%X PCIe CFG RD: 0x%p return 0xFFFFFFFF\n", + GET_BUS_NUM (CfgBase), + GET_DEV_NUM (CfgBase), + CfgBase + )); + return Value; + } + } + } 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 + ) +{ + UINTN CfgBase; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + CfgBase =3D GetMmcfgBase (GET_SEG_NUM (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