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

/* ------------------------ Includes --------------------------------------- */

#include "common_nvswitch.h"
#include "haldef_nvswitch.h"
#include "ls10/ls10.h"
#include "ls10/soe_ls10.h"

#include "nvswitch/ls10/dev_nvlsaw_ip.h"
#include "nvswitch/ls10/dev_nvlsaw_ip_addendum.h"
#include "nvswitch/ls10/dev_ctrl_ip.h"
#include "nvswitch/ls10/dev_ctrl_ip_addendum.h"
#include "nvswitch/ls10/dev_cpr_ip.h"
#include "nvswitch/ls10/dev_npg_ip.h"
#include "nvswitch/ls10/dev_fsp_pri.h"
#include "nvswitch/ls10/dev_soe_ip.h"
#include "nvswitch/ls10/ptop_discovery_ip.h"
#include "nvswitch/ls10/dev_minion_ip.h"

#include <stddef.h>

/* ------------------------ Macros ----------------------------------------- */
#define TNVL_MAX_CERT_CHAIN_SIZE         (0x1000)
#define TNVL_MAX_ENCODED_CERT_CHAIN_SIZE (0x1400)

#define DER_LONG_FORM_LENGTH_FIELD_BIT   (0x80)
#define DER_CERT_SIZE_FIELD_LENGTH       (0x4)

#define TNVL_PEM_BEGIN_CERTIFICATE "-----BEGIN CERTIFICATE-----\n"
#define TNVL_PEM_END_CERTIFICATE   "-----END CERTIFICATE-----\n"

#define TNVL_MAX_MEASUREMENT_SIZE        (0x2000)

#define TNVL_L1_CERTIFICATE_PEM "-----BEGIN CERTIFICATE-----\n"\
                                "MIICCzCCAZCgAwIBAgIQLTZwscoQBBHB/sDoKgZbVDAKBggqhkjOPQQDAzA1MSIw\n"\
                                "IAYDVQQDDBlOVklESUEgRGV2aWNlIElkZW50aXR5IENBMQ8wDQYDVQQKDAZOVklE\n"\
                                "SUEwIBcNMjExMTA1MDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMDUxIjAgBgNVBAMM\n"\
                                "GU5WSURJQSBEZXZpY2UgSWRlbnRpdHkgQ0ExDzANBgNVBAoMBk5WSURJQTB2MBAG\n"\
                                "ByqGSM49AgEGBSuBBAAiA2IABA5MFKM7+KViZljbQSlgfky/RRnEQScW9NDZF8SX\n"\
                                "gAW96r6u/Ve8ZggtcYpPi2BS4VFu6KfEIrhN6FcHG7WP05W+oM+hxj7nyA1r1jkB\n"\
                                "2Ry70YfThX3Ba1zOryOP+MJ9vaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"\
                                "Af8EBAMCAQYwHQYDVR0OBBYEFFeF/4PyY8xlfWi3Olv0jUrL+0lfMB8GA1UdIwQY\n"\
                                "MBaAFFeF/4PyY8xlfWi3Olv0jUrL+0lfMAoGCCqGSM49BAMDA2kAMGYCMQCPeFM3\n"\
                                "TASsKQVaT+8S0sO9u97PVGCpE9d/I42IT7k3UUOLSR/qvJynVOD1vQKVXf0CMQC+\n"\
                                "EY55WYoDBvs2wPAH1Gw4LbcwUN8QCff8bFmV4ZxjCRr4WXTLFHBKjbfneGSBWwA=\n"\
                                "-----END CERTIFICATE-----\n"

#define TNVL_L2_CERTIFICATE_PEM "-----BEGIN CERTIFICATE-----\n"\
                                "MIICijCCAhCgAwIBAgIQTCVe3jvQAb8/SjtgX8qJijAKBggqhkjOPQQDAzA1MSIw\n"\
                                "IAYDVQQDDBlOVklESUEgRGV2aWNlIElkZW50aXR5IENBMQ8wDQYDVQQKDAZOVklE\n"\
                                "SUEwIBcNMjIwMTEyMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMD0xHjAcBgNVBAMM\n"\
                                "FU5WSURJQSBHSDEwMCBJZGVudGl0eTEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0\n"\
                                "aW9uMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+pg+tDUuILlZILk5wg22YEJ9Oh6c\n"\
                                "yPcsv3IvgRWcV4LeZK1pTCoQDIplZ0E4qsLG3G04pxsbMhxbqkiz9pqlTV2rtuVg\n"\
                                "SmIqnSYkU1jWXsPS9oVLCGE8VRLl1JvqyOxUo4HaMIHXMA8GA1UdEwEB/wQFMAMB\n"\
                                "Af8wDgYDVR0PAQH/BAQDAgEGMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwu\n"\
                                "bmRpcy5udmlkaWEuY29tL2NybC9sMS1yb290LmNybDA3BggrBgEFBQcBAQQrMCkw\n"\
                                "JwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLm5kaXMubnZpZGlhLmNvbTAdBgNVHQ4E\n"\
                                "FgQUB0Kg6wOcgGB7oUFhmU2uJffCmx4wHwYDVR0jBBgwFoAUV4X/g/JjzGV9aLc6\n"\
                                "W/SNSsv7SV8wCgYIKoZIzj0EAwMDaAAwZQIxAPIQhnveFxYIrPzBqViT2I34SfS4\n"\
                                "JGWFnk/1UcdmgJmp+7l6rH/C4qxwntYSgeYrlQIwdjQuofHnhd1RL09OBO34566J\n"\
                                "C9bYAosT/86cCojiGjhLnal9hJOH0nS/lrbaoc5a\n"\
                                "-----END CERTIFICATE-----\n"

#define TNVL_L3_CERTIFICATE_PEM "-----BEGIN CERTIFICATE-----\n"\
                                "MIICqTCCAi+gAwIBAgIQcidIXMg4KYZ1y7ooFz5gUjAKBggqhkjOPQQDAzA9MR4w\n"\
                                "HAYDVQQDDBVOVklESUEgR0gxMDAgSWRlbnRpdHkxGzAZBgNVBAoMEk5WSURJQSBD\n"\
                                "b3Jwb3JhdGlvbjAgFw0yMjAzMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowUzEn\n"\
                                "MCUGA1UEAwweTlZJRElBIExTXzEwIFByb3Zpc2lvbmVyIElDQSAxMRswGQYDVQQK\n"\
                                "DBJOVklESUEgQ29ycG9yYXRpb24xCzAJBgNVBAYTAlVTMHYwEAYHKoZIzj0CAQYF\n"\
                                "K4EEACIDYgAEyGbP8B2aF0Zd0V5GhWfcnC8K8BXUJMGPhAWQo88WymU0Az+u2Y7B\n"\
                                "zI9li0TyXhth18dB1yqodYgH3KKU1c0beV1OkAUvnlx3JpNPhx8nfdlhpM9jqsXG\n"\
                                "JXeJixW5+VOlo4HbMIHYMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG\n"\
                                "MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwubmRpcy5udmlkaWEuY29tL2Ny\n"\
                                "bC9sMi1naDEwMC5jcmwwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRw\n"\
                                "Oi8vb2NzcC5uZGlzLm52aWRpYS5jb20wHQYDVR0OBBYEFBFA9xSZ0ALwvOeei4fR\n"\
                                "von435VEMB8GA1UdIwQYMBaAFAdCoOsDnIBge6FBYZlNriX3wpseMAoGCCqGSM49\n"\
                                "BAMDA2gAMGUCMQDWLHcBKxi9QVrfMoDcIg3gLBRe5oEo/Q4KR3WaUMz9ABxMHK9Y\n"\
                                "K4xPtjXW4Bup5FwCMBhLpTQqsly8gQ6w1CIyMEC4n/LSjM65TC4pGVokSyjpoyp0\n"\
                                "gWjuEBq1vBNs76Ge8A==\n"\
                                "-----END CERTIFICATE-----\n"

