/*
 * SPDX-FileCopyrightText: Copyright (c) 2001-2020 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.
 */

#ifndef _PRINTF_H_
#define _PRINTF_H_

/*
 * RM PRINTF definitions.
 *
 * Provides RM internal definitions built on the generic nvprintf utilities
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "nvport/nvport.h"
#include "utils/nvprintf.h"
#include "nvlog/nvlog.h"

#define DBG_FILE_LINE_FUNCTION  NV_FILE_STR, __LINE__, NV_FUNCTION_STR

/**
 * @todo bug 1583359 - Move to NvPort compiler specifics
 */
#if defined(__GNUC__) || defined(__clang__)
#define NV_RETURN_ADDRESS()    __builtin_return_address(0)
#else
#define NV_RETURN_ADDRESS()    _ReturnAddress()
#endif


//******************************************************************************
//                                  BREAKPOINTS
//******************************************************************************

// NV_DBG_BREAKPOINT_ALLOWED can be overridden through CFLAGS
#if !defined(NV_DBG_BREAKPOINT_ALLOWED)
#if defined(DEBUG) || defined(ASSERT_BUILD) || defined(NV_MODS) || defined(QA_BUILD) || (defined(NVRM) && NVCPU_IS_RISCV64)
#define NV_DBG_BREAKPOINT_ALLOWED 1
#else
#define NV_DBG_BREAKPOINT_ALLOWED 0
#endif
#endif // !defined(NV_DBG_BREAKPOINT_ALLOWED)

#define NV_DEBUG_BREAK_FLAGS_RC                        0:0
#define NV_DEBUG_BREAK_FLAGS_RC_DISABLE                (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_RC_ENABLE                 (0x00000001)
#define NV_DEBUG_BREAK_FLAGS_ASSERT                    1:1
#define NV_DEBUG_BREAK_FLAGS_ASSERT_DISABLE            (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_ASSERT_ENABLE             (0x00000001)
#define NV_DEBUG_BREAK_FLAGS_DBG_BREAK                 2:2
#define NV_DEBUG_BREAK_FLAGS_DBG_BREAK_DISABLE         (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_DBG_BREAK_ENABLE          (0x00000001)
#define NV_DEBUG_BREAK_FLAGS_GPU_TIMEOUT               3:3
#define NV_DEBUG_BREAK_FLAGS_GPU_TIMEOUT_DISABLE       (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_GPU_TIMEOUT_ENABLE        (0x00000001)
#define NV_DEBUG_BREAK_FLAGS_POOL_TAGS                 4:4
#define NV_DEBUG_BREAK_FLAGS_POOL_TAGS_DISABLE         (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_POOL_TAGS_ENABLE          (0x00000001)
#define NV_DEBUG_BREAK_FLAGS_POWER_ON                  5:5
#define NV_DEBUG_BREAK_FLAGS_POWER_ON_DISABLE          (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_POWER_ON_ENABLE           (0x00000001)
#define NV_DEBUG_BREAK_FLAGS_SMU_ERROR                 6:6
#define NV_DEBUG_BREAK_FLAGS_SMU_ERROR_DISABLE         (0x0)
#define NV_DEBUG_BREAK_FLAGS_SMU_ERROR_ENABLE          (0x1)
#define NV_DEBUG_BREAK_FLAGS_CRASH                     7:7
#define NV_DEBUG_BREAK_FLAGS_CRASH_DISABLE             (0x00000000)
#define NV_DEBUG_BREAK_FLAGS_CRASH_ENABLE              (0x00000001)

#define NV_DEBUG_BREAK_ATTRIBUTES                      7:0
#define NV_DEBUG_BREAK_ATTRIBUTES_NONE                 (0x00000000)
#define NV_DEBUG_BREAK_ATTRIBUTES_RC                   (0x00000001)
#define NV_DEBUG_BREAK_ATTRIBUTES_ASSERT               (0x00000002)
#define NV_DEBUG_BREAK_ATTRIBUTES_DBG_BREAK            (0x00000004)
#define NV_DEBUG_BREAK_ATTRIBUTES_GPU_TIMEOUT          (0x00000008)
#define NV_DEBUG_BREAK_ATTRIBUTES_POOL_TAGS            (0x00000010)
#define NV_DEBUG_BREAK_ATTRIBUTES_POWER_ON             (0x00000020)
#define NV_DEBUG_BREAK_ATTRIBUTES_SMU_ERROR            (0x00000040)
#define NV_DEBUG_BREAK_ATTRIBUTES_CRASH                (0x00000080)

