/*
 * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "kernel/gpu/fifo/kernel_fifo.h"
#include "kernel/gpu/mem_mgr/virt_mem_allocator.h"
#include "kernel/gpu/mmu/kern_gmmu.h"
#include "gpu/mem_mgr/mem_mgr.h"
#include "lib/base_utils.h"

#include "published/hopper/gh100/dev_fault.h"
#include "published/hopper/gh100/dev_vm.h"
#include "published/hopper/gh100/dev_ram.h"
#include "published/hopper/gh100/dev_esched_pbdma.h"

#include "kernel/gpu/conf_compute/conf_compute.h"

/*!
 * Checks the USERD and GPFIFO/PushBuffer location attributes
 * to make sure that when USERD is in sysmem, GPFIFO or
 * PushBuffer is not in vidmem.
 *
 * @param[in]   pKernelFifo         KernelFifo pointer
 * @param[in]   userdAddrSpace      USERD address space
 * @param[in]   pushBuffAddrSpace   PushBuffer address space
 * @param[in]   gpFifoAddrSpace     GPFIFO address space
 *
 */
NV_STATUS
kfifoCheckChannelAllocAddrSpaces_GH100
(
    KernelFifo       *pKernelFifo,
    NV_ADDRESS_SPACE  userdAddrSpace,
    NV_ADDRESS_SPACE  pushBuffAddrSpace,
    NV_ADDRESS_SPACE  gpFifoAddrSpace
)
{
    if ((userdAddrSpace == ADDR_SYSMEM) &&
        ((pushBuffAddrSpace == ADDR_FBMEM || gpFifoAddrSpace == ADDR_FBMEM)))
    {
        return NV_ERR_NOT_SUPPORTED;
    }

    return NV_OK;
}

/*
 * Returns VA alloc flags to be passed into dmaMapBuffer.
 *
 * @param[in]   pGpu               OBJGPU pointer
 * @param[in]   pKernelFifo        KernelFifo pointer
 * @param[in]   engine             engine tells us which engine's ctx buffer are we getting the flags for
 * @param[out]  pflags             NvU32* returned alloc flags to pass into dmaMapBuffer.
 */
void
kfifoGetCtxBufferMapFlags_GH100
(
    OBJGPU      *pGpu,
    KernelFifo  *pKernelFifo,
    NvU32        engine,
    NvU32       *pflags
)
{
    if (IS_GR(engine))
        *pflags |= DMA_VA_LIMIT_57B;

    return;
}

/*
 * Allocate Memory Descriptors for BAR1 VF pages
 *
 * @param[in]   pGpu               OBJGPU pointer
 * @param[in]   pKernelFifo        KernelFifo pointer
 */
NV_STATUS
kfifoConstructUsermodeMemdescs_GH100
(
    OBJGPU     *pGpu,
    KernelFifo *pKernelFifo
)
{
    MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
    NvU32 attr                    = 0;
    NvU32 attr2                   = 0;
    NvU32 i                       = 0;
    NV_STATUS status              = NV_OK;

    attr = FLD_SET_DRF(OS32, _ATTR,  _PHYSICALITY, _CONTIGUOUS, attr);
    attr = FLD_SET_DRF(OS32, _ATTR,  _COHERENCY, _CACHED, attr);

    attr2 = FLD_SET_DRF(OS32, _ATTR2, _GPU_CACHEABLE, _NO, attr2 );

    for(i = 0; i < 2; i++)
    {
        NvBool bPriv = (i==0);
        NvU64 offset = bPriv ? DRF_BASE(NV_VIRTUAL_FUNCTION_PRIV) :  DRF_BASE(NV_VIRTUAL_FUNCTION);
        NvU64 size   = bPriv ? DRF_SIZE(NV_VIRTUAL_FUNCTION_PRIV) : DRF_SIZE(NV_VIRTUAL_FUNCTION);
        MEMORY_DESCRIPTOR **ppMemDesc = bPriv ? &(pKernelFifo->pBar1PrivVF) : &(pKernelFifo->pBar1VF);
        NV_ASSERT_OK_OR_GOTO(status,
            memCreateMemDesc(pGpu, ppMemDesc, ADDR_SYSMEM, offset, size, attr, attr2),
            err);
        memdescSetPteKind(*ppMemDesc, memmgrGetMessageKind_HAL(pGpu, pMemoryManager));
        memdescSetFlag(*ppMemDesc, MEMDESC_FLAGS_MAP_SYSCOH_OVER_BAR1, NV_TRUE);
        memdescSetPageSize(*ppMemDesc, AT_GPU, RM_PAGE_SIZE);
        
        //
        // Set cache snoop settings. SYSCOH_OVER_BAR1 signals a special mapping type of HW registers.
        // By definition should be mapped as SYSCOH.
        //
        memdescSetGpuCacheSnoop(*ppMemDesc, MEMDESC_CACHE_SNOOP_ENABLE);
        memdescSetCpuCacheSnoop(*ppMemDesc, MEMDESC_CACHE_SNOOP_ENABLE);
    }

    NV_ASSERT_OK_OR_GOTO(status,
        kfifoConstructUsermodeMemdescs_GV100(pGpu, pKernelFifo),
        err);
    return NV_OK;
err:
    memdescDestroy(pKernelFifo->pBar1VF);
    memdescDestroy(pKernelFifo->pBar1PrivVF);
    return status;
}

/*!
 * @brief Converts an mmu engine id (NV_PFAULT_MMU_ENG_ID_*) into a string.
 *
 * @param[in] pGpu
 * @param[in] pKernelFifo
 * @param[in] engineID NV_PFAULT_MMU_ENG_ID_*
 *
 * @returns a string (always non-null)
 */
const char*
kfifoPrintInternalEngine_GH100
(
    OBJGPU     *pGpu,
    KernelFifo *pKernelFifo,
    NvU32       engineID
)
{
    NV_STATUS status = NV_OK;
    KernelGmmu *pKernelGmmu = GPU_GET_KERNEL_GMMU(pGpu);
    NvU32 engTag;

    if (kfifoIsMmuFaultEngineIdPbdma(pGpu, pKernelFifo, engineID))
    {
        return kfifoPrintFaultingPbdmaEngineName(pGpu, pKernelFifo, engineID);
    }

    if (kgmmuIsFaultEngineBar1_HAL(pKernelGmmu, engineID))
    {
        return "BAR1";
    }
    else if (kgmmuIsFaultEngineBar2_HAL(pKernelGmmu, engineID))
    {
        return "BAR2";
    }

    switch (engineID)
    {
        case NV_PFAULT_MMU_ENG_ID_DISPLAY:
            return "DISPLAY";
        case NV_PFAULT_MMU_ENG_ID_PERF:
            return "PERF";
        case NV_PFAULT_MMU_ENG_ID_PWR_PMU:
            return "PMU";
        case NV_PFAULT_MMU_ENG_ID_PTP:
            return "PTP";
        case NV_PFAULT_MMU_ENG_ID_FLA:
            return "FLA";
        case NV_PFAULT_MMU_ENG_ID_GSP:
            return "GSP";
        case NV_PFAULT_MMU_ENG_ID_FSP:
            return "FSP";
        default:
            break;
    }

    status = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, ENGINE_INFO_TYPE_MMU_FAULT_ID,
                                      engineID, ENGINE_INFO_TYPE_ENG_DESC, &engTag);
    if (status == NV_OK)
    {
        switch (engTag)
        {
            case ENG_GR(0):
                return "GRAPHICS";
            default:
                return kfifoGetEngineName_HAL(pKernelFifo, ENGINE_INFO_TYPE_ENG_DESC, engTag);
        }
    }

    return "UNKNOWN";
}

/**
 * @brief Converts a subid/clientid into a client string.
 *        This common function may be used by subsequent chips
 *
 * @param[in] pGpu
 * @param[in] pKernelFifo
 * @param[in] pMmuExceptData

 * @returns a string (always non-null)
 */
const char*
kfifoGetClientIdStringCommon_GH100
(
    OBJGPU                  *pGpu,
    KernelFifo              *pKernelFifo,
    FIFO_MMU_EXCEPTION_DATA *pMmuExceptInfo
)
{
    if (pMmuExceptInfo->bGpc)
    {
        switch (pMmuExceptInfo->clientId)
        {
            case NV_PFAULT_CLIENT_GPC_T1_0:
                return "GPCCLIENT_T1_0";
            case NV_PFAULT_CLIENT_GPC_T1_1:
                return "GPCCLIENT_T1_1";
            case NV_PFAULT_CLIENT_GPC_T1_2:
                return "GPCCLIENT_T1_2";
            case NV_PFAULT_CLIENT_GPC_T1_3:
                return "GPCCLIENT_T1_3";
            case NV_PFAULT_CLIENT_GPC_T1_4:
                return "GPCCLIENT_T1_4";
            case NV_PFAULT_CLIENT_GPC_T1_5:
                return "GPCCLIENT_T1_5";
            case NV_PFAULT_CLIENT_GPC_T1_6:
                return "GPCCLIENT_T1_6";
            case NV_PFAULT_CLIENT_GPC_T1_7:
                return "GPCCLIENT_T1_7";
            case NV_PFAULT_CLIENT_GPC_PE_0:
                return "GPCCLIENT_PE_0";
            case NV_PFAULT_CLIENT_GPC_PE_1:
                return "GPCCLIENT_PE_1";
            case NV_PFAULT_CLIENT_GPC_PE_2:
                return "GPCCLIENT_PE_2";
            case NV_PFAULT_CLIENT_GPC_PE_3:
                return "GPCCLIENT_PE_3";
            case NV_PFAULT_CLIENT_GPC_PE_4:
                return "GPCCLIENT_PE_4";
            case NV_PFAULT_CLIENT_GPC_PE_5:
                return "GPCCLIENT_PE_5";
            case NV_PFAULT_CLIENT_GPC_PE_6:
                return "GPCCLIENT_PE_6";
            case NV_PFAULT_CLIENT_GPC_PE_7:
                return "GPCCLIENT_PE_7";
            case NV_PFAULT_CLIENT_GPC_RAST:
                return "GPCCLIENT_RAST";
            case NV_PFAULT_CLIENT_GPC_GCC:
                return "GPCCLIENT_GCC";
            case NV_PFAULT_CLIENT_GPC_GPCCS:
                return "GPCCLIENT_GPCCS";
            case NV_PFAULT_CLIENT_GPC_PROP_0:
                return "GPCCLIENT_PROP_0";
            case NV_PFAULT_CLIENT_GPC_PROP_1:
                return "GPCCLIENT_PROP_1";
            case NV_PFAULT_CLIENT_GPC_T1_8:
                return "GPCCLIENT_T1_8";
            case NV_PFAULT_CLIENT_GPC_T1_9:
                return "GPCCLIENT_T1_9";
            case NV_PFAULT_CLIENT_GPC_T1_10:
                return "GPCCLIENT_T1_10";
            case NV_PFAULT_CLIENT_GPC_T1_11:
                return "GPCCLIENT_T1_11";
            case NV_PFAULT_CLIENT_GPC_T1_12:
                return "GPCCLIENT_T1_12";
            case NV_PFAULT_CLIENT_GPC_T1_13:
                return "GPCCLIENT_T1_13";
            case NV_PFAULT_CLIENT_GPC_T1_14:
                return "GPCCLIENT_T1_14";
            case NV_PFAULT_CLIENT_GPC_T1_15:
                return "GPCCLIENT_T1_15";
            case NV_PFAULT_CLIENT_GPC_TPCCS_0:
                return "GPCCLIENT_TPCCS_0";
            case NV_PFAULT_CLIENT_GPC_TPCCS_1:
                return "GPCCLIENT_TPCCS_1";
            case NV_PFAULT_CLIENT_GPC_TPCCS_2:
                return "GPCCLIENT_TPCCS_2";
            case NV_PFAULT_CLIENT_GPC_TPCCS_3:
                return "GPCCLIENT_TPCCS_3";
            case NV_PFAULT_CLIENT_GPC_TPCCS_4:
                return "GPCCLIENT_TPCCS_4";
            case NV_PFAULT_CLIENT_GPC_TPCCS_5:
                return "GPCCLIENT_TPCCS_5";
            case NV_PFAULT_CLIENT_GPC_TPCCS_6:
                return "GPCCLIENT_TPCCS_6";
            case NV_PFAULT_CLIENT_GPC_TPCCS_7:
                return "GPCCLIENT_TPCCS_7";
            case NV_PFAULT_CLIENT_GPC_PE_8:
                return "GPCCLIENT_PE_8";
            case NV_PFAULT_CLIENT_GPC_TPCCS_8:
                return "GPCCLIENT_TPCCS_8";
            case NV_PFAULT_CLIENT_GPC_T1_16:
                return "GPCCLIENT_T1_16";
            case NV_PFAULT_CLIENT_GPC_T1_17:
                return "GPCCLIENT_T1_17";
            case NV_PFAULT_CLIENT_GPC_ROP_0:
                return "GPCCLIENT_ROP_0";
            case NV_PFAULT_CLIENT_GPC_ROP_1:
                return "GPCCLIENT_ROP_1";
            case NV_PFAULT_CLIENT_GPC_GPM:
                return "GPCCLIENT_GPM";
            default:
                return "UNRECOGNIZED_CLIENT";
        }
    }
    else
    {
        switch (pMmuExceptInfo->clientId)
        {
            case NV_PFAULT_CLIENT_HUB_VIP:
                return "HUBCLIENT_VIP";
            case NV_PFAULT_CLIENT_HUB_CE0:
                return "HUBCLIENT_CE0";
            case NV_PFAULT_CLIENT_HUB_CE1:
                return "HUBCLIENT_CE1";
            case NV_PFAULT_CLIENT_HUB_CE2:
                return "HUBCLIENT_CE2";
            case NV_PFAULT_CLIENT_HUB_CE3:
                return "HUBCLIENT_CE3";
            case NV_PFAULT_CLIENT_HUB_DNISO:
                return "HUBCLIENT_DNISO";
            case NV_PFAULT_CLIENT_HUB_FE:
                return "HUBCLIENT_FE";
            case NV_PFAULT_CLIENT_HUB_FECS:
                return "HUBCLIENT_FECS";
            case NV_PFAULT_CLIENT_HUB_HOST:
                return "HUBCLIENT_HOST";
            case NV_PFAULT_CLIENT_HUB_HOST_CPU:
                return "HUBCLIENT_HOST_CPU";
            case NV_PFAULT_CLIENT_HUB_HOST_CPU_NB:
                return "HUBCLIENT_HOST_CPU_NB";
            case NV_PFAULT_CLIENT_HUB_ISO:
                return "HUBCLIENT_ISO";
            case NV_PFAULT_CLIENT_HUB_MMU:
                return "HUBCLIENT_MMU";
            case NV_PFAULT_CLIENT_HUB_NVDEC0:
                return "HUBCLIENT_NVDEC0";
            case NV_PFAULT_CLIENT_HUB_NVENC1:
                return "HUBCLIENT_NVENC1";
            case NV_PFAULT_CLIENT_HUB_NISO:
                return "HUBCLIENT_NISO";
            case NV_PFAULT_CLIENT_HUB_P2P:
                return "HUBCLIENT_P2P";
            case NV_PFAULT_CLIENT_HUB_PD:
                return "HUBCLIENT_PD";
            case NV_PFAULT_CLIENT_HUB_PERF0:
                return "HUBCLIENT_PERF";
            case NV_PFAULT_CLIENT_HUB_PMU:
                return "HUBCLIENT_PMU";
            case NV_PFAULT_CLIENT_HUB_RASTERTWOD:
                return "HUBCLIENT_RASTERTWOD";
            case NV_PFAULT_CLIENT_HUB_SCC:
                return "HUBCLIENT_SCC";
            case NV_PFAULT_CLIENT_HUB_SCC_NB:
                return "HUBCLIENT_SCC_NB";
            case NV_PFAULT_CLIENT_HUB_SEC:
                return "HUBCLIENT_SEC";
            case NV_PFAULT_CLIENT_HUB_SSYNC:
                return "HUBCLIENT_SSYNC";
            case NV_PFAULT_CLIENT_HUB_XV:
                return "HUBCLIENT_XV";
            case NV_PFAULT_CLIENT_HUB_MMU_NB:
                return "HUBCLIENT_MMU_NB";
            case NV_PFAULT_CLIENT_HUB_DFALCON:
                return "HUBCLIENT_DFALCON";
            case NV_PFAULT_CLIENT_HUB_SKED:
                return "HUBCLIENT_SKED";
            case NV_PFAULT_CLIENT_HUB_DONT_CARE:
                return "HUBCLIENT_DONT_CARE";
            case NV_PFAULT_CLIENT_HUB_HSCE0:
                return "HUBCLIENT_HSCE0";
            case NV_PFAULT_CLIENT_HUB_HSCE1:
                return "HUBCLIENT_HSCE1";
            case NV_PFAULT_CLIENT_HUB_HSCE2:
                return "HUBCLIENT_HSCE2";
            case NV_PFAULT_CLIENT_HUB_HSCE3:
                return "HUBCLIENT_HSCE3";
            case NV_PFAULT_CLIENT_HUB_HSCE4:
                return "HUBCLIENT_HSCE4";
            case NV_PFAULT_CLIENT_HUB_HSCE5:
                return "HUBCLIENT_HSCE5";
            case NV_PFAULT_CLIENT_HUB_HSCE6:
                return "HUBCLIENT_HSCE6";
            case NV_PFAULT_CLIENT_HUB_HSCE7:
                return "HUBCLIENT_HSCE7";
            case NV_PFAULT_CLIENT_HUB_HSHUB:
                return "HUBCLIENT_HSHUB";
            case NV_PFAULT_CLIENT_HUB_PTP_X0:
                return "HUBCLIENT_PTP_X0";
            case NV_PFAULT_CLIENT_HUB_PTP_X1:
                return "HUBCLIENT_PTP_X1";
            case NV_PFAULT_CLIENT_HUB_PTP_X2:
                return "HUBCLIENT_PTP_X2";
            case NV_PFAULT_CLIENT_HUB_PTP_X3:
                return "HUBCLIENT_PTP_X3";
            case NV_PFAULT_CLIENT_HUB_PTP_X4:
                return "HUBCLIENT_PTP_X4";
            case NV_PFAULT_CLIENT_HUB_PTP_X5:
                return "HUBCLIENT_PTP_X5";
            case NV_PFAULT_CLIENT_HUB_PTP_X6:
                return "HUBCLIENT_PTP_X6";
            case NV_PFAULT_CLIENT_HUB_PTP_X7:
                return "HUBCLIENT_PTP_X7";
            case NV_PFAULT_CLIENT_HUB_NVENC2:
                return "HUBCLIENT_NVENC2";
            case NV_PFAULT_CLIENT_HUB_VPR_SCRUBBER0:
                return "HUBCLIENT_VPR_SCRUBBER0";
            case NV_PFAULT_CLIENT_HUB_VPR_SCRUBBER1:
                return "HUBCLIENT_VPR_SCRUBBER1";
            case NV_PFAULT_CLIENT_HUB_FBFALCON:
                return "HUBCLIENT_FBFALCON";
            case NV_PFAULT_CLIENT_HUB_CE_SHIM:
                return "HUBCLIENT_CE_SHIM";
            case NV_PFAULT_CLIENT_HUB_GSP:
                return "HUBCLIENT_GSP";
            case NV_PFAULT_CLIENT_HUB_FSP:
                return "HUBCLIENT_FSP";
            case NV_PFAULT_CLIENT_HUB_NVDEC1:
                return "HUBCLIENT_NVDEC1";
            case NV_PFAULT_CLIENT_HUB_NVDEC2:
                return "HUBCLIENT_NVDEC2";
            case NV_PFAULT_CLIENT_HUB_NVJPG0:
                return "HUBCLIENT_NVJPG0";
            case NV_PFAULT_CLIENT_HUB_NVJPG1:
                return "HUBCLIENT_NVJPG1";
            case NV_PFAULT_CLIENT_HUB_NVJPG2:
                return "HUBCLIENT_NVJPG2";
            case NV_PFAULT_CLIENT_HUB_NVJPG3:
                return "HUBCLIENT_NVJPG3";
            case NV_PFAULT_CLIENT_HUB_NVJPG4:
                return "HUBCLIENT_NVJPG4";
            case NV_PFAULT_CLIENT_HUB_NVJPG5:
                return "HUBCLIENT_NVJPG5";
            case NV_PFAULT_CLIENT_HUB_NVJPG6:
                return "HUBCLIENT_NVJPG6";
            case NV_PFAULT_CLIENT_HUB_NVJPG7:
                return "HUBCLIENT_NVJPG7";
            case NV_PFAULT_CLIENT_HUB_NVDEC3:
                return "HUBCLIENT_NVDEC3";
            case NV_PFAULT_CLIENT_HUB_NVDEC4:
                return "HUBCLIENT_NVDEC4";
            case NV_PFAULT_CLIENT_HUB_NVDEC5:
                return "HUBCLIENT_NVDEC5";
            case NV_PFAULT_CLIENT_HUB_NVDEC6:
                return "HUBCLIENT_NVDEC6";
            case NV_PFAULT_CLIENT_HUB_NVDEC7:
                return "HUBCLIENT_NVDEC7";
            case NV_PFAULT_CLIENT_HUB_OFA0:
                return "HUBCLIENT_OFA0";
            case NV_PFAULT_CLIENT_HUB_FE1:
                return "HUBCLIENT_FE1";
            case NV_PFAULT_CLIENT_HUB_FE2:
                return "HUBCLIENT_FE2";
            case NV_PFAULT_CLIENT_HUB_FE3:
                return "HUBCLIENT_FE3";
            case NV_PFAULT_CLIENT_HUB_FE4:
                return "HUBCLIENT_FE4";
            case NV_PFAULT_CLIENT_HUB_FE5:
                return "HUBCLIENT_FE5";
            case NV_PFAULT_CLIENT_HUB_FE6:
                return "HUBCLIENT_FE6";
            case NV_PFAULT_CLIENT_HUB_FE7:
                return "HUBCLIENT_FE7";
            case NV_PFAULT_CLIENT_HUB_FECS1:
                return "HUBCLIENT_FECS1";
            case NV_PFAULT_CLIENT_HUB_FECS2:
                return "HUBCLIENT_FECS2";
            case NV_PFAULT_CLIENT_HUB_FECS3:
                return "HUBCLIENT_FECS3";
            case NV_PFAULT_CLIENT_HUB_FECS4:
                return "HUBCLIENT_FECS4";
            case NV_PFAULT_CLIENT_HUB_FECS5:
                return "HUBCLIENT_FECS5";
            case NV_PFAULT_CLIENT_HUB_FECS6:
                return "HUBCLIENT_FECS6";
            case NV_PFAULT_CLIENT_HUB_FECS7:
                return "HUBCLIENT_FECS7";
            case NV_PFAULT_CLIENT_HUB_SKED1:
                return "HUBCLIENT_SKED1";
            case NV_PFAULT_CLIENT_HUB_SKED2:
                return "HUBCLIENT_SKED2";
            case NV_PFAULT_CLIENT_HUB_SKED3:
                return "HUBCLIENT_SKED3";
            case NV_PFAULT_CLIENT_HUB_SKED4:
                return "HUBCLIENT_SKED4";
            case NV_PFAULT_CLIENT_HUB_SKED5:
                return "HUBCLIENT_SKED5";
            case NV_PFAULT_CLIENT_HUB_SKED6:
                return "HUBCLIENT_SKED6";
            case NV_PFAULT_CLIENT_HUB_SKED7:
                return "HUBCLIENT_SKED7";
            case NV_PFAULT_CLIENT_HUB_ESC:
                return "HUBCLIENT_ESC";
            default:
                return kfifoGetClientIdStringCheck_HAL(pGpu, pKernelFifo, pMmuExceptInfo->clientId);
        }
    }
}

