/*
 * SPDX-FileCopyrightText: Copyright OpenBMC Authors
 * SPDX-License-Identifier: Apache-2.0
 */

#include "NvidiaPciePort.hpp"

#include "Utils.hpp"

#include <bits/basic_string.h>

#include <MctpRequester.hpp>
#include <NvidiaGpuMctpVdm.hpp>
#include <NvidiaPcieInterface.hpp>
#include <NvidiaUtils.hpp>
#include <OcpMctpVdm.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/message/native_types.hpp>

#include <cstddef>
#include <cstdint>
#include <functional>
#include <limits>
#include <memory>
#include <span>
#include <string>
#include <system_error>
#include <vector>

using std::string;

using namespace std::literals;

NvidiaPciePortInfo::NvidiaPciePortInfo(
    std::shared_ptr<sdbusplus::asio::connection>& conn,
    mctp::MctpRequester& mctpRequester, const std::string& name,
    const std::string& pcieDeviceName, const std::string& path, uint8_t eid,
    gpu::PciePortType portType, uint8_t upstreamPortNumber, uint8_t portNumber,
    sdbusplus::asio::object_server& objectServer,
    gpu::DeviceIdentification deviceType) :
    eid(eid), portType(portType), upstreamPortNumber(upstreamPortNumber),
    portNumber(portNumber), path(path), conn(conn),
    mctpRequester(mctpRequester), objectServer(objectServer),
    deviceType(deviceType)
{
    int rc = 0;
    switch (deviceType)
    {
        case gpu::DeviceIdentification::DEVICE_GPU:
            request.resize(gpu::queryScalarGroupTelemetryV1RequestSize);
            rc = gpu::encodeQueryScalarGroupTelemetryV1Request(
                0, 0, gpu::PcieScalarGroupId::LinkSpeedWidth, request);
            break;
        case gpu::DeviceIdentification::DEVICE_PCIE:
            request.resize(gpu::queryScalarGroupTelemetryV2RequestSize);
            rc = gpu::encodeQueryScalarGroupTelemetryV2Request(
                0, portType, this->upstreamPortNumber, portNumber,
                gpu::PcieScalarGroupId::LinkSpeedWidth, request);
            break;
        default:
            break;
    }
    if (rc != 0)
    {
        request.clear();
        lg2::error(
            "Failed to encode PCIe Port Info request: rc={RC}, EID={EID}, PortType={PT}, PortNumber={PN}",
            "RC", rc, "EID", eid, "PT", static_cast<uint8_t>(portType), "PN",
            portNumber);
    }

    const sdbusplus::object_path dbusPath =
        inventoryPrefix / pcieDeviceName / name;

    pciePortInterface = objectServer.add_interface(
        dbusPath, "xyz.openbmc_project.Inventory.Connector.Port");

    std::string portTypeStr;

    if (portType == gpu::PciePortType::UPSTREAM)
    {
        portTypeStr = "Upstream";
    }
    else
    {
        portTypeStr = "Downstream";
    }

    pciePortInterface->register_property(
        "PortType",
        "xyz.openbmc_project.Inventory.Connector.Port.PortType." + portTypeStr);

    pciePortInterface->register_property(
        "PortProtocol",
        std::string(
            "xyz.openbmc_project.Inventory.Connector.Port.PortProtocol.PCIe"));

    pciePortInterface->register_property("Speed",
                                         std::numeric_limits<uint64_t>::max());

    pciePortInterface->register_property("Width",
                                         std::numeric_limits<size_t>::max());

    if (!pciePortInterface->initialize())
    {
        lg2::error(
            "Error initializing PCIe Device interface, eid={EID}, portType={PT}, portNumber={PN}",
            "EID", eid, "PT", static_cast<uint8_t>(portType), "PN", portNumber);
    }

    std::vector<Association> associations;
    associations.emplace_back("connected_to", "connecting",
                              inventoryPrefix / pcieDeviceName);

    associationInterface =
        objectServer.add_interface(dbusPath, association::interface);
    associationInterface->register_property("Associations", associations);

    if (!associationInterface->initialize())
    {
        lg2::error(
            "Error initializing Association interface for PCIe Port Info, eid={EID}, portType={PT}, portNumber={PN}",
            "EID", eid, "PT", static_cast<uint8_t>(portType), "PN", portNumber);
    }
}

