497 lines
15 KiB
C
497 lines
15 KiB
C
/** @file
|
|
USB4 host router routines used before PCI bus driver enumeration.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains a 'Sample Driver' and is licensed as such under the terms
|
|
of your license agreement with Intel or your vendor. This file may be modified
|
|
by the user, subject to the additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/CmUtilsLib.h>
|
|
#include <Library/Usb4HrSrvLib.h>
|
|
#include <Library/Usb4HiCoreLib.h>
|
|
#include <Library/Usb4DomainLib.h>
|
|
#include <Library/Usb4RouterLib.h>
|
|
#include <Library/CmEvtLib.h>
|
|
#include <Usb4HrInst.h>
|
|
#include <Usb4DomainDefs.h>
|
|
#include "Usb4Hr.h"
|
|
#include "Usb4IhrPci.h"
|
|
#include "Usb4DhrPci.h"
|
|
|
|
/**
|
|
Set host router state based on USB4 control fields.
|
|
If PtOn is set to 0 in host router, PCIe tunneling is disabled for all downstream routers.
|
|
If UtOn is set to 0 in host router, USB3 tunneling is disabled for all downstream routers.
|
|
|
|
@param[in] Router - Pointer to host router instance.
|
|
@param[in] Usb4Ctrl - Pointer to USB4 control fields.
|
|
|
|
@retval EFI_SUCCESS - Set host router control fields successfully.
|
|
@retval EFI_UNSUPPORTED - Router is not host router.
|
|
@retval EFI_INVALID_PARAMETER - Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
Usb4HrSetUsb4Control (
|
|
IN USB4_ROUTER *Router,
|
|
IN USB4_CONTROL *Usb4Ctrl
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "Usb4HrSetUsb4Control entry\n"));
|
|
|
|
if ((Router == NULL) || (Usb4Ctrl == NULL)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrSetUsb4Control: Invalid parameter (%p, %p)\n", Router, Usb4Ctrl));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Router->Depth != 0) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrSetUsb4Control: Rt 0x%016llX is not host router\n", Router->TopologyId));
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Host Router can support PCIe Tunneling and USB3 Tunneling without setting Router CS5 PTO and UTO bit.
|
|
// Router codes use these bits as one of conditions to determine whether PCIe/USB3 Tunneling should be turned on
|
|
// for the downstream Router. Downstream Router will not turn on PTO or UTO if the upstream Router doesn't turn on
|
|
// PTO or UTO.
|
|
//
|
|
// Set PtOn to 1 only if USB4 control PCIe bit is 1 and PCIe adapter is present in host router.
|
|
// Set UtOn to 1 only if USB4 control USB3 bit is 1 and USB3 adapter is present in host router.
|
|
//
|
|
Router->State.PtOn = (Usb4Ctrl->Fields.Pcie == 1) ? Router->State.Pcie : 0;
|
|
Router->State.UtOn = (Usb4Ctrl->Fields.Usb3 == 1) ? Router->State.Usb3 : 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "Host router PCIe Enable = %d, USB3 Enable = %d\n", Router->State.PtOn, Router->State.UtOn));
|
|
Status = EFI_SUCCESS;
|
|
|
|
Exit:
|
|
DEBUG ((DEBUG_INFO, "Usb4HrSetUsb4Control exit\n"));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Create USB4 domain root router instance to represent host router in domain.
|
|
|
|
@param[in] Usb4Hr - Pointer to USB4 host router instance.
|
|
|
|
@retval EFI_SUCCESS - Create USB4 domain root successfully.
|
|
@retval EFI_UNSUPPORTED - Fail to create USB4 domain root.
|
|
@retval EFI_INVALID_PARAMETER - Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
Usb4HrCreateDomainRoot (
|
|
IN USB4_HR_INSTANCE *Usb4Hr
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
TOPOLOGY_ID TopologyId;
|
|
USB4_ROUTER *Router;
|
|
|
|
DEBUG ((DEBUG_INFO, "Usb4HrCreateDomainRoot entry\n"));
|
|
|
|
Router = NULL;
|
|
|
|
if (Usb4Hr == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomainRoot: Null Usb4Hr\n"));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create router instance to represent host router in domain.
|
|
//
|
|
TopologyId.Value = 0;
|
|
Status = Usb4RtCreate (&TopologyId, 0, (USB4_DOMAIN_CONTEXT) Usb4Hr->Usb4Domain, &Router);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomainRoot: Create router instance failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
Router->RouterType = USB4_ROUTER_HOST_ROUTER;
|
|
|
|
//
|
|
// Set Topology ID and Topology valid bit in router config space to enumerate the Router.
|
|
// This must be done before any access to the router other than router config space.
|
|
//
|
|
Status = Usb4RtEnumerate (Router);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomainRoot: Enumerate Router failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Scan router adapters and adapter capabilities
|
|
//
|
|
Status = Usb4RtScanAdapters (Router);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomainRoot: Enumerate router adapters failure 0x%0x\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Set host router protocol tunneling control based on USB4 control fields in HrInfo
|
|
//
|
|
DEBUG ((DEBUG_INFO, "USB4 control value = 0x%0x\n", Usb4Hr->HrInfo.Usb4Control.Value));
|
|
Status = Usb4HrSetUsb4Control (Router, &(Usb4Hr->HrInfo.Usb4Control));
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomainRoot: Set USB4 control failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Add the host router into domain
|
|
//
|
|
Status = Usb4DomainAddRouter (Router);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomainRoot: Add Host Router to Domain failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if (EFI_ERROR (Status) && (Router != NULL)) {
|
|
Usb4RtDestroy (Router);
|
|
}
|
|
DEBUG ((DEBUG_INFO, "Usb4HrCreateDomainRoot exit\n"));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Create USB4 domain and add router instance of host router in the domain.
|
|
Router instance represents the entity in domain topology defined in USB4 configuration layer.
|
|
|
|
@param[in] Usb4Hr - Pointer to USB4 hsot router instance.
|
|
|
|
@retval EFI_SUCCESS - Enumerate host router and all connected routers successfully.
|
|
@retval EFI_OUT_OF_RESOURCES - Insufficient resources to create router instance.
|
|
@retval EFI_UNSUPPORTED - Fail to enumerate all connected routers from host router.
|
|
@retval EFI_INVALID_PARAMETER - Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
Usb4HrCreateDomain (
|
|
IN USB4_HR_INSTANCE *Usb4Hr
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "Usb4HrCreateDomain entry\n"));
|
|
|
|
if (Usb4Hr == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomain: NULL Usb4Hr\n"));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create USB4 domain instance for managing USB4 domain topology
|
|
//
|
|
Status = Usb4DomainCreate (Usb4Hr, &(Usb4Hr->Usb4Domain));
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomain: Create USB4 domain failure, %r\n", Status));
|
|
Usb4Hr->Usb4Domain = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create root router instance to represent USB4 host router in domain.
|
|
//
|
|
Status = Usb4HrCreateDomainRoot (Usb4Hr);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreateDomain: Create USB4 domain root router failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
DEBUG ((DEBUG_INFO, "Usb4HrCreateDomain exit\n"));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Build USB4 domain topology of host router.
|
|
|
|
@param[in] Usb4Hr - Pointer to USB4 host router instance.
|
|
|
|
@retval EFI_SUCCESS - Build USB4 topology successfully.
|
|
@retval EFI_UNSUPPORTED - Fail to build USB4 topology.
|
|
@retval EFI_INVALID_PARAMETER - Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
Usb4HrBuildTopology (
|
|
IN USB4_HR_INSTANCE *Usb4Hr
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "Usb4HrBuildTopology entry - HR = %p\n", Usb4Hr));
|
|
|
|
if (Usb4Hr == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrBuildTopology: NULL Usb4Hr\n"));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create USB4 domain for domain topology management on host router.
|
|
//
|
|
Status = Usb4HrCreateDomain (Usb4Hr);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrBuildTopology: Create USB4 domain for HR %p failure, %r\n", Usb4Hr, Status));
|
|
Usb4Hr->Usb4Domain = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Enumerate and add all downstream routers of host router into domain topology
|
|
//
|
|
Status = Usb4RtEnumAllDsRouters (Usb4Hr->Usb4Domain->RootRt);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrBuildTopology: Enumerate the downstream Routers of Host Router failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Check and process the pending hot plug events in Rx event queue.
|
|
// Usually, DP hot plug events may be received here.
|
|
// DP HPD bit may not be set when CM enumerates new Router with DP monitor connected.
|
|
// DP hot plug or router hot plug events may be received during topology establishment.
|
|
//
|
|
CmProcessRxEvents (Usb4Hr);
|
|
|
|
//
|
|
// Dump domain information
|
|
//
|
|
Usb4DomainDumpInfo (Usb4Hr->Usb4Domain);
|
|
Exit:
|
|
DEBUG ((DEBUG_INFO, "Usb4HrBuildTopology exit\n"));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Stop USB4 host router.
|
|
- Un-initialize PCI config space.
|
|
- Free the allocated MMIO space.
|
|
|
|
@param[in] Usb4HrInst - Pointer to USB4 host router instance.
|
|
**/
|
|
VOID
|
|
Usb4HrStop (
|
|
IN USB4_HR_INSTANCE *Usb4HrInst
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Usb4HrStop entry\n"));
|
|
|
|
if (Usb4HrInst == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrStop: Invalid parameter\n"));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Destory host interface core.
|
|
// DMA buffer should be allocated by PCI I/O protocol after PCI enumeration.
|
|
//
|
|
Usb4HiCoreDestroy (&(Usb4HrInst->HiCore));
|
|
|
|
//
|
|
// Un-init PCI actions done by SW CM Dxe prior to PCI enumeration
|
|
//
|
|
if (Usb4HrInst->HrInfo.IntegratedHr) {
|
|
Iusb4HrPciUnInit (Usb4HrInst);
|
|
} else {
|
|
Dusb4HrPciUnInit (Usb4HrInst);
|
|
}
|
|
|
|
//
|
|
// Free the MMIO space allocated for Tx/Rx Ring access.
|
|
//
|
|
if (Usb4HrInst->MmioBase != 0) {
|
|
DEBUG ((DEBUG_INFO, "Free MMIO base = 0x%0X, len = 0x%x\n", Usb4HrInst->MmioBase, Usb4HrInst->MmioLen));
|
|
CmFreeMmio (Usb4HrInst->MmioBase, Usb4HrInst->MmioLen);
|
|
Usb4HrInst->MmioBase = 0;
|
|
Usb4HrInst->MmioLen = 0;
|
|
}
|
|
Exit:
|
|
DEBUG ((DEBUG_INFO, "Usb4HrStop exit\n"));
|
|
}
|
|
|
|
/**
|
|
Destroy USB4 host router instance.
|
|
- Un-initialize PCI config space.
|
|
- Free the allocated MMIO space.
|
|
- Free the host router instance.
|
|
|
|
@param[in] Usb4HrInst - Pointer to USB4 host router instance.
|
|
**/
|
|
VOID
|
|
Usb4HrDestroy (
|
|
IN USB4_HR_INSTANCE *Usb4HrInst
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Usb4HrDestroy entry\n"));
|
|
|
|
if (Usb4HrInst == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrDestroy: Invalid parameter\n"));
|
|
goto Exit;
|
|
}
|
|
|
|
Usb4HrStop (Usb4HrInst);
|
|
|
|
//
|
|
// Free host router router instance.
|
|
//
|
|
CmFreeMem (Usb4HrInst);
|
|
|
|
Exit:
|
|
DEBUG ((DEBUG_INFO, "Usb4HrDestroy exit\n"));
|
|
}
|
|
|
|
/**
|
|
Create and initialize host router instance.
|
|
- Allocate and assign MMIO space for Tx/Rx ring access
|
|
- Initialize PCI config space.
|
|
|
|
@param[in] ImageHandle - Usb4CmDxe image handle.
|
|
@param[in] HrInfo - Host router information.
|
|
@param[out] Usb4HrInst - Pointer of pointer to the created USB4 host router instance.
|
|
|
|
@retval EFI_SUCCESS - Create host router instance successfully.
|
|
@retval EFI_INVALID_PARAMETER - Invalid parameter.
|
|
@retval EFI_NOT_FOUND - Device is not present.
|
|
@retval EFI_OUT_OF_RESOURCES - Insufficient to initialize host router instance.
|
|
**/
|
|
EFI_STATUS
|
|
Usb4HrCreate (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN PUSB4_HR_INFO HrInfo,
|
|
OUT USB4_HR_INSTANCE **Usb4HrInst
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB4_HR_INSTANCE *HrInst;
|
|
PHYSICAL_ADDRESS MmioBase;
|
|
|
|
DEBUG ((DEBUG_INFO, "Usb4HrCreate entry\n"));
|
|
|
|
HrInst = NULL;
|
|
if ((ImageHandle == NULL) || (HrInfo == NULL) || (Usb4HrInst == NULL)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreate: Invalid parameter (%p, %p, %p)\n", ImageHandle, HrInfo, Usb4HrInst));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
HrInst = CmAllocateZeroMem (sizeof (USB4_HR_INSTANCE));
|
|
if (HrInst == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreate: Insufficient resources\n"));
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
HrInst->Signature = USB4_HR_INSTANCE_SIGNATURE;
|
|
|
|
//
|
|
// Set host router information.
|
|
//
|
|
CmCopyMem (&(HrInst->HrInfo), HrInfo, sizeof(USB4_HR_INFO));
|
|
|
|
//
|
|
// Allocated MMIO space for the programming interface of Tx/Rx Ring access.
|
|
//
|
|
Status = CmAllocMmio (ImageHandle, USB4_RING_MMIO_LENGTH, &MmioBase);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreate: Alloc MMIO failure, %r\n", Status));
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
HrInst->MmioBase = MmioBase;
|
|
HrInst->MmioLen = USB4_RING_MMIO_LENGTH;
|
|
HrInst->PciIo = NULL;
|
|
DEBUG ((DEBUG_INFO, "Allocated MMIO base = 0x%0X, len = 0x%x\n", HrInst->MmioBase, HrInst->MmioLen));
|
|
|
|
//
|
|
// Initialize PCI configuration space of host router
|
|
//
|
|
if (HrInfo->IntegratedHr) {
|
|
Status = Iusb4HrPciInit (HrInst);
|
|
} else {
|
|
Status = Dusb4HrPciInit (HrInst);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreate: PCI configuration space init failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Dump BAR0 MMIO content:\n"));
|
|
HrSrvMmioDump (HrInst->MmioBase, 16);
|
|
|
|
//
|
|
// Create USB4 host interface core for USB4 config space access
|
|
//
|
|
Status = Usb4HiCoreCreate (HrInst);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrCreate: Init Host Interface Core failure, %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
*Usb4HrInst = HrInst;
|
|
|
|
Exit:
|
|
if ((EFI_ERROR (Status)) && (HrInst != NULL)) {
|
|
Usb4HrDestroy (HrInst);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Usb4HrCreate exit\n"));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Unpower USB4 host router
|
|
|
|
@param[in] Usb4Hr - Pointer to USB4 host router instance.
|
|
**/
|
|
VOID
|
|
Usb4HrUnPower (
|
|
IN USB4_HR_INSTANCE *Usb4Hr
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Usb4HrUnPower entry - Usb4Hr %p\n", Usb4Hr));
|
|
if (Usb4Hr == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Usb4HrUnPower: Invalid parameter\n"));
|
|
goto Exit;
|
|
}
|
|
|
|
if (Usb4Hr->HrInfo.IntegratedHr) {
|
|
Iusb4HrForcePwr (Usb4Hr, FALSE);
|
|
}
|
|
|
|
Exit:
|
|
DEBUG ((DEBUG_INFO, "Usb4HrUnPower exit\n"));
|
|
return;
|
|
} |