diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 7d37e458e2f5..c3122154d738 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -299,6 +299,11 @@ core_initcall(init_amu_fie);
 #ifdef CONFIG_ACPI_CPPC_LIB
 #include <acpi/cppc_acpi.h>
 
+struct amu_counters {
+	u64 corecnt;
+	u64 constcnt;
+};
+
 static void cpu_read_corecnt(void *val)
 {
 	/*
@@ -322,8 +327,27 @@ static void cpu_read_constcnt(void *val)
 		      0UL : read_constcnt();
 }
 
+static void cpu_read_amu_counters(void *data)
+{
+	struct amu_counters *cnt = (struct amu_counters *)data;
+
+	/*
+	 * The running time of the this_cpu_has_cap() might have a couple of
+	 * microseconds and is significantly increased to tens of microseconds.
+	 * But AMU core and constant counter need to be read togeter without any
+	 * time interval to reduce the calculation discrepancy using this counters.
+	 */
+	if (this_cpu_has_cap(ARM64_WORKAROUND_2457168)) {
+		cnt->corecnt = read_corecnt();
+		cnt->constcnt = 0;
+	} else {
+		cnt->corecnt = read_corecnt();
+		cnt->constcnt = read_constcnt();
+	}
+}
+
 static inline
-int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val)
+int counters_read_on_cpu(int cpu, smp_call_func_t func, void *data)
 {
 	/*
 	 * Abort call on counterless CPU or when interrupts are
@@ -335,7 +359,7 @@ int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val)
 	if (WARN_ON_ONCE(irqs_disabled()))
 		return -EPERM;
 
-	smp_call_function_single(cpu, func, val, 1);
+	smp_call_function_single(cpu, func, data, 1);
 
 	return 0;
 }
@@ -364,6 +388,21 @@ bool cpc_ffh_supported(void)
 	return true;
 }
 
+int cpc_read_arch_counters_on_cpu(int cpu, u64 *delivered, u64 *reference)
+{
+	struct amu_counters cnts = {0};
+	int ret;
+
+	ret = counters_read_on_cpu(cpu, cpu_read_amu_counters, &cnts);
+	if (ret)
+		return ret;
+
+	*delivered = cnts.corecnt;
+	*reference = cnts.constcnt;
+
+	return 0;
+}
+
 int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
 {
 	int ret = -EOPNOTSUPP;
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 7ff269a78c20..f303fabd7cfe 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1299,6 +1299,11 @@ bool cppc_perf_ctrs_in_pcc(void)
 }
 EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc);
 
+int __weak cpc_read_arch_counters_on_cpu(int cpu, u64 *delivered, u64 *reference)
+{
+	return 0;
+}
+
 /**
  * cppc_get_perf_ctrs - Read a CPU's performance feedback counters.
  * @cpunum: CPU from which to read counters.
@@ -1313,7 +1318,8 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
 		*ref_perf_reg, *ctr_wrap_reg;
 	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
 	struct cppc_pcc_data *pcc_ss_data = NULL;
-	u64 delivered, reference, ref_perf, ctr_wrap_time;
+	u64 delivered = 0, reference = 0;
+	u64 ref_perf, ctr_wrap_time;
 	int ret = 0, regs_in_pcc = 0;
 
 	if (!cpc_desc) {
@@ -1350,8 +1356,18 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
 		}
 	}
 
-	cpc_read(cpunum, delivered_reg, &delivered);
-	cpc_read(cpunum, reference_reg, &reference);
+	if (cpc_ffh_supported()) {
+		ret = cpc_read_arch_counters_on_cpu(cpunum, &delivered, &reference);
+		if (ret) {
+			pr_debug("read arch counters failed, ret=%d.\n", ret);
+			ret = 0;
+		}
+	}
+	if (!delivered || !reference) {
+		cpc_read(cpunum, delivered_reg, &delivered);
+		cpc_read(cpunum, reference_reg, &reference);
+	}
+
 	cpc_read(cpunum, ref_perf_reg, &ref_perf);
 
 	/*
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 6126c977ece0..07d4fd82d499 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -152,6 +152,7 @@ extern bool cpc_ffh_supported(void);
 extern bool cpc_supported_by_cpu(void);
 extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
 extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
+extern int cpc_read_arch_counters_on_cpu(int cpu, u64 *delivered, u64 *reference);
 extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
 extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
 extern int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps);
@@ -209,6 +210,10 @@ static inline int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
 {
 	return -ENOTSUPP;
 }
+static inline int cpc_read_arch_counters_on_cpu(int cpu, u64 *delivered, u64 *reference)
+{
+	return -EOPNOTSUPP;
+}
 static inline int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
 {
 	return -ENOTSUPP;
