// Copyright 2017 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/devices/bus/drivers/platform/platform-proxy.h"

#include <lib/zircon-internal/align.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>

#include <utility>

#include <ddk/debug.h>
#include <fbl/algorithm.h>
#include <fbl/auto_lock.h>

#include "src/devices/bus/drivers/platform/platform-bus-bind.h"

namespace platform_bus {

void PlatformProxy::DdkRelease() { delete this; }

zx_status_t PlatformProxy::PDevGetMmio(uint32_t index, pdev_mmio_t* out_mmio) {
  if (index >= mmios_.size()) {
    return ZX_ERR_OUT_OF_RANGE;
  }

  const Mmio& mmio = mmios_[index];
  const zx_paddr_t vmo_base = ZX_ROUNDDOWN(mmio.base, ZX_PAGE_SIZE);
  const size_t vmo_size = ZX_ROUNDUP(mmio.base + mmio.length - vmo_base, ZX_PAGE_SIZE);
  zx::vmo vmo;

  zx_status_t status = zx::vmo::create_physical(mmio.resource, vmo_base, vmo_size, &vmo);
  if (status != ZX_OK) {
    zxlogf(ERROR, "%s %s: creating vmo failed %d", name_, __FUNCTION__, status);
    return status;
  }

  char name[32];
  snprintf(name, sizeof(name), "%s mmio %u", name_, index);
  status = vmo.set_property(ZX_PROP_NAME, name, sizeof(name));
  if (status != ZX_OK) {
    zxlogf(ERROR, "%s %s: setting vmo name failed %d", name_, __FUNCTION__, status);
    return status;
  }

  out_mmio->offset = mmio.base - vmo_base;
  out_mmio->vmo = vmo.release();
  out_mmio->size = mmio.length;
  return ZX_OK;
}

zx_status_t PlatformProxy::PDevGetInterrupt(uint32_t index, uint32_t flags,
                                            zx::interrupt* out_irq) {
  if (index >= irqs_.size()) {
    return ZX_ERR_OUT_OF_RANGE;
  }

  Irq* irq = &irqs_[index];
  if (flags == 0) {
    flags = irq->mode;
  }
  zx_status_t status = zx::interrupt::create(irq->resource, irq->irq, flags, out_irq);
  if (status != ZX_OK) {
    zxlogf(ERROR, "%s %s: creating interrupt failed: %d", name_, __FUNCTION__, status);
    return status;
  }

  return ZX_OK;
}

zx_status_t PlatformProxy::PDevGetBti(uint32_t index, zx::bti* out_bti) {
  rpc_pdev_req_t req = {};
  rpc_pdev_rsp_t resp = {};
  req.header.op = PDEV_GET_BTI;
  req.index = index;

  return Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp), nullptr, 0,
             out_bti->reset_and_get_address(), 1, nullptr);
}

zx_status_t PlatformProxy::PDevGetSmc(uint32_t index, zx::resource* out_resource) {
  rpc_pdev_req_t req = {};
  rpc_pdev_rsp_t resp = {};
  req.header.op = PDEV_GET_SMC;
  req.index = index;

  return Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp), nullptr, 0,
             out_resource->reset_and_get_address(), 1, nullptr);
}

zx_status_t PlatformProxy::PDevGetDeviceInfo(pdev_device_info_t* out_info) {
  rpc_pdev_req_t req = {};
  rpc_pdev_rsp_t resp = {};
  req.header.op = PDEV_GET_DEVICE_INFO;

  auto status = Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp));
  if (status != ZX_OK) {
    return status;
  }
  memcpy(out_info, &resp.device_info, sizeof(*out_info));
  return ZX_OK;
}

zx_status_t PlatformProxy::PDevGetBoardInfo(pdev_board_info_t* out_info) {
  rpc_pdev_req_t req = {};
  rpc_pdev_rsp_t resp = {};
  req.header.op = PDEV_GET_BOARD_INFO;

  auto status = Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp));
  if (status != ZX_OK) {
    return status;
  }
  memcpy(out_info, &resp.board_info, sizeof(*out_info));
  return ZX_OK;
}

