struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset()

in src/arm/linux/chipset.c [3618:3769]


	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset(
		const struct cpuinfo_android_properties properties[restrict static 1],
		uint32_t cores,
		uint32_t max_cpu_freq_max)
	{
		struct cpuinfo_arm_chipset chipset = {
			.vendor = cpuinfo_arm_chipset_vendor_unknown,
			.series = cpuinfo_arm_chipset_series_unknown,
		};

		const bool tegra_platform = is_tegra(
			properties->ro_board_platform,
			properties->ro_board_platform + strnlen(properties->ro_board_platform, CPUINFO_BUILD_PROP_VALUE_MAX));

		struct cpuinfo_arm_chipset chipsets[cpuinfo_android_chipset_property_max] = {
			[cpuinfo_android_chipset_property_proc_cpuinfo_hardware] =
				cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
					properties->proc_cpuinfo_hardware, cores, max_cpu_freq_max, tegra_platform),
			[cpuinfo_android_chipset_property_ro_product_board] =
				cpuinfo_arm_android_decode_chipset_from_ro_product_board(
					properties->ro_product_board, cores, max_cpu_freq_max),
			[cpuinfo_android_chipset_property_ro_board_platform] =
				cpuinfo_arm_android_decode_chipset_from_ro_board_platform(
					properties->ro_board_platform, cores, max_cpu_freq_max),
			[cpuinfo_android_chipset_property_ro_mediatek_platform] =
				cpuinfo_arm_android_decode_chipset_from_ro_mediatek_platform(properties->ro_mediatek_platform),
			[cpuinfo_android_chipset_property_ro_arch] =
				cpuinfo_arm_android_decode_chipset_from_ro_arch(properties->ro_arch),
			[cpuinfo_android_chipset_property_ro_chipname] =
				cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_chipname),
			[cpuinfo_android_chipset_property_ro_hardware_chipname] =
				cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_hardware_chipname),
		};
		enum cpuinfo_arm_chipset_vendor vendor = cpuinfo_arm_chipset_vendor_unknown;
		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
			const enum cpuinfo_arm_chipset_vendor decoded_vendor = chipsets[i].vendor;
			if (decoded_vendor != cpuinfo_arm_chipset_vendor_unknown) {
				if (vendor == cpuinfo_arm_chipset_vendor_unknown) {
					vendor = decoded_vendor;
				} else if (vendor != decoded_vendor) {
					/* Parsing different system properties produces different chipset vendors. This situation is rare. */
					cpuinfo_log_error(
						"chipset detection failed: different chipset vendors reported in different system properties");
					goto finish;
				}
			}
		}
		if (vendor == cpuinfo_arm_chipset_vendor_unknown) {
			cpuinfo_log_warning(
				"chipset detection failed: none of the system properties matched known signatures");
			goto finish;
		}

		/* Fix common bugs in reported chipsets */
		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
			cpuinfo_arm_fixup_chipset(&chipsets[i], cores, max_cpu_freq_max);
		}

		/*
		 * Propagate suffixes: consider all pairs of chipsets, if both chipsets in the pair are from the same series,
		 * and one's suffix is a prefix of another's chipset suffix, use the longest suffix.
		 */
		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
			const size_t chipset_i_suffix_length = strnlen(chipsets[i].suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
			for (size_t j = 0; j < i; j++) {
				if (chipsets[i].series == chipsets[j].series) {
					const size_t chipset_j_suffix_length = strnlen(chipsets[j].suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
					if (chipset_i_suffix_length != chipset_j_suffix_length) {
						const size_t common_prefix_length = (chipset_i_suffix_length < chipset_j_suffix_length) ?
							chipset_i_suffix_length : chipset_j_suffix_length;
						if (common_prefix_length == 0 ||
							memcmp(chipsets[i].suffix, chipsets[j].suffix, common_prefix_length) == 0)
						{
							if (chipset_i_suffix_length > chipset_j_suffix_length) {
								memcpy(chipsets[j].suffix, chipsets[i].suffix, chipset_i_suffix_length);
							} else {
								memcpy(chipsets[i].suffix, chipsets[j].suffix, chipset_j_suffix_length);
							}
						}
					}
				}
			}
		}

		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
			if (chipsets[i].series != cpuinfo_arm_chipset_series_unknown) {
				if (chipset.series == cpuinfo_arm_chipset_series_unknown) {
					chipset = chipsets[i];
				} else if (chipsets[i].series != chipset.series || chipsets[i].model != chipset.model ||
					strncmp(chipsets[i].suffix, chipset.suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX) != 0)
				{
					cpuinfo_log_info(
						"different chipsets reported in different system properties; "
						"vendor-specific disambiguation heuristic would be used");
					switch (vendor) {
						case cpuinfo_arm_chipset_vendor_qualcomm:
							return disambiguate_qualcomm_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
								&chipsets[cpuinfo_android_chipset_property_ro_board_platform],
								&chipsets[cpuinfo_android_chipset_property_ro_chipname],
								&chipsets[cpuinfo_android_chipset_property_ro_hardware_chipname]);
						case cpuinfo_arm_chipset_vendor_mediatek:
							return disambiguate_mediatek_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
								&chipsets[cpuinfo_android_chipset_property_ro_board_platform],
								&chipsets[cpuinfo_android_chipset_property_ro_mediatek_platform],
								&chipsets[cpuinfo_android_chipset_property_ro_chipname]);
						case cpuinfo_arm_chipset_vendor_hisilicon:
							return disambiguate_hisilicon_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
								&chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
						case cpuinfo_arm_chipset_vendor_amlogic:
							return disambiguate_amlogic_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
						case cpuinfo_arm_chipset_vendor_marvell:
							return disambiguate_marvell_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
								&chipsets[cpuinfo_android_chipset_property_ro_chipname]);
						case cpuinfo_arm_chipset_vendor_rockchip:
							return disambiguate_rockchip_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
								&chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
						case cpuinfo_arm_chipset_vendor_spreadtrum:
							return disambiguate_spreadtrum_chipset(
								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
								&chipsets[cpuinfo_android_chipset_property_ro_board_platform],
								&chipsets[cpuinfo_android_chipset_property_ro_chipname]);
						default:
							cpuinfo_log_error(
								"chipset detection failed: "
								"could not disambiguate different chipsets reported in different system properties");
							/* chipset variable contains valid, but inconsistent chipset information, overwrite it */
							chipset = (struct cpuinfo_arm_chipset) {
								.vendor = cpuinfo_arm_chipset_vendor_unknown,
								.series = cpuinfo_arm_chipset_series_unknown,
							};
							goto finish;
					}
				}
			}
		}

	finish:
		return chipset;
	}