diff --git a/zircon/kernel/arch/arm64/BUILD.gn b/zircon/kernel/arch/arm64/BUILD.gn index c4f0d94bf0eb2871ee045a65b3739d2cc9ddb573..964909f36c0cd6c72838bc18fa86fa0762ba9182 100644 --- a/zircon/kernel/arch/arm64/BUILD.gn +++ b/zircon/kernel/arch/arm64/BUILD.gn @@ -61,10 +61,6 @@ if (current_toolchain == default_toolchain) { } source_set("arm64") { - defines = [ - "SMP_CPU_MAX_CLUSTER_CPUS=$smp_max_cpus", - "SMP_CPU_MAX_CLUSTERS=$smp_max_clusters", - ] sources = [ "arch.cpp", "asm.S", diff --git a/zircon/kernel/arch/arm64/include/arch/arm64/mp.h b/zircon/kernel/arch/arm64/include/arch/arm64/mp.h index 27a78e70894ee4191614d8dc69381f79ebf22da2..1125dab3cdf3ab7824cd71cf76064a32b77d5c85 100644 --- a/zircon/kernel/arch/arm64/include/arch/arm64/mp.h +++ b/zircon/kernel/arch/arm64/include/arch/arm64/mp.h @@ -107,8 +107,6 @@ static inline uint arch_cpu_num_to_cpu_id(uint cpu) { return arm64_cpu_cpu_ids[cpu]; } -cpu_num_t arch_mpid_to_cpu_num(uint cluster, uint cpu); - #define READ_PERCPU_FIELD32(field) \ arm64_read_percpu_u32(offsetof(struct arm64_percpu, field)) diff --git a/zircon/kernel/arch/arm64/mp.cpp b/zircon/kernel/arch/arm64/mp.cpp index e3e4d862bc2b68af86dafce81db50b58fbc53b87..1a633c00d8b310d707935babe661e463abaa79a0 100644 --- a/zircon/kernel/arch/arm64/mp.cpp +++ b/zircon/kernel/arch/arm64/mp.cpp @@ -27,11 +27,6 @@ struct MpidCpuidPair { uint cpu_id; }; -// TODO(ZX-3068) Switch completely to list and remove map. -bool use_cpu_map = true; - -// map of cluster/cpu to cpu_id -uint arm64_cpu_map[SMP_CPU_MAX_CLUSTERS][SMP_CPU_MAX_CLUSTER_CPUS] = {{0}}; MpidCpuidPair arm64_cpu_list[SMP_MAX_CPUS]; size_t arm64_cpu_list_count = 0; @@ -47,34 +42,6 @@ uint arm_num_cpus = 1; // per cpu structures, each cpu will point to theirs using the x18 register arm64_percpu arm64_percpu_array[SMP_MAX_CPUS]; -// initializes cpu_map and arm_num_cpus -void arch_init_cpu_map(uint cluster_count, const uint* cluster_cpus) { - ASSERT(cluster_count <= SMP_CPU_MAX_CLUSTERS); - - // assign cpu_ids sequentially - uint cpu_id = 0; - for (uint cluster = 0; cluster < cluster_count; cluster++) { - uint cpus = *cluster_cpus++; - ASSERT(cpus <= SMP_CPU_MAX_CLUSTER_CPUS); - for (uint cpu = 0; cpu < cpus; cpu++) { - // given cluster:cpu, translate to global cpu id - arm64_cpu_map[cluster][cpu] = cpu_id; - - // given global gpu_id, translate to cluster and cpu number within cluster - arm64_cpu_cluster_ids[cpu_id] = cluster; - arm64_cpu_cpu_ids[cpu_id] = cpu; - - // set the per cpu structure's cpu id - arm64_percpu_array[cpu_id].cpu_num = cpu_id; - - cpu_id++; - } - } - arm_num_cpus = cpu_id; - use_cpu_map = true; - smp_mb(); -} - void arch_register_mpid(uint cpu_id, uint64_t mpid) { // TODO(ZX-3068) transition off of these maps to the topology. arm64_cpu_cluster_ids[cpu_id] = (mpid & 0xFF00) >> MPIDR_AFF1_SHIFT; // "cluster" here is AFF1. @@ -83,37 +50,25 @@ void arch_register_mpid(uint cpu_id, uint64_t mpid) { arm64_percpu_array[cpu_id].cpu_num = cpu_id; arm64_cpu_list[arm64_cpu_list_count++] = {.mpid = mpid, .cpu_id = cpu_id}; - - use_cpu_map = false; } // do the 'slow' lookup by mpidr to cpu number static uint arch_curr_cpu_num_slow() { uint64_t mpidr = __arm_rsr64("mpidr_el1"); - if (use_cpu_map) { - uint cluster = (mpidr & MPIDR_AFF1_MASK) >> MPIDR_AFF1_SHIFT; - uint cpu = (mpidr & MPIDR_AFF0_MASK) >> MPIDR_AFF0_SHIFT; - - return arm64_cpu_map[cluster][cpu]; - } else { - mpidr &= kMpidAffMask; - for (size_t i = 0; i < arm64_cpu_list_count; ++i) { - if (arm64_cpu_list[i].mpid == mpidr) { - return arm64_cpu_list[i].cpu_id; - } - } - - // The only time we shouldn't find a cpu is when the list isn't - // defined yet during early boot, in this case the only processor up is 0 - // so returning 0 is correct. - DEBUG_ASSERT(arm64_cpu_list_count == 0); + mpidr &= kMpidAffMask; - return 0; + for (size_t i = 0; i < arm64_cpu_list_count; ++i) { + if (arm64_cpu_list[i].mpid == mpidr) { + return arm64_cpu_list[i].cpu_id; + } } -} -cpu_num_t arch_mpid_to_cpu_num(uint cluster, uint cpu) { - return arm64_cpu_map[cluster][cpu]; + // The only time we shouldn't find a cpu is when the list isn't + // defined yet during early boot, in this case the only processor up is 0 + // so returning 0 is correct. + DEBUG_ASSERT(arm64_cpu_list_count == 0); + + return 0; } void arch_prepare_current_cpu_idle_state(bool idle) { diff --git a/zircon/kernel/lib/topology/include/lib/system-topology.h b/zircon/kernel/lib/topology/include/lib/system-topology.h index e30161c0b57b7b6a658b9ade6a22c69fc0f51b92..299cb1df79559b01a6d0e8fbff08f789c3e1741e 100644 --- a/zircon/kernel/lib/topology/include/lib/system-topology.h +++ b/zircon/kernel/lib/topology/include/lib/system-topology.h @@ -47,7 +47,7 @@ public: // 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); + zx_status_t Update(const zbi_topology_node_t* nodes, size_t count); // Provides iterable container of pointers to all processor nodes. IterableProcessors processors() const { @@ -75,7 +75,7 @@ private: // - 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; + bool Validate(const zbi_topology_node_t* nodes, int count) const; fbl::unique_ptr<Node[]> nodes_; fbl::Vector<Node*> processors_; diff --git a/zircon/kernel/lib/topology/system-topology.cpp b/zircon/kernel/lib/topology/system-topology.cpp index 17a9fbd6cecf3d6e4d57ea7e825f601626745a14..cf9dbf216bbcac1d9e75d437ae590910d28eea11 100644 --- a/zircon/kernel/lib/topology/system-topology.cpp +++ b/zircon/kernel/lib/topology/system-topology.cpp @@ -22,26 +22,30 @@ zx_status_t GrowVector(size_t new_size, fbl::Vector<T>* vector, fbl::AllocChecke } // namespace -zx_status_t Graph::Update(zbi_topology_node_t* flat_nodes, size_t count) { - if (flat_nodes == nullptr || count == 0 || !Validate(flat_nodes, static_cast<int>(count))) { - return ZX_ERR_INVALID_ARGS; - } - +zx_status_t Graph::Update(const zbi_topology_node_t* flat_nodes, size_t count) { if (nodes_.get() != nullptr) { return ZX_ERR_ALREADY_EXISTS; } + if (flat_nodes == nullptr || count == 0 || !Validate(flat_nodes, static_cast<int>(count))) { + return ZX_ERR_INVALID_ARGS; + } + fbl::AllocChecker checker; - nodes_.reset(new (&checker) Node[count]{{}}); + fbl::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; + Node* node = nullptr; - zbi_topology_node_t* flat_node = nullptr; + const zbi_topology_node_t* flat_node = nullptr; for (size_t i = 0; i < count; ++i) { flat_node = &flat_nodes[i]; - node = &nodes_[i]; + node = &nodes[i]; node->entity_type = flat_node->entity_type; @@ -50,18 +54,16 @@ zx_status_t Graph::Update(zbi_topology_node_t* flat_nodes, size_t count) { case ZBI_TOPOLOGY_ENTITY_PROCESSOR: node->entity.processor = flat_node->entity.processor; - processors_.push_back(node, &checker); + processors.push_back(node, &checker); if (!checker.check()) { - nodes_.reset(nullptr); return ZX_ERR_NO_MEMORY; } for (int i = 0; i < node->entity.processor.logical_id_count; ++i) { const auto index = node->entity.processor.logical_ids[i]; - GrowVector(index + 1, &processors_by_logical_id_, &checker); - processors_by_logical_id_[index] = node; + GrowVector(index + 1, &processors_by_logical_id, &checker); + processors_by_logical_id[index] = node; if (!checker.check()) { - nodes_.reset(nullptr); return ZX_ERR_NO_MEMORY; } } @@ -82,19 +84,22 @@ zx_status_t Graph::Update(zbi_topology_node_t* flat_nodes, size_t count) { 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 = &nodes[flat_node->parent_index]; node->parent->children.push_back(node, &checker); if (!checker.check()) { - nodes_.reset(nullptr); return ZX_ERR_NO_MEMORY; } } } + nodes_.swap(nodes); + processors_ = std::move(processors); + processors_by_logical_id_ = std::move(processors_by_logical_id); + return ZX_OK; } -bool Graph::Validate(zbi_topology_node_t* nodes, int count) const { +bool Graph::Validate(const zbi_topology_node_t* nodes, int count) const { uint16_t parents[kMaxTopologyDepth]; for (size_t i = 0; i < kMaxTopologyDepth; ++i) { parents[i] = ZBI_TOPOLOGY_NO_PARENT; @@ -103,7 +108,7 @@ bool Graph::Validate(zbi_topology_node_t* nodes, int count) const { uint8_t current_type = ZBI_TOPOLOGY_ENTITY_UNDEFINED; int current_depth = 0; - zbi_topology_node_t* node; + const zbi_topology_node_t* node; for (int current_index = count - 1; current_index >= 0; current_index--) { node = &nodes[current_index]; diff --git a/zircon/kernel/params.gni b/zircon/kernel/params.gni index 9e0acfed8f4090983d64bc7d2fa0816d6db8deec..55a50d2e8c66ef3d1c4c05225cd39a7ba5c6d1ad 100644 --- a/zircon/kernel/params.gni +++ b/zircon/kernel/params.gni @@ -7,10 +7,7 @@ declare_args() { smp_max_cpus = 32 if (current_cpu == "arm64") { - # Maximum number of CPU clusters the kernel will support. - # The kernel will panic at boot on hardware with more clusters. smp_max_cpus = 16 - smp_max_clusters = 2 } # Virtual address where the kernel is mapped statically. This is the diff --git a/zircon/kernel/platform/generic-arm/BUILD.gn b/zircon/kernel/platform/generic-arm/BUILD.gn index 0aa57e83867bae48f4ddaf2e39b04cf9e9b3e6bf..da0558aa574c3df648b80835163c2565d89cf1b3 100644 --- a/zircon/kernel/platform/generic-arm/BUILD.gn +++ b/zircon/kernel/platform/generic-arm/BUILD.gn @@ -8,7 +8,6 @@ source_set("generic-arm") { sources = [ "platform.cpp", ] - defines = [ "SMP_CPU_MAX_CLUSTERS=$smp_max_clusters" ] deps = [ "$zx/kernel/dev/hdcp/amlogic_s912", "$zx/kernel/dev/hw_rng", diff --git a/zircon/kernel/platform/generic-arm/platform.cpp b/zircon/kernel/platform/generic-arm/platform.cpp index 97e4293ad1e4a2c5b71d5cfcaeedcd1237e5bd4d..220ad31a3890fb4510a789643af16040639aa016 100644 --- a/zircon/kernel/platform/generic-arm/platform.cpp +++ b/zircon/kernel/platform/generic-arm/platform.cpp @@ -69,9 +69,6 @@ static zbi_header_t* zbi_root = nullptr; static zbi_nvram_t lastlog_nvram; -static uint cpu_cluster_count = 0; -static uint cpu_cluster_cpus[SMP_CPU_MAX_CLUSTERS] = {0}; - static bool halt_on_panic = false; static bool uart_disabled = false; @@ -92,9 +89,6 @@ static size_t mexec_zbi_length = 0; static volatile int panic_started; -// TODO(ZX-3068) This is temporary until we fully deprecate ZBI_CPU_CONFIG. -static bool use_topology = false; - static constexpr bool kProcessZbiEarly = true; static void halt_other_cpus(void) { @@ -221,38 +215,6 @@ static void topology_cpu_init(void) { } } -static void platform_cpu_init(void) { - for (uint cluster = 0; cluster < cpu_cluster_count; cluster++) { - for (uint cpu = 0; cpu < cpu_cluster_cpus[cluster]; cpu++) { - if (cluster != 0 || cpu != 0) { - const uint cpu_num = arch_mpid_to_cpu_num(cluster, cpu); - const uint64_t mpid = ARM64_MPID(cluster, cpu); - - // create a stack for the cpu we're about to start - zx_status_t status = arm64_create_secondary_stack(cpu_num, mpid); - - DEBUG_ASSERT(status == ZX_OK); - - // start the cpu - status = platform_start_cpu(mpid); - - if (status != ZX_OK) { - // TODO(maniscalco): Is continuing really the right thing to do here? - - // start failed, free the stack - zx_status_t status = arm64_free_secondary_stack(cpu_num); - DEBUG_ASSERT(status == ZX_OK); - continue; - } - - // the cpu booted - // - // bootstrap thread is now responsible for freeing its stack - } - } - } -} - static inline bool is_zbi_container(void* addr) { DEBUG_ASSERT(addr); @@ -335,16 +297,7 @@ static zbi_result_t process_zbi_item_early(zbi_header_t* item, save_mexec_zbi(item); break; } - case ZBI_TYPE_CPU_CONFIG: { - zbi_cpu_config_t* cpu_config = reinterpret_cast<zbi_cpu_config_t*>(payload); - cpu_cluster_count = cpu_config->cluster_count; - for (uint32_t i = 0; i < cpu_cluster_count; i++) { - cpu_cluster_cpus[i] = cpu_config->clusters[i].cpu_count; - } - arch_init_cpu_map(cpu_cluster_count, cpu_cluster_cpus); - save_mexec_zbi(item); - break; - } + case ZBI_TYPE_NVRAM: { zbi_nvram_t* nvram = reinterpret_cast<zbi_nvram_t*>(payload); memcpy(&lastlog_nvram, nvram, sizeof(lastlog_nvram)); @@ -359,40 +312,125 @@ static zbi_result_t process_zbi_item_early(zbi_header_t* item, return ZBI_RESULT_OK; } +static constexpr zbi_topology_node_t fallback_topology = { + .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR, + .parent_index = ZBI_TOPOLOGY_NO_PARENT, + .entity = { + .processor = { + .logical_ids = {0}, + .logical_id_count = 1, + .flags = 0, + .architecture = ZBI_TOPOLOGY_ARCH_ARM, + .architecture_info = { + .arm = { + .cluster_1_id = 0, + .cluster_2_id = 0, + .cluster_3_id = 0, + .cpu_id = 0, + .gic_id = 0, + } + } + } + } +}; + +static void init_topology(zbi_topology_node_t* nodes, size_t node_count) { + auto result = system_topology::GetMutableSystemTopology() + .Update(nodes, node_count); + if (result != ZX_OK) { + printf("Failed to initialize system topology! error: %d \n", + result); + + // Try to fallback to a topology of just this processor. + result = system_topology::GetMutableSystemTopology() + .Update(&fallback_topology, 1); + ASSERT(result == ZX_OK); + } + + arch_set_num_cpus(static_cast<uint>( + system_topology::GetSystemTopology().processor_count())); + + // TODO(ZX-3068) Print the whole topology of the system. + if (LK_DEBUGLEVEL >= INFO) { + for (auto* proc : + system_topology::GetSystemTopology().processors()) { + auto& info = proc->entity.processor.architecture_info.arm; + dprintf(INFO, "System topology: CPU %u:%u:%u:%u\n", + info.cluster_3_id, + info.cluster_2_id, + info.cluster_1_id, + info.cpu_id); + } + } +} + // Called after heap is up, but before multithreading. static zbi_result_t process_zbi_item_late(zbi_header_t* item, void* payload, void*) { switch (item->type) { + case ZBI_TYPE_CPU_CONFIG: { + zbi_cpu_config_t* cpu_config = reinterpret_cast<zbi_cpu_config_t*>(payload); + + // Convert old zbi_cpu_config into zbi_topology structure. + + // Allocate some memory to work in. + size_t node_count = 0; + for (size_t cluster = 0; cluster < cpu_config->cluster_count; cluster++) { + // Each cluster will get a node. + node_count++; + node_count += cpu_config->clusters[cluster].cpu_count; + } + + fbl::AllocChecker checker; + auto flat_topology = ktl::unique_ptr<zbi_topology_node_t[]> { + new (&checker) zbi_topology_node_t[node_count]}; + if (!checker.check()) { + return ZBI_RESULT_ERROR; + } + + // Initialize to 0. + memset(flat_topology.get(), 0, sizeof(zbi_topology_node_t) * node_count); + + // Create topology structure. + size_t flat_index = 0; + uint16_t logical_id = 0; + for (size_t cluster = 0; cluster < cpu_config->cluster_count; cluster++) { + const auto cluster_index = flat_index; + auto& node = flat_topology.get()[flat_index++]; + node.entity_type = ZBI_TOPOLOGY_ENTITY_CLUSTER; + node.parent_index = ZBI_TOPOLOGY_NO_PARENT; + + // We don't have this data so it is a guess that little cores are + // first. + node.entity.cluster.performance_class = static_cast<uint8_t>(cluster); + + for (size_t i = 0; i < cpu_config->clusters[cluster].cpu_count; i++) { + auto& node = flat_topology.get()[flat_index++]; + node.entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR; + node.parent_index = static_cast<uint16_t>(cluster_index); + node.entity.processor.logical_id_count = 1; + node.entity.processor.logical_ids[0] = logical_id++; + node.entity.processor.architecture = ZBI_TOPOLOGY_ARCH_ARM; + node.entity.processor.architecture_info.arm.cluster_1_id = + static_cast<uint8_t>(cluster); + node.entity.processor.architecture_info.arm.cpu_id = static_cast<uint8_t>(i); + } + } + DEBUG_ASSERT(flat_index == node_count); + + // Initialize topology subsystem. + init_topology(flat_topology.get(), node_count); + save_mexec_zbi(item); + break; + } case ZBI_TYPE_CPU_TOPOLOGY: { const int node_count = item->length / item->extra; zbi_topology_node_t* nodes = reinterpret_cast<zbi_topology_node_t*>(payload); - auto result = system_topology::GetMutableSystemTopology() - .Update(nodes, node_count); - if (result != ZX_OK) { - printf("Failed to initialize system topology! error: %d \n", - result); - } else { - use_topology = true; - arch_set_num_cpus(static_cast<uint>( - system_topology::GetSystemTopology().processor_count())); - - // TODO(ZX-3068) Print the whole topology of the system. - if (LK_DEBUGLEVEL >= INFO) { - for (auto* proc : - system_topology::GetSystemTopology().processors()) { - auto& info = proc->entity.processor.architecture_info.arm; - dprintf(INFO, "System topology: CPU %u:%u:%u:%u\n", - info.cluster_3_id, - info.cluster_2_id, - info.cluster_1_id, - info.cpu_id); - } - } - } - + init_topology(nodes, node_count); + save_mexec_zbi(item); break; } } @@ -500,11 +538,7 @@ LK_INIT_HOOK(platform_init_pre_thread, platform_init_pre_thread, LK_INIT_LEVEL_THREADING - 1) void platform_init(void) { - if (use_topology) { - topology_cpu_init(); - } else { - platform_cpu_init(); - } + topology_cpu_init(); } // after the fact create a region to reserve the peripheral map(s)