const static NvU8 TNVL_L1_CERTIFICATE_DER[527] =
{
    0x30, 0x82, 0x02, 0x0b, 0x30, 0x82, 0x01, 0x90, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x2d,
    0x36, 0x70, 0xb1, 0xca, 0x10, 0x04, 0x11, 0xc1, 0xfe, 0xc0, 0xe8, 0x2a, 0x06, 0x5b, 0x54, 0x30,
    0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x35, 0x31, 0x22, 0x30,
    0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x44,
    0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x43,
    0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4e, 0x56, 0x49, 0x44,
    0x49, 0x41, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
    0x39, 0x35, 0x39, 0x5a, 0x30, 0x35, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
    0x19, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x49,
    0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x43, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
    0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x30, 0x76, 0x30, 0x10, 0x06,
    0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03,
    0x62, 0x00, 0x04, 0x0e, 0x4c, 0x14, 0xa3, 0x3b, 0xf8, 0xa5, 0x62, 0x66, 0x58, 0xdb, 0x41, 0x29,
    0x60, 0x7e, 0x4c, 0xbf, 0x45, 0x19, 0xc4, 0x41, 0x27, 0x16, 0xf4, 0xd0, 0xd9, 0x17, 0xc4, 0x97,
    0x80, 0x05, 0xbd, 0xea, 0xbe, 0xae, 0xfd, 0x57, 0xbc, 0x66, 0x08, 0x2d, 0x71, 0x8a, 0x4f, 0x8b,
    0x60, 0x52, 0xe1, 0x51, 0x6e, 0xe8, 0xa7, 0xc4, 0x22, 0xb8, 0x4d, 0xe8, 0x57, 0x07, 0x1b, 0xb5,
    0x8f, 0xd3, 0x95, 0xbe, 0xa0, 0xcf, 0xa1, 0xc6, 0x3e, 0xe7, 0xc8, 0x0d, 0x6b, 0xd6, 0x39, 0x01,
    0xd9, 0x1c, 0xbb, 0xd1, 0x87, 0xd3, 0x85, 0x7d, 0xc1, 0x6b, 0x5c, 0xce, 0xaf, 0x23, 0x8f, 0xf8,
    0xc2, 0x7d, 0xbd, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
    0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
    0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
    0x16, 0x04, 0x14, 0x57, 0x85, 0xff, 0x83, 0xf2, 0x63, 0xcc, 0x65, 0x7d, 0x68, 0xb7, 0x3a, 0x5b,
    0xf4, 0x8d, 0x4a, 0xcb, 0xfb, 0x49, 0x5f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
    0x30, 0x16, 0x80, 0x14, 0x57, 0x85, 0xff, 0x83, 0xf2, 0x63, 0xcc, 0x65, 0x7d, 0x68, 0xb7, 0x3a,
    0x5b, 0xf4, 0x8d, 0x4a, 0xcb, 0xfb, 0x49, 0x5f, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
    0x3d, 0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0x8f, 0x78, 0x53, 0x37,
    0x4c, 0x04, 0xac, 0x29, 0x05, 0x5a, 0x4f, 0xef, 0x12, 0xd2, 0xc3, 0xbd, 0xbb, 0xde, 0xcf, 0x54,
    0x60, 0xa9, 0x13, 0xd7, 0x7f, 0x23, 0x8d, 0x88, 0x4f, 0xb9, 0x37, 0x51, 0x43, 0x8b, 0x49, 0x1f,
    0xea, 0xbc, 0x9c, 0xa7, 0x54, 0xe0, 0xf5, 0xbd, 0x02, 0x95, 0x5d, 0xfd, 0x02, 0x31, 0x00, 0xbe,
    0x11, 0x8e, 0x79, 0x59, 0x8a, 0x03, 0x06, 0xfb, 0x36, 0xc0, 0xf0, 0x07, 0xd4, 0x6c, 0x38, 0x2d,
    0xb7, 0x30, 0x50, 0xdf, 0x10, 0x09, 0xf7, 0xfc, 0x6c, 0x59, 0x95, 0xe1, 0x9c, 0x63, 0x09, 0x1a,
    0xf8, 0x59, 0x74, 0xcb, 0x14, 0x70, 0x4a, 0x8d, 0xb7, 0xe7, 0x78, 0x64, 0x81, 0x5b, 0x00
};

