// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/qemu_edu/qemu_edu.h"

#include <fidl/fuchsia.driver.compat/cpp/wire.h>

#include "src/qemu_edu/registers.h"

namespace fdf {
using namespace fuchsia_driver_framework;
}  // namespace fdf

namespace qemu_edu {

namespace {
namespace regs = qemu_edu_regs;
namespace fio = fuchsia_io;
namespace fpci = fuchsia_hardware_pci;

zx::status<fidl::ClientEnd<fuchsia_driver_compat::Device>>
ConnectToParentDevice(const driver::Namespace* ns, std::string_view name) {
  auto result = ns->OpenService<fuchsia_driver_compat::Service>(name);
  if (result.is_error()) {
    return result.take_error();
  }
  return result.value().connect_device();
}
}  // namespace

// static
zx::status<std::unique_ptr<QemuEduDriver>> QemuEduDriver::Start(
    fdf::wire::DriverStartArgs& start_args, fdf::UnownedDispatcher dispatcher,
    fidl::WireSharedClient<fdf::Node> node, driver::Namespace ns,
    driver::Logger logger) {
  auto driver = std::make_unique<QemuEduDriver>(dispatcher->async_dispatcher(),
                                                std::move(node), std::move(ns),
                                                std::move(logger));
  auto result = driver->Run(dispatcher->async_dispatcher(),
                            std::move(start_args.outgoing_dir()));
  if (result.is_error()) {
    return result.take_error();
  }
  return zx::ok(std::move(driver));
}

zx::status<> QemuEduDriver::MapInterruptAndMmio(
    fidl::ClientEnd<fpci::Device> pci_client) {
  auto pci = fidl::BindSyncClient(std::move(pci_client));

  auto bar = pci->GetBar(0);
  if (!bar.ok()) {
    FDF_SLOG(ERROR, "failed to get bar", KV("status", bar.status()));
    return zx::error(bar.status());
  }
  if (bar->result.is_err()) {
    FDF_SLOG(ERROR, "failed to get bar", KV("status", bar->result.err()));
    return zx::error(bar->result.err());
  }

  {
    auto& bar_result = bar->result.response().result;
    if (!bar_result.result.is_vmo()) {
      FDF_SLOG(ERROR, "unexpected bar type");
      return zx::error(ZX_ERR_NO_RESOURCES);
    }

    zx::status<fdf::MmioBuffer> mmio = fdf::MmioBuffer::Create(
        0, bar_result.size, std::move(bar_result.result.vmo()),
        ZX_CACHE_POLICY_UNCACHED_DEVICE);
    if (mmio.is_error()) {
      FDF_SLOG(ERROR, "failed to map mmio", KV("status", mmio.status_value()));
      return mmio.take_error();
    }
    mmio_ = *std::move(mmio);
  }

  // Read the version information from the edu device.
  auto version_reg = regs::Identification::Get().ReadFrom(&*mmio_);

  // TODO(surajmalhotra): Report version via inspect.
  major_version_ = version_reg.major_version();
  minor_version_ = version_reg.minor_version();

  // Map the interrupt.
  auto result = pci->SetInterruptMode(fpci::wire::InterruptMode::kLegacy, 1);
  if (!result.ok()) {
    FDF_SLOG(ERROR, "failed configure interrupt mode",
             KV("status", result.status()));
    return zx::error(result.status());
  }
  if (result->result.is_err()) {
    FDF_SLOG(ERROR, "failed configure interrupt mode",
             KV("status", result->result.err()));
    return zx::error(result->result.err());
  }

  auto interrupt = pci->MapInterrupt(0);
  if (!interrupt.ok()) {
    FDF_SLOG(ERROR, "failed to map interrupt",
             KV("status", interrupt.status()));
    return zx::error(interrupt.status());
  }
  if (interrupt->result.is_err()) {
    FDF_SLOG(ERROR, "failed to map interrupt",
             KV("status", interrupt->result.err()));
    return zx::error(interrupt->result.err());
  }
  irq_ = std::move(interrupt->result.response().interrupt);

  return zx::ok();
}

zx::status<> QemuEduDriver::Run(async_dispatcher* dispatcher,
                                fidl::ServerEnd<fio::Directory> outgoing_dir) {
  // Connect to DevfsExporter.
  auto exporter = ns_.Connect<fuchsia_device_fs::Exporter>();
  if (exporter.is_error()) {
    return exporter.take_error();
  }
  exporter_ = fidl::WireClient(std::move(*exporter), dispatcher);

  // Connect to parent.
  auto parent = ConnectToParentDevice(&ns_, "default");
  if (parent.is_error()) {
    FDF_SLOG(ERROR, "Failed to connect to parent",
             KV("status", parent.status_string()));
    return parent.take_error();
  }

  // Connect to pci protocol.
  auto pci_endpoints = fidl::CreateEndpoints<fpci::Device>();
  if (pci_endpoints.is_error()) {
    return pci_endpoints.take_error();
  }
  auto connect_result = fidl::WireCall(*parent)->ConnectFidl(
      fidl::StringView::FromExternal(
          fidl::DiscoverableProtocolName<fpci::Device>),
      pci_endpoints->server.TakeChannel());
  if (!connect_result.ok()) {
    return zx::error(connect_result.status());
  }
  auto pci_status = MapInterruptAndMmio(std::move(pci_endpoints->client));
  if (pci_status.is_error()) {
    return pci_status.take_error();
  }

  auto result = fidl::WireCall(*parent)->GetTopologicalPath();
  if (!result.ok()) {
    FDF_SLOG(ERROR, "Failed to get topological path",
             KV("status", result.status_string()));
    return zx::error(result.status());
  }

  std::string path(result->path.get());

  auto status =
      outgoing_.AddProtocol<fuchsia_hardware_qemuedu::Device>(this, Name());
  if (status.is_error()) {
    FDF_SLOG(ERROR, "Failed to add protocol",
             KV("status", status.status_string()));
    return status;
  }

  // Serve a connection to outgoing.
  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
  if (endpoints.is_error()) {
    FDF_SLOG(ERROR, "Failed to create endpoints",
             KV("status", endpoints.status_string()));
    return endpoints.take_error();
  }
  {
    auto status = outgoing_.Serve(std::move(endpoints->server));
    if (status.is_error()) {
      FDF_SLOG(ERROR, "Failed to serve outgoing directory",
               KV("status", status.status_string()));
      return status.take_error();
    }
  }
  exporter_
      ->Export(
          std::move(endpoints->client),
          fidl::StringView::FromExternal(std::string("svc/").append(Name())),
          fidl::StringView::FromExternal(path.append("/").append(Name())), 0)
      .Then([this](fidl::WireUnownedResult<fuchsia_device_fs::Exporter::Export>&
                       result) {
        if (!result.ok()) {
          FDF_SLOG(ERROR, "Failed to export",
                   KV("status", result.status_string()));
        }
      });
  return outgoing_.Serve(std::move(outgoing_dir));
}

void QemuEduDriver::ComputeFactorial(
    ComputeFactorialRequestView request,
    ComputeFactorialCompleter::Sync& completer) {
  // Write a value into the factorial register.
  uint32_t input = request->input;

  mmio_->Write32(input, regs::kFactorialCompoutationOffset);

  // Busy wait on the factorial status bit.
  while (true) {
    const auto status = regs::Status::Get().ReadFrom(&*mmio_);
    if (!status.busy()) break;
  }

  // Return the result.
  uint32_t factorial = mmio_->Read32(regs::kFactorialCompoutationOffset);

  FDF_SLOG(INFO, "Replying with", KV("factorial", factorial));
  completer.Reply(factorial);
}

void QemuEduDriver::LivenessCheck(LivenessCheckRequestView request,
                                  LivenessCheckCompleter::Sync& completer) {
  constexpr uint32_t kChallenge = 0xdeadbeef;
  constexpr uint32_t kExpectedResponse = ~(kChallenge);

  // Write the challenge and observe that the expected response is received.
  mmio_->Write32(kChallenge, regs::kLivenessCheckOffset);
  auto value = mmio_->Read32(regs::kLivenessCheckOffset);

  const bool alive = value == kExpectedResponse;

  FDF_SLOG(INFO, "Replying with", KV("result", alive));
  completer.Reply(alive);
}

}  // namespace qemu_edu

FUCHSIA_DRIVER_RECORD_CPP_V1(qemu_edu::QemuEduDriver);