zx_status_t PlatformProxy::Rpc(const platform_proxy_req_t* req, size_t req_length,
                               platform_proxy_rsp_t* resp, size_t resp_length,
                               const zx_handle_t* in_handles, size_t in_handle_count,
                               zx_handle_t* out_handles, size_t out_handle_count,
                               size_t* out_actual) {
  uint32_t resp_size, handle_count;

  zx_channel_call_args_t args = {
      .wr_bytes = req,
      .wr_handles = in_handles,
      .rd_bytes = resp,
      .rd_handles = out_handles,
      .wr_num_bytes = static_cast<uint32_t>(req_length),
      .wr_num_handles = static_cast<uint32_t>(in_handle_count),
      .rd_num_bytes = static_cast<uint32_t>(resp_length),
      .rd_num_handles = static_cast<uint32_t>(out_handle_count),
  };
  auto status = rpc_channel_.call(0, zx::time::infinite(), &args, &resp_size, &handle_count);
  if (status != ZX_OK) {
    // This is a fairly serious error; subsequent requests are very likely
    // to also fail.
    //
    // TODO(fxbug.dev/33622): Make this less likely and/or handle differently.
    zxlogf(ERROR, "PlatformProxy::Rpc rpc_channel_.call failed - status: %d", status);
    return status;
  }

  status = resp->status;

  if (status == ZX_OK && resp_size < sizeof(*resp)) {
    zxlogf(ERROR, "PlatformProxy::Rpc resp_size too short: %u", resp_size);
    status = ZX_ERR_INTERNAL;
    goto fail;
  } else if (status == ZX_OK && handle_count != out_handle_count) {
    zxlogf(ERROR, "PlatformProxy::Rpc handle count %u expected %zu", handle_count,
           out_handle_count);
    status = ZX_ERR_INTERNAL;
    goto fail;
  }

  if (out_actual) {
    *out_actual = resp_size;
  }

fail:
  if (status != ZX_OK) {
    for (uint32_t i = 0; i < handle_count; i++) {
      zx_handle_close(out_handles[i]);
    }
  }
  return status;
}

zx_status_t PlatformProxy::Create(void* ctx, zx_device_t* parent, const char* name,
                                  const char* args, zx_handle_t rpc_channel) {
  fbl::AllocChecker ac;

  auto proxy = fbl::make_unique_checked<PlatformProxy>(&ac, parent, rpc_channel);
  if (!ac.check()) {
    return ZX_ERR_NO_MEMORY;
  }

  auto status = proxy->Init(parent);
  if (status != ZX_OK) {
    return status;
  }

  // devmgr is now in charge of the device.
  __UNUSED auto* dummy = proxy.release();

  return ZX_OK;
}

zx_status_t PlatformProxy::Init(zx_device_t* parent) {
  pdev_device_info_t info;
  auto status = PDevGetDeviceInfo(&info);
  if (status != ZX_OK) {
    return status;
  }
  memcpy(name_, info.name, sizeof(name_));
  metadata_count_ = info.metadata_count;

  fbl::AllocChecker ac;

  for (uint32_t i = 0; i < info.mmio_count; i++) {
    rpc_pdev_req_t req = {};
    rpc_pdev_rsp_t resp = {};
    zx_handle_t rsrc_handle;

    req.header.op = PDEV_GET_MMIO;
    req.index = i;
    status =
        Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp), NULL, 0, &rsrc_handle, 1, NULL);
    if (status != ZX_OK) {
      return status;
    }

    Mmio mmio;
    mmio.base = resp.paddr;
    mmio.length = resp.length;
    mmio.resource.reset(rsrc_handle);
    mmios_.push_back(std::move(mmio), &ac);
    if (!ac.check()) {
      return ZX_ERR_NO_MEMORY;
    }

    zxlogf(TRACE, "%s: received MMIO %u (base %#lx length %#lx handle %#x)", name_, i, mmio.base,
           mmio.length, mmio.resource.get());
  }

  for (uint32_t i = 0; i < info.irq_count; i++) {
    rpc_pdev_req_t req = {};
    rpc_pdev_rsp_t resp = {};
    zx_handle_t rsrc_handle;

    req.header.op = PDEV_GET_INTERRUPT;
    req.index = i;
    status =
        Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp), NULL, 0, &rsrc_handle, 1, NULL);
    if (status != ZX_OK) {
      return status;
    }

    Irq irq;
    irq.irq = resp.irq;
    irq.mode = resp.mode;
    irq.resource.reset(rsrc_handle);
    irqs_.push_back(std::move(irq), &ac);
    if (!ac.check()) {
      return ZX_ERR_NO_MEMORY;
    }

    zxlogf(TRACE, "%s: received IRQ %u (irq %#x handle %#x)", name_, i, irq.irq,
           irq.resource.get());
  }

  return DdkAdd(name_);
}

static constexpr zx_driver_ops_t proxy_driver_ops = []() {
  zx_driver_ops_t ops = {};
  ops.version = DRIVER_OPS_VERSION;
  ops.create = PlatformProxy::Create;
  return ops;
}();

}  // namespace platform_bus

ZIRCON_DRIVER(platform_bus_proxy, platform_bus::proxy_driver_ops, "zircon", "0.1");