const static NvU8 TNVL_L2_CERTIFICATE_DER[654] =
{
    0x30, 0x82, 0x02, 0x8a, 0x30, 0x82, 0x02, 0x10, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x4c,
    0x25, 0x5e, 0xde, 0x3b, 0xd0, 0x01, 0xbf, 0x3f, 0x4a, 0x3b, 0x60, 0x5f, 0xca, 0x89, 0x8a, 0x30,
    0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x35, 0x31, 0x22, 0x30,
    0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x44,
    0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x43,
    0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4e, 0x56, 0x49, 0x44,
    0x49, 0x41, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
    0x39, 0x35, 0x39, 0x5a, 0x30, 0x3d, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
    0x15, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x47, 0x48, 0x31, 0x30, 0x30, 0x20, 0x49, 0x64,
    0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
    0x12, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
    0x69, 0x6f, 0x6e, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
    0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xfa, 0x98, 0x3e, 0xb4, 0x35,
    0x2e, 0x20, 0xb9, 0x59, 0x20, 0xb9, 0x39, 0xc2, 0x0d, 0xb6, 0x60, 0x42, 0x7d, 0x3a, 0x1e, 0x9c,
    0xc8, 0xf7, 0x2c, 0xbf, 0x72, 0x2f, 0x81, 0x15, 0x9c, 0x57, 0x82, 0xde, 0x64, 0xad, 0x69, 0x4c,
    0x2a, 0x10, 0x0c, 0x8a, 0x65, 0x67, 0x41, 0x38, 0xaa, 0xc2, 0xc6, 0xdc, 0x6d, 0x38, 0xa7, 0x1b,
    0x1b, 0x32, 0x1c, 0x5b, 0xaa, 0x48, 0xb3, 0xf6, 0x9a, 0xa5, 0x4d, 0x5d, 0xab, 0xb6, 0xe5, 0x60,
    0x4a, 0x62, 0x2a, 0x9d, 0x26, 0x24, 0x53, 0x58, 0xd6, 0x5e, 0xc3, 0xd2, 0xf6, 0x85, 0x4b, 0x08,
    0x61, 0x3c, 0x55, 0x12, 0xe5, 0xd4, 0x9b, 0xea, 0xc8, 0xec, 0x54, 0xa3, 0x81, 0xda, 0x30, 0x81,
    0xd7, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
    0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
    0x01, 0x06, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0xa0,
    0x2e, 0xa0, 0x2c, 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
    0x6e, 0x64, 0x69, 0x73, 0x2e, 0x6e, 0x76, 0x69, 0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
    0x63, 0x72, 0x6c, 0x2f, 0x6c, 0x31, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30,
    0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2b, 0x30, 0x29, 0x30,
    0x27, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, 0x74, 0x74,
    0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x6e, 0x64, 0x69, 0x73, 0x2e, 0x6e, 0x76,
    0x69, 0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
    0x16, 0x04, 0x14, 0x07, 0x42, 0xa0, 0xeb, 0x03, 0x9c, 0x80, 0x60, 0x7b, 0xa1, 0x41, 0x61, 0x99,
    0x4d, 0xae, 0x25, 0xf7, 0xc2, 0x9b, 0x1e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
    0x30, 0x16, 0x80, 0x14, 0x57, 0x85, 0xff, 0x83, 0xf2, 0x63, 0xcc, 0x65, 0x7d, 0x68, 0xb7, 0x3a,
    0x5b, 0xf4, 0x8d, 0x4a, 0xcb, 0xfb, 0x49, 0x5f, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
    0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xf2, 0x10, 0x86, 0x7b,
    0xde, 0x17, 0x16, 0x08, 0xac, 0xfc, 0xc1, 0xa9, 0x58, 0x93, 0xd8, 0x8d, 0xf8, 0x49, 0xf4, 0xb8,
    0x24, 0x65, 0x85, 0x9e, 0x4f, 0xf5, 0x51, 0xc7, 0x66, 0x80, 0x99, 0xa9, 0xfb, 0xb9, 0x7a, 0xac,
    0x7f, 0xc2, 0xe2, 0xac, 0x70, 0x9e, 0xd6, 0x12, 0x81, 0xe6, 0x2b, 0x95, 0x02, 0x30, 0x76, 0x34,
    0x2e, 0xa1, 0xf1, 0xe7, 0x85, 0xdd, 0x51, 0x2f, 0x4f, 0x4e, 0x04, 0xed, 0xf8, 0xe7, 0xae, 0x89,
    0x0b, 0xd6, 0xd8, 0x02, 0x8b, 0x13, 0xff, 0xce, 0x9c, 0x0a, 0x88, 0xe2, 0x1a, 0x38, 0x4b, 0x9d,
    0xa9, 0x7d, 0x84, 0x93, 0x87, 0xd2, 0x74, 0xbf, 0x96, 0xb6, 0xda, 0xa1, 0xce, 0x5a,
};

const static NvU8 TNVL_L3_CERTIFICATE_DER[686] =
{
    0x30, 0x82, 0x02, 0xaa, 0x30, 0x82, 0x02, 0x2f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x6a,
    0xfe, 0x71, 0x84, 0xf9, 0x22, 0x32, 0xc8, 0xdf, 0x7b, 0x24, 0x22, 0x61, 0x77, 0x6e, 0x56, 0x30,
    0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x3d, 0x31, 0x1e, 0x30,
    0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x47,
    0x48, 0x31, 0x30, 0x30, 0x20, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x31, 0x1b, 0x30,
    0x19, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x12, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x43,
    0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32,
    0x30, 0x33, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39,
    0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x53, 0x31, 0x27,
    0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20,
    0x47, 0x48, 0x31, 0x30, 0x30, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
    0x72, 0x20, 0x49, 0x43, 0x41, 0x20, 0x31, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0a,
    0x0c, 0x12, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61,
    0x74, 0x69, 0x6f, 0x6e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
    0x53, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
    0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xcd, 0x47, 0x56, 0xaa, 0x39, 0xf5, 0x3a,
    0x55, 0xe1, 0x2d, 0xf1, 0x4e, 0x28, 0x01, 0x53, 0x82, 0x1a, 0x86, 0xf9, 0x0d, 0xf3, 0x17, 0x8c,
    0x60, 0x48, 0x16, 0xd9, 0xb1, 0x41, 0x32, 0x59, 0x80, 0x82, 0xde, 0xb2, 0xa3, 0x13, 0xd3, 0x67,
    0xa3, 0xcf, 0x19, 0xa4, 0x14, 0x31, 0xf3, 0x93, 0xa8, 0xd0, 0xf9, 0x2a, 0x3f, 0x67, 0x70, 0xa0,
    0xc5, 0x4d, 0x4d, 0x03, 0x2f, 0xe5, 0xcb, 0xf2, 0xf6, 0x32, 0xda, 0x4e, 0xf4, 0x93, 0x5d, 0x9c,
    0x0d, 0xd8, 0x74, 0x07, 0x13, 0xdb, 0xbb, 0xc7, 0xb0, 0x48, 0x62, 0xb5, 0xa2, 0xd2, 0xc1, 0xb7,
    0xe6, 0xad, 0x48, 0x24, 0xd4, 0x8e, 0x18, 0xee, 0x4b, 0xa3, 0x81, 0xdb, 0x30, 0x81, 0xd8, 0x30,
    0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
    0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
    0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x35, 0x30, 0x33, 0x30, 0x31, 0xa0, 0x2f, 0xa0,
    0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x6e, 0x64,
    0x69, 0x73, 0x2e, 0x6e, 0x76, 0x69, 0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
    0x6c, 0x2f, 0x6c, 0x32, 0x2d, 0x67, 0x68, 0x31, 0x30, 0x30, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x37,
    0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27,
    0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, 0x74, 0x74, 0x70,
    0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x6e, 0x64, 0x69, 0x73, 0x2e, 0x6e, 0x76, 0x69,
    0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
    0x04, 0x14, 0x29, 0x68, 0xcb, 0x16, 0x2c, 0xd0, 0x77, 0x95, 0x72, 0xa2, 0x79, 0x10, 0x03, 0xe6,
    0x9e, 0xba, 0x0c, 0xcc, 0x0a, 0x94, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
    0x16, 0x80, 0x14, 0x07, 0x42, 0xa0, 0xeb, 0x03, 0x9c, 0x80, 0x60, 0x7b, 0xa1, 0x41, 0x61, 0x99,
    0x4d, 0xae, 0x25, 0xf7, 0xc2, 0x9b, 0x1e, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0xca, 0xd0, 0x10, 0xab, 0xe3,
    0xd0, 0xcd, 0x27, 0x8f, 0x18, 0x87, 0x9c, 0x2e, 0xdf, 0xcf, 0x1b, 0x66, 0x27, 0xc3, 0x17, 0x10,
    0x2c, 0x89, 0x44, 0xb8, 0x53, 0x57, 0xc6, 0x9a, 0x92, 0x59, 0x16, 0x10, 0x9b, 0x38, 0x31, 0xfa,
    0x99, 0x1c, 0x1c, 0x33, 0x1a, 0x7a, 0x10, 0xe6, 0xb2, 0x66, 0xe6, 0x02, 0x31, 0x00, 0xd8, 0x29,
    0x3c, 0x8d, 0x73, 0x61, 0x71, 0x58, 0x5b, 0xa1, 0x1e, 0xd7, 0x42, 0x13, 0x79, 0x6c, 0xe1, 0x2e,
    0xd2, 0x22, 0x77, 0xa1, 0x74, 0x4a, 0xd3, 0x64, 0xdb, 0xa1, 0x17, 0x29, 0x9c, 0xe1, 0x83, 0x8c,
    0xe9, 0x59, 0x4b, 0x59, 0x36, 0x3f, 0x08, 0xcf, 0xab, 0x7a, 0xc8, 0xe3, 0xab, 0x14,
};