NvidiaPciePortInfo::~NvidiaPciePortInfo()
{
    objectServer.remove_interface(pciePortInterface);
    objectServer.remove_interface(associationInterface);
}

uint64_t NvidiaPciePortInfo::mapPcieGenToLinkSpeedBitsPerSecond(uint32_t value)
{
    static constexpr uint64_t gbpsToBps = 1000000000;

    switch (value)
    {
        case 1:
            return 2.5 * gbpsToBps;
        case 2:
            return 5.0 * gbpsToBps;
        case 3:
            return 8.0 * gbpsToBps;
        case 4:
            return 16.0 * gbpsToBps;
        case 5:
            return 32.0 * gbpsToBps;
        case 6:
            return 64.0 * gbpsToBps;
        default:
            return 0;
    }
}

void NvidiaPciePortInfo::processResponse(
    const std::error_code& sendRecvMsgResult, std::span<const uint8_t> response)
{
    if (sendRecvMsgResult)
    {
        lg2::error(
            "Error updating PCIe Port Info: sending message over MCTP failed, "
            "rc={RC}, EID={EID}, PortType={PT}, UpstreamPortNumber={UP}, PortNumber={PN}",
            "RC", sendRecvMsgResult.message(), "EID", eid, "PT",
            static_cast<uint8_t>(portType), "UP", upstreamPortNumber, "PN",
            portNumber);
        return;
    }

    ocp::accelerator_management::CompletionCode cc{};
    uint16_t reasonCode = 0;
    size_t numTelemetryValue = 0;

    int rc = 0;
    switch (deviceType)
    {
        case gpu::DeviceIdentification::DEVICE_GPU:
            rc = gpu::decodeQueryScalarGroupTelemetryV1Response(
                response, cc, reasonCode, numTelemetryValue, telemetryValues);
            break;
        case gpu::DeviceIdentification::DEVICE_PCIE:
            rc = gpu::decodeQueryScalarGroupTelemetryV2Response(
                response, cc, reasonCode, numTelemetryValue, telemetryValues);
            break;
        default:
            return;
    }

    if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
    {
        lg2::error(
            "Error updating PCIe Port Info: decode failed, "
            "rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}, PortType={PT}, UpstreamPortNumber={UP}, PortNumber={PN}",
            "RC", rc, "CC", static_cast<uint8_t>(cc), "RESC", reasonCode, "EID",
            eid, "PT", static_cast<uint8_t>(portType), "UP", upstreamPortNumber,
            "PN", portNumber);
        return;
    }

    if (telemetryValues.size() < 2)
    {
        lg2::error(
            "Error updating PCIe Port Info: insufficient telemetry values, "
            "NumValues={NUM}, EID={EID}, PortType={PT}, UpstreamPortNumber={UP}, PortNumber={PN}",
            "NUM", telemetryValues.size(), "EID", eid, "PT",
            static_cast<uint8_t>(portType), "UP", upstreamPortNumber, "PN",
            portNumber);
        return;
    }

    pciePortInterface->set_property(
        "Speed", mapPcieGenToLinkSpeedBitsPerSecond(telemetryValues[0]));

    pciePortInterface->set_property(
        "Width", NvidiaPcieInterface::decodeLinkWidth(telemetryValues[1]));
}

void NvidiaPciePortInfo::update()
{
    if (request.empty())
    {
        return;
    }

    mctpRequester.sendRecvMsg(
        eid, request,
        [weak{weak_from_this()}](const std::error_code& ec,
                                 std::span<const uint8_t> buffer) {
            std::shared_ptr<NvidiaPciePortInfo> self = weak.lock();
            if (!self)
            {
                lg2::error("Invalid reference to NvidiaPciePortInfo");
                return;
            }
            self->processResponse(ec, buffer);
        });
}
