From: Greg Kroah-Hartman Date: Fri, 30 Jul 2010 01:07:32 +0000 (-0700) Subject: .34 patches X-Git-Tag: v2.6.27.49~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=863a20830bfd2ebd4abe78de317454151e4539c9;p=thirdparty%2Fkernel%2Fstable-queue.git .34 patches --- diff --git a/queue-2.6.34/acpi-store-nvs-state-even-when-entering-suspend-to-ram.patch b/queue-2.6.34/acpi-store-nvs-state-even-when-entering-suspend-to-ram.patch deleted file mode 100644 index 26fd517aca1..00000000000 --- a/queue-2.6.34/acpi-store-nvs-state-even-when-entering-suspend-to-ram.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 2a6b69765ad794389f2fc3e14a0afa1a995221c2 Mon Sep 17 00:00:00 2001 -From: Matthew Garrett -Date: Fri, 28 May 2010 16:32:15 -0400 -Subject: ACPI: Store NVS state even when entering suspend to RAM - -From: Matthew Garrett - -commit 2a6b69765ad794389f2fc3e14a0afa1a995221c2 upstream. - -https://bugzilla.kernel.org/show_bug.cgi?id=13931 describes a bug where -a system fails to successfully resume after the second suspend. Maxim -Levitsky discovered that this could be rectified by forcibly saving -and restoring the ACPI non-volatile state. The spec indicates that this -is only required for S4, but testing the behaviour of Windows by adding -an ACPI NVS region to qemu's e820 map and registering a custom memory -read/write handler reveals that it's saved and restored even over suspend -to RAM. We should mimic that behaviour to avoid other broken platforms. - -Signed-off-by: Matthew Garrett -Signed-off-by: Len Brown -Cc: Rafael Wysocki -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/acpi/sleep.c | 21 +++++++++++++-------- - 1 file changed, 13 insertions(+), 8 deletions(-) - ---- a/drivers/acpi/sleep.c -+++ b/drivers/acpi/sleep.c -@@ -112,6 +112,8 @@ static int __acpi_pm_prepare(void) - { - int error = acpi_sleep_prepare(acpi_target_sleep_state); - -+ suspend_nvs_save(); -+ - if (error) - acpi_target_sleep_state = ACPI_STATE_S0; - return error; -@@ -140,6 +142,8 @@ static void acpi_pm_finish(void) - { - u32 acpi_state = acpi_target_sleep_state; - -+ suspend_nvs_free(); -+ - if (acpi_state == ACPI_STATE_S0) - return; - -@@ -189,6 +193,11 @@ static int acpi_suspend_begin(suspend_st - u32 acpi_state = acpi_suspend_states[pm_state]; - int error = 0; - -+ error = suspend_nvs_alloc(); -+ -+ if (error) -+ return error; -+ - if (sleep_states[acpi_state]) { - acpi_target_sleep_state = acpi_state; - acpi_sleep_tts_switch(acpi_target_sleep_state); -@@ -264,6 +273,8 @@ static int acpi_suspend_enter(suspend_st - if (acpi_state == ACPI_STATE_S3) - acpi_restore_state_mem(); - -+ suspend_nvs_restore(); -+ - return ACPI_SUCCESS(status) ? 0 : -EFAULT; - } - -@@ -430,12 +441,6 @@ static int acpi_hibernation_enter(void) - return ACPI_SUCCESS(status) ? 0 : -EFAULT; - } - --static void acpi_hibernation_finish(void) --{ -- suspend_nvs_free(); -- acpi_pm_finish(); --} -- - static void acpi_hibernation_leave(void) - { - /* -@@ -473,7 +478,7 @@ static struct platform_hibernation_ops a - .begin = acpi_hibernation_begin, - .end = acpi_pm_end, - .pre_snapshot = acpi_hibernation_pre_snapshot, -- .finish = acpi_hibernation_finish, -+ .finish = acpi_pm_finish, - .prepare = acpi_pm_prepare, - .enter = acpi_hibernation_enter, - .leave = acpi_hibernation_leave, -@@ -526,7 +531,7 @@ static struct platform_hibernation_ops a - .begin = acpi_hibernation_begin_old, - .end = acpi_pm_end, - .pre_snapshot = acpi_hibernation_pre_snapshot_old, -- .finish = acpi_hibernation_finish, -+ .finish = acpi_pm_finish, - .prepare = acpi_pm_disable_gpes, - .enter = acpi_hibernation_enter, - .leave = acpi_hibernation_leave, diff --git a/queue-2.6.34/drm-i915-add-panel_unlock_regs-definition.patch b/queue-2.6.34/drm-i915-add-panel_unlock_regs-definition.patch new file mode 100644 index 00000000000..fb4394145e3 --- /dev/null +++ b/queue-2.6.34/drm-i915-add-panel_unlock_regs-definition.patch @@ -0,0 +1,53 @@ +From 4a655f043160eeae447efd3be297b6b4c397a640 Mon Sep 17 00:00:00 2001 +From: Jesse Barnes +Date: Thu, 22 Jul 2010 13:18:18 -0700 +Subject: drm/i915: add PANEL_UNLOCK_REGS definition + +From: Jesse Barnes + +commit 4a655f043160eeae447efd3be297b6b4c397a640 upstream. + +In some cases, unlocking the panel regs is safe and can help us avoid a +flickery, full mode set sequence. So define the unlock key and use it. + +Signed-off-by: Jesse Barnes +Signed-off-by: Eric Anholt +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_reg.h | 1 + + drivers/gpu/drm/i915/intel_display.c | 6 ++++-- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_reg.h ++++ b/drivers/gpu/drm/i915/i915_reg.h +@@ -2687,6 +2687,7 @@ + + #define PCH_PP_STATUS 0xc7200 + #define PCH_PP_CONTROL 0xc7204 ++#define PANEL_UNLOCK_REGS (0xabcd << 16) + #define EDP_FORCE_VDD (1 << 3) + #define EDP_BLC_ENABLE (1 << 2) + #define PANEL_POWER_RESET (1 << 1) +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -3950,7 +3950,8 @@ static void intel_increase_pllclock(stru + DRM_DEBUG_DRIVER("upclocking LVDS\n"); + + /* Unlock panel regs */ +- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16)); ++ I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | ++ PANEL_UNLOCK_REGS); + + dpll &= ~DISPLAY_RATE_SELECT_FPA1; + I915_WRITE(dpll_reg, dpll); +@@ -3993,7 +3994,8 @@ static void intel_decrease_pllclock(stru + DRM_DEBUG_DRIVER("downclocking LVDS\n"); + + /* Unlock panel regs */ +- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16)); ++ I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | ++ PANEL_UNLOCK_REGS); + + dpll |= DISPLAY_RATE_SELECT_FPA1; + I915_WRITE(dpll_reg, dpll); diff --git a/queue-2.6.34/drm-i915-make-sure-edp-panel-is-turned-on.patch b/queue-2.6.34/drm-i915-make-sure-edp-panel-is-turned-on.patch new file mode 100644 index 00000000000..eaf536908ff --- /dev/null +++ b/queue-2.6.34/drm-i915-make-sure-edp-panel-is-turned-on.patch @@ -0,0 +1,103 @@ +From 9934c132989d5c488d2e15188220ce240960ce96 Mon Sep 17 00:00:00 2001 +From: Jesse Barnes +Date: Thu, 22 Jul 2010 13:18:19 -0700 +Subject: drm/i915: make sure eDP panel is turned on + +From: Jesse Barnes + +commit 9934c132989d5c488d2e15188220ce240960ce96 upstream. + +When enabling the eDP port, we need to make sure the panel is turned on +after training the link. If we don't, it likely won't come back after +suspend or may not come up at all. + +For unknown reasons, unlocking the panel regs before initiating a power +on sequence is necessary. There are known bugs in the PCH panel +sequencing logic, apparently this is one possible workaround. + +Fixes https://bugs.freedesktop.org/show_bug.cgi?id=28739. + +Signed-off-by: Jesse Barnes +Tested-by: "Paulo J. S. Silva" +Signed-off-by: Eric Anholt +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/intel_dp.c | 53 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 51 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -677,6 +677,51 @@ intel_dp_mode_set(struct drm_encoder *en + } + } + ++static void ironlake_edp_panel_on (struct drm_device *dev) ++{ ++ struct drm_i915_private *dev_priv = dev->dev_private; ++ unsigned long timeout = jiffies + msecs_to_jiffies(5000); ++ u32 pp, pp_status; ++ ++ pp_status = I915_READ(PCH_PP_STATUS); ++ if (pp_status & PP_ON) ++ return; ++ ++ pp = I915_READ(PCH_PP_CONTROL); ++ pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; ++ I915_WRITE(PCH_PP_CONTROL, pp); ++ do { ++ pp_status = I915_READ(PCH_PP_STATUS); ++ } while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout)); ++ ++ if (time_after(jiffies, timeout)) ++ DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status); ++ ++ pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); ++ I915_WRITE(PCH_PP_CONTROL, pp); ++} ++ ++static void ironlake_edp_panel_off (struct drm_device *dev) ++{ ++ struct drm_i915_private *dev_priv = dev->dev_private; ++ unsigned long timeout = jiffies + msecs_to_jiffies(5000); ++ u32 pp, pp_status; ++ ++ pp = I915_READ(PCH_PP_CONTROL); ++ pp &= ~POWER_TARGET_ON; ++ I915_WRITE(PCH_PP_CONTROL, pp); ++ do { ++ pp_status = I915_READ(PCH_PP_STATUS); ++ } while ((pp_status & PP_ON) && !time_after(jiffies, timeout)); ++ ++ if (time_after(jiffies, timeout)) ++ DRM_DEBUG_KMS("panel off wait timed out\n"); ++ ++ /* Make sure VDD is enabled so DP AUX will work */ ++ pp |= EDP_FORCE_VDD; ++ I915_WRITE(PCH_PP_CONTROL, pp); ++} ++ + static void ironlake_edp_backlight_on (struct drm_device *dev) + { + struct drm_i915_private *dev_priv = dev->dev_private; +@@ -711,14 +756,18 @@ intel_dp_dpms(struct drm_encoder *encode + if (mode != DRM_MODE_DPMS_ON) { + if (dp_reg & DP_PORT_EN) { + intel_dp_link_down(intel_encoder, dp_priv->DP); +- if (IS_eDP(intel_encoder)) ++ if (IS_eDP(intel_encoder)) { ++ ironlake_edp_backlight_off(dev); + ironlake_edp_backlight_off(dev); ++ } + } + } else { + if (!(dp_reg & DP_PORT_EN)) { + intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); +- if (IS_eDP(intel_encoder)) ++ if (IS_eDP(intel_encoder)) { ++ ironlake_edp_panel_on(dev); + ironlake_edp_backlight_on(dev); ++ } + } + } + dp_priv->dpms_mode = mode; diff --git a/queue-2.6.34/drm-i915-make-sure-we-shut-off-the-panel-in-edp-configs.patch b/queue-2.6.34/drm-i915-make-sure-we-shut-off-the-panel-in-edp-configs.patch new file mode 100644 index 00000000000..73d2df1df04 --- /dev/null +++ b/queue-2.6.34/drm-i915-make-sure-we-shut-off-the-panel-in-edp-configs.patch @@ -0,0 +1,31 @@ +From 5620ae29f1eabe655f44335231b580a78c8364ea Mon Sep 17 00:00:00 2001 +From: Jesse Barnes +Date: Mon, 26 Jul 2010 13:51:22 -0700 +Subject: drm/i915: make sure we shut off the panel in eDP configs + +From: Jesse Barnes + +commit 5620ae29f1eabe655f44335231b580a78c8364ea upstream. + +Fix error from the last pull request. Making sure we shut the panel off +is more correct and saves power. + +Signed-off-by: Jesse Barnes +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/intel_dp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -758,7 +758,7 @@ intel_dp_dpms(struct drm_encoder *encode + intel_dp_link_down(intel_encoder, dp_priv->DP); + if (IS_eDP(intel_encoder)) { + ironlake_edp_backlight_off(dev); +- ironlake_edp_backlight_off(dev); ++ ironlake_edp_panel_off(dev); + } + } + } else { diff --git a/queue-2.6.34/series b/queue-2.6.34/series index 2d01f239b3f..b3432814e9e 100644 --- a/queue-2.6.34/series +++ b/queue-2.6.34/series @@ -184,8 +184,6 @@ block-don-t-count_vm_events-for-discard-bio-in-submit_bio.patch iwlagn-verify-flow-id-in-compressed-ba-packet.patch iwlwifi-recover-tx-flow-stall-due-to-stuck-queue.patch iwl3945-enable-stuck-queue-detection-on-3945.patch -suspend-move-nvs-save-restore-code-to-generic-suspend-functionality.patch -acpi-store-nvs-state-even-when-entering-suspend-to-ram.patch kbuild-fix-modpost-segfault.patch acpi-acpica-use-helper-function-for-computing-gpe-masks.patch acpi-acpica-fix-low-level-gpe-manipulation-code.patch @@ -202,3 +200,6 @@ input-rx51-keymap-fix-recent-compile-breakage.patch ocfs2-make-xattr-extension-work-with-new-local-alloc-reservation.patch acpi-processor-fix-processor_physically_present-on-up.patch alsa-hda-fix-pin-detection-of-nvidia-hdmi.patch +drm-i915-add-panel_unlock_regs-definition.patch +drm-i915-make-sure-edp-panel-is-turned-on.patch +drm-i915-make-sure-we-shut-off-the-panel-in-edp-configs.patch diff --git a/queue-2.6.34/suspend-move-nvs-save-restore-code-to-generic-suspend-functionality.patch b/queue-2.6.34/suspend-move-nvs-save-restore-code-to-generic-suspend-functionality.patch deleted file mode 100644 index 49fd27375a5..00000000000 --- a/queue-2.6.34/suspend-move-nvs-save-restore-code-to-generic-suspend-functionality.patch +++ /dev/null @@ -1,468 +0,0 @@ -From dd4c4f17d722ffeb2515bf781400675a30fcead7 Mon Sep 17 00:00:00 2001 -From: Matthew Garrett -Date: Fri, 28 May 2010 16:32:14 -0400 -Subject: suspend: Move NVS save/restore code to generic suspend functionality - -From: Matthew Garrett - -commit dd4c4f17d722ffeb2515bf781400675a30fcead7 upstream. - -Saving platform non-volatile state may be required for suspend to RAM as -well as hibernation. Move it to more generic code. - -Signed-off-by: Matthew Garrett -Acked-by: Rafael J. Wysocki -Tested-by: Maxim Levitsky -Signed-off-by: Len Brown -Signed-off-by: Greg Kroah-Hartman - ---- - arch/x86/kernel/e820.c | 2 - drivers/acpi/sleep.c | 12 +-- - include/linux/suspend.h | 26 ++++---- - kernel/power/Kconfig | 9 +- - kernel/power/Makefile | 2 - kernel/power/hibernate_nvs.c | 136 ------------------------------------------- - kernel/power/nvs.c | 136 +++++++++++++++++++++++++++++++++++++++++++ - kernel/power/suspend.c | 6 + - 8 files changed, 168 insertions(+), 161 deletions(-) - ---- a/arch/x86/kernel/e820.c -+++ b/arch/x86/kernel/e820.c -@@ -729,7 +729,7 @@ static int __init e820_mark_nvs_memory(v - struct e820entry *ei = &e820.map[i]; - - if (ei->type == E820_NVS) -- hibernate_nvs_register(ei->addr, ei->size); -+ suspend_nvs_register(ei->addr, ei->size); - } - - return 0; ---- a/drivers/acpi/sleep.c -+++ b/drivers/acpi/sleep.c -@@ -393,7 +393,7 @@ static int acpi_hibernation_begin(void) - { - int error; - -- error = s4_no_nvs ? 0 : hibernate_nvs_alloc(); -+ error = s4_no_nvs ? 0 : suspend_nvs_alloc(); - if (!error) { - acpi_target_sleep_state = ACPI_STATE_S4; - acpi_sleep_tts_switch(acpi_target_sleep_state); -@@ -407,7 +407,7 @@ static int acpi_hibernation_pre_snapshot - int error = acpi_pm_prepare(); - - if (!error) -- hibernate_nvs_save(); -+ suspend_nvs_save(); - - return error; - } -@@ -432,7 +432,7 @@ static int acpi_hibernation_enter(void) - - static void acpi_hibernation_finish(void) - { -- hibernate_nvs_free(); -+ suspend_nvs_free(); - acpi_pm_finish(); - } - -@@ -452,7 +452,7 @@ static void acpi_hibernation_leave(void) - panic("ACPI S4 hardware signature mismatch"); - } - /* Restore the NVS memory area */ -- hibernate_nvs_restore(); -+ suspend_nvs_restore(); - } - - static int acpi_pm_pre_restore(void) -@@ -501,7 +501,7 @@ static int acpi_hibernation_begin_old(vo - - if (!error) { - if (!s4_no_nvs) -- error = hibernate_nvs_alloc(); -+ error = suspend_nvs_alloc(); - if (!error) - acpi_target_sleep_state = ACPI_STATE_S4; - } -@@ -513,7 +513,7 @@ static int acpi_hibernation_pre_snapshot - int error = acpi_pm_disable_gpes(); - - if (!error) -- hibernate_nvs_save(); -+ suspend_nvs_save(); - - return error; - } ---- a/include/linux/suspend.h -+++ b/include/linux/suspend.h -@@ -256,22 +256,22 @@ static inline int hibernate(void) { retu - static inline bool system_entering_hibernation(void) { return false; } - #endif /* CONFIG_HIBERNATION */ - --#ifdef CONFIG_HIBERNATION_NVS --extern int hibernate_nvs_register(unsigned long start, unsigned long size); --extern int hibernate_nvs_alloc(void); --extern void hibernate_nvs_free(void); --extern void hibernate_nvs_save(void); --extern void hibernate_nvs_restore(void); --#else /* CONFIG_HIBERNATION_NVS */ --static inline int hibernate_nvs_register(unsigned long a, unsigned long b) -+#ifdef CONFIG_SUSPEND_NVS -+extern int suspend_nvs_register(unsigned long start, unsigned long size); -+extern int suspend_nvs_alloc(void); -+extern void suspend_nvs_free(void); -+extern void suspend_nvs_save(void); -+extern void suspend_nvs_restore(void); -+#else /* CONFIG_SUSPEND_NVS */ -+static inline int suspend_nvs_register(unsigned long a, unsigned long b) - { - return 0; - } --static inline int hibernate_nvs_alloc(void) { return 0; } --static inline void hibernate_nvs_free(void) {} --static inline void hibernate_nvs_save(void) {} --static inline void hibernate_nvs_restore(void) {} --#endif /* CONFIG_HIBERNATION_NVS */ -+static inline int suspend_nvs_alloc(void) { return 0; } -+static inline void suspend_nvs_free(void) {} -+static inline void suspend_nvs_save(void) {} -+static inline void suspend_nvs_restore(void) {} -+#endif /* CONFIG_SUSPEND_NVS */ - - #ifdef CONFIG_PM_SLEEP - void save_processor_state(void); ---- a/kernel/power/Kconfig -+++ b/kernel/power/Kconfig -@@ -99,9 +99,13 @@ config PM_SLEEP_ADVANCED_DEBUG - depends on PM_ADVANCED_DEBUG - default n - -+config SUSPEND_NVS -+ bool -+ - config SUSPEND - bool "Suspend to RAM and standby" - depends on PM && ARCH_SUSPEND_POSSIBLE -+ select SUSPEND_NVS if HAS_IOMEM - default y - ---help--- - Allow the system to enter sleep states in which main memory is -@@ -130,13 +134,10 @@ config SUSPEND_FREEZER - - Turning OFF this setting is NOT recommended! If in doubt, say Y. - --config HIBERNATION_NVS -- bool -- - config HIBERNATION - bool "Hibernation (aka 'suspend to disk')" - depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE -- select HIBERNATION_NVS if HAS_IOMEM -+ select SUSPEND_NVS if HAS_IOMEM - ---help--- - Enable the suspend to disk (STD) functionality, which is usually - called "hibernation" in user interfaces. STD checkpoints the ---- a/kernel/power/Makefile -+++ b/kernel/power/Makefile -@@ -9,6 +9,6 @@ obj-$(CONFIG_FREEZER) += process.o - obj-$(CONFIG_SUSPEND) += suspend.o - obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o - obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o --obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o -+obj-$(CONFIG_SUSPEND_NVS) += nvs.o - - obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o ---- a/kernel/power/hibernate_nvs.c -+++ /dev/null -@@ -1,136 +0,0 @@ --/* -- * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory -- * -- * Copyright (C) 2008,2009 Rafael J. Wysocki , Novell Inc. -- * -- * This file is released under the GPLv2. -- */ -- --#include --#include --#include --#include --#include --#include -- --/* -- * Platforms, like ACPI, may want us to save some memory used by them during -- * hibernation and to restore the contents of this memory during the subsequent -- * resume. The code below implements a mechanism allowing us to do that. -- */ -- --struct nvs_page { -- unsigned long phys_start; -- unsigned int size; -- void *kaddr; -- void *data; -- struct list_head node; --}; -- --static LIST_HEAD(nvs_list); -- --/** -- * hibernate_nvs_register - register platform NVS memory region to save -- * @start - physical address of the region -- * @size - size of the region -- * -- * The NVS region need not be page-aligned (both ends) and we arrange -- * things so that the data from page-aligned addresses in this region will -- * be copied into separate RAM pages. -- */ --int hibernate_nvs_register(unsigned long start, unsigned long size) --{ -- struct nvs_page *entry, *next; -- -- while (size > 0) { -- unsigned int nr_bytes; -- -- entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); -- if (!entry) -- goto Error; -- -- list_add_tail(&entry->node, &nvs_list); -- entry->phys_start = start; -- nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); -- entry->size = (size < nr_bytes) ? size : nr_bytes; -- -- start += entry->size; -- size -= entry->size; -- } -- return 0; -- -- Error: -- list_for_each_entry_safe(entry, next, &nvs_list, node) { -- list_del(&entry->node); -- kfree(entry); -- } -- return -ENOMEM; --} -- --/** -- * hibernate_nvs_free - free data pages allocated for saving NVS regions -- */ --void hibernate_nvs_free(void) --{ -- struct nvs_page *entry; -- -- list_for_each_entry(entry, &nvs_list, node) -- if (entry->data) { -- free_page((unsigned long)entry->data); -- entry->data = NULL; -- if (entry->kaddr) { -- iounmap(entry->kaddr); -- entry->kaddr = NULL; -- } -- } --} -- --/** -- * hibernate_nvs_alloc - allocate memory necessary for saving NVS regions -- */ --int hibernate_nvs_alloc(void) --{ -- struct nvs_page *entry; -- -- list_for_each_entry(entry, &nvs_list, node) { -- entry->data = (void *)__get_free_page(GFP_KERNEL); -- if (!entry->data) { -- hibernate_nvs_free(); -- return -ENOMEM; -- } -- } -- return 0; --} -- --/** -- * hibernate_nvs_save - save NVS memory regions -- */ --void hibernate_nvs_save(void) --{ -- struct nvs_page *entry; -- -- printk(KERN_INFO "PM: Saving platform NVS memory\n"); -- -- list_for_each_entry(entry, &nvs_list, node) -- if (entry->data) { -- entry->kaddr = ioremap(entry->phys_start, entry->size); -- memcpy(entry->data, entry->kaddr, entry->size); -- } --} -- --/** -- * hibernate_nvs_restore - restore NVS memory regions -- * -- * This function is going to be called with interrupts disabled, so it -- * cannot iounmap the virtual addresses used to access the NVS region. -- */ --void hibernate_nvs_restore(void) --{ -- struct nvs_page *entry; -- -- printk(KERN_INFO "PM: Restoring platform NVS memory\n"); -- -- list_for_each_entry(entry, &nvs_list, node) -- if (entry->data) -- memcpy(entry->kaddr, entry->data, entry->size); --} ---- /dev/null -+++ b/kernel/power/nvs.c -@@ -0,0 +1,136 @@ -+/* -+ * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory -+ * -+ * Copyright (C) 2008,2009 Rafael J. Wysocki , Novell Inc. -+ * -+ * This file is released under the GPLv2. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Platforms, like ACPI, may want us to save some memory used by them during -+ * suspend and to restore the contents of this memory during the subsequent -+ * resume. The code below implements a mechanism allowing us to do that. -+ */ -+ -+struct nvs_page { -+ unsigned long phys_start; -+ unsigned int size; -+ void *kaddr; -+ void *data; -+ struct list_head node; -+}; -+ -+static LIST_HEAD(nvs_list); -+ -+/** -+ * suspend_nvs_register - register platform NVS memory region to save -+ * @start - physical address of the region -+ * @size - size of the region -+ * -+ * The NVS region need not be page-aligned (both ends) and we arrange -+ * things so that the data from page-aligned addresses in this region will -+ * be copied into separate RAM pages. -+ */ -+int suspend_nvs_register(unsigned long start, unsigned long size) -+{ -+ struct nvs_page *entry, *next; -+ -+ while (size > 0) { -+ unsigned int nr_bytes; -+ -+ entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); -+ if (!entry) -+ goto Error; -+ -+ list_add_tail(&entry->node, &nvs_list); -+ entry->phys_start = start; -+ nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); -+ entry->size = (size < nr_bytes) ? size : nr_bytes; -+ -+ start += entry->size; -+ size -= entry->size; -+ } -+ return 0; -+ -+ Error: -+ list_for_each_entry_safe(entry, next, &nvs_list, node) { -+ list_del(&entry->node); -+ kfree(entry); -+ } -+ return -ENOMEM; -+} -+ -+/** -+ * suspend_nvs_free - free data pages allocated for saving NVS regions -+ */ -+void suspend_nvs_free(void) -+{ -+ struct nvs_page *entry; -+ -+ list_for_each_entry(entry, &nvs_list, node) -+ if (entry->data) { -+ free_page((unsigned long)entry->data); -+ entry->data = NULL; -+ if (entry->kaddr) { -+ iounmap(entry->kaddr); -+ entry->kaddr = NULL; -+ } -+ } -+} -+ -+/** -+ * suspend_nvs_alloc - allocate memory necessary for saving NVS regions -+ */ -+int suspend_nvs_alloc(void) -+{ -+ struct nvs_page *entry; -+ -+ list_for_each_entry(entry, &nvs_list, node) { -+ entry->data = (void *)__get_free_page(GFP_KERNEL); -+ if (!entry->data) { -+ suspend_nvs_free(); -+ return -ENOMEM; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * suspend_nvs_save - save NVS memory regions -+ */ -+void suspend_nvs_save(void) -+{ -+ struct nvs_page *entry; -+ -+ printk(KERN_INFO "PM: Saving platform NVS memory\n"); -+ -+ list_for_each_entry(entry, &nvs_list, node) -+ if (entry->data) { -+ entry->kaddr = ioremap(entry->phys_start, entry->size); -+ memcpy(entry->data, entry->kaddr, entry->size); -+ } -+} -+ -+/** -+ * suspend_nvs_restore - restore NVS memory regions -+ * -+ * This function is going to be called with interrupts disabled, so it -+ * cannot iounmap the virtual addresses used to access the NVS region. -+ */ -+void suspend_nvs_restore(void) -+{ -+ struct nvs_page *entry; -+ -+ printk(KERN_INFO "PM: Restoring platform NVS memory\n"); -+ -+ list_for_each_entry(entry, &nvs_list, node) -+ if (entry->data) -+ memcpy(entry->kaddr, entry->data, entry->size); -+} ---- a/kernel/power/suspend.c -+++ b/kernel/power/suspend.c -@@ -16,6 +16,12 @@ - #include - #include - #include -+#include -+#include -+#include -+#include -+#include -+#include - - #include "power.h" -