WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Add suspend/resume to devices owned by Xe

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Add suspend/resume to devices owned by Xen.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 14 Jun 2007 12:53:16 -0700
Delivery-date: Thu, 14 Jun 2007 15:24:18 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1181573088 -3600
# Node ID 35e38c9048c8ec0762743626d69a07b91c754e84
# Parent  bd94f75fe469a5593e49545824e656818f320d86
Add suspend/resume to devices owned by Xen.

Signed-off-by: Ke Yu <ke.yu@xxxxxxxxx>
Signed-off-by: Kevin Tian <kevin.tian@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/apic.c           |   94 +++++++++++++++++++++++++++++++++++++++++-
 xen/arch/x86/i8259.c          |   30 +++++++++++++
 xen/arch/x86/io_apic.c        |   74 +++++++++++++++++++++++++++++++++
 xen/arch/x86/time.c           |   65 ++++++++++++++++++++++++-----
 xen/drivers/char/console.c    |   25 ++++++++++-
 xen/drivers/char/serial.c     |   14 ++++++
 xen/include/asm-x86/apic.h    |    4 +
 xen/include/asm-x86/io_apic.h |    4 +
 xen/include/asm-x86/irq.h     |    2 
 xen/include/asm-x86/time.h    |    5 ++
 xen/include/xen/console.h     |    3 +
 xen/include/xen/serial.h      |    4 +
 xen/include/xen/time.h        |    1 
 13 files changed, 311 insertions(+), 14 deletions(-)

diff -r bd94f75fe469 -r 35e38c9048c8 xen/arch/x86/apic.c
--- a/xen/arch/x86/apic.c       Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/arch/x86/apic.c       Mon Jun 11 15:44:48 2007 +0100
@@ -579,6 +579,95 @@ void __devinit setup_local_APIC(void)
     apic_pm_activate();
 }
 
