aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-12-07 14:06:24 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2010-12-14 10:48:41 -0800
commit3e38142b237ab1c79e2ef3dafbd1eaf52219ba41 (patch)
treeab737d56238bab7b2d836962877ae3d2dd7faece
parent039babf20aa5c4a9976e63d0f57e06aacfcd7b36 (diff)
downloadmrst-s0i3-test-3e38142b237ab1c79e2ef3dafbd1eaf52219ba41.tar.gz
mrst-s0i3-test-3e38142b237ab1c79e2ef3dafbd1eaf52219ba41.tar.xz
mrst-s0i3-test-3e38142b237ab1c79e2ef3dafbd1eaf52219ba41.zip
s0i3: add support for putting the secondary thread back into C6
We need to SIPI the secondary thread just in order to put it back into C6, in order for S0i3 to be possible again. Sigh. Note: this really should be done on top of the unified trampoline patchset; that will cut the number of lines roughly in half. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/x86/kernel/setup.c2
-rw-r--r--drivers/idle/mrst_s0i3.c34
-rw-r--r--drivers/idle/mrst_s0i3_asm.S29
3 files changed, 61 insertions, 4 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 35c256b319c..bcd8a76f7b9 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -690,6 +690,7 @@ static u64 __init get_max_mapped(void)
*
* Note: On x86_64, fixmaps are ready for use even before this is called.
*/
+extern void s0i3_reserve_memory(void);
void __init setup_arch(char **cmdline_p)
{
@@ -926,6 +927,7 @@ void __init setup_arch(char **cmdline_p)
max_pfn_mapped<<PAGE_SHIFT);
reserve_trampoline_memory();
+ s0i3_reserve_memory();
#ifdef CONFIG_ACPI_SLEEP
/*
diff --git a/drivers/idle/mrst_s0i3.c b/drivers/idle/mrst_s0i3.c
index 90030e23dda..3044cae899d 100644
--- a/drivers/idle/mrst_s0i3.c
+++ b/drivers/idle/mrst_s0i3.c
@@ -29,6 +29,8 @@
#include <linux/sched.h>
#include <linux/suspend.h>
#include <linux/sfi.h>
+#include <linux/memblock.h>
+#include <asm/apic.h>
#include <asm/i387.h>
#include <asm/msr.h>
#include <asm/mtrr.h>
@@ -55,6 +57,8 @@ static void do_s0i3(void);
static volatile struct mrst_pmu_reg *pmu_reg;
static struct pci_dev *pmu_dev; /* South Complex PMU unit */
static u64 *wakeup_ptr;
+static phys_addr_t s0i3_trampoline_phys;
+static void *s0i3_trampoline_base;
/**
* mrst_s0i3_idle
@@ -202,10 +206,7 @@ static void s0i3_restore_lapic(void)
*/
static void s0i3_poke_other_cpu(void)
{
-#if 0
- cpu_up(1);
- cpu_down(1);
-#endif
+ wakeup_secondary_cpu_via_init(1, s0i3_trampoline_phys);
}
/*
@@ -318,6 +319,27 @@ static irqreturn_t s0i3_pmu_irq(int irq, void *dummy)
return IRQ_HANDLED;
}
+/* XXX: Replace this with unified trampoline code */
+extern const char s0i3_trampoline_data[], s0i3_trampoline_data_end[];
+
+void s0i3_reserve_memory(void)
+{
+ phys_addr_t mem;
+ size_t size;
+
+ size = s0i3_trampoline_data_end - s0i3_trampoline_data;
+ size = ALIGN(size, PAGE_SIZE);
+
+ /* Has to be in very low memory so we can execute real-mode AP code. */
+ mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
+ if (mem == MEMBLOCK_ERROR)
+ panic("Cannot allocate S0i3 trampoline\n");
+
+ s0i3_trampoline_phys = mem;
+ s0i3_trampoline_base = __va(mem);
+ memblock_x86_reserve_range(mem, mem + size, "S0I3");
+}
+
/* Hacky! */
static int s0i3_prepare(void)
{
@@ -364,6 +386,10 @@ static int s0i3_prepare(void)
tmp |= 0x100; /* Enable interrupts */
writel(tmp, &pmu_reg->pm_ics);
+ /* Set up the wakeup trampoline */
+ memcpy(s0i3_trampoline_base, s0i3_trampoline_data,
+ s0i3_trampoline_data_end - s0i3_trampoline_data);
+
return 0;
err_disable_pdev:
diff --git a/drivers/idle/mrst_s0i3_asm.S b/drivers/idle/mrst_s0i3_asm.S
index 4561a53c347..1482bf78416 100644
--- a/drivers/idle/mrst_s0i3_asm.S
+++ b/drivers/idle/mrst_s0i3_asm.S
@@ -18,6 +18,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <linux/init.h>
#include <linux/linkage.h>
#include <asm/asm.h>
#include <asm/msr-index.h>
@@ -203,6 +204,34 @@ ENTRY(mrst_s0i3_resume)
ret
ENDPROC(mrst_s0i3_resume)
+/*
+ * Simple loop in C6 MWAIT
+ */
+ __INITRODATA
+ .code16
+ .balign 64
+ENTRY(s0i3_trampoline_data)
+r_base = .
+1:
+ movl $(dummy_mem - r_base), %eax
+ clflush (%eax)
+
+ xorl %edx, %edx
+ xorl %ecx, %ecx
+ monitor
+
+ movl $MRST_C6_HINTS_EAX, %eax
+ xorl %ecx, %ecx /* No wakeups necessary or wanted */
+ mwait
+ jmp 1b
+
+ .balign 64
+ /* One cache line of otherwise unused memory */
+dummy_mem:
+ .space 64
+END(s0i3_trampoline_data)
+ENTRY(s0i3_trampoline_data_end)
+
.bss
.balign 4
mrst_s0i3_resume_stack: