diff options
author | Matt Redfearn <matt.redfearn@mips.com> | 2018-02-20 04:58:16 -0500 |
---|---|---|
committer | James Hogan <jhogan@kernel.org> | 2018-03-09 08:53:26 -0500 |
commit | b2ed33a895676738dfad11cedcba1e3a0a8b6203 (patch) | |
tree | a9014cce241b25f4822bf2f3301194d4b651eb44 | |
parent | ce6828faeb543d00f0697997c858bd82b5905670 (diff) |
MIPS: pm-cps: Block system suspend when a JTAG probe is present
If a JTAG probe is connected to a MIPS cluster, then the CPC detects it
and latches the CPC.STAT_CONF.EJTAG_PROBE bit to 1. While set,
attempting to send a power-down command to a core will be blocked, and
the CPC will instead send the core to clock-off state. This can
interfere with systems fully entering a low power state where all cores,
CM, GIC, etc are powered down.
Detect that a JTAG probe is / has been connected to the cluster and
block the suspend attempt.
Attempting to suspend the system while a JTAG probe is connected now
yields:
# echo mem > /sys/power/state
[ 11.654000] PM: Syncing filesystems ... done.
[ 11.658000] JTAG probe is connected - abort suspend
-sh: echo: write error: Operation not permitted
#
To restore suspend, the JTAG probe should be disconnected or put into
quiescent state. Platform code can then clear the
CPC.STAT_CONF.EJTAG_PROBE bit.
Reported-by: Ed Blake <ed.blake@sondrel.com>
Signed-off-by: Matt Redfearn <matt.redfearn@mips.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Burton <paul.burton@mips.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/18641/
Signed-off-by: James Hogan <jhogan@kernel.org>
-rw-r--r-- | arch/mips/kernel/pm-cps.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 421e06dfee72..55c3fbeb2df6 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/percpu.h> | 13 | #include <linux/percpu.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/suspend.h> | ||
15 | 16 | ||
16 | #include <asm/asm-offsets.h> | 17 | #include <asm/asm-offsets.h> |
17 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
@@ -670,6 +671,34 @@ static int cps_pm_online_cpu(unsigned int cpu) | |||
670 | return 0; | 671 | return 0; |
671 | } | 672 | } |
672 | 673 | ||
674 | static int cps_pm_power_notifier(struct notifier_block *this, | ||
675 | unsigned long event, void *ptr) | ||
676 | { | ||
677 | unsigned int stat; | ||
678 | |||
679 | switch (event) { | ||
680 | case PM_SUSPEND_PREPARE: | ||
681 | stat = read_cpc_cl_stat_conf(); | ||
682 | /* | ||
683 | * If we're attempting to suspend the system and power down all | ||
684 | * of the cores, the JTAG detect bit indicates that the CPC will | ||
685 | * instead put the cores into clock-off state. In this state | ||
686 | * a connected debugger can cause the CPU to attempt | ||
687 | * interactions with the powered down system. At best this will | ||
688 | * fail. At worst, it can hang the NoC, requiring a hard reset. | ||
689 | * To avoid this, just block system suspend if a JTAG probe | ||
690 | * is detected. | ||
691 | */ | ||
692 | if (stat & CPC_Cx_STAT_CONF_EJTAG_PROBE) { | ||
693 | pr_warn("JTAG probe is connected - abort suspend\n"); | ||
694 | return NOTIFY_BAD; | ||
695 | } | ||
696 | return NOTIFY_DONE; | ||
697 | default: | ||
698 | return NOTIFY_DONE; | ||
699 | } | ||
700 | } | ||
701 | |||
673 | static int __init cps_pm_init(void) | 702 | static int __init cps_pm_init(void) |
674 | { | 703 | { |
675 | /* A CM is required for all non-coherent states */ | 704 | /* A CM is required for all non-coherent states */ |
@@ -705,6 +734,8 @@ static int __init cps_pm_init(void) | |||
705 | pr_warn("pm-cps: no CPC, clock & power gating unavailable\n"); | 734 | pr_warn("pm-cps: no CPC, clock & power gating unavailable\n"); |
706 | } | 735 | } |
707 | 736 | ||
737 | pm_notifier(cps_pm_power_notifier, 0); | ||
738 | |||
708 | return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mips/cps_pm:online", | 739 | return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mips/cps_pm:online", |
709 | cps_pm_online_cpu, NULL); | 740 | cps_pm_online_cpu, NULL); |
710 | } | 741 | } |