/* ------------------------ Static Functions ------------------------------- */
/*!
 @param pCert       : The pointer to certification chain start
 @param bufferEnd   : The pointer to certification chain end
 @parsm pCertLength : The pointer to store return certification size

 @return Return NV-OK if no error.

* Static function that calculates the length of the X509 certificate in DER/TLV
* format. It assumes that the certificate is valid.
*/
static NvlStatus
_calc_x509_cert_size_ls10
(
    nvswitch_device *device,
    NvU8 *pCert,
    NvU8 *bufferEnd,
    NvU32 *pCertLength
)
{
    // The cert is in TLV format.
    NvU32 certSize       = pCert[1];

    // Check to make sure that some data exists after TNVL header, and it is enough to check cert size.
    if (pCert + DER_CERT_SIZE_FIELD_LENGTH >= bufferEnd ||
        pCert + DER_CERT_SIZE_FIELD_LENGTH <= pCert)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: pCert + DER_CERT_SIZE_FIELD_LENGTH(0x%x) is not valid value !! \n",
            __FUNCTION__, DER_CERT_SIZE_FIELD_LENGTH);

       return -NVL_NO_MEM;
    }

    // Check if the length is in DER longform.
    // MSB in the length field is set for long form notation.
    // fields.
    if (certSize & DER_LONG_FORM_LENGTH_FIELD_BIT)
    {
        //
        // The remaining bits in the length field indicate the
        // number of following bytes used to represent the length.
        // in base 256, most significant digit first.
        //
        NvU32 numLenBytes = certSize & 0x3f;
        NvU8 *pStart      = &pCert[2];
        NvU8 *pEnd        = pStart + numLenBytes; // NOTE: Don't need to subtract numLenBytes 1 here.

        // Checking for buffer overflow.
        if (pEnd > bufferEnd)
        {
            return -NVL_NO_MEM;
        }

        certSize = *pStart;
        while (++pStart < pEnd)
        {
            certSize = (certSize << 8) + *pStart ;
        }
        // Total cert length includes the Tag + length
        // Adding it here.
        certSize += 2 + numLenBytes;
    }

    //
    // Check to make sure we have not hit end of buffer, and there is space for AK cert.
    // Check for underflow as well. This makes sure we haven't missed the calculation to
    // go past the end of the buffer
    //
    if (pCert + (certSize - 1) > bufferEnd ||
        pCert + (certSize - 1) <= pCert)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: pCert + (certSize(0x%x) - 1) is not a valid value !! \n",
            __FUNCTION__, certSize);

        return -NVL_NO_MEM;
    }

    *pCertLength = certSize;
    return NVL_SUCCESS;
}

static NvlStatus
_pem_write_buffer_ls10
(
    nvswitch_device *device,
    NvU8 const *der,
    NvU64       derLen,
    NvU8       *buffer,
    NvU64       bufferLen,
    NvU64      *bufferUsed
)
{
    static const NvU8 base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    NvU64 i, tmp, size;
    NvU64 printed = 0;
    NvU8 *ptr = buffer;

    // Base64 encoded size
    size = (derLen + 2) / 3 * 4;

    // Add 1 byte per 64 for newline
    size = size + (size + 63) / 64;

    // Add header excluding the terminating null and footer including the null
    size += sizeof(TNVL_PEM_BEGIN_CERTIFICATE) - 1 +
            sizeof(TNVL_PEM_END_CERTIFICATE);

    if (bufferLen < size)
    {
        return -NVL_NO_MEM;
    }

    nvswitch_os_memcpy(ptr, TNVL_PEM_BEGIN_CERTIFICATE, sizeof(TNVL_PEM_BEGIN_CERTIFICATE) - 1);
    ptr += sizeof(TNVL_PEM_BEGIN_CERTIFICATE) - 1;

    for (i = 0; (i + 2) < derLen; i += 3)
    {
        tmp = (der[i] << 16) | (der[i + 1] << 8) | (der[i + 2]);
        *ptr++ = base64[(tmp >> 18) & 63];
        *ptr++ = base64[(tmp >> 12) & 63];
        *ptr++ = base64[(tmp >> 6) & 63];
        *ptr++ = base64[(tmp >> 0) & 63];

        printed += 4;
        if (printed == 64)
        {
            *ptr++ = '\n';
            printed = 0;
        }
    }

    if ((i == derLen) && (printed != 0))
    {
        *ptr++ = '\n';
    }

    // 1 byte extra
    if (i == (derLen - 1))
    {
        tmp = der[i] << 4;
        *ptr++ = base64[(tmp >> 6) & 63];
        *ptr++ = base64[(tmp >> 0) & 63];
        *ptr++ = '=';
        *ptr++ = '=';
        *ptr++ = '\n';
    }

    // 2 byte extra
    if (i == (derLen - 2))
    {
        tmp = ((der[i] << 8) | (der[i + 1])) << 2;
        *ptr++ = base64[(tmp >> 12) & 63];
        *ptr++ = base64[(tmp >> 6) & 63];
        *ptr++ = base64[(tmp >> 0) & 63];
        *ptr++ = '=';
        *ptr++ = '\n';
    }

     nvswitch_os_memcpy(ptr, TNVL_PEM_END_CERTIFICATE, sizeof(TNVL_PEM_END_CERTIFICATE));
     ptr += sizeof(TNVL_PEM_END_CERTIFICATE);

    *bufferUsed = size;
    return NVL_SUCCESS;
}