/**
 * @brief Converts a subid/clientid into a client string
 *
 * @param[in] pGpu
 * @param[in] pKernelFifo
 * @param[in] pMmuExceptData
 *
 * @returns a string (always non-null)
 */
const char*
kfifoGetClientIdString_GH100
(
    OBJGPU                  *pGpu,
    KernelFifo              *pKernelFifo,
    FIFO_MMU_EXCEPTION_DATA *pMmuExceptionInfo
)
{
    if (pMmuExceptionInfo->bGpc)
    {
        return kfifoGetClientIdStringCommon_HAL(pGpu, pKernelFifo, pMmuExceptionInfo);
    }
    else
    {
        switch (pMmuExceptionInfo->clientId)
        {
            case NV_PFAULT_CLIENT_HUB_AFALCON:
                return "HUBCLIENT_AFALCON";
            case NV_PFAULT_CLIENT_HUB_HSCE8:
                return "HUBCLIENT_HSCE8";
            case NV_PFAULT_CLIENT_HUB_HSCE9:
                return "HUBCLIENT_HSCE9";
            case NV_PFAULT_CLIENT_HUB_DWBIF:
                return "HUBCLIENT_DWBIF";
            case NV_PFAULT_CLIENT_HUB_HSCE10:
                return "HUBCLIENT_HSCE10";
            case NV_PFAULT_CLIENT_HUB_HSCE11:
                return "HUBCLIENT_HSCE11";
            case NV_PFAULT_CLIENT_HUB_HSCE12:
                return "HUBCLIENT_HSCE12";
            case NV_PFAULT_CLIENT_HUB_HSCE13:
                return "HUBCLIENT_HSCE13";
            case NV_PFAULT_CLIENT_HUB_HSCE14:
                return "HUBCLIENT_HSCE14";
            case NV_PFAULT_CLIENT_HUB_HSCE15:
                return "HUBCLIENT_HSCE15";
            default:
                return kfifoGetClientIdStringCommon_HAL(pGpu, pKernelFifo, pMmuExceptionInfo);
        }
    }
}

