aboutsummaryrefslogtreecommitdiff
path: root/plat/hisilicon
diff options
context:
space:
mode:
authorWei Yu <yuwei3@hisilicon.com>2019-04-07 11:29:28 +0800
committerLeo Yan <leo.yan@linaro.org>2019-04-10 21:09:46 +0800
commit7d76df7db2c79b37f3c2357758fb2c565d4cce6f (patch)
tree54e49e32f1df3c2c638a984c8fd4a22293f7d0c9 /plat/hisilicon
parentc48991e1fe918f48508c088b443742622b9f2181 (diff)
downloadtrusted-firmware-a-7d76df7db2c79b37f3c2357758fb2c565d4cce6f.tar.gz
hikey960: Fix race condition between hotplug and idles
From the hotplug testing on Hikey960, in some case cores fail to become online in the system. When some cores are hotplugged off, if other cores in the same cluster enter into CPU idle states at the meantime, the cluster will be powered off. This introduces the state machine malfunction in the power controller, thus when hotplug on the core afterwards, it fails to boot up the core because the power controller thinks the cluster is powered on. This patch is to avoid race condition between hotplug and idles by preventing cluster power off when some of cores in the cluster are hotplugged off, if all cores in the same cluster are hotplugged off, the cluster can be powered off. Change-Id: Ib2feeb093357c70409a3536cb4f9da9b504fdcbe Signed-off-by: Wei Yu <yuwei3@hisilicon.com> Signed-off-by: Leo Yan <leo.yan@linaro.org>
Diffstat (limited to 'plat/hisilicon')
-rw-r--r--plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c33
-rw-r--r--plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h2
-rw-r--r--plat/hisilicon/hikey960/hikey960_pm.c4
3 files changed, 29 insertions, 10 deletions
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
index 659a1c4ad2..bcf68650cd 100644
--- a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
@@ -147,13 +147,19 @@ void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
}
-int hisi_test_ap_suspend_flag(unsigned int cluster)
+int hisi_test_ap_suspend_flag(void)
{
- unsigned int val;
+ unsigned int val1;
+ unsigned int val2;
- val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
- val &= AP_SUSPEND_FLAG;
- return !!val;
+ val1 = mmio_read_32(CPUIDLE_FLAG_REG(0));
+ val1 &= AP_SUSPEND_FLAG;
+
+ val2 = mmio_read_32(CPUIDLE_FLAG_REG(1));
+ val2 &= AP_SUSPEND_FLAG;
+
+ val1 |= val2;
+ return (val1 != 0);
}
void hisi_set_cluster_pwdn_flag(unsigned int cluster,
@@ -164,7 +170,8 @@ void hisi_set_cluster_pwdn_flag(unsigned int cluster,
hisi_cpuhotplug_lock(cluster, core);
val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
- val = (value << (cluster << 1)) | (val & 0xFFFFFFF);
+ val &= ~(0x3U << ((2 * cluster) + 28));
+ val |= (value << (2 * cluster));
mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
hisi_cpuhotplug_unlock(cluster, core);
@@ -258,6 +265,17 @@ static unsigned int hisi_get_pdc_stat(unsigned int cluster)
return val;
}
+static int check_hotplug(unsigned int cluster, unsigned int boot_flag)
+{
+ unsigned int mask = 0xF;
+
+ if (hisi_test_ap_suspend_flag() ||
+ ((boot_flag & mask) == mask))
+ return 0;
+
+ return 1;
+}
+
int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
{
unsigned int mask = 0xf << (core * 4);
@@ -268,7 +286,8 @@ int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
mask = (PDC_COREPWRSTAT_MASK & (~mask));
pdc_stat &= mask;
- if ((boot_flag ^ cpuidle_flag) || pdc_stat)
+ if ((boot_flag ^ cpuidle_flag) || pdc_stat ||
+ check_hotplug(cluster, boot_flag))
return 0;
else
return 1;
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
index c0170ad96a..e0cb3815fb 100644
--- a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
@@ -39,7 +39,7 @@ void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core);
int cluster_is_powered_on(unsigned int cluster);
void hisi_enter_core_idle(unsigned int cluster, unsigned int core);
void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core);
-int hisi_test_ap_suspend_flag(unsigned int cluster);
+int hisi_test_ap_suspend_flag(void);
void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core);
diff --git a/plat/hisilicon/hikey960/hikey960_pm.c b/plat/hisilicon/hikey960/hikey960_pm.c
index 676cfa3f3c..ede893ecbd 100644
--- a/plat/hisilicon/hikey960/hikey960_pm.c
+++ b/plat/hisilicon/hikey960/hikey960_pm.c
@@ -228,7 +228,7 @@ static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
/* check the SR flag bit to determine
* CLUSTER_IDLE_IPC or AP_SR_IPC to send
*/
- if (hisi_test_ap_suspend_flag(cluster))
+ if (hisi_test_ap_suspend_flag())
hisi_enter_ap_suspend(cluster, core);
else
hisi_enter_cluster_idle(cluster, core);
@@ -268,7 +268,7 @@ hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
hisi_clear_cpuidle_flag(cluster, core);
hisi_cpuidle_unlock(cluster, core);
- if (hisi_test_ap_suspend_flag(cluster)) {
+ if (hisi_test_ap_suspend_flag()) {
hikey960_sr_dma_reinit();
gicv2_cpuif_enable();
console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,