/*!
* Static function builds the cert chain in DER format. It is assumed that
* the all the certificates are valid. Also it is assumed that there is a valid
* tnvl session already established.
*/
static NvlStatus
_tnvl_build_cert_chain_der_ls10
(
    nvswitch_device *device,
    NvU8   *pFirstCert,
    NvU32   firstCertSize,
    NvU8   *pSecondCert,
    NvU32   secondCertSize,
    NvU8   *pOutBuffer,
    size_t *outBufferSize
)
{
    NvU64      remainingOutBufferSize = 0;
    NvU64      totalSize              = 0;
    void      *pPortMemCopyStatus     = NULL;

    if (pFirstCert == NULL || pSecondCert == NULL || pOutBuffer == NULL || outBufferSize == NULL)
    {
        return -NVL_BAD_ARGS;
    }

    // Calculate the total size of the certificate chain (in DER).
    totalSize = sizeof(TNVL_L1_CERTIFICATE_DER) +
                sizeof(TNVL_L2_CERTIFICATE_DER) +
                sizeof(TNVL_L3_CERTIFICATE_DER) +
                secondCertSize                  +
                firstCertSize;

    remainingOutBufferSize = *outBufferSize;
    if (remainingOutBufferSize < totalSize)
    {
        return -NVL_NO_MEM;
    }

    //
    // Write the L1 DER certificate to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     TNVL_L1_CERTIFICATE_DER,
                                     sizeof(TNVL_L1_CERTIFICATE_DER));
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    remainingOutBufferSize -= sizeof(TNVL_L1_CERTIFICATE_DER);
    pOutBuffer             += sizeof(TNVL_L1_CERTIFICATE_DER);

    //
    // Write the L2 DER certificate to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     TNVL_L2_CERTIFICATE_DER,
                                     sizeof(TNVL_L2_CERTIFICATE_DER));
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    remainingOutBufferSize -= sizeof(TNVL_L2_CERTIFICATE_DER);
    pOutBuffer             += sizeof(TNVL_L2_CERTIFICATE_DER);

    //
    // Write the L3 DER certificate to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     TNVL_L3_CERTIFICATE_DER,
                                     sizeof(TNVL_L3_CERTIFICATE_DER));
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    remainingOutBufferSize -= sizeof(TNVL_L3_CERTIFICATE_DER);
    pOutBuffer             += sizeof(TNVL_L3_CERTIFICATE_DER);

    //
    // Write the IK certificate in DER to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     pSecondCert,
                                     secondCertSize);
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    remainingOutBufferSize -= secondCertSize;
    pOutBuffer             += secondCertSize;

    //
    // Write the AK certificate in DER to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     pFirstCert,
                                     firstCertSize);
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    remainingOutBufferSize -= firstCertSize;
    pOutBuffer             += firstCertSize;

    // Output the total certificate chain size
    *outBufferSize = totalSize;

    return NVL_SUCCESS;
}

/*!
* Static function that first converts the IK and AK certificates from DER to
* PEM format. Then it builds the cert chain in PEM format. It is assumed that
* the all the certificates are valid. Also it is assumed that there is a valid
* tnvl session already established.
*/
static NvlStatus
_tnvl_build_cert_chain_pem_ls10
(
    nvswitch_device *device,
    NvU8   *pFirstCert,
    NvU32   firstCertSize,
    NvU8   *pSecondCert,
    NvU32   secondCertSize,
    NvU8   *pOutBuffer,
    size_t *outBufferSize
)
{
    NvU64              firstCertOutputSize      = 0;
    NvU64              secondCertOutputSize     = 0;
    NvU64              remainingOutBufferSize   = 0;
    void              *pPortMemCopyStatus       = NULL;
    NvlStatus          status;

    if (pFirstCert == NULL || pSecondCert == NULL || pOutBuffer == NULL || outBufferSize == NULL)
    {
        return -NVL_BAD_ARGS;
    }

    remainingOutBufferSize = *outBufferSize;

    //
    // Write the AK certificate to the output buffer
    //
    status = _pem_write_buffer_ls10(device, pFirstCert, firstCertSize, pOutBuffer,
                              remainingOutBufferSize, &firstCertOutputSize);
    if (status != NVL_SUCCESS)
    {
        return status;
    }

    //
    // Keep track how much space we have left in the output buffer
    // and where the next certificate should start.
    // Clear the last byte (NULL).
    //
    remainingOutBufferSize -= firstCertOutputSize - 1;
    pOutBuffer             += firstCertOutputSize - 1;

    //
    // Write the IK certificate to the output buffer
    //
    status = _pem_write_buffer_ls10(device, pSecondCert, secondCertSize, pOutBuffer,
                              remainingOutBufferSize, &secondCertOutputSize);
    if (status != NVL_SUCCESS)
    {
        return status;
    }

    remainingOutBufferSize -= secondCertOutputSize - 1;
    pOutBuffer             += secondCertOutputSize - 1;

    // Checking if the available size of buffer is enough to keep the whole
    // certificate chain otherwise raise error.
    if (remainingOutBufferSize < sizeof(TNVL_L1_CERTIFICATE_PEM)
                               + sizeof(TNVL_L2_CERTIFICATE_PEM)
                               + sizeof(TNVL_L3_CERTIFICATE_PEM))
    {
        return -NVL_NO_MEM;
    }

    //
    // Write the L3 certificate to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     TNVL_L3_CERTIFICATE_PEM,
                                     sizeof(TNVL_L3_CERTIFICATE_PEM) - 1);
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    remainingOutBufferSize -= sizeof(TNVL_L3_CERTIFICATE_PEM) - 1;
    pOutBuffer             += sizeof(TNVL_L3_CERTIFICATE_PEM) - 1;

    //
    // Write the L2 certificate to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     TNVL_L2_CERTIFICATE_PEM,
                                     sizeof(TNVL_L2_CERTIFICATE_PEM) - 1);
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }
    remainingOutBufferSize -= sizeof(TNVL_L2_CERTIFICATE_PEM) - 1;
    pOutBuffer             += sizeof(TNVL_L2_CERTIFICATE_PEM) - 1;

    //
    // Write the L1 certificate to the output buffer
    //
    pPortMemCopyStatus = nvswitch_os_memcpy(pOutBuffer,
                                     TNVL_L1_CERTIFICATE_PEM,
                                     sizeof(TNVL_L1_CERTIFICATE_PEM) - 1);
    if (pPortMemCopyStatus == NULL)
    {
        return -NVL_NO_MEM;
    }

    //
    // Output the total certificate chain size
    // Do not count the NULL bytes.
    //
    *outBufferSize = firstCertOutputSize - 1 +
                     secondCertOutputSize - 1 +
                     sizeof(TNVL_L3_CERTIFICATE_PEM) - 1 +
                     sizeof(TNVL_L2_CERTIFICATE_PEM) - 1 +
                     sizeof(TNVL_L1_CERTIFICATE_PEM) - 1;

    return NVL_SUCCESS;
}

/* ------------------------ Public Functions ------------------------------- */

