// Copyright 2018 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT

#include <assert.h>
#include <debug.h>
#include <lib/system-topology.h>
#include <zircon/boot/image.h>
#include <zircon/errors.h>

#include <ktl/move.h>
#include <ktl/unique_ptr.h>

#include <ktl/enforce.h>

namespace system_topology {

decltype(Graph::system_topology_) Graph::system_topology_;

namespace {

constexpr size_t kMaxTopologyDepth = 20;

inline void ValidationError(size_t index, const char* message) {
  printf("Error validating topology at node %zu : %s\n", index, message);
}

template <typename T>
zx_status_t GrowVector(size_t new_size, fbl::Vector<T>* vector, fbl::AllocChecker* checker) {
  for (size_t i = vector->size(); i < new_size; i++) {
    vector->push_back(T(), checker);
    if (!checker->check()) {
      return ZX_ERR_NO_MEMORY;
    }
  }
  return ZX_OK;
}

}  // namespace

zx_status_t Graph::Initialize(Graph* graph, const zbi_topology_node_t* flat_nodes, size_t count) {
  DEBUG_ASSERT(flat_nodes != nullptr);
  DEBUG_ASSERT(count > 0);

  if (!Validate(flat_nodes, count)) {
    return ZX_ERR_INVALID_ARGS;
  }

  fbl::AllocChecker checker;
  ktl::unique_ptr<Node[]> nodes(new (&checker) Node[count]{{}});
  if (!checker.check()) {
    return ZX_ERR_NO_MEMORY;
  }

  // Create local instances, if successful we will move them to the Graph's fields.
  fbl::Vector<Node*> processors;
  fbl::Vector<Node*> processors_by_logical_id;
  size_t logical_processor_count = 0;

  Node* node = nullptr;
  const zbi_topology_node_t* flat_node = nullptr;
  for (size_t flat_node_index = 0; flat_node_index < count; ++flat_node_index) {
    flat_node = &flat_nodes[flat_node_index];
    node = &nodes[flat_node_index];

    node->entity_type = flat_node->entity_type;

    // Copy info.
    switch (node->entity_type) {
      case ZBI_TOPOLOGY_ENTITY_PROCESSOR:
        node->entity.processor = flat_node->entity.processor;

        processors.push_back(node, &checker);
        logical_processor_count += node->entity.processor.logical_id_count;
        if (!checker.check()) {
          return ZX_ERR_NO_MEMORY;
        }

        for (int i = 0; i < node->entity.processor.logical_id_count; ++i) {
          const uint16_t index = node->entity.processor.logical_ids[i];
          GrowVector(index + 1, &processors_by_logical_id, &checker);
          processors_by_logical_id[index] = node;
          if (!checker.check()) {
            return ZX_ERR_NO_MEMORY;
          }
        }
        break;
      case ZBI_TOPOLOGY_ENTITY_CLUSTER:
        node->entity.cluster = flat_node->entity.cluster;
        break;
      case ZBI_TOPOLOGY_ENTITY_NUMA_REGION:
        node->entity.numa_region = flat_node->entity.numa_region;
        break;
      case ZBI_TOPOLOGY_ENTITY_CACHE:
        node->entity.cache = flat_node->entity.cache;
        break;
      default:
        // Other types don't have attached info.
        break;
    }

    if (flat_node->parent_index != ZBI_TOPOLOGY_NO_PARENT) {
      // Validation should have prevented this.
      ZX_DEBUG_ASSERT_MSG(flat_node->parent_index >= 0 && flat_node->parent_index < count,
                          "parent_index out of range: %u\n", flat_node->parent_index);

      node->parent = &nodes[flat_node->parent_index];
      node->parent->children.push_back(node, &checker);
      if (!checker.check()) {
        return ZX_ERR_NO_MEMORY;
      }
    }
  }

  *graph = Graph{ktl::move(nodes), ktl::move(processors), logical_processor_count,
                 ktl::move(processors_by_logical_id)};
  return ZX_OK;
}

zx_status_t Graph::InitializeSystemTopology(const zbi_topology_node_t* nodes, size_t count) {
  Graph graph;
  const auto status = Graph::Initialize(&graph, nodes, count);
  if (status != ZX_OK) {
    return status;
  }

  // Initialize the global system topology graph instance.
  system_topology_.Initialize(ktl::move(graph));
  return ZX_OK;
}

bool Graph::Validate(const zbi_topology_node_t* nodes, size_t count) {
  DEBUG_ASSERT(nodes != nullptr);
  DEBUG_ASSERT(count > 0);

  uint16_t parents[kMaxTopologyDepth];
  for (size_t i = 0; i < kMaxTopologyDepth; ++i) {
    parents[i] = ZBI_TOPOLOGY_NO_PARENT;
  }

  uint8_t current_type = ZBI_TOPOLOGY_ENTITY_UNDEFINED;
  int current_depth = 0;

  const zbi_topology_node_t* node;
  for (size_t index = 0; index < count; index++) {
    // Traverse the nodes in reverse order.
    const size_t current_index = count - index - 1;

    node = &nodes[current_index];

    if (current_type == ZBI_TOPOLOGY_ENTITY_UNDEFINED) {
      current_type = node->entity_type;
    }

    if (current_type != node->entity_type) {
      if (current_index == parents[current_depth]) {
        // If the type changes then it should be the parent of the
        // previous level.
        current_depth++;

        if (current_depth == kMaxTopologyDepth) {
          ValidationError(current_index, "Structure is too deep, we only support 20 levels.");
          return false;
        }
      } else if (node->entity_type == ZBI_TOPOLOGY_ENTITY_PROCESSOR) {
        // If it isn't the parent of the previous level, but it is a process than we have
        // encountered a new branch and should start walking from the bottom again.

        // Clear the parent index's for all levels but the top, we want to ensure that the
        // top level of the new branch reports to the same parent as we do.
        for (int i = current_depth - 1; i >= 0; --i) {
          parents[i] = ZBI_TOPOLOGY_NO_PARENT;
        }
        current_depth = 0;
      } else {
        // Otherwise the structure is incorrect.
        ValidationError(current_index,
                        "Graph is not stored in correct order, with children adjacent to "
                        "parents");
        return false;
      }
      current_type = node->entity_type;
    }

    if (parents[current_depth] == ZBI_TOPOLOGY_NO_PARENT) {
      parents[current_depth] = node->parent_index;
    } else if (parents[current_depth] != node->parent_index) {
      ValidationError(current_index, "Parents at level do not match.");
      return false;
    }

    // Ensure that all leaf nodes are processors.
    if (current_depth == 0 && node->entity_type != ZBI_TOPOLOGY_ENTITY_PROCESSOR) {
      ValidationError(current_index, "Encountered a leaf node that isn't a processor.");
      return false;
    }

    // Ensure that all processors are leaf nodes.
    if (current_depth != 0 && node->entity_type == ZBI_TOPOLOGY_ENTITY_PROCESSOR) {
      ValidationError(current_index, "Encountered a processor that isn't a leaf node.");
      return false;
    }

    // By the time we reach the first parent we should be at the maximum depth and have no
    // parents defined.
    if (current_index == 0 && parents[current_depth] != ZBI_TOPOLOGY_NO_PARENT &&
        (current_depth == kMaxTopologyDepth - 1 ||
         parents[current_depth + 1] == ZBI_TOPOLOGY_NO_PARENT)) {
      ValidationError(current_index, "Top level of tree should not have a parent");
      return false;
    }
  }
  return true;
}

uint8_t GetPerformanceClass(cpu_num_t cpu_id) {
  Node* cpu_node = nullptr;
  if (GetSystemTopology().ProcessorByLogicalId(cpu_id, &cpu_node) != ZX_OK) {
    dprintf(INFO, "System topology: Failed to get processor node for cpu %u\n", cpu_id);
    return 0;
  }
  DEBUG_ASSERT(cpu_node != nullptr);

  for (Node* node = cpu_node->parent; node != nullptr; node = node->parent) {
    if (node->entity_type == ZBI_TOPOLOGY_ENTITY_CLUSTER) {
      return node->entity.cluster.performance_class;
    }
  }

  return 0;
}

}  // namespace system_topology
