summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2019-03-12 17:57:58 +0100
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2019-03-12 18:01:47 +0100
commitdb3c129322c70c6ea15d681dec8fe405bb775218 (patch)
tree37dbdf84b5a09f03fde5009958ddb536b99b5b55
parentd6253d2f9a33831565eb6167fd34a5b2de98046a (diff)
CcixPkg: add PoC code for CcixIo and Ccix Pcie transport driverccix
Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
-rw-r--r--CcixPkg/CcixPkg.dec43
-rw-r--r--CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.c318
-rw-r--r--CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.inf49
-rw-r--r--CcixPkg/Include/Protocol/CcixIo.h73
4 files changed, 483 insertions, 0 deletions
diff --git a/CcixPkg/CcixPkg.dec b/CcixPkg/CcixPkg.dec
new file mode 100644
index 0000000000..015df87b96
--- /dev/null
+++ b/CcixPkg/CcixPkg.dec
@@ -0,0 +1,43 @@
+#/** @file
+# CCIX support package
+#
+# Copyright (c) 2019, Linaro Ltd. All rights reserved.
+#
+# 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
+# http://opensource.org/licenses/bsd-license.php
+#
+# 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]
+ DEC_SPECIFICATION = 1.27
+ PACKAGE_NAME = CcixPkg
+ PACKAGE_GUID = 0bc3e281-6818-43c0-b07b-9601293d3a0a
+ PACKAGE_VERSION = 0.1
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+# Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+[Includes]
+ Include # Root include for the package
+
+[Guids]
+ gCcixTokenSpaceGuid = { 0x4e7bbb19, 0x2f2d, 0x4ff4, { 0x93, 0xac, 0x09, 0x41, 0x5d, 0x14, 0x9f, 0x43 } }
+
+[Protocols]
+ ## Include/Protocol/CcixIo.h
+ gCcixIoProtocolGuid = { 0x76ac4eb3, 0xbaa8, 0x43d4, { 0x8c, 0xb8, 0x16, 0x66, 0x8b, 0xb6, 0xfa, 0xad } }
+
+[PcdsFixedAtBuild]
+ gCcixTokenSpaceGuid.PcdCcixTransportPcieSegment|0x0|UINT32|0x00000001
+ gCcixTokenSpaceGuid.PcdCcixTransportPcieBusStart|0x0|UINT32|0x00000002
diff --git a/CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.c b/CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.c
new file mode 100644
index 0000000000..18d454e5b3
--- /dev/null
+++ b/CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.c
@@ -0,0 +1,318 @@
+/** @file
+
+ CCIX PCIe transport driver
+
+ Copyright (c) 2019, Linaro Limited. All rights reserved.
+
+ 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
+ http://opensource.org/licenses/bsd-license.php
+
+ 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 <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/CcixIo.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#define CCIX_IO_PCI_DEVICE_SIGNATURE SIGNATURE_32 ('C', 'C', 'X', 'P')
+
+typedef struct {
+ UINT32 Signature;
+ CCIX_IO_PROTOCOL CcixIo;
+ UINT64 CapAddress; // TODO use 2 address for 2 cap structures
+} CCIX_IO_PCI_DEVICE;
+
+#define CCIX_IO_PCI_DEVICE_FROM_CCIX_IO(p) \
+ CR (p, CCIX_IO_PCI_DEVICE, CcixIo, CCIX_IO_PCI_DEVICE_SIGNATURE)
+
+STATIC EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *mCcixPcieRootBridgeIo;
+
+STATIC
+BOOLEAN
+IsPciBridge (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function,
+ OUT UINT8 *Secondary
+ )
+{
+ UINT8 ClassCode[3];
+ EFI_STATUS Status;
+ UINTN Reg;
+
+ Reg = OFFSET_OF (PCI_TYPE_GENERIC, Bridge.Hdr.ClassCode);
+ Status = mCcixPcieRootBridgeIo->Pci.Read (mCcixPcieRootBridgeIo, EfiPciWidthUint8,
+ EFI_PCI_ADDRESS (Bus, Device, Function, Reg),
+ ARRAY_SIZE (ClassCode), ClassCode);
+ if (EFI_ERROR (Status) ||
+ ClassCode[2] != PCI_CLASS_BRIDGE ||
+ ClassCode[1] != PCI_CLASS_BRIDGE_P2P) {
+ return FALSE;
+ }
+
+ Reg = OFFSET_OF (PCI_TYPE_GENERIC, Bridge.Bridge.SecondaryBus);
+ Status = mCcixPcieRootBridgeIo->Pci.Read (mCcixPcieRootBridgeIo, EfiPciWidthUint8,
+ EFI_PCI_ADDRESS (Bus, Device, Function, Reg),
+ 1, Secondary);
+ ASSERT_EFI_ERROR (Status);
+
+ return TRUE;
+}
+
+STATIC
+BOOLEAN
+IsCcixDevice (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function,
+ OUT UINTN *CapOffset
+ )
+{
+ // look for DVSEC capability in the ECAM space and return it if found
+ UINTN Offset;
+ UINTN Reg;
+ EFI_STATUS Status;
+ UINT8 HeaderType;
+ UINT16 Cap[2];
+
+ Reg = OFFSET_OF (PCI_TYPE_GENERIC, Bridge.Hdr.HeaderType);
+ Status = mCcixPcieRootBridgeIo->Pci.Read (mCcixPcieRootBridgeIo, EfiPciWidthUint8,
+ EFI_PCI_ADDRESS (Bus, Device, Function, Reg),
+ 1, &HeaderType);
+
+ if (EFI_ERROR (Status) ||
+ (HeaderType & HEADER_LAYOUT_CODE) != HEADER_TYPE_DEVICE) {
+ return FALSE;
+ }
+
+ Offset = EFI_PCIE_CAPABILITY_BASE_OFFSET;
+ do {
+ Status = mCcixPcieRootBridgeIo->Pci.Read (mCcixPcieRootBridgeIo, EfiPciWidthUint16,
+ EFI_PCI_ADDRESS (Bus, Device, Function, Offset),
+ ARRAY_SIZE (Cap), Cap);
+ if (EFI_ERROR (Status) || Cap[0] == 0xffff) {
+ return FALSE;
+ }
+
+ // TODO find both types of capability structure
+ if (Cap[0] == 0x23) {
+ *CapOffset = Offset + 2;
+ return TRUE;
+ }
+
+ Offset = Cap[1] >> 4;
+ } while (Cap[0] != 0);
+
+ return FALSE;
+}
+
+/**
+ Reads a logical DVSEC address in the specified CCIX DVSEC region.
+
+ @param This A pointer to the EFI_CCIX_IO_PROTOCOL instance.
+ @param RegionType Specifies the type of DVSEC region.
+ @param Address Offset from the beginning of the DVSEC space.
+ @param Size Number of bytes to read.
+ @param Val Returns the read data.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CcixPciRead (
+ IN CCIX_IO_PROTOCOL *This,
+ IN CCIX_DVSEC_TYPE RegionType,
+ IN UINTN Address,
+ IN UINTN Size,
+ OUT UINTN *Val
+ )
+{
+ CCIX_IO_PCI_DEVICE *Dev;
+ EFI_STATUS Status;
+
+ Dev = CCIX_IO_PCI_DEVICE_FROM_CCIX_IO (This);
+
+ // TODO take address arg into account
+ Status = mCcixPcieRootBridgeIo->Pci.Read (mCcixPcieRootBridgeIo, EfiPciWidthUint8,
+ Dev->CapAddress, Size, Val);
+
+ return Status;
+}
+
+/**
+ Writes to a logical DVSEC address in the specified CCIX DVSEC region.
+
+ @param This A pointer to the EFI_CCIX_IO_PROTOCOL instance.
+ @param RegionType Specifies the type of DVSEC region.
+ @param Address Offset from the beginning of the DVSEC space.
+ @param Size Number of bytes to write.
+ @param Val Data to be written.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CcixPciWrite (
+ IN CCIX_IO_PROTOCOL *This,
+ IN CCIX_DVSEC_TYPE RegionType,
+ IN UINTN Address,
+ IN UINTN Size,
+ IN UINTN Val
+ )
+{
+ CCIX_IO_PCI_DEVICE *Dev;
+ EFI_STATUS Status;
+
+ Dev = CCIX_IO_PCI_DEVICE_FROM_CCIX_IO (This);
+
+ // TODO take address arg into account
+ Status = mCcixPcieRootBridgeIo->Pci.Write (mCcixPcieRootBridgeIo, EfiPciWidthUint8,
+ Dev->CapAddress, Size, &Val);
+
+ return Status;
+}
+
+STATIC
+VOID
+EnumeratePciBus (
+ IN UINT8 BusNumber
+ )
+{
+ UINTN DeviceNr;
+ UINTN FunctionNr;
+ UINT8 Secondary;
+ UINTN CapOffset;
+ CCIX_IO_PCI_DEVICE *Dev;
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "%a: enumerating CCIX devices on bus segment#%d\n",
+ __FUNCTION__, BusNumber));
+
+ for (DeviceNr = 0; DeviceNr <= PCI_MAX_DEVICE; DeviceNr++) {
+ for (FunctionNr = 0; FunctionNr <= PCI_MAX_FUNC; FunctionNr++) {
+ if (IsPciBridge (BusNumber, DeviceNr, FunctionNr, &Secondary)) {
+
+ ASSERT (Secondary > BusNumber);
+
+ EnumeratePciBus (Secondary);
+
+ } else if (IsCcixDevice (BusNumber, DeviceNr, FunctionNr, &CapOffset)) {
+ // add DvSec to a linked list of CCIX devices
+ DEBUG ((DEBUG_INFO, "Found CCIX device at %04x:%02x:%02x.%x\n",
+ mCcixPcieRootBridgeIo->SegmentNumber, BusNumber, DeviceNr, FunctionNr));
+
+ Dev = AllocateZeroPool (sizeof *Dev);
+ ASSERT (Dev != NULL);
+
+ Dev->Signature = CCIX_IO_PCI_DEVICE_SIGNATURE;
+ Dev->CapAddress = EFI_PCI_ADDRESS (BusNumber, DeviceNr, FunctionNr, CapOffset),
+ Dev->CcixIo.Read = CcixPciRead;
+ Dev->CcixIo.Write = CcixPciWrite;
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (&Handle,
+ &gCcixIoProtocolGuid, &Dev->CcixIo, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+}
+
+/**
+ PciEnumerationComplete Protocol notification event handler.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+STATIC
+VOID
+EFIAPI
+OnPciEnumerationComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo;
+ UINTN Idx;
+ VOID *Interface;
+
+ //
+ // The event will trigger once right after registration, but the protocol
+ // may not be installed yet.
+ //
+ Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL,
+ &Interface);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Status = gBS->LocateHandleBuffer (ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid, NULL, &NoHandles,
+ &Handles);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (NoHandles > 0);
+
+ for (Idx = 0; Idx < NoHandles; ++Idx) {
+ Status = gBS->HandleProtocol (Handles[Idx],
+ &gEfiPciRootBridgeIoProtocolGuid, (VOID **)&RootBridgeIo);
+ ASSERT_EFI_ERROR (Status);
+
+ if (RootBridgeIo->SegmentNumber == FixedPcdGet32 (PcdCcixTransportPcieSegment)) {
+ mCcixPcieRootBridgeIo = RootBridgeIo;
+ break;
+ }
+ }
+
+ gBS->FreePool (Handles);
+
+ if (mCcixPcieRootBridgeIo != NULL) {
+ DEBUG ((DEBUG_INFO, "%a: enumerating CCIX devices on PCIe segment#%d\n",
+ __FUNCTION__, mCcixPcieRootBridgeIo->SegmentNumber));
+
+ EnumeratePciBus (FixedPcdGet32 (PcdCcixTransportPcieBusStart));
+ }
+}
+
+/**
+
+ Entry point of this driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval other Driver failed to initialize
+
+**/
+EFI_STATUS
+EFIAPI
+CcixPcieTransportDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *Registration;
+ EFI_EVENT ProtocolNotifyEvent;
+
+ ProtocolNotifyEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiPciEnumerationCompleteProtocolGuid,
+ TPL_CALLBACK, OnPciEnumerationComplete, NULL,
+ &Registration);
+ ASSERT (ProtocolNotifyEvent != NULL);
+
+ return EFI_SUCCESS;
+}
diff --git a/CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.inf b/CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.inf
new file mode 100644
index 0000000000..285fce40cc
--- /dev/null
+++ b/CcixPkg/Drivers/CcixPcieTransportDxe/CcixPcieTransportDxe.inf
@@ -0,0 +1,49 @@
+#/** @file
+# CCIX PCIe transport driver
+#
+# Copyright (c) 2019, Linaro Ltd. All rights reserved.
+#
+# 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
+# http://opensource.org/licenses/bsd-license.php
+#
+# 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 = 1.27
+ BASE_NAME = CcixPcieTransportDxe
+ FILE_GUID = 5b182187-894a-4b1c-858f-7d41a4ab01dd
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CcixPcieTransportDxeEntryPoint
+
+[Sources.common]
+ CcixPcieTransportDxe.c
+
+[Packages]
+ CcixPkg/CcixPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid ## CONSUMES
+ gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES
+ gCcixIoProtocolGuid ## PRODUCES
+
+[FixedPcd]
+ gCcixTokenSpaceGuid.PcdCcixTransportPcieSegment
+ gCcixTokenSpaceGuid.PcdCcixTransportPcieBusStart
+
+[Depex]
+ gEfiPciRootBridgeIoProtocolGuid
diff --git a/CcixPkg/Include/Protocol/CcixIo.h b/CcixPkg/Include/Protocol/CcixIo.h
new file mode 100644
index 0000000000..04206fbbea
--- /dev/null
+++ b/CcixPkg/Include/Protocol/CcixIo.h
@@ -0,0 +1,73 @@
+/** @file
+
+ CCIX_IO_PROTOCOL as specified by CCIX SW Spec x.xx
+
+ Copyright (c) 2019, Linaro Limited. All rights reserved.
+
+ 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
+ http://opensource.org/licenses/bsd-license.php
+
+ 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 CCIX_IO_H__
+#define CCIX_IO_H__
+
+#define CCIX_IO_PROTOCOL_GUID \
+ { 0x76ac4eb3, 0xbaa8, 0x43d4, { 0x8c, 0xb8, 0x16, 0x66, 0x8b, 0xb6, 0xfa, 0xad } }
+
+typedef struct _CCIX_IO_PROTOCOL CCIX_IO_PROTOCOL;
+
+typedef enum {
+ CcixTransportDvsecType = 0x01,
+ CcixProtocolDvsecType
+} CCIX_DVSEC_TYPE;
+
+/**
+ Reads a logical DVSEC address in the specified CCIX DVSEC region.
+
+ @param This A pointer to the EFI_CCIX_IO_PROTOCOL instance.
+ @param RegionType Specifies the type of DVSEC region.
+ @param Address Offset from the beginning of the DVSEC space.
+ @param Size Number of bytes to read.
+ @param Val Returns the read data.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *CCIX_IO_PROTOCOL_READ) (
+ IN CCIX_IO_PROTOCOL *This,
+ IN CCIX_DVSEC_TYPE RegionType,
+ IN UINTN Address,
+ IN UINTN Size,
+ OUT UINTN *Val
+ );
+
+/**
+ Writes to a logical DVSEC address in the specified CCIX DVSEC region.
+
+ @param This A pointer to the EFI_CCIX_IO_PROTOCOL instance.
+ @param RegionType Specifies the type of DVSEC region.
+ @param Address Offset from the beginning of the DVSEC space.
+ @param Size Number of bytes to write.
+ @param Val Data to be written.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *CCIX_IO_PROTOCOL_WRITE) (
+ IN CCIX_IO_PROTOCOL *This,
+ IN CCIX_DVSEC_TYPE RegionType,
+ IN UINTN Address,
+ IN UINTN Size,
+ IN UINTN Val
+ );
+
+typedef struct _CCIX_IO_PROTOCOL {
+ CCIX_IO_PROTOCOL_READ Read;
+ CCIX_IO_PROTOCOL_WRITE Write;
+} CCIX_IO_PROTOCOL;
+
+#endif // CCIX__IO_H_