static NvlStatus
_nvswitch_tnvl_get_cert_chain_from_fsp_ls10
(
    nvswitch_device *device,
    NvU8 *pCertChain,
    size_t *pCertChainLength
)
{
    NvlStatus status;
    TNVL_GET_ATT_CERTS_CMD_PAYLOAD *pCmdPayload   = nvswitch_os_malloc(sizeof(TNVL_GET_ATT_CERTS_CMD_PAYLOAD));
    TNVL_GET_ATT_CERTS_RSP_PAYLOAD *pRspPayload   = nvswitch_os_malloc(sizeof(TNVL_GET_ATT_CERTS_RSP_PAYLOAD));
    NVSWITCH_TIMEOUT timeout;

    if ((pCertChainLength == NULL) || (pCertChain == NULL))
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Invalid Args\n",
            __FUNCTION__);
        status = -NVL_BAD_ARGS;
        goto ErrorExit;
    }

    if (pCmdPayload == NULL || pRspPayload == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to allocate memory\n",
            __FUNCTION__);
        status = -NVL_NO_MEM;
        goto ErrorExit;
    }

    pCmdPayload->subMessageId = TNVL_GET_ATT_CERTS_SUBMESSAGE_ID;
    pCmdPayload->minorVersion = 0;
    pCmdPayload->majorVersion = 1;

    nvswitch_timeout_create(5 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);

    status = nvswitch_fsp_send_and_read_message(device,
        (NvU8*) pCmdPayload, sizeof(TNVL_GET_ATT_CERTS_CMD_PAYLOAD), NVDM_TYPE_TNVL,
        (NvU8*) pRspPayload, sizeof(TNVL_GET_ATT_CERTS_RSP_PAYLOAD), &timeout);
    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: RPC failed for FSP cert query\n",
            __FUNCTION__);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    // Validate response
    if (pRspPayload->subMessageId != TNVL_GET_ATT_CERTS_SUBMESSAGE_ID)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Unknown submessage Id %d, Expected %d\n",
            __FUNCTION__,
            pRspPayload->subMessageId, TNVL_GET_ATT_CERTS_SUBMESSAGE_ID);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    // Validate response certChainLength
    if (pRspPayload->certChainLength > TNVL_MAX_CERT_CHAIN_SIZE)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Response Cert-chain length (%d) is greater than max size (%d)\n",
            __FUNCTION__,
            pRspPayload->certChainLength, TNVL_MAX_CERT_CHAIN_SIZE);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    nvswitch_os_memcpy(pCertChain, pRspPayload->certChain, pRspPayload->certChainLength);
    *pCertChainLength = pRspPayload->certChainLength;

ErrorExit:
    nvswitch_os_free(pCmdPayload);
    nvswitch_os_free(pRspPayload);

    return status;
}

/*!
 * This function retrieves nvswitch certificates.
 *
 * @param  device    nvswitch device pointer
 * @param  params   certificate params
 *
 * @return Returns NVL_SUCCESS on success. Anything else should be considered a failure.
 */
NvlStatus
nvswitch_tnvl_get_attestation_certificate_chain_ls10
(
    nvswitch_device *device,
    NVSWITCH_GET_ATTESTATION_CERTIFICATE_CHAIN_PARAMS *params
)
{
    NvlStatus          status = NVL_SUCCESS;
    NvU8              *pIkCertificate           = NULL;
    NvU32              ikCertificateSize        = 0;
    NvU8              *pAkCertificate           = NULL;
    NvU32              akCertificateSize        = 0;
    NvU8              *pCertChain               = NULL;
    size_t             certChainLength          = 0;
    NvU8              *pDerCertChain            = NULL;
    size_t             derCertChainSize         = 0;
    NvU8              *pCertChainBufferEnd      = NULL;
    NvU8              *pAttestationCertChain    = NULL;
    size_t             attestationCertChainSize = 0;
    NvU32              totalSize                = 0;

    if (params == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Bad args!\n",
            __FUNCTION__);
        return -NVL_BAD_ARGS;
    }

    if (!nvswitch_is_tnvl_mode_enabled(device))
    {
        NVSWITCH_PRINT(device, ERROR,
           "%s: TNVL is not enabled\n",
           __FUNCTION__);
        return -NVL_ERR_NOT_SUPPORTED;
    }

    // Allocate buffer for certificates.
    certChainLength                 = TNVL_MAX_CERT_CHAIN_SIZE;
    pCertChain                      = nvswitch_os_malloc(certChainLength);
    derCertChainSize                = TNVL_MAX_ENCODED_CERT_CHAIN_SIZE;
    pDerCertChain                   = nvswitch_os_malloc(derCertChainSize);
    attestationCertChainSize        = TNVL_MAX_ENCODED_CERT_CHAIN_SIZE;
    pAttestationCertChain           = nvswitch_os_malloc(attestationCertChainSize);

    if (pCertChain == NULL || pDerCertChain == NULL || pAttestationCertChain == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to allocate memory\n",
            __FUNCTION__);
        status = -NVL_NO_MEM;
        goto ErrorExit;
    }

    nvswitch_os_memset(pCertChain, 0, certChainLength);
    nvswitch_os_memset(pDerCertChain, 0, derCertChainSize);
    nvswitch_os_memset(pAttestationCertChain, 0, attestationCertChainSize);

    // Fetch Attestation cert chain from FSP
    status = _nvswitch_tnvl_get_cert_chain_from_fsp_ls10(device, pCertChain, &certChainLength);
    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to get nvswitch certs from FSP\n",
            __FUNCTION__);
        goto ErrorExit;
    }

    certChainLength = certChainLength -
                      NVSWITCH_IK_HASH_LENGTH -
                      NVSWITCH_ATT_CERT_SIZE_FIELD_LENGTH -
                      NVSWITCH_ATT_RSVD1_FIELD_LENGTH;
    //
    // pCertChainBufferEnd represents last valid byte for cert buffer.
    //
    pCertChainBufferEnd = pCertChain + certChainLength - 1;
    pIkCertificate      = (NvU8 *)pCertChain;

    // Calculate the size of the IK cert, and skip past it to get the AK cert.
    status = _calc_x509_cert_size_ls10(device, pIkCertificate, pCertChainBufferEnd, &ikCertificateSize);

    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to calculate IK size\n",
            __FUNCTION__);
        goto ErrorExit;
    }

    pAkCertificate = (NvU8 *)pIkCertificate + ikCertificateSize;

    // Calculate the size of the AK certificate.
    status = _calc_x509_cert_size_ls10(device, pAkCertificate, pCertChainBufferEnd, &akCertificateSize);
    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to calculate AK size\n",
            __FUNCTION__);
        goto ErrorExit;
    }

    // Make sure we have calculated the size correctly.
    if ((pAkCertificate + akCertificateSize - 1) != pCertChainBufferEnd)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Error in calculating AK size\n",
            __FUNCTION__);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    // Retrieve the entire certificate chain in DER format in order to validate it.
    status = _tnvl_build_cert_chain_der_ls10(device,
                                    pAkCertificate, akCertificateSize,
                                    pIkCertificate, ikCertificateSize,
                                    pDerCertChain,
                                    &derCertChainSize);
    if (status != NVL_SUCCESS)
    {
        goto ErrorExit;
    }

    totalSize = sizeof(TNVL_L1_CERTIFICATE_DER)  +
                sizeof(TNVL_L2_CERTIFICATE_DER)  +
                sizeof(TNVL_L3_CERTIFICATE_DER)  +
                akCertificateSize                +
                ikCertificateSize;

    if (derCertChainSize != totalSize)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: derCertChainSize(%llu) != totalSize(0x%x) !! \n",
            __FUNCTION__, ((NvU64)derCertChainSize), totalSize);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    //
    // Now that the cert chain is valid, retrieve the cert chain in PEM format,
    // as the Verifier can only parse PEM format.
    //
    status = _tnvl_build_cert_chain_pem_ls10(device,
                                    pAkCertificate, akCertificateSize,
                                    pIkCertificate, ikCertificateSize,
                                    pAttestationCertChain,
                                    &attestationCertChainSize);
    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to build PEM cert chain\n",
            __FUNCTION__);
        goto ErrorExit;
    }

    if (attestationCertChainSize > NVSWITCH_ATTESTATION_CERT_CHAIN_MAX_SIZE)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Attestation cert chain size (%lu) greater than max size (%d)\n",
            __FUNCTION__, attestationCertChainSize, NVSWITCH_ATTESTATION_CERT_CHAIN_MAX_SIZE);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    nvswitch_os_memcpy(params->attestationCertChain, pAttestationCertChain, attestationCertChainSize);
    params->attestationCertChainSize = attestationCertChainSize;