// Checks RMINFO and OS config to see if triggering a breakpoint is ever allowed
NvBool nvDbgBreakpointEnabled(void);
// Flushes the logs before a breakpoint, so we can see all the prints.
void osFlushLog(void);

#define DBG_ROUTINE()                                                          \
    do                                                                         \
    {                                                                          \
        if (nvDbgBreakpointEnabled())                                          \
            PORT_BREAKPOINT_ALWAYS();                                          \
    } while (0)

#define REL_DBG_BREAKPOINT() \
    REL_DBG_BREAKPOINT_MSG("NVRM-RC: Nvidia GPU Error Detected\n")

#if NV_DBG_BREAKPOINT_ALLOWED

#if !NVCPU_IS_RISCV64

#define DBG_BREAKPOINT_EX(PGPU, LEVEL)                                         \
    do                                                                         \
    {                                                                          \
        NV_PRINTF(LEVEL_ERROR, "bp @ " NV_FILE_FMT ":%d\n", NV_FILE, __LINE__);\
        osFlushLog();                                                          \
        DBG_ROUTINE();                                                         \
    } while (0)

#else // !NVCPU_IS_RISCV64

#define DBG_BREAKPOINT_EX(PGPU, LEVEL)                                         \
    do                                                                         \
    {                                                                          \
        NV_ASSERT_FAILED("DBG_BREAKPOINT");                                    \
    } while (0)

#endif // !NVCPU_IS_RISCV64

#define DBG_BREAKPOINT() DBG_BREAKPOINT_EX(NULL, 0)

#define DBG_BREAKPOINT_EX_ARGS_IGNORED 1
#define REL_DBG_BREAKPOINT_MSG(msg)                                            \
    do                                                                         \
    {                                                                          \
        PORT_DBG_PRINT_STRING_LITERAL(msg);                                    \
        DBG_BREAKPOINT();                                                      \
    } while (0)

#else // !NV_DBG_BREAKPOINT_ALLOWED

#define DBG_BREAKPOINT()
#define DBG_BREAKPOINT_EX(PGPU, LEVEL)
#define DBG_BREAKPOINT_EX_ARGS_IGNORED 1

#define REL_DBG_BREAKPOINT_MSG(msg)                                            \
    do                                                                         \
    {                                                                          \
        PORT_DBG_PRINT_STRING_LITERAL(msg);                                    \
        DBG_ROUTINE();                                                         \
    } while (0)


#endif // NV_DBG_BREAKPOINT_ALLOWED

#define DBG_BREAKPOINT_REASON(reason) DBG_BREAKPOINT()

#define DBG_BREAKPOINT_ERROR_INFO(errorCategory, errorInfo) DBG_BREAKPOINT()

//******************************************************************************
//                                  PRINTS
//******************************************************************************

#include "utils/nvprintf.h"

#define MAX_ERROR_STRING 256
#ifndef NVPORT_CHECK_PRINTF_ARGUMENTS
#define NVPORT_CHECK_PRINTF_ARGUMENTS(x,c)
#endif
//
// Prototypes
//
NvBool nvDbgInit(void);
void nvDbgDestroy(void);
void nvDbg_Printf  (const char *file, int line, const char *function, int debuglevel, const char *s, ...) NVPORT_CHECK_PRINTF_ARGUMENTS(5, 6);

//
// Like libc's vsnprintf(), nvDbg_vPrintf() invalidates its va_list argument. The va_list argument
// may not be reused after nvDbg_vPrintf() returns.  If the va_list is needed after the
// nvDbg_vPrintf() call, create a copy of the va_list using va_copy().
// The caller controls the lifetime of the va_list argument, and should free it using va_end.
//
void nvDbg_vPrintf (const char *file, int line, const char *function, int debuglevel, const char *s, va_list args);
void nvDbg_PrintBuf(const char *file, int line, const char *function, int debgulevel, NvU8 buffer[], NvU32 bufsize);

int nvDbgVsnprintf(char *dest, NvU32 destSize, const char *fmt, va_list args);
int nvDbgSnprintf (char *dest, NvU32 destSize, const char *fmt, ...);

