blob: e30161c0b57b7b6a658b9ade6a22c69fc0f51b92 [file] [log] [blame]
// Copyright 2018 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.
#ifndef KERNEL_LIB_TOPOLOGY_SYSTEM_TOPOLOGY_H_
#define KERNEL_LIB_TOPOLOGY_SYSTEM_TOPOLOGY_H_
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include <zircon/boot/image.h>
#include <zircon/types.h>
/*
* Captures the physical layout of the core system (processors, caches, etc..).
* The data will be layed out as a tree, with processor nodes on the bottom and other types above
* them. The expected usage is to start from a processor node and walk up/down to discover the
* relationships you are interested in.
*/
namespace system_topology {
// A single node in the topology graph. The union and types here mirror the flat structure,
// zbi_topology_node_t.
struct Node {
uint8_t entity_type;
union {
zbi_topology_processor_t processor;
zbi_topology_cluster_t cluster;
zbi_topology_numa_region_t numa_region;
} entity;
Node* parent;
fbl::Vector<Node*> children;
};
// We define a typedef here as we may want to change this type as the design evolves. For example,
// if we add run-time updateability we may want to hold a lock.
typedef const fbl::Vector<Node*>& IterableProcessors;
// A view of the system topology that is defined in early boot and static during the run of the
// system.
class Graph {
public:
// Takes the flat topology array, validates it, and sets it as the current topology. Returns an
// error if the topology is invalid.
//
// This should only be called during early boot (platform_init), after that this data is
// considered static so no locks are used. If it is desired to set this later in operation than
// we MUST redesign this process to consider concurrent readers.
// Returns ZX_ERR_ALREADY_EXISTS if state already set or ZX_ERR_INVALID_ARGS if provided graph
// fails validation.
zx_status_t Update(zbi_topology_node_t* nodes, size_t count);
// Provides iterable container of pointers to all processor nodes.
IterableProcessors processors() const {
return processors_;
}
size_t processor_count() const {
return processors_.size();
}
// Finds the processor node that is assigned the given logical id.
// Sets processor to point to that node. If it wasn't found, returns ZX_ERR_NOT_FOUND.
zx_status_t ProcessorByLogicalId(uint16_t id, Node** processor) const {
if (id > processors_by_logical_id_.size()) {
return ZX_ERR_NOT_FOUND;
}
*processor = processors_by_logical_id_[id];
return ZX_OK;
}
private:
// Validates that in the provided flat topology:
// - all processors are leaf nodes, and all leaf nodes are processors.
// - there are no cycles.
// - It is stored in a "depth first" ordering, with parents adjacent to
// their children.
bool Validate(zbi_topology_node_t* nodes, int count) const;
fbl::unique_ptr<Node[]> nodes_;
fbl::Vector<Node*> processors_;
// This is in essence a map with logical ID being the index in the vector.
// It will contain duplicates for SMT processors so we need it in addition to processors_.
fbl::Vector<Node*> processors_by_logical_id_;
};
// Get the global instance of the SystemTopology. This will be updated in early boot to contain the
// source of truth view of the system.
// This should be called once before the platform becomes multithreaded. We don't use a raw global
// because we can't ensure that it is initialized, if this is used in the initialization of other
// global objects.
inline Graph& GetMutableSystemTopology() {
static Graph graph;
return graph;
}
// The method of the above most things should use, only the platform init code needs the mutable
// version.
inline const Graph& GetSystemTopology() {
return GetMutableSystemTopology();
}
} // namespace system_topology
#endif //KERNEL_LIB_TOPOLOGY_SYSTEM_TOPOLOGY_H_