ErrorExit:
    nvswitch_os_free(pCertChain);
    nvswitch_os_free(pDerCertChain);
    nvswitch_os_free(pAttestationCertChain);

    return status;
}

NvlStatus
nvswitch_tnvl_get_attestation_report_ls10
(
    nvswitch_device *device,
    NVSWITCH_GET_ATTESTATION_REPORT_PARAMS *params
)
{
    NvlStatus status;
    TNVL_GET_ATT_REPORT_CMD_PAYLOAD *pCmdPayload;
    TNVL_GET_ATT_REPORT_RSP_PAYLOAD *pRspPayload;
    NVSWITCH_TIMEOUT timeout;

    if (params == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
           "%s: Invalid args\n",
           __FUNCTION__);
        return -NVL_BAD_ARGS;
    }

    if (!nvswitch_is_tnvl_mode_enabled(device))
    {
        NVSWITCH_PRINT(device, ERROR,
           "%s: TNVL is not enabled\n",
           __FUNCTION__);
        return -NVL_ERR_NOT_SUPPORTED;
    }

    pCmdPayload  = nvswitch_os_malloc(sizeof(TNVL_GET_ATT_REPORT_CMD_PAYLOAD));
    pRspPayload  = nvswitch_os_malloc(sizeof(TNVL_GET_ATT_REPORT_RSP_PAYLOAD));

    if (pCmdPayload == NULL || pRspPayload == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to allocate memory\n",
            __FUNCTION__);
        status = -NVL_NO_MEM;
        goto ErrorExit;
    }

    // Request the Attestation Report using the provided nonce, signed by the AK cert.
    pCmdPayload->subMessageId = TNVL_GET_ATT_REPORT_SUBMESSAGE_ID;
    pCmdPayload->minorVersion = 0;
    pCmdPayload->majorVersion = 1;
    nvswitch_os_memcpy(pCmdPayload->nonce, params->nonce, NVSWITCH_NONCE_SIZE);

    nvswitch_timeout_create(10 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);

    status = nvswitch_fsp_send_and_read_message(device,
        (NvU8*) pCmdPayload, sizeof(TNVL_GET_ATT_REPORT_CMD_PAYLOAD), NVDM_TYPE_TNVL,
        (NvU8*) pRspPayload, sizeof(TNVL_GET_ATT_REPORT_RSP_PAYLOAD), &timeout);
    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to get nvswitch measurements from FSP\n",
            __FUNCTION__);
        goto ErrorExit;
    }

    // Validate response
    if (pRspPayload->subMessageId != TNVL_GET_ATT_REPORT_SUBMESSAGE_ID)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Unknown submessage Id %d, Expected %d\n",
            __FUNCTION__,
            pRspPayload->subMessageId, TNVL_GET_ATT_REPORT_SUBMESSAGE_ID);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    // Validate measurement size
    if (pRspPayload->measurementSize > NVSWITCH_ATTESTATION_REPORT_MAX_SIZE)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Response measurement size (%d) is greater than the attestation max size (%d)\n",
            __FUNCTION__,
            pRspPayload->measurementSize, NVSWITCH_ATTESTATION_REPORT_MAX_SIZE);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    nvswitch_os_memcpy(params->attestationReport,
        pRspPayload->measurementBuffer, pRspPayload->measurementSize);
    params->attestationReportSize = pRspPayload->measurementSize;

ErrorExit:
    nvswitch_os_free(pCmdPayload);
    nvswitch_os_free(pRspPayload);

    return status;
}

NvlStatus
nvswitch_detect_tnvl_mode_ls10
(
    nvswitch_device *device
)
{
    NvU32 val;

    // Detect for TNVL mode
    val = NVSWITCH_SAW_RD32_LS10(device, _NVLSAW, _TNVL_MODE);
    if (FLD_TEST_DRF(_NVLSAW, _TNVL_MODE, _STATUS, _ENABLED, val))
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: TNVL Mode Detected\n",
            __FUNCTION__);
        device->tnvl_mode = NVSWITCH_DEVICE_TNVL_MODE_ENABLED;
    }

    return NVL_SUCCESS;
}

NvBool
nvswitch_is_tnvl_mode_enabled_ls10
(
    nvswitch_device *device
)
{
    return (device->tnvl_mode != NVSWITCH_DEVICE_TNVL_MODE_DISABLED);
}

NvBool
nvswitch_is_tnvl_mode_locked_ls10
(
    nvswitch_device *device
)
{
    return (device->tnvl_mode == NVSWITCH_DEVICE_TNVL_MODE_LOCKED);
}

NvlStatus
nvswitch_tnvl_send_fsp_lock_config_ls10
(
    nvswitch_device *device
)
{
    NvlStatus status;
    TNVL_LOCK_CONFIG_CMD_PAYLOAD *pCmdPayload;
    TNVL_LOCK_CONFIG_RSP_PAYLOAD *pRspPayload;
    NVSWITCH_TIMEOUT timeout;

    if (!nvswitch_is_tnvl_mode_enabled(device))
    {
        NVSWITCH_PRINT(device, ERROR,
           "%s: TNVL is not enabled\n",
           __FUNCTION__);
        return -NVL_ERR_NOT_SUPPORTED;
    }

    pCmdPayload   = nvswitch_os_malloc(sizeof(TNVL_LOCK_CONFIG_CMD_PAYLOAD));
    pRspPayload   = nvswitch_os_malloc(sizeof(TNVL_LOCK_CONFIG_RSP_PAYLOAD));

    if (pCmdPayload == NULL || pRspPayload == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Failed to allocate memory\n",
            __FUNCTION__);
        status = -NVL_NO_MEM;
        goto ErrorExit;
    }

    pCmdPayload->subMessageId = TNVL_LOCK_CONFIG_SUBMESSAGE_ID;
    pCmdPayload->minorVersion = 0;
    pCmdPayload->majorVersion = 1;

    nvswitch_timeout_create(5 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);

    status = nvswitch_fsp_send_and_read_message(device,
        (NvU8*) pCmdPayload, sizeof(TNVL_LOCK_CONFIG_CMD_PAYLOAD), NVDM_TYPE_TNVL,
        (NvU8*) pRspPayload, sizeof(TNVL_LOCK_CONFIG_RSP_PAYLOAD), &timeout);
    if (status != NVL_SUCCESS)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: RPC failed for FSP lock config command\n",
            __FUNCTION__);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

    // Validate response
    if (pRspPayload->subMessageId != TNVL_LOCK_CONFIG_SUBMESSAGE_ID)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: Unknown submessage Id %d, Expected %d\n",
            __FUNCTION__,
            pRspPayload->subMessageId, TNVL_LOCK_CONFIG_SUBMESSAGE_ID);
        status = -NVL_ERR_INVALID_STATE;
        goto ErrorExit;
    }