+static struct {
+    int active;
+    /* r/w apic fields */
+    unsigned int apic_id;
+    unsigned int apic_taskpri;
+    unsigned int apic_ldr;
+    unsigned int apic_dfr;
+    unsigned int apic_spiv;
+    unsigned int apic_lvtt;
+    unsigned int apic_lvtpc;
+    unsigned int apic_lvt0;
+    unsigned int apic_lvt1;
+    unsigned int apic_lvterr;
+    unsigned int apic_tmict;
+    unsigned int apic_tdcr;
+    unsigned int apic_thmr;
+} apic_pm_state;
+
+int lapic_suspend(void)
+{
+    unsigned long flags;
+
+    if (!apic_pm_state.active)
+        return 0;
+
+    apic_pm_state.apic_id = apic_read(APIC_ID);
+    apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
+    apic_pm_state.apic_ldr = apic_read(APIC_LDR);
+    apic_pm_state.apic_dfr = apic_read(APIC_DFR);
+    apic_pm_state.apic_spiv = apic_read(APIC_SPIV);
+    apic_pm_state.apic_lvtt = apic_read(APIC_LVTT);
+    apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
+    apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0);
+    apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1);
+    apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
+    apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
+    apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
+    apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
+    
+    local_irq_save(flags);
+    disable_local_APIC();
+    local_irq_restore(flags);
+    return 0;
+}
+
+int lapic_resume(void)
+{
+    unsigned int l, h;
+    unsigned long flags;
+
+    if (!apic_pm_state.active)
+        return 0;
+
+    local_irq_save(flags);
+
+    /*
+     * Make sure the APICBASE points to the right address
+     *
+     * FIXME! This will be wrong if we ever support suspend on
+     * SMP! We'll need to do this as part of the CPU restore!
+     */
+    rdmsr(MSR_IA32_APICBASE, l, h);
+    l &= ~MSR_IA32_APICBASE_BASE;
+    l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+    wrmsr(MSR_IA32_APICBASE, l, h);
+
+    apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
+    apic_write(APIC_ID, apic_pm_state.apic_id);
+    apic_write(APIC_DFR, apic_pm_state.apic_dfr);
+    apic_write(APIC_LDR, apic_pm_state.apic_ldr);
+    apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri);
+    apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
+    apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
+    apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
+    apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
+    apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
+    apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
+    apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
+    apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
+    apic_write(APIC_ESR, 0);
+    apic_read(APIC_ESR);
+    apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
+    apic_write(APIC_ESR, 0);
+    apic_read(APIC_ESR);
+    local_irq_restore(flags);
+    return 0;
+}
+
+
 /*
  * If Linux enabled the LAPIC against the BIOS default
  * disable it down before re-entering the BIOS on shutdown.
@@ -602,7 +691,10 @@ void lapic_shutdown(void)
     local_irq_restore(flags);
 }
 
-static void apic_pm_activate(void) { }
+static void apic_pm_activate(void)
+{
+    apic_pm_state.active = 1;
+}
 
 /*
  * Detect and enable local APICs on non-SMP boards.
diff -r bd94f75fe469 -r 35e38c9048c8 xen/arch/x86/i8259.c
--- a/xen/arch/x86/i8259.c      Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/arch/x86/i8259.c      Mon Jun 11 15:44:48 2007 +0100
@@ -306,6 +306,36 @@ static void mask_and_ack_8259A_vector(un
     }
 }
 
+static char irq_trigger[2];
+/**
+ * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
+ */
+static void restore_ELCR(char *trigger)
+{
+    outb(trigger[0], 0x4d0);
+    outb(trigger[1], 0x4d1);
+}
+
+static void save_ELCR(char *trigger)
+{
+    /* IRQ 0,1,2,8,13 are marked as reserved */
+    trigger[0] = inb(0x4d0) & 0xF8;
+    trigger[1] = inb(0x4d1) & 0xDE;
+}
+
+int i8259A_resume(void)
+{
+    init_8259A(0);
+    restore_ELCR(irq_trigger);
+    return 0;
+}
+
+int i8259A_suspend(void)
+{
+    save_ELCR(irq_trigger);
+    return 0;
+}
+
 void __init init_8259A(int auto_eoi)
 {
     unsigned long flags;
diff -r bd94f75fe469 -r 35e38c9048c8 xen/arch/x86/io_apic.c
--- a/xen/arch/x86/io_apic.c    Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/arch/x86/io_apic.c    Mon Jun 11 15:44:48 2007 +0100
@@ -1793,6 +1793,80 @@ void __init setup_IO_APIC(void)
     register_keyhandler('z', print_IO_APIC_keyhandler, "print ioapic info");
 }
 
+struct IO_APIC_route_entry *ioapic_pm_state=NULL;
+
+void ioapic_pm_state_alloc(void)
+{
+    int i, nr_entry = 0;
+
+    if (ioapic_pm_state != NULL)
+        return;
+
+    for (i = 0; i < nr_ioapics; i++)
+        nr_entry += nr_ioapic_registers[i];
+
+    ioapic_pm_state = _xmalloc(sizeof(struct IO_APIC_route_entry)*nr_entry,
+                               sizeof(struct IO_APIC_route_entry));
+}
+
+int ioapic_suspend(void)
+{
+    struct IO_APIC_route_entry *entry;
+    unsigned long flags;
+    int apic,i;
+
+    ioapic_pm_state_alloc();
+
+    if (ioapic_pm_state == NULL) {
+        printk("Cannot suspend ioapic due to lack of memory\n");
+        return 1;
+    }
+
+    entry = ioapic_pm_state;
+
+    spin_lock_irqsave(&ioapic_lock, flags);
+    for (apic = 0; apic < nr_ioapics; apic++) {
+        for (i = 0; i < nr_ioapic_registers[apic]; i ++, entry ++ ) {
+            *(((int *)entry) + 1) = io_apic_read(apic, 0x11 + 2 * i);
+            *(((int *)entry) + 0) = io_apic_read(apic, 0x10 + 2 * i);
+        }
+    }
+    spin_unlock_irqrestore(&ioapic_lock, flags);
+
+    return 0;
+}
+
+int ioapic_resume(void)
+{
+    struct IO_APIC_route_entry *entry;
+    unsigned long flags;
+    union IO_APIC_reg_00 reg_00;
+    int i,apic;
+    
+    if (ioapic_pm_state == NULL){
+        printk("Cannot resume ioapic due to lack of memory\n");
+        return 1;
+    }
+    
+    entry = ioapic_pm_state;
+
+    spin_lock_irqsave(&ioapic_lock, flags);
+    for (apic = 0; apic < nr_ioapics; apic++){
+        reg_00.raw = io_apic_read(apic, 0);
+        if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) {
+            reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
+            io_apic_write(apic, 0, reg_00.raw);
+        }
+        for (i = 0; i < nr_ioapic_registers[apic]; i++, entry++) {
+            io_apic_write(apic, 0x11+2*i, *(((int *)entry)+1));
+            io_apic_write(apic, 0x10+2*i, *(((int *)entry)+0));
+        }
+    }
+    spin_unlock_irqrestore(&ioapic_lock, flags);
+
+    return 0;
+}
+
 /* --------------------------------------------------------------------------
                           ACPI-based IOAPIC Configuration
    -------------------------------------------------------------------------- 
*/
diff -r bd94f75fe469 -r 35e38c9048c8 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/arch/x86/time.c       Mon Jun 11 15:44:48 2007 +0100
@@ -171,10 +171,17 @@ static struct irqaction irq0 = { timer_i
 #define CALIBRATE_FRAC  20      /* calibrate over 50ms */
 #define CALIBRATE_LATCH ((CLOCK_TICK_RATE+(CALIBRATE_FRAC/2))/CALIBRATE_FRAC)
 
-static u64 calibrate_boot_tsc(void)
+static u64 init_pit_and_calibrate_tsc(void)
 {
     u64 start, end;
     unsigned long count;
+
+    /* Set PIT channel 0 to HZ Hz. */
+#define CLOCK_TICK_RATE 1193180 /* crystal freq (Hz) */
+#define LATCH (((CLOCK_TICK_RATE)+(HZ/2))/HZ)
+    outb_p(0x34, PIT_MODE);        /* binary, mode 2, LSB/MSB, ch 0 */
+    outb_p(LATCH & 0xff, PIT_CH0); /* LSB */
+    outb(LATCH >> 8, PIT_CH0);     /* MSB */
 
     /* Set the Gate high, disable speaker */
     outb((inb(0x61) & ~0x02) | 0x01, 0x61);
@@ -489,11 +496,12 @@ static s_time_t read_platform_stime(void
 {
     u64 count;
     s_time_t stime;
-
-    spin_lock_irq(&platform_timer_lock);
+    unsigned long flags;
+
+    spin_lock_irqsave(&platform_timer_lock, flags);
     count = plt_count64 + ((plt_src.read_counter() - plt_count) & plt_mask);
     stime = __read_platform_stime(count);
-    spin_unlock_irq(&platform_timer_lock);
+    spin_unlock_irqrestore(&platform_timer_lock, flags);
 
     return stime;
 }
@@ -502,13 +510,21 @@ static void platform_time_calibration(vo
 {
     u64 count;
     s_time_t stamp;
-
-    spin_lock_irq(&platform_timer_lock);
+    unsigned long flags;
+
+    spin_lock_irqsave(&platform_timer_lock, flags);
     count = plt_count64 + ((plt_src.read_counter() - plt_count) & plt_mask);
     stamp = __read_platform_stime(count);
     stime_platform_stamp = stamp;
     platform_timer_stamp = count;
-    spin_unlock_irq(&platform_timer_lock);
+    spin_unlock_irqrestore(&platform_timer_lock, flags);
+}
+
+static void resume_platform_timer(void)
+{
+    /* No change in platform_stime across suspend/resume. */
+    platform_timer_stamp = plt_count64;
+    plt_count = plt_src.read_counter();
 }
 
 static void init_platform_timer(void)
@@ -875,7 +891,7 @@ void init_percpu_time(void)
 
     local_irq_save(flags);
     rdtscll(t->local_tsc_stamp);
-    now = (smp_processor_id() == 0) ? 0 : read_platform_stime();
+    now = !plt_src.read_counter ? 0 : read_platform_stime();
     local_irq_restore(flags);
 
     t->stime_master_stamp = now;
@@ -907,9 +923,9 @@ int __init init_xen_time(void)
 /* Early init function. */
 void __init early_time_init(void)
 {
-    u64 tmp = calibrate_boot_tsc();
-
-    set_time_scale(&per_cpu(cpu_time, 0).tsc_scale, tmp);
+    u64 tmp = init_pit_and_calibrate_tsc();
+
+    set_time_scale(&this_cpu(cpu_time).tsc_scale, tmp);
 
     do_div(tmp, 1000);
     cpu_khz = (unsigned long)tmp;
@@ -929,6 +945,33 @@ unsigned long get_localtime(struct domai
 {
     return wc_sec + (wc_nsec + NOW()) / 1000000000ULL 
         + d->time_offset_seconds;
+}
+
+int time_suspend(void)
+{
+    /* Better to cancel calibration timer for accuracy. */
+    kill_timer(&this_cpu(cpu_time).calibration_timer);
+
+    return 0;
+}
+
+int time_resume(void)
+{
+    u64 now_sec, tmp = init_pit_and_calibrate_tsc();
+
+    set_time_scale(&this_cpu(cpu_time).tsc_scale, tmp);
+
+    resume_platform_timer();
+    now_sec = read_platform_stime();
+    do_div(now_sec, SECONDS(1));
+    wc_sec = get_cmos_time() - now_sec;
+
+    init_percpu_time();
+
+    if ( !is_idle_vcpu(current) )
+        update_vcpu_system_time(current);
+
+    return 0;
 }
 
 /*
diff -r bd94f75fe469 -r 35e38c9048c8 xen/drivers/char/console.c
--- a/xen/drivers/char/console.c        Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/drivers/char/console.c        Mon Jun 11 15:44:48 2007 +0100
@@ -848,7 +848,6 @@ __initcall(debugtrace_init);
 #endif /* !NDEBUG */
 
 
-
 /*
  * **************************************************************
  * *************** Debugging/tracing/error-report ***************
@@ -914,6 +913,30 @@ void __warn(char *file, int line)
     dump_execution_state();
 }
 
+
+/*
+ * **************************************************************
+ * ****************** Console suspend/resume ********************
+ * **************************************************************
+ */
+
+static void suspend_steal_fn(const char *str) { }
+static int suspend_steal_id;
+
+int console_suspend(void)
+{
+    suspend_steal_id = console_steal(sercon_handle, suspend_steal_fn);
+    serial_suspend();
+    return 0;
+}
+
+int console_resume(void)
+{
+    serial_resume();
+    console_giveback(suspend_steal_id);
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff -r bd94f75fe469 -r 35e38c9048c8 xen/drivers/char/serial.c
--- a/xen/drivers/char/serial.c Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/drivers/char/serial.c Mon Jun 11 15:44:48 2007 +0100
@@ -381,6 +381,20 @@ int serial_irq(int idx)
     return -1;
 }
 
+void serial_suspend(void)
+{
+    int i, irq;
+    for ( i = 0; i < ARRAY_SIZE(com); i++ )
+        if ( (irq = serial_irq(i)) >= 0 )
+            free_irq(irq);
+}
+
+void serial_resume(void)
+{
+    serial_init_preirq();
+    serial_init_postirq();
+}
+
 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
 {
     /* Store UART-specific info. */
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/asm-x86/apic.h
--- a/xen/include/asm-x86/apic.h        Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/asm-x86/apic.h        Mon Jun 11 15:44:48 2007 +0100
@@ -108,6 +108,8 @@ extern int APIC_init_uniprocessor (void)
 extern int APIC_init_uniprocessor (void);
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
+extern int lapic_suspend(void);
+extern int lapic_resume(void);
 
 extern int check_nmi_watchdog (void);
 extern void enable_NMI_through_LVT0 (void * dummy);
@@ -123,6 +125,8 @@ extern unsigned int nmi_watchdog;
 
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
+static inline int lapic_suspend(void) {return 0;}
+static inline int lapic_resume(void) {return 0;}
 
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/asm-x86/io_apic.h
--- a/xen/include/asm-x86/io_apic.h     Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/asm-x86/io_apic.h     Mon Jun 11 15:44:48 2007 +0100
@@ -169,9 +169,13 @@ extern int timer_uses_ioapic_pin_0;
 #endif /*CONFIG_ACPI_BOOT*/
 
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
+extern int ioapic_suspend(void);
+extern int ioapic_resume(void);
 
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
+static inline int ioapic_suspend(void) {return 0};
+static inline int ioapic_resume(void) {return 0};
 #endif
 
 extern int assign_irq_vector(int irq);
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/asm-x86/irq.h
--- a/xen/include/asm-x86/irq.h Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/asm-x86/irq.h Mon Jun 11 15:44:48 2007 +0100
@@ -35,6 +35,8 @@ void enable_8259A_irq(unsigned int irq);
 void enable_8259A_irq(unsigned int irq);
 int i8259A_irq_pending(unsigned int irq);
 void init_8259A(int aeoi);
+int i8259A_suspend(void);
+int i8259A_resume(void);
 
 void setup_IO_APIC(void);
 void disable_IO_APIC(void);
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/asm-x86/time.h
--- a/xen/include/asm-x86/time.h        Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/asm-x86/time.h        Mon Jun 11 15:44:48 2007 +0100
@@ -21,4 +21,9 @@ mktime (unsigned int year, unsigned int 
         unsigned int day, unsigned int hour,
         unsigned int min, unsigned int sec);
 
+extern int time_suspend(void);
+extern int time_resume(void);
+
+extern void init_percpu_time(void);
+
 #endif /* __X86_TIME_H__ */
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/xen/console.h
--- a/xen/include/xen/console.h Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/xen/console.h Mon Jun 11 15:44:48 2007 +0100
@@ -38,4 +38,7 @@ int console_steal(int handle, void (*fn)
 /* Give back stolen console. Takes the identifier returned by console_steal. */
 void console_giveback(int id);
 
+int console_suspend(void);
+int console_resume(void);
+
 #endif /* __CONSOLE_H__ */
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/xen/serial.h
--- a/xen/include/xen/serial.h  Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/xen/serial.h  Mon Jun 11 15:44:48 2007 +0100
@@ -104,6 +104,10 @@ int serial_tx_space(int handle);
 /* Return irq number for specified serial port (identified by index). */
 int serial_irq(int idx);
 
+/* Serial suspend/resume. */
+void serial_suspend(void);
+void serial_resume(void);
+
 /*
  * Initialisation and helper functions for uart drivers.
  */
diff -r bd94f75fe469 -r 35e38c9048c8 xen/include/xen/time.h
--- a/xen/include/xen/time.h    Mon Jun 11 15:10:23 2007 +0100
+++ b/xen/include/xen/time.h    Mon Jun 11 15:44:48 2007 +0100
@@ -31,7 +31,6 @@
 #include <asm/time.h>
 
 extern int init_xen_time(void);
-extern void init_percpu_time(void);
 
 extern unsigned long cpu_khz;
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Add suspend/resume to devices owned by Xen., Xen patchbot-unstable <=