struct OBJGPU;
void nvDbgInitRmMsg(struct OBJGPU *);
// RmMsgPrefix return value
#define NVRM_MSG_PREFIX_NVRM            NVBIT(0)
#define NVRM_MSG_PREFIX_FILE            NVBIT(1)
#define NVRM_MSG_PREFIX_FUNCTION        NVBIT(2)
#define NVRM_MSG_PREFIX_LINE            NVBIT(3)
#define NVRM_MSG_PREFIX_OSTIMESTAMP     NVBIT(4)
NvU32 RmMsgPrefix(NvU32 prefix, const char *filename, NvU32 linenumber, const char *function, char *str, NvU32 len);
// nvDbgRmMsgCheck return code
#define NVRM_MSG_NORMAL 0    // Use normal message handling (warnings/errors)
#define NVRM_MSG_HIDE   1    // Skip this message
#define NVRM_MSG_PRINT  2    // Force printing of this message
NvU32 nvDbgRmMsgCheck(const char *filename, NvU32 linenumber, const char *function, NvU32 level, const char *format, NvU32 *pPrefix);
void nvDbgDumpBufferBytes(void *pBuffer, NvU32 length);


#if NV_PRINTF_STRINGS_ALLOWED
#define DBG_STRING(str) str
#define DBG_INIT()                               nvDbgInit()
#define DBG_DESTROY()                            nvDbgDestroy()
#define DBG_VSNPRINTF(ptr_size_format_and_stuff) nvDbgVsnprintf ptr_size_format_and_stuff
#define DBG_PRINTBUF(dbglevel, buffer, bufsize)  nvDbg_PrintBuf(DBG_FILE_LINE_FUNCTION, dbglevel, buffer, bufsize)
#define DBG_RMMSG_CHECK(level)            (nvDbgRmMsgCheck(DBG_FILE_LINE_FUNCTION, level, NULL, NULL) == NVRM_MSG_PRINT)
#else  // ! NV_PRINTF_STRINGS_ALLOWED -- debug printf strings not enabled
#define DBG_STRING(str) ""
#define DBG_INIT()      (NV_TRUE)
#define DBG_DESTROY()
#define DBG_VSNPRINTF(ptr_size_format_and_stuff)
#define DBG_PRINTBUF(dbglevel, buffer, bufsize)
#define DBG_RMMSG_CHECK(level)   (0)
#endif // NV_PRINTF_STRINGS_ALLOWED



//******************************************************************************
//                            POWER SANITY CHECKS
//******************************************************************************
//
// Make sure the GPU is in full power or resuming from D3 state. Else,
// bailout from the calling function. An exception for systems, which support
// surprise removal feature. See Bugs 440565, 479003, and 499228.DO NOT IGNORE
// OR REMOVE THIS ASSERT.  If you have problems with it, please talk to cplummer.
//
// bAllowWithoutSysmemAccess: Allow this RM Control when sysmem access is not available
// from the GPU. SHould be NV_TRUE only for NV2080_CTRL_CMD_BUS_SYSMEM_ACCESS
//
// On systems supporting surprise removal, if the GPU is in D3 cold
// and still attached we would consider it a true D3 cold state
// and return NOT_FULL_POWER. See bug 1679965.
//
//
#define API_GPU_FULL_POWER_SANITY_CHECK(pGpu, bGpuAccess, bAllowWithoutSysmemAccess)  \
    if ((!gpuIsGpuFullPower(pGpu)) &&                                       \
              (!(pGpu)->getProperty((pGpu),                                 \
                             PDB_PROP_GPU_IN_PM_RESUME_CODEPATH)))          \
    {                                                                       \
        DBG_BREAKPOINT();                                                   \
        if (bGpuAccess || (!gpuIsSurpriseRemovalSupported(pGpu)))           \
        {                                                                   \
            return NV_ERR_GPU_NOT_FULL_POWER;                               \
        }                                                                   \
        else if (gpuIsSurpriseRemovalSupported(pGpu) &&                     \
                 (pGpu)->getProperty((pGpu), PDB_PROP_GPU_IS_CONNECTED))    \
        {                                                                   \
            return NV_ERR_GPU_NOT_FULL_POWER;                               \
        }                                                                   \
    }                                                                       \
    if (!(bAllowWithoutSysmemAccess) && !gpuCheckSysmemAccess(pGpu))        \
    {                                                                       \
        return NV_ERR_GPU_NOT_FULL_POWER;                                   \
    }