/*!
 * @brief Update the usermode doorbell register with work submit token to notify
 *        host that work is available on this channel.
 *
 * @param[in] pGpu
 * @param[in] pFifo
 * @param[in] pKernelChannel  Channel to ring the doorbell for
 */
NV_STATUS
kfifoRingChannelDoorBell_GH100
(
    OBJGPU          *pGpu,
    KernelFifo      *pKernelFifo,
    KernelChannel   *pKernelChannel
)
{
    return kfifoRingChannelDoorBell_GV100(pGpu, pKernelFifo, pKernelChannel);
}

/*
 * @  Function to write gpfifo info in RAMFC
 * @param[in] pGpu           - GPU object pointer
 * @param[in] pKernelFifo    - KernelFifo pointer
 * @param[in] pInstMem       - CPU pointer to instance mem
 * @param[in] gpFifoOffset   - GPFIFO virtual address
 * @param[in] gpFifoEntries  - GPFIFO entries
 */
void
kfifoWriteRamfcGpfifo_GH100
(
    OBJGPU        *pGpu,
    KernelFifo    *pKernelFifo,
    NvU8          *pInstMem,
    NvU64         gpFifoOffset,
    NvU32         gpFifoEntries
)
{
    // GPBASE
    NV_ASSERT(FLD_TEST_DRF(_PBDMA, _GP_BASE, _RSVD, _ZERO, NvU64_LO32(gpFifoOffset)));
    MEM_WR32(pInstMem + SF_OFFSET(NV_RAMFC_GP_BASE), NvU64_LO32(gpFifoOffset));
    
    MEM_WR32(pInstMem + SF_OFFSET(NV_RAMFC_GP_BASE_HI),
                 DRF_NUM(_PBDMA, _GP_BASE_HI, _OFFSET, NvU64_HI32(gpFifoOffset)));

    MEM_WR32(pInstMem + SF_OFFSET(NV_RAMFC_GP_INFO),
             DRF_NUM(_PBDMA, _GP_INFO, _LIMIT2, nvLogBase2(gpFifoEntries) |
             DRF_NUM(_PBDMA, _GP_INFO, _PB_SEGMENT_EXTENDED_BASE, 0)));

    MEM_WR32(pInstMem + SF_OFFSET(NV_RAMFC_GP_PUT), 0);
    MEM_WR32(pInstMem + SF_OFFSET(NV_RAMFC_GP_GET), 0);
}

