summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2017-05-24 13:33:01 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2017-05-24 13:33:01 +0000
commit41d468b9e505cc0805b5cdff947859554896fe8c (patch)
treedbb8443ace184562a58990021a3c03e71c6c88e1
parent3d5d9c3cc643a0562be079f11040d4bc73984726 (diff)
Add an idle cycle implementation for R4600/R5000/RM7000 CPUs and their
derivatives. This lets the kernel utilize the CPUs' Standby Mode to reduce the power consumption of an idle system. Suggested by and input from miod@. He also tested this patch on an RM7000 O2.
-rw-r--r--sys/arch/mips64/include/cpu.h5
-rw-r--r--sys/arch/mips64/mips64/context.S35
-rw-r--r--sys/arch/mips64/mips64/cpu.c26
3 files changed, 59 insertions, 7 deletions
diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h
index 5213837ace9..260e8585361 100644
--- a/sys/arch/mips64/include/cpu.h
+++ b/sys/arch/mips64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.116 2017/04/20 15:42:26 visa Exp $ */
+/* $OpenBSD: cpu.h,v 1.117 2017/05/24 13:33:00 visa Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -234,6 +234,9 @@ extern struct cpu_info *cpu_info_list;
#define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0)
+extern void (*cpu_idle_cycle_func)(void);
+#define cpu_idle_cycle() (*cpu_idle_cycle_func)()
+
#ifdef MULTIPROCESSOR
#define MAXCPUS 4
#define getcurcpu() hw_getcurcpu()
diff --git a/sys/arch/mips64/mips64/context.S b/sys/arch/mips64/mips64/context.S
index 7843e76ae52..c5cbe1e25dd 100644
--- a/sys/arch/mips64/mips64/context.S
+++ b/sys/arch/mips64/mips64/context.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: context.S,v 1.59 2017/04/20 15:42:26 visa Exp $ */
+/* $OpenBSD: context.S,v 1.60 2017/05/24 13:33:00 visa Exp $ */
/*
* Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -80,13 +80,38 @@ LEAF(cpu_idle_leave, 0)
NOP
END(cpu_idle_leave)
-LEAF(cpu_idle_cycle, 0)
-#ifdef CPU_OCTEON
+LEAF(cpu_idle_cycle_nop, 0)
+ j ra
+ NOP
+END(cpu_idle_cycle_nop)
+
+LEAF(cpu_idle_cycle_wait, 0)
wait
-#endif
j ra
NOP
-END(cpu_idle_cycle)
+END(cpu_idle_cycle_wait)
+
+LEAF(cpu_idle_cycle_rm7k, 0)
+ /*
+ * RM7000 errata #38: The R4600, R4640, R4700, R5000, RM52xx,
+ * and RM7xxx processors do not handle bus signalling properly
+ * in the standby mode, which can cause incorrect behaviour
+ * upon leaving the mode. This can be avoided by flushing
+ * any writes from the pipeline before the WAIT instruction
+ * is executed.
+ */
+ mfc0 a0, COP_0_STATUS_REG # save status
+ ori a1, a0, SR_INT_ENAB
+ xori a1, SR_INT_ENAB
+ mtc0 a1, COP_0_STATUS_REG # disable interrupts
+ sync # flush pending writes
+ mtc0 a1, COP_0_STATUS_REG # stall until W stage
+ wait # enter standby mode
+ mtc0 a0, COP_0_STATUS_REG # stall until W stage,
+ # and restore status
+ j ra
+ NOP
+END(cpu_idle_cycle_rm7k)
/*
* cpu_switchto_asm(struct proc *oldproc, struct proc *newproc)
diff --git a/sys/arch/mips64/mips64/cpu.c b/sys/arch/mips64/mips64/cpu.c
index bb40e5b77e7..53aed7c95da 100644
--- a/sys/arch/mips64/mips64/cpu.c
+++ b/sys/arch/mips64/mips64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.67 2017/05/11 15:42:10 visa Exp $ */
+/* $OpenBSD: cpu.c,v 1.68 2017/05/24 13:33:00 visa Exp $ */
/*
* Copyright (c) 1997-2004 Opsycon AB (www.opsycon.se)
@@ -50,6 +50,11 @@ struct cpu_info *cpu_info_secondaries;
struct cpuset cpus_running;
#endif
+extern void cpu_idle_cycle_nop(void);
+extern void cpu_idle_cycle_rm7k(void);
+extern void cpu_idle_cycle_wait(void);
+void (*cpu_idle_cycle_func)(void) = cpu_idle_cycle_nop;
+
vaddr_t cache_valias_mask;
int cpu_has_userlocal;
@@ -366,6 +371,25 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
else
printf("%d way", ci->ci_l3.sets);
}
+
+ if (cpuno == 0) {
+ switch (ch->type) {
+ case MIPS_R4600:
+ case MIPS_R4700:
+ case MIPS_R5000:
+ case MIPS_RM52X0:
+ case MIPS_RM7000:
+ cpu_idle_cycle_func = cpu_idle_cycle_rm7k;
+ break;
+ case MIPS_CN50XX:
+ case MIPS_CN61XX:
+ case MIPS_CN71XX:
+ case MIPS_CN73XX:
+ cpu_idle_cycle_func = cpu_idle_cycle_wait;
+ break;
+ }
+ }
+
printf("\n");
#ifdef DEBUG