#define API_GPU_FULL_POWER_SANITY_CHECK_OR_GOTO(pGpu, bGpuAccess, bAllowWithoutSysmemAccess, status, tag) \
    if ((!gpuIsGpuFullPower(pGpu)) &&                                       \
              (!(pGpu)->getProperty((pGpu),                                 \
                             PDB_PROP_GPU_IN_PM_RESUME_CODEPATH)))          \
    {                                                                       \
        DBG_BREAKPOINT();                                                   \
        if (bGpuAccess || (!gpuIsSurpriseRemovalSupported(pGpu)))           \
        {                                                                   \
            status = NV_ERR_GPU_NOT_FULL_POWER;                             \
            goto tag;                                                       \
        }                                                                   \
        else if (gpuIsSurpriseRemovalSupported(pGpu) &&                     \
                (pGpu)->getProperty((pGpu), PDB_PROP_GPU_IS_CONNECTED))     \
        {                                                                   \
            status = NV_ERR_GPU_NOT_FULL_POWER;                             \
            goto tag;                                                       \
        }                                                                   \
    }                                                                       \
    if (!(bAllowWithoutSysmemAccess) && !gpuCheckSysmemAccess(pGpu))        \
    {                                                                       \
        return NV_ERR_GPU_NOT_FULL_POWER;                                   \
    }


#if defined(PORT_IS_FUNC_SUPPORTED)
#if PORT_IS_FUNC_SUPPORTED(portMemExValidate)
#define DBG_VAL_PTR(p) portMemExValidate(p, NV_TRUE)
#endif
#endif
#ifndef DBG_VAL_PTR
#define DBG_VAL_PTR(p)
#endif


//********************************************************************************
//
//  NVRM_TRACE support
//    low-overhead runtime state capture
//    to enable, define USE_NVRM_TRACE (retail or debug builds)
//
//********************************************************************************

#ifdef USE_NVRM_TRACE

NvU32 NVRM_TRACE_INIT(void);
NvU32 NVRM_TRACE_DISABLE(void);
void NVRM_TRACE_ENABLE(void);
void NVRM_TRACE_DUMP(void);
void NVRM_TRACE(NvU32);
void NVRM_TRACEV(NvU32 *,NvU32);
void NVRM_TRACE1(NvU32);
void NVRM_TRACE2(NvU32, NvU32);
void NVRM_TRACE3(NvU32, NvU32, NvU32);
void NVRM_TRACE4(NvU32, NvU32, NvU32, NvU32);
void NVRM_TRACE5(NvU32, NvU32, NvU32, NvU32, NvU32);

// versions of reg read/write that log to trace buffer
//NvU32 NVRM_TRACE_REG_RD32(OBJGPU *, NvU32);
//void NVRM_TRACE_REG_WR32(OBJGPU *, NvU32, NvU32);

// fifolog format looks like:
//  31:28   = unique file number
//  27:4    = file line number
//  1:0     = fifo state bits (bit1 = puller, bit0 = reassign)
#define FIFOLOG(fn,fa,fb) NVRM_TRACE2('FIFO', ((fn << 28) | (__LINE__ << 4) |       \
                                                    ((fa & 0x1) ? 1 : 0) << 1 |     \
                                                    ((fb & 0x1) ? 1 : 0)) )

#else  // ! USE_NVRM_TRACE

#define NVRM_TRACE_INIT()
#define NVRM_TRACE_DISABLE() 0
#define NVRM_TRACE_ENABLE()
#define NVRM_TRACE_DUMP()
#define NVRM_TRACE(c0)
#define NVRM_TRACE1(c0)
#define NVRM_TRACE2(c0, c1)
#define NVRM_TRACE3(c0, c1, c2)
#define NVRM_TRACE4(c0, c1, c2, c3)
#define NVRM_TRACE5(c0, c1, c2, c3, c4)
#define FIFOLOG(a,b,c)

#endif  // ! USE_NVRM_TRACE

#define NVRM_TRACE_ERROR(code, status)   NVRM_TRACE3('EEEE', (code), (status))
#define NVRM_TRACE_API(code, p0, p1, p2) NVRM_TRACE5('API ', (code), (p0), (p1), (p2))

void nvErrorLog(void *pVoid, NvU32 num, const char *pFormat, va_list arglist);
void nvErrorLog_va(void * pGpu, NvU32 num, const char * pFormat, ...);

// memory allocation tracking data structs and globals
#define MAX_STACK_LEVEL 6

#ifdef __cplusplus
}
#endif

#endif // _PRINTF_H_