NV_STATUS
kfifoDisableChannelsForKeyRotation_GH100
(
    OBJGPU         *pGpu,
    KernelFifo     *pKernelFifo,
    RmCtrlParams   *pRmCtrlParams,
    NvBool          bEnableAfterKeyRotation,
    NvBool          bForceKeyRotation,
    NV2080_CTRL_FIFO_DISABLE_CHANNELS_PARAMS *pParams
)
{
    NvU32           i;
    NV_STATUS       status        = NV_OK;
    NV_STATUS       tmpStatus     = NV_OK;
    KernelChannel  *pKernelChannel = NULL;
    RM_API         *pRmApi        = GPU_GET_PHYSICAL_RMAPI(pGpu);

    // Send RPC to handle message on GSP-RM
    if (IS_GSP_CLIENT(pGpu))
    {
        status = pRmApi->Control(pRmApi,
                                 pRmCtrlParams->hClient,
                                 pRmCtrlParams->hObject,
                                 pRmCtrlParams->cmd,
                                 pRmCtrlParams->pParams,
                                 pRmCtrlParams->paramsSize);
    }
    // Send internal control call to actually disable channels and preempt channels
    else
    {
        status = NV_ERR_NOT_SUPPORTED;
        NV_ASSERT_OR_RETURN(status == NV_OK, status);
    }

    // Loop through all the channels and mark them disabled
    NvU32 keyIndex = 0;
    NvBool bFound = NV_FALSE;
    NvU32 h2dKeyList[CC_KEYSPACE_TOTAL_SIZE];
    ConfidentialCompute *pConfCompute = GPU_GET_CONF_COMPUTE(pGpu);

    for (i = 0; i < pParams->numChannels; i++)
    {
        RsClient              *pClient = NULL;
        tmpStatus = serverGetClientUnderLock(&g_resServ,
                                          pParams->hClientList[i], &pClient);
        if (tmpStatus != NV_OK)
        {
            status = tmpStatus;
            NV_PRINTF(LEVEL_ERROR, "Failed to get client with hClient = 0x%x status = 0x%x\n", pParams->hClientList[i], status);
            continue;
        }
        tmpStatus = CliGetKernelChannel(pClient,
                                     pParams->hChannelList[i], &pKernelChannel);
        if (tmpStatus != NV_OK)
        {
            status = tmpStatus;
            NV_PRINTF(LEVEL_ERROR, "Failed to get channel with hclient = 0x%x hChannel = 0x%x status = 0x%x\n",
                                    pParams->hClientList[i], pParams->hChannelList[i], status);
            continue;
        }
        kchannelDisableForKeyRotation(pGpu, pKernelChannel, NV_TRUE);
        kchannelEnableAfterKeyRotation(pGpu, pKernelChannel, bEnableAfterKeyRotation);
        if (IS_GSP_CLIENT(pGpu))
        {
            NvU32 h2dKey, d2hKey;
            NV_ASSERT_OK_OR_RETURN(confComputeGetKeyPairByChannel_HAL(pGpu, pConfCompute, pKernelChannel,
                                                                      &h2dKey, &d2hKey));
            if (bForceKeyRotation)
            {
                //
                // This loop doesn't need to execute in the first iteration of above loop
                // since keyList is empty.
                //
                for (NvU32 j = 0; j < keyIndex; j++)
                {
                    if (h2dKeyList[j] == h2dKey)
                    {
                        bFound = NV_TRUE;
                        break;
                    }
                }
                if (!bFound)
                {
                    NV_ASSERT_OR_RETURN(keyIndex < CC_KEYSPACE_TOTAL_SIZE, NV_ERR_INVALID_STATE);
                    h2dKeyList[keyIndex++] = h2dKey;
                }
                bFound = NV_FALSE;
            }
            else
            {
                KEY_ROTATION_STATUS state;
                NV_ASSERT_OK_OR_RETURN(confComputeGetKeyRotationStatus(pConfCompute, h2dKey, &state));
                if ((state == KEY_ROTATION_STATUS_PENDING) ||
                    (state == KEY_ROTATION_STATUS_PENDING_TIMER_SUSPENDED))
                {
                    NV_ASSERT_OK_OR_RETURN(confComputeCheckAndPerformKeyRotation(pGpu, pConfCompute, h2dKey, d2hKey));
                }
            }
        }
    }

    if (IS_GSP_CLIENT(pGpu) && bForceKeyRotation)
    {
        for (NvU32 j = 0; j < keyIndex; j++)
        {
            NvU32 h2dKey, d2hKey;
            confComputeGetKeyPairByKey(pConfCompute, h2dKeyList[j], &h2dKey, &d2hKey);
            NV_PRINTF(LEVEL_INFO, "Forcing key rotation on h2dKey 0x%x\n", h2dKey);
            status = confComputeForceKeyRotation(pGpu, pConfCompute, h2dKey, d2hKey);
            if (status != NV_OK)
            {
                NV_PRINTF(LEVEL_ERROR, "Forced key rotation for key 0x%x failed\n", h2dKey);
                return status;
            }
        }
    }
    return status;
}