ErrorExit:
    nvswitch_os_free(pCmdPayload);
    nvswitch_os_free(pRspPayload);

    return status;
}

NvlStatus
nvswitch_tnvl_get_status_ls10
(
    nvswitch_device *device,
    NVSWITCH_GET_TNVL_STATUS_PARAMS *params
)
{
    params->status = device->tnvl_mode;
    return NVL_SUCCESS;
}

static NvBool
_nvswitch_tnvl_eng_wr_cpu_allow_list_ls10
(
    nvswitch_device *device,
    NVSWITCH_ENGINE_ID eng_id,
    NvU32 offset
)
{
    switch (eng_id)
    {
        case NVSWITCH_ENGINE_ID_SOE:
        case NVSWITCH_ENGINE_ID_GIN:
        case NVSWITCH_ENGINE_ID_FSP:
            return NV_TRUE;
        case NVSWITCH_ENGINE_ID_SAW:
        {
            if (offset == NV_NVLSAW_DRIVER_ATTACH_DETACH)
                return NV_TRUE;
            break;
        }
        case NVSWITCH_ENGINE_ID_NPG:
        {
            if ((offset == NV_NPG_INTR_RETRIGGER(0)) ||
                (offset == NV_NPG_INTR_RETRIGGER(1)))
                   return NV_TRUE;
            break;
        }
        case NVSWITCH_ENGINE_ID_CPR:
        {
            if ((offset == NV_CPR_SYS_INTR_RETRIGGER(0)) ||
                (offset == NV_CPR_SYS_INTR_RETRIGGER(1)))
                   return NV_TRUE;
            break;
        }
        case NVSWITCH_ENGINE_ID_MINION:
        {
            if ((offset == NV_MINION_NVLINK_DL_STAT(0)) ||
                (offset == NV_MINION_NVLINK_DL_STAT(1)) ||
                (offset == NV_MINION_NVLINK_DL_STAT(2)) ||
                (offset == NV_MINION_NVLINK_DL_STAT(3)))
                    return NV_TRUE;
            break;
        }
        default :
            return NV_FALSE;
    }

    return NV_FALSE;
}

void
nvswitch_tnvl_eng_wr_32_ls10
(
    nvswitch_device *device,
    NVSWITCH_ENGINE_ID eng_id,
    NvU32 eng_bcast,
    NvU32 eng_instance,
    NvU32 base_addr,
    NvU32 offset,
    NvU32 data
)
{
    if (device->nvlink_device->pciInfo.bars[0].pBar == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: register write failed at offset 0x%x\n",
            __FUNCTION__, offset);
        return;
    }

    if (!nvswitch_is_tnvl_mode_enabled(device))
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "ENG reg-write failed. TNVL mode is not enabled\n");
        return;
    }

    if (_nvswitch_tnvl_eng_wr_cpu_allow_list_ls10(device, eng_id, offset))
    {
        nvswitch_os_mem_write32((NvU8 *)device->nvlink_device->pciInfo.bars[0].pBar + base_addr + offset, data);
        return;
    }

    if (nvswitch_is_tnvl_mode_locked(device))
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "TNVL ENG_WR failure - 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
            eng_id, eng_instance, eng_bcast, base_addr, offset, data);

        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "TNVL mode is locked\n");
        return;
    }

    if (nvswitch_soe_eng_wr_32_ls10(device, eng_id, eng_bcast, eng_instance, base_addr, offset, data) != NVL_SUCCESS)
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "TNVL ENG_WR failure - 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
            eng_id, eng_instance, eng_bcast, base_addr, offset, data);

        NVSWITCH_PRINT(device, ERROR,
            "%s: SOE ENG_WR failed for 0x%x[%d] %s @0x%08x+0x%06x = 0x%08x\n",
            __FUNCTION__,
            eng_id, eng_instance,
            (
                (eng_bcast == NVSWITCH_GET_ENG_DESC_TYPE_UNICAST) ? "UC" :
                (eng_bcast == NVSWITCH_GET_ENG_DESC_TYPE_BCAST) ? "BC" :
                (eng_bcast == NVSWITCH_GET_ENG_DESC_TYPE_MULTICAST) ? "MC" :
                "??"
            ),
            base_addr, offset, data);
    }
}

static NvBool
_nvswitch_tnvl_reg_wr_cpu_allow_list_ls10
(
    nvswitch_device *device,
    NvU32 offset
)
{
    if ((offset >= DRF_BASE(NV_PFSP)) && 
       (offset <= DRF_EXTENT(NV_PFSP)))
    {
        return NV_TRUE;
    }

    if ((offset >= NV_PTOP_UNICAST_SW_DEVICE_BASE_SOE_0 + DRF_BASE(NV_SOE)) && 
       (offset <=  NV_PTOP_UNICAST_SW_DEVICE_BASE_SOE_0 + DRF_EXTENT(NV_SOE)))
    {
        return NV_TRUE;
    }

    return NV_FALSE;
}

void
nvswitch_tnvl_reg_wr_32_ls10
(
    nvswitch_device *device,
    NvU32 offset,
    NvU32 data
)
{
    if (device->nvlink_device->pciInfo.bars[0].pBar == NULL)
    {
        NVSWITCH_PRINT(device, ERROR,
            "%s: register write failed at offset 0x%x\n",
            __FUNCTION__, offset);
        NVSWITCH_ASSERT(0);
        return;
    }

    if (!nvswitch_is_tnvl_mode_enabled(device))
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "Reg-write failed. TNVL mode is not enabled\n");
        return;
    }

    if (_nvswitch_tnvl_reg_wr_cpu_allow_list_ls10(device, offset))
    {
        nvswitch_os_mem_write32((NvU8 *)device->nvlink_device->pciInfo.bars[0].pBar + offset, data);
        return;
    }

    if (nvswitch_is_tnvl_mode_locked(device))
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "TNVL REG_WR failure - 0x%08x, 0x%08x\n", offset, data);

        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "TNVL mode is locked\n");
        return;
    }

    if (nvswitch_soe_reg_wr_32_ls10(device, offset, data) != NVL_SUCCESS)
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "TNVL REG_WR failure - 0x%08x, 0x%08x\n", offset, data);
    }
}

void
nvswitch_tnvl_disable_interrupts_ls10
(
    nvswitch_device *device
)
{

    if (!nvswitch_is_tnvl_mode_enabled(device))
    {
        NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_TNVL_ERROR,
           "Failed to disable non-fatal/legacy interrupts. TNVL mode is not enabled\n");
        return;
    }

    //
    // In TNVL locked disable non-fatal NVLW, NPG, and legacy interrupt,
    // disable additional non-fatals on those partitions.
    //
    NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NVLW_NON_FATAL_IDX),
        0xFFFF);

    NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_NPG_NON_FATAL_IDX),
        0xFFFF);

    NVSWITCH_ENG_WR32(device, GIN, , 0, _CTRL, _CPU_INTR_LEAF_EN_CLEAR(NV_CTRL_CPU_INTR_UNITS_IDX),
        0xFFFFFFFF);
}

