From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.1.71; helo=eur01-ve1-obe.outbound.protection.outlook.com; envelope-from=vabhav.sharma@nxp.com; receiver=edk2-devel@lists.01.org Received: from EUR01-VE1-obe.outbound.protection.outlook.com (mail-ve1eur01on0071.outbound.protection.outlook.com [104.47.1.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 5407521EBD1CC for ; Thu, 19 Apr 2018 23:40:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=RM0SoOZco+EcFjYTHGe29vXtdyOky5Cjz5DjvUmg2vE=; b=D9K57wUBpYpufw5/64+vKPsNxxZYMtD7YpYIRFsB9l1YElnMTxNXQg5J85r0q8zdXaFOFu5SYx+YwQUrstHukWJSc3X634CvF4oNq66p8rqhjYhFYvf0YwZwRSX45Tvt5CFL8jLbalEnlpQU9LZiB4JQZm2nnttUO7cDSZm9Ws8= Received: from DB4PR04MB299.eurprd04.prod.outlook.com (10.141.239.21) by DB4PR04MB0783.eurprd04.prod.outlook.com (10.242.222.22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.696.13; Fri, 20 Apr 2018 06:40:28 +0000 Received: from DB4PR04MB299.eurprd04.prod.outlook.com ([fe80::2dcd:1bc7:8d4e:5dc2]) by DB4PR04MB299.eurprd04.prod.outlook.com ([fe80::2dcd:1bc7:8d4e:5dc2%15]) with mapi id 15.20.0675.015; Fri, 20 Apr 2018 06:40:27 +0000 From: Vabhav Sharma To: Leif Lindholm , Meenakshi Aggarwal CC: "ard.biesheuvel@linaro.org" , "edk2-devel@lists.01.org" , Udit Kumar , Varun Sethi Thread-Topic: [PATCH edk2-platforms 32/39] Silicon/NXP: Implement PciSegmentLib to support multiple RCs Thread-Index: AQHTpwPSsYa6nWGpX0Sp5+KXPgod+6QI2t+AgAClscA= Date: Fri, 20 Apr 2018 06:40:27 +0000 Message-ID: References: <1518771035-6733-1-git-send-email-meenakshi.aggarwal@nxp.com> <1518771035-6733-33-git-send-email-meenakshi.aggarwal@nxp.com> <20180419192727.zj3xb3dcf4zjsl2x@bivouac.eciton.net> In-Reply-To: <20180419192727.zj3xb3dcf4zjsl2x@bivouac.eciton.net> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: linaro.org; dkim=none (message not signed) header.d=none;linaro.org; dmarc=none action=none header.from=nxp.com; x-originating-ip: [14.142.187.166] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DB4PR04MB0783; 7:kpVmaTP3ncGMxPBPrvCwYvTxj+q3hjXssCHUrZOhRjjuEEV7aKymnR2io8T4emYXNMFX7OVmNc3TbQcw9eYaTlilOfjKNB9RUcDFJhw+QDgJmq6PB93YhThEByZRNzto7cu8TnDV2j5EtIVPgPnkTaRdXDPh94uL/dokQKCLRVmS6xMPdarumUTxDfmR3fQu6l75KlE+Kl3GuKTpRwYqKB9E4EdZROUAtCSuyE/0gkXTdTaOnZrHZRaRSk/Rz643 x-ms-exchange-antispam-srfa-diagnostics: SOS; x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(5600026)(4534165)(7168020)(4627221)(201703031133081)(201702281549075)(48565401081)(2017052603328)(7153060)(7193020); SRVR:DB4PR04MB0783; x-ms-traffictypediagnostic: DB4PR04MB0783: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(189930954265078)(185117386973197)(162533806227266)(45079756050767); x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(3002001)(93006095)(93001095)(10201501046)(3231232)(944501391)(52105095)(6055026)(6041310)(20161123558120)(20161123560045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123564045)(6072148)(201708071742011); SRVR:DB4PR04MB0783; BCL:0; PCL:0; RULEID:; SRVR:DB4PR04MB0783; x-forefront-prvs: 0648FCFFA8 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(346002)(39860400002)(376002)(39380400002)(366004)(396003)(13464003)(6506007)(53936002)(53946003)(4326008)(11346002)(6246003)(9686003)(5660300001)(55016002)(6306002)(476003)(446003)(102836004)(55236004)(33656002)(66066001)(2900100001)(5250100002)(16799955002)(59450400001)(54906003)(305945005)(44832011)(74316002)(76176011)(7696005)(110136005)(6636002)(81166006)(3846002)(45080400002)(6116002)(478600001)(316002)(229853002)(6436002)(3280700002)(8676002)(186003)(7736002)(3660700001)(25786009)(86362001)(2906002)(575784001)(26005)(8936002)(579004)(559001)(19627235001); DIR:OUT; SFP:1101; SCL:1; SRVR:DB4PR04MB0783; H:DB4PR04MB299.eurprd04.prod.outlook.com; FPR:; SPF:None; LANG:en; MLV:sfv; x-microsoft-antispam-message-info: RqQFMRGoYuK30gJomuowVUo9h6rt2+DFmoVDbVEjuy9vqnJIGYQpHq0LGdOzsDfo1RKyh9Tzo8MkYCXt2OHtrKjhM6vrVHQ0AM8DE+xIQudv/yj+UmRgeUBsGACI6YdfLcLI9ze0fCuYWNDA/VQkxZh7cxND816JkKeXHP/mCqH65WKnfRFFQabDzth37TsP spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 53faa2f6-cbe3-444a-f6be-08d5a6899abf X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 53faa2f6-cbe3-444a-f6be-08d5a6899abf X-MS-Exchange-CrossTenant-originalarrivaltime: 20 Apr 2018 06:40:27.7139 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB4PR04MB0783 Subject: Re: [PATCH edk2-platforms 32/39] Silicon/NXP: Implement PciSegmentLib to support multiple RCs X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Apr 2018 06:40:34 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable >-----Original Message----- >From: Leif Lindholm [mailto:leif.lindholm@linaro.org] >Sent: Friday, April 20, 2018 12:57 AM >To: Meenakshi Aggarwal >Cc: ard.biesheuvel@linaro.org; edk2-devel@lists.01.org; Udit Kumar >; Varun Sethi ; Vabhav Sharma > >Subject: Re: [PATCH edk2-platforms 32/39] Silicon/NXP: Implement >PciSegmentLib to support multiple RCs > >On Fri, Feb 16, 2018 at 02:20:28PM +0530, Meenakshi wrote: >> From: Vabhav >> >> Multiple root complex support is not provided by standard library >> PciLib/PciExpressLib/PciSegmentLib, Reimplementing it and provide >> function for reading/writing into PCIe configuration Space. >> >> Contributed-under: TianoCore Contribution Agreement 1.1 >> Signed-off-by: Vabhav >> Signed-off-by: Meenakshi Aggarwal >> --- >> Silicon/NXP/Include/Pcie.h | 143 +++++ >> Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.c | 604 >+++++++++++++++++++++ >> .../NXP/Library/PciSegmentLib/PciSegmentLib.inf | 41 ++ >> 3 files changed, 788 insertions(+) >> create mode 100644 Silicon/NXP/Include/Pcie.h create mode 100644 >> Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.c >> create mode 100644 >> Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.inf >> >> diff --git a/Silicon/NXP/Include/Pcie.h b/Silicon/NXP/Include/Pcie.h >> new file mode 100644 index 0000000..a7e6f9b >> --- /dev/null >> +++ b/Silicon/NXP/Include/Pcie.h >> @@ -0,0 +1,143 @@ >> +/** @file >> + PCI memory configuration for NXP >> + >> + Copyright 2018 NXP >> + >> + This program and the accompanying materials are licensed and made >> + available under the terms and conditions of the BSD License which >> + accompanies this distribution. The full text of the license may be >> + found at >https://emea01.safelinks.protection.outlook.com/?url=3Dhttp%3A%2F%2Fopenso= u >rce.org%2Flicenses%2Fbsd- >license.php&data=3D02%7C01%7Cvabhav.sharma%40nxp.com%7C081a2ebc43af4a >daaf8e08d5a62b9921%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6 >36597628604269440&sdata=3Dkt661HfkUD2E3sYswy0I4vVFTV3%2Fq%2FiM%2BiW >egCISP%2BU%3D&reserved=3D0. >> + >> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" >> + BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER >EXPRESS OR IMPLIED. >> + >> +**/ >> + >> +#ifndef __PCI_H__ >> +#define __PCI_H__ > >I'm not super happy about reusing such a generic name for the include guar= d - or >really even the filename. (MdePkg/Include/Pci.h has >_PCI_H_.) > >Could you rename this header NxpPcie.h and change the include guard to >_NXP_PCIE_H_? I see, Sure. > >> + >> +// Segment 0 >> +#define PCI_SEG0_NUM 0 >> + >> +#define PCI_SEG0_BUSNUM_MIN 0x0 >> +#define PCI_SEG0_BUSNUM_MAX 0xff >> + >> +#define PCI_SEG0_PORTIO_MIN 0x0 >> +#define PCI_SEG0_PORTIO_MAX 0xffff >> + >> +#define PCI_SEG0_MMIO32_MIN 0x40000000 >> +#define PCI_SEG0_MMIO32_MAX 0x4fffffff >> +#define PCI_SEG0_MMIO64_MIN PCI_SEG0_MMIO_MEMBASE + >SEG_MEM_SIZE >> +#define PCI_SEG0_MMIO64_MAX PCI_SEG0_MMIO_MEMBASE + >SEG_MEM_LIMIT >> +#define PCI_SEG0_MMIO_MEMBASE FixedPcdGet64 (PcdPciExp1BaseAddr) >> + >> +#define PCI_SEG0_DBI_BASE 0x03400000 >> + >> +// Segment 1 >> +#define PCI_SEG1_NUM 1 >> + >> +#define PCI_SEG1_BUSNUM_MIN 0x0 >> +#define PCI_SEG1_BUSNUM_MAX 0xff >> + >> +#define PCI_SEG1_PORTIO_MIN 0x10000 >> +#define PCI_SEG1_PORTIO_MAX 0x1ffff >> + >> +#define PCI_SEG1_MMIO32_MIN 0x50000000 >> +#define PCI_SEG1_MMIO32_MAX 0x5fffffff >> +#define PCI_SEG1_MMIO64_MIN PCI_SEG1_MMIO_MEMBASE + >SEG_MEM_SIZE >> +#define PCI_SEG1_MMIO64_MAX PCI_SEG1_MMIO_MEMBASE + >SEG_MEM_LIMIT >> +#define PCI_SEG1_MMIO_MEMBASE FixedPcdGet64 (PcdPciExp2BaseAddr) >> + >> +#define PCI_SEG1_DBI_BASE 0x03500000 >> + >> +// Segment 2 >> +#define PCI_SEG2_NUM 2 >> + >> +#define PCI_SEG2_BUSNUM_MIN 0x0 >> +#define PCI_SEG2_BUSNUM_MAX 0xff >> + >> +#define PCI_SEG2_PORTIO_MIN 0x20000 >> +#define PCI_SEG2_PORTIO_MAX 0x2ffff >> + >> +#define PCI_SEG2_MMIO32_MIN 0x60000000 >> +#define PCI_SEG2_MMIO32_MAX 0x6fffffff >> +#define PCI_SEG2_MMIO64_MIN PCI_SEG2_MMIO_MEMBASE + >SEG_MEM_SIZE >> +#define PCI_SEG2_MMIO64_MAX PCI_SEG2_MMIO_MEMBASE + >SEG_MEM_LIMIT >> +#define PCI_SEG2_MMIO_MEMBASE FixedPcdGet64 (PcdPciExp3BaseAddr) >> + >> +#define PCI_SEG2_DBI_BASE 0x03600000 >> + >> +// Segment 3 >> +#define PCI_SEG3_NUM 3 >> + >> +#define PCI_SEG3_BUSNUM_MIN 0x0 >> +#define PCI_SEG3_BUSNUM_MAX 0xff >> + >> +#define PCI_SEG3_PORTIO_MIN 0x30000 >> +#define PCI_SEG3_PORTIO_MAX 0x3ffff >> + >> +#define PCI_SEG3_MMIO32_MIN 0x70000000 >> +#define PCI_SEG3_MMIO32_MAX 0x7fffffff >> +#define PCI_SEG3_MMIO64_MIN PCI_SEG3_MMIO_MEMBASE + >SEG_MEM_SIZE >> +#define PCI_SEG3_MMIO64_MAX PCI_SEG3_MMIO_MEMBASE + >SEG_MEM_LIMIT >> +#define PCI_SEG3_MMIO_MEMBASE FixedPcdGet64 (PcdPciExp4BaseAddr) >> + >> +#define PCI_SEG3_DBI_BASE 0x03700000 >> + >> +// Segment configuration >> +#define SEG_CFG_SIZE 0x00001000 >> +#define SEG_CFG_BUS 0x00000000 >> +#define SEG_MEM_SIZE 0x40000000 >> +#define SEG_MEM_LIMIT 0x7fffffff >> +#define SEG_MEM_BUS 0x40000000 >> +#define SEG_IO_SIZE 0x00010000 >> +#define SEG_IO_BUS 0x00000000 >> +#define PCI_BASE_DIFF 0x800000000 >> +#define PCI_DBI_SIZE_DIFF 0x100000 >> +#define PCI_SEG0_PHY_CFG0_BASE PCI_SEG0_MMIO_MEMBASE >> +#define PCI_SEG0_PHY_CFG1_BASE PCI_SEG0_PHY_CFG0_BASE + >SEG_CFG_SIZE >> +#define PCI_SEG0_PHY_MEM_BASE PCI_SEG0_MMIO64_MIN >> +#define PCI_SEG0_PHY_IO_BASE PCI_SEG0_MMIO_MEMBASE + >SEG_IO_SIZE >> + >> +// iATU configuration >> +#define IATU_VIEWPORT_OFF 0x900 >> +#define IATU_VIEWPORT_OUTBOUND 0 >> + >> +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0 0x904 >> +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM 0x0 >> +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO 0x2 >> +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0 0x4 #define >> +IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1 0x5 >> + >> +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0 0x908 >> +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN BIT31 >> + >> +#define IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0 0x90C >> +#define IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0 0x910 >> +#define IATU_LIMIT_ADDR_OFF_OUTBOUND_0 0x914 >> +#define IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0 0x918 >> +#define IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0 0x91C >> + >> +#define IATU_REGION_INDEX0 0x0 >> +#define IATU_REGION_INDEX1 0x1 >> +#define IATU_REGION_INDEX2 0x2 >> +#define IATU_REGION_INDEX3 0x3 >> + >> +// PCIe Controller configuration >> +#define NUM_PCIE_CONTROLLER FixedPcdGet32 (PcdNumPciController) >> +#define PCI_LUT_DBG FixedPcdGet32 (PcdPcieLutDbg) >> +#define PCI_LUT_BASE FixedPcdGet32 (PcdPcieLutBase) >> +#define LTSSM_STATE_MASK 0x3f >> +#define LTSSM_PCIE_L0 0x11 >> +#define PCI_LINK_CAP 0x7c >> +#define PCI_LINK_SPEED_MASK 0xf >> +#define PCI_CLASS_BRIDGE_PCI 0x6040010 >> +#define PCI_CLASS_DEVICE 0x8 >> +#define PCI_DBI_RO_WR_EN 0x8bc >> +#define PCI_BASE_ADDRESS_0 0x10 >> + >> +VOID GetSerdesProtocolMaps (UINT64 *); >> + >> +BOOLEAN IsSerDesLaneProtocolConfigured (UINT64, UINT16); >> + >> +#endif >> diff --git a/Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.c >> b/Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.c >> new file mode 100644 >> index 0000000..acb614d >> --- /dev/null >> +++ b/Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.c >> @@ -0,0 +1,604 @@ >> +/** @file >> + PCI Segment Library for NXP SoCs with multiple RCs >> + >> + Copyright 2018 NXP >> + >> + This program and the accompanying materials are licensed and made >> + available under the terms and conditions of the BSD License which >> + accompanies this distribution. The full text of the license may be >> + found at >> + >https://emea01.safelinks.protection.outlook.com/?url=3Dhttp%3A%2F%2Fopenso= u >rce.org%2Flicenses%2Fbsd- >license.php&data=3D02%7C01%7Cvabhav.sharma%40nxp.com%7C081a2ebc43af4a >daaf8e08d5a62b9921%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6 >36597628604269440&sdata=3Dkt661HfkUD2E3sYswy0I4vVFTV3%2Fq%2FiM%2BiW >egCISP%2BU%3D&reserved=3D0. >> + >> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" >> + BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER >EXPRESS OR IMPLIED. >> + >> +**/ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +typedef enum { >> + PciCfgWidthUint8 =3D 0, >> + PciCfgWidthUint16, >> + PciCfgWidthUint32, >> + PciCfgWidthMax >> +} PCI_CFG_WIDTH; >> + >> +/** >> + 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) >> + >> +/** >> + Function to return PCIe Physical Address(PCIe view) or Controller >> + Address(CPU view) for different RCs >> + >> + @param Address Address passed from bus layer. >> + @param Segment Segment number for Root Complex. >> + >> + @return Return PCIe CPU or Controller address. >> + >> +**/ >> +STATIC >> +UINT64 >> +PciSegmentLibGetConfigBase ( >> + IN UINT64 Address, >> + IN UINT16 Segment >> + ) >> +{ >> + >> + switch (Segment) { >> + // Root Complex 1 >> + case PCI_SEG0_NUM: >> + // Reading bus number(bits 20-27) >> + if ((Address >> 20) & 1) { >> + return PCI_SEG0_MMIO_MEMBASE; >> + } else { >> + // On Bus 0 RCs are connected >> + return PCI_SEG0_DBI_BASE; >> + } >> + // Root Complex 2 >> + case PCI_SEG1_NUM: >> + // Reading bus number(bits 20-27) >> + if ((Address >> 20) & 1) { >> + return PCI_SEG1_MMIO_MEMBASE; >> + } else { >> + // On Bus 0 RCs are connected >> + return PCI_SEG1_DBI_BASE; >> + } >> + // Root Complex 3 >> + case PCI_SEG2_NUM: >> + // Reading bus number(bits 20-27) >> + if ((Address >> 20) & 1) { >> + return PCI_SEG2_MMIO_MEMBASE; >> + } else { >> + // On Bus 0 RCs are connected >> + return PCI_SEG2_DBI_BASE; >> + } >> + // Root Complex 4 >> + case PCI_SEG3_NUM: >> + // Reading bus number(bits 20-27) >> + if ((Address >> 20) & 1) { >> + return PCI_SEG3_MMIO_MEMBASE; >> + } else { >> + // On Bus 0 RCs are connected >> + return PCI_SEG3_DBI_BASE; >> + } >> + default: >> + return 0; >> + } >> + >> +} >> + >> +/** >> + Internal worker function to read a PCI configuration register. >> + >> + @param Address The address that encodes the Segment, PCI Bus, Device= , >> + Function and Register. >> + @param Width The width of data to read >> + >> + @return The value read from the PCI configuration register. >> + >> +**/ >> +STATIC >> +UINT32 >> +PciSegmentLibReadWorker ( >> + IN UINT64 Address, >> + IN PCI_CFG_WIDTH Width >> + ) >> +{ >> + UINT64 Base; >> + UINT16 Offset; >> + UINT16 Segment; >> + >> + // >> + // Reading Segment number(47-32) bits in Address // Segment =3D >> + (Address >> 32); // // Reading Function(12-0) bits in Address // >> + Offset =3D (Address & 0xfff ); >> + >> + Base =3D PciSegmentLibGetConfigBase (Address, Segment); >> + >> + // >> + // ignore devices > 0 on bus 0 >> + // >> + if ((Address & 0xff00000) =3D=3D 0 && (Address & 0xf8000) !=3D 0) { >> + return MAX_UINT32; >> + } >> + >> + // >> + // ignore device > 0 on bus 1 >> + // >> + if ((Address & 0xfe00000) =3D=3D 0 && (Address & 0xf8000) !=3D 0) { >> + return MAX_UINT32; >> + } >> + >> + switch (Width) { >> + case PciCfgWidthUint8: >> + return MmioRead8 (Base + (UINT8)Offset); case PciCfgWidthUint16: >> + return MmioRead16 (Base + (UINT16)Offset); case >> + PciCfgWidthUint32: >> + return MmioRead32 (Base + (UINT32)Offset); >> + default: >> + ASSERT (FALSE); >> + } >> + >> + return CHAR_NULL; >> +} >> + >> +/** >> + Internal worker function to writes a PCI configuration register. >> + >> + @param Address The address that encodes the Segment, PCI Bus, Device= , >> + Function and Register. >> + @param Width The width of data to write >> + @param Data The value to write. >> + >> + @return The value written to the PCI configuration register. >> + >> +**/ >> +STATIC >> +UINT32 >> +PciSegmentLibWriteWorker ( >> + IN UINT64 Address, >> + IN PCI_CFG_WIDTH Width, >> + IN UINT32 Data >> + ) >> +{ >> + UINT64 Base; >> + UINT32 Offset; >> + UINT16 Segment; >> + >> + // >> + // Reading Segment number(47-32 bits) in Address Segment =3D >> + (Address >> 32); // // Reading Function(12-0 bits) in Address // >> + Offset =3D (Address & 0xfff ); > >Spurious space after 0xfff. Alright, Thanks. Same applies to PciSegmentLibReadWorker() > >Could we have some macros and #defines instead of live-coded values in thi= s >function? Sure, I assume Similar changes in PciSegmentLibReadWorker() required. > >> + >> + Base =3D PciSegmentLibGetConfigBase (Address, Segment); >> + >> + // >> + // ignore devices > 0 on bus 0 >> + // >> + if ((Address & 0xff00000) =3D=3D 0 && (Address & 0xf8000) !=3D 0) { >> + return Data; >> + } >> + >> + // >> + // ignore device > 0 on bus 1 >> + // >> + if ((Address & 0xfe00000) =3D=3D 0 && (Address & 0xf8000) !=3D 0) { >> + return MAX_UINT32; >> + } >> + >> + switch (Width) { >> + case PciCfgWidthUint8: >> + MmioWrite8 (Base + (UINT8)Offset, Data); >> + break; >> + case PciCfgWidthUint16: >> + MmioWrite16 (Base + (UINT16)Offset, Data); >> + break; >> + case PciCfgWidthUint32: >> + MmioWrite32 (Base + (UINT16)Offset, Data); >> + break; >> + default: >> + ASSERT (FALSE); >> + } >> + >> + return Data; >> +} >> + >> +/** >> + Register a PCI device so PCI configuration registers may be >> +accessed after >> + SetVirtualAddressMap(). >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Bus= , Device, >> + Function and Register. >> + >> + @retval RETURN_SUCCESS The PCI device was registered for ru= ntime >access. >> + @retval RETURN_UNSUPPORTED An attempt was made to call this >function >> + after ExitBootServices(). >> + @retval RETURN_UNSUPPORTED The resources required to access the >PCI device >> + at runtime could not be mapped. >> + @retval RETURN_OUT_OF_RESOURCES There are not enough resources >available 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 A= ddress. >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Segment, Bus, Devi= ce, >Function, >> + 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); >> + >> + return (UINT8) PciSegmentLibReadWorker (Address, PciCfgWidthUint8); >> +} >> + >> +/** >> + Writes an 8-bit PCI configuration register. >> + >> + Writes the 8-bit PCI configuration register specified by Address with= the value >specified by Value. >> + Value is returned. This function must guarantee that all PCI read an= d write >operations are serialized. >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Segment, Bus, De= vice, >Function, 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 >> + ) >> +{ >> + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); >> + >> + return (UINT8) PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, >> +Value); } >> + >> +/** >> + Reads a 16-bit PCI configuration register. >> + >> + Reads and returns the 16-bit PCI configuration register specified by = Address. >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + If Address is not aligned on a 16-bit boundary, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Segment, Bus, Devi= ce, >Function, 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); >> + >> + return (UINT16) PciSegmentLibReadWorker (Address, >> +PciCfgWidthUint16); } >> + >> +/** >> + Writes a 16-bit PCI configuration register. >> + >> + Writes the 16-bit PCI configuration register specified by Address >> + with the value specified by Value. >> + >> + Value is returned. >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + If Address is not aligned on a 16-bit boundary, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Segment, Bus, De= vice, >Function, and Register. >> + @param Value The value to write. >> + >> + @return The parameter of Value. >> + >> +**/ >> +UINT16 >> +EFIAPI >> +PciSegmentWrite16 ( >> + IN UINT64 Address, >> + IN UINT16 Value >> + ) >> +{ >> + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); >> + >> + return (UINT16) PciSegmentLibWriteWorker (Address, >> +PciCfgWidthUint16, Value); } >> + >> +/** >> + Reads a 32-bit PCI configuration register. >> + >> + Reads and returns the 32-bit PCI configuration register specified by = Address. >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + If Address is not aligned on a 32-bit boundary, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Segment, Bus, Devi= ce, >Function, >> + and Register. >> + >> + @return The 32-bit PCI configuration register specified by Address. >> + >> +**/ >> +UINT32 >> +EFIAPI >> +PciSegmentRead32 ( >> + IN UINT64 Address >> + ) >> +{ >> + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); >> + >> + return PciSegmentLibReadWorker (Address, PciCfgWidthUint32); } >> + >> +/** >> + Writes a 32-bit PCI configuration register. >> + >> + Writes the 32-bit PCI configuration register specified by Address >> + with the value specified by Value. >> + >> + Value is returned. >> + >> + If any reserved bits in Address are set, then ASSERT(). >> + If Address is not aligned on a 32-bit boundary, then ASSERT(). >> + >> + @param Address The address that encodes the PCI Segment, Bus, De= vice, >> + Function, 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); >> + >> + return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, >> +Value); } >> + >> +/** >> + Reads a range of PCI configuration registers into a caller supplied b= uffer. >> + >> + 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. >> + >> + 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 The starting address that encodes the PCI Segme= nt, >Bus, >> + Device, Function and Register. >> + @param Size The size in bytes of the transfer. >> + @param Buffer The 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); // 0xFFF is >> + used as limit for 4KB config space 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); > >Why volatile on Buffer? I took reference from Socionext, Not required . PCIe region has device attribute. > >> + StartAddress +=3D sizeof (UINT8); >> + Size -=3D sizeof (UINT8); >> + Buffer =3D (UINT8*)Buffer + BIT0; > >sizeof (UINT8) instead of BIT0? > >And this is a VOID *, so can just write. > Buffer +=3D sizeof (UINT8); > Yes,Sure. >> + } >> + >> + 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 + BIT0; > >That is a very confusing use of pointer arithmetic. > Buffer +=3D sizeof (UINT16); > Agree, alright. >> + } >> + >> + 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 + BIT0; > > Buffer +=3D sizeof (UINT32); Ok > >> + } >> + >> + 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 + BIT0; > > Buffer +=3D sizeof (UINT16); Ok > >> + } >> + >> + if (Size >=3D sizeof (UINT8)) { >> + // >> + // Read the last remaining byte if exist >> + // >> + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); > >There is that scary volatile again. Not required. > >> + } >> + >> + 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 >> + StartAddress 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 is returned. >> + >> + 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 The starting address that encodes the PCI Segme= nt, >Bus, >> + Device, Function and Register. >> + @param Size The size in bytes of the transfer. >> + @param Buffer The 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); // 0xFFF is >> + used as limit for 4KB config space ASSERT (((StartAddress & 0xFFF) >> + + Size) <=3D SIZE_4KB); > >Can you use (SIZE_4KB - 1) instead of 0xFFF? Yes,Sure. > >> + >> + 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 + BIT0; > >Same comments for Buffer pointer update as previous function, throughout. Ok > >/ > Leif > >> + } >> + >> + 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 + BIT0; >> + } >> + >> + 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 + BIT0; >> + } >> + >> + 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 + BIT0; >> + } >> + >> + if (Size >=3D sizeof (UINT8)) { >> + // >> + // Write the last remaining byte if exist >> + // >> + PciSegmentWrite8 (StartAddress, *(UINT8*)Buffer); } >> + >> + return ReturnValue; >> +} >> diff --git a/Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.inf >> b/Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.inf >> new file mode 100644 >> index 0000000..1ac83d4 >> --- /dev/null >> +++ b/Silicon/NXP/Library/PciSegmentLib/PciSegmentLib.inf >> @@ -0,0 +1,41 @@ >> +## @file >> +# PCI Segment Library for NXP SoCs with multiple RCs # # Copyright >> +2018 NXP # # This program and the accompanying materials # are >> +licensed and made available under the terms and conditions of the BSD >> +License # which accompanies this distribution. The full text of the >> +license may be found at # >https://emea01.safelinks.protection.outlook.com/?url=3Dhttp%3A%2F%2Fopenso= u >rce.org%2Flicenses%2Fbsd- >license.php&data=3D02%7C01%7Cvabhav.sharma%40nxp.com%7C081a2ebc43af4a >daaf8e08d5a62b9921%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6 >36597628604269440&sdata=3Dkt661HfkUD2E3sYswy0I4vVFTV3%2Fq%2FiM%2BiW >egCISP%2BU%3D&reserved=3D0. >> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" >> +BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, >EITHER EXPRESS OR IMPLIED. >> +# >> +# >> +## >> + >> +[Defines] >> + INF_VERSION =3D 0x0001001A >> + BASE_NAME =3D PciSegmentLib >> + FILE_GUID =3D c9f59261-5a60-4a4c-82f6-1f520442e1= 00 >> + MODULE_TYPE =3D BASE >> + VERSION_STRING =3D 1.0 >> + LIBRARY_CLASS =3D PciSegmentLib >> + >> +[Sources] >> + PciSegmentLib.c >> + >> +[Packages] >> + MdePkg/MdePkg.dec >> + Silicon/NXP/NxpQoriqLs.dec >> + >> +[LibraryClasses] >> + BaseLib >> + DebugLib >> + IoLib >> + PcdLib >> + >> +[Pcd] >> + gNxpQoriqLsTokenSpaceGuid.PcdPciExp1BaseAddr >> + gNxpQoriqLsTokenSpaceGuid.PcdPciExp2BaseAddr >> + gNxpQoriqLsTokenSpaceGuid.PcdPciExp3BaseAddr >> + gNxpQoriqLsTokenSpaceGuid.PcdPciExp4BaseAddr >> -- >> 1.9.1 >>