Loading Documentation/driver-api/pm/devices.rst +24 −1 Original line number Diff line number Diff line Loading @@ -328,7 +328,10 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``. After the ``->prepare`` callback method returns, no new children may be registered below the device. The method may also prepare the device or driver in some way for the upcoming system power transition, but it should not put the device into a low-power state. should not put the device into a low-power state. Moreover, if the device supports runtime power management, the ``->prepare`` callback method must not update its state in case it is necessary to resume it from runtime suspend later on. For devices supporting runtime power management, the return value of the prepare callback can be used to indicate to the PM core that it may Loading Loading @@ -356,6 +359,16 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``. the appropriate low-power state, depending on the bus type the device is on, and they may enable wakeup events. However, for devices supporting runtime power management, the ``->suspend`` methods provided by subsystems (bus types and PM domains in particular) must follow an additional rule regarding what can be done to the devices before their drivers' ``->suspend`` methods are called. Namely, they can only resume the devices from runtime suspend by calling :c:func:`pm_runtime_resume` for them, if that is necessary, and they must not update the state of the devices in any other way at that time (in case the drivers need to resume the devices from runtime suspend in their ``->suspend`` methods). 3. For a number of devices it is convenient to split suspend into the "quiesce device" and "save device state" phases, in which cases ``suspend_late`` is meant to do the latter. It is always executed after Loading Loading @@ -729,6 +742,16 @@ state temporarily, for example so that its system wakeup capability can be disabled. This all depends on the hardware and the design of the subsystem and device driver in question. If it is necessary to resume a device from runtime suspend during a system-wide transition into a sleep state, that can be done by calling :c:func:`pm_runtime_resume` for it from the ``->suspend`` callback (or its couterpart for transitions related to hibernation) of either the device's driver or a subsystem responsible for it (for example, a bus type or a PM domain). That is guaranteed to work by the requirement that subsystems must not change the state of devices (possibly except for resuming them from runtime suspend) from their ``->prepare`` and ``->suspend`` callbacks (or equivalent) *before* invoking device drivers' ``->suspend`` callbacks (or equivalent). During system-wide resume from a sleep state it's easiest to put devices into the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`. Refer to that document for more information regarding this particular issue as Loading arch/arm/common/locomo.c +0 −24 Original line number Diff line number Diff line Loading @@ -826,28 +826,6 @@ static int locomo_match(struct device *_dev, struct device_driver *_drv) return dev->devid == drv->devid; } static int locomo_bus_suspend(struct device *dev, pm_message_t state) { struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv && drv->suspend) ret = drv->suspend(ldev, state); return ret; } static int locomo_bus_resume(struct device *dev) { struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv && drv->resume) ret = drv->resume(ldev); return ret; } static int locomo_bus_probe(struct device *dev) { struct locomo_dev *ldev = LOCOMO_DEV(dev); Loading Loading @@ -875,8 +853,6 @@ struct bus_type locomo_bus_type = { .match = locomo_match, .probe = locomo_bus_probe, .remove = locomo_bus_remove, .suspend = locomo_bus_suspend, .resume = locomo_bus_resume, }; int locomo_driver_register(struct locomo_driver *driver) Loading arch/arm/include/asm/hardware/locomo.h +0 −2 Original line number Diff line number Diff line Loading @@ -189,8 +189,6 @@ struct locomo_driver { unsigned int devid; int (*probe)(struct locomo_dev *); int (*remove)(struct locomo_dev *); int (*suspend)(struct locomo_dev *, pm_message_t); int (*resume)(struct locomo_dev *); }; #define LOCOMO_DRV(_d) container_of((_d), struct locomo_driver, drv) Loading kernel/power/qos.c +2 −2 Original line number Diff line number Diff line Loading @@ -701,8 +701,8 @@ static int __init pm_qos_power_init(void) for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { ret = register_pm_qos_misc(pm_qos_array[i], d); if (ret < 0) { printk(KERN_ERR "pm_qos_param: %s setup failed\n", pm_qos_array[i]->name); pr_err("%s: %s setup failed\n", __func__, pm_qos_array[i]->name); return ret; } } Loading kernel/power/snapshot.c +18 −17 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ * */ #define pr_fmt(fmt) "PM: " fmt #include <linux/version.h> #include <linux/module.h> #include <linux/mm.h> Loading Loading @@ -967,7 +969,7 @@ void __init __register_nosave_region(unsigned long start_pfn, region->end_pfn = end_pfn; list_add_tail(®ion->list, &nosave_regions); Report: printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n", pr_info("Registered nosave memory: [mem %#010llx-%#010llx]\n", (unsigned long long) start_pfn << PAGE_SHIFT, ((unsigned long long) end_pfn << PAGE_SHIFT) - 1); } Loading Loading @@ -1039,7 +1041,7 @@ static void mark_nosave_pages(struct memory_bitmap *bm) list_for_each_entry(region, &nosave_regions, list) { unsigned long pfn; pr_debug("PM: Marking nosave pages: [mem %#010llx-%#010llx]\n", pr_debug("Marking nosave pages: [mem %#010llx-%#010llx]\n", (unsigned long long) region->start_pfn << PAGE_SHIFT, ((unsigned long long) region->end_pfn << PAGE_SHIFT) - 1); Loading Loading @@ -1095,7 +1097,7 @@ int create_basic_memory_bitmaps(void) free_pages_map = bm2; mark_nosave_pages(forbidden_pages_map); pr_debug("PM: Basic memory bitmaps created\n"); pr_debug("Basic memory bitmaps created\n"); return 0; Loading Loading @@ -1131,7 +1133,7 @@ void free_basic_memory_bitmaps(void) memory_bm_free(bm2, PG_UNSAFE_CLEAR); kfree(bm2); pr_debug("PM: Basic memory bitmaps freed\n"); pr_debug("Basic memory bitmaps freed\n"); } void clear_free_pages(void) Loading @@ -1152,7 +1154,7 @@ void clear_free_pages(void) pfn = memory_bm_next_pfn(bm); } memory_bm_position_reset(bm); pr_info("PM: free pages cleared after restore\n"); pr_info("free pages cleared after restore\n"); #endif /* PAGE_POISONING_ZERO */ } Loading Loading @@ -1690,7 +1692,7 @@ int hibernate_preallocate_memory(void) ktime_t start, stop; int error; printk(KERN_INFO "PM: Preallocating image memory... "); pr_info("Preallocating image memory... "); start = ktime_get(); error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY); Loading Loading @@ -1821,13 +1823,13 @@ int hibernate_preallocate_memory(void) out: stop = ktime_get(); printk(KERN_CONT "done (allocated %lu pages)\n", pages); pr_cont("done (allocated %lu pages)\n", pages); swsusp_show_speed(start, stop, pages, "Allocated"); return 0; err_out: printk(KERN_CONT "\n"); pr_cont("\n"); swsusp_free(); return -ENOMEM; } Loading Loading @@ -1867,7 +1869,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem) free += zone_page_state(zone, NR_FREE_PAGES); nr_pages += count_pages_for_highmem(nr_highmem); pr_debug("PM: Normal pages needed: %u + %u, available pages: %u\n", pr_debug("Normal pages needed: %u + %u, available pages: %u\n", nr_pages, PAGES_FOR_IO, free); return free > nr_pages + PAGES_FOR_IO; Loading Loading @@ -1961,20 +1963,20 @@ asmlinkage __visible int swsusp_save(void) { unsigned int nr_pages, nr_highmem; printk(KERN_INFO "PM: Creating hibernation image:\n"); pr_info("Creating hibernation image:\n"); drain_local_pages(NULL); nr_pages = count_data_pages(); nr_highmem = count_highmem_pages(); printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem); pr_info("Need to copy %u pages\n", nr_pages + nr_highmem); if (!enough_free_mem(nr_pages, nr_highmem)) { printk(KERN_ERR "PM: Not enough free memory\n"); pr_err("Not enough free memory\n"); return -ENOMEM; } if (swsusp_alloc(©_bm, nr_pages, nr_highmem)) { printk(KERN_ERR "PM: Memory allocation failed\n"); pr_err("Memory allocation failed\n"); return -ENOMEM; } Loading @@ -1995,8 +1997,7 @@ asmlinkage __visible int swsusp_save(void) nr_copy_pages = nr_pages; nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE); printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n", nr_pages); pr_info("Hibernation image created (%d pages copied)\n", nr_pages); return 0; } Loading Loading @@ -2170,7 +2171,7 @@ static int check_header(struct swsusp_info *info) if (!reason && info->num_physpages != get_num_physpages()) reason = "memory size"; if (reason) { printk(KERN_ERR "PM: Image mismatch: %s\n", reason); pr_err("Image mismatch: %s\n", reason); return -EPERM; } return 0; Loading Loading
Documentation/driver-api/pm/devices.rst +24 −1 Original line number Diff line number Diff line Loading @@ -328,7 +328,10 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``. After the ``->prepare`` callback method returns, no new children may be registered below the device. The method may also prepare the device or driver in some way for the upcoming system power transition, but it should not put the device into a low-power state. should not put the device into a low-power state. Moreover, if the device supports runtime power management, the ``->prepare`` callback method must not update its state in case it is necessary to resume it from runtime suspend later on. For devices supporting runtime power management, the return value of the prepare callback can be used to indicate to the PM core that it may Loading Loading @@ -356,6 +359,16 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``. the appropriate low-power state, depending on the bus type the device is on, and they may enable wakeup events. However, for devices supporting runtime power management, the ``->suspend`` methods provided by subsystems (bus types and PM domains in particular) must follow an additional rule regarding what can be done to the devices before their drivers' ``->suspend`` methods are called. Namely, they can only resume the devices from runtime suspend by calling :c:func:`pm_runtime_resume` for them, if that is necessary, and they must not update the state of the devices in any other way at that time (in case the drivers need to resume the devices from runtime suspend in their ``->suspend`` methods). 3. For a number of devices it is convenient to split suspend into the "quiesce device" and "save device state" phases, in which cases ``suspend_late`` is meant to do the latter. It is always executed after Loading Loading @@ -729,6 +742,16 @@ state temporarily, for example so that its system wakeup capability can be disabled. This all depends on the hardware and the design of the subsystem and device driver in question. If it is necessary to resume a device from runtime suspend during a system-wide transition into a sleep state, that can be done by calling :c:func:`pm_runtime_resume` for it from the ``->suspend`` callback (or its couterpart for transitions related to hibernation) of either the device's driver or a subsystem responsible for it (for example, a bus type or a PM domain). That is guaranteed to work by the requirement that subsystems must not change the state of devices (possibly except for resuming them from runtime suspend) from their ``->prepare`` and ``->suspend`` callbacks (or equivalent) *before* invoking device drivers' ``->suspend`` callbacks (or equivalent). During system-wide resume from a sleep state it's easiest to put devices into the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`. Refer to that document for more information regarding this particular issue as Loading
arch/arm/common/locomo.c +0 −24 Original line number Diff line number Diff line Loading @@ -826,28 +826,6 @@ static int locomo_match(struct device *_dev, struct device_driver *_drv) return dev->devid == drv->devid; } static int locomo_bus_suspend(struct device *dev, pm_message_t state) { struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv && drv->suspend) ret = drv->suspend(ldev, state); return ret; } static int locomo_bus_resume(struct device *dev) { struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv && drv->resume) ret = drv->resume(ldev); return ret; } static int locomo_bus_probe(struct device *dev) { struct locomo_dev *ldev = LOCOMO_DEV(dev); Loading Loading @@ -875,8 +853,6 @@ struct bus_type locomo_bus_type = { .match = locomo_match, .probe = locomo_bus_probe, .remove = locomo_bus_remove, .suspend = locomo_bus_suspend, .resume = locomo_bus_resume, }; int locomo_driver_register(struct locomo_driver *driver) Loading
arch/arm/include/asm/hardware/locomo.h +0 −2 Original line number Diff line number Diff line Loading @@ -189,8 +189,6 @@ struct locomo_driver { unsigned int devid; int (*probe)(struct locomo_dev *); int (*remove)(struct locomo_dev *); int (*suspend)(struct locomo_dev *, pm_message_t); int (*resume)(struct locomo_dev *); }; #define LOCOMO_DRV(_d) container_of((_d), struct locomo_driver, drv) Loading
kernel/power/qos.c +2 −2 Original line number Diff line number Diff line Loading @@ -701,8 +701,8 @@ static int __init pm_qos_power_init(void) for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { ret = register_pm_qos_misc(pm_qos_array[i], d); if (ret < 0) { printk(KERN_ERR "pm_qos_param: %s setup failed\n", pm_qos_array[i]->name); pr_err("%s: %s setup failed\n", __func__, pm_qos_array[i]->name); return ret; } } Loading
kernel/power/snapshot.c +18 −17 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ * */ #define pr_fmt(fmt) "PM: " fmt #include <linux/version.h> #include <linux/module.h> #include <linux/mm.h> Loading Loading @@ -967,7 +969,7 @@ void __init __register_nosave_region(unsigned long start_pfn, region->end_pfn = end_pfn; list_add_tail(®ion->list, &nosave_regions); Report: printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n", pr_info("Registered nosave memory: [mem %#010llx-%#010llx]\n", (unsigned long long) start_pfn << PAGE_SHIFT, ((unsigned long long) end_pfn << PAGE_SHIFT) - 1); } Loading Loading @@ -1039,7 +1041,7 @@ static void mark_nosave_pages(struct memory_bitmap *bm) list_for_each_entry(region, &nosave_regions, list) { unsigned long pfn; pr_debug("PM: Marking nosave pages: [mem %#010llx-%#010llx]\n", pr_debug("Marking nosave pages: [mem %#010llx-%#010llx]\n", (unsigned long long) region->start_pfn << PAGE_SHIFT, ((unsigned long long) region->end_pfn << PAGE_SHIFT) - 1); Loading Loading @@ -1095,7 +1097,7 @@ int create_basic_memory_bitmaps(void) free_pages_map = bm2; mark_nosave_pages(forbidden_pages_map); pr_debug("PM: Basic memory bitmaps created\n"); pr_debug("Basic memory bitmaps created\n"); return 0; Loading Loading @@ -1131,7 +1133,7 @@ void free_basic_memory_bitmaps(void) memory_bm_free(bm2, PG_UNSAFE_CLEAR); kfree(bm2); pr_debug("PM: Basic memory bitmaps freed\n"); pr_debug("Basic memory bitmaps freed\n"); } void clear_free_pages(void) Loading @@ -1152,7 +1154,7 @@ void clear_free_pages(void) pfn = memory_bm_next_pfn(bm); } memory_bm_position_reset(bm); pr_info("PM: free pages cleared after restore\n"); pr_info("free pages cleared after restore\n"); #endif /* PAGE_POISONING_ZERO */ } Loading Loading @@ -1690,7 +1692,7 @@ int hibernate_preallocate_memory(void) ktime_t start, stop; int error; printk(KERN_INFO "PM: Preallocating image memory... "); pr_info("Preallocating image memory... "); start = ktime_get(); error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY); Loading Loading @@ -1821,13 +1823,13 @@ int hibernate_preallocate_memory(void) out: stop = ktime_get(); printk(KERN_CONT "done (allocated %lu pages)\n", pages); pr_cont("done (allocated %lu pages)\n", pages); swsusp_show_speed(start, stop, pages, "Allocated"); return 0; err_out: printk(KERN_CONT "\n"); pr_cont("\n"); swsusp_free(); return -ENOMEM; } Loading Loading @@ -1867,7 +1869,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem) free += zone_page_state(zone, NR_FREE_PAGES); nr_pages += count_pages_for_highmem(nr_highmem); pr_debug("PM: Normal pages needed: %u + %u, available pages: %u\n", pr_debug("Normal pages needed: %u + %u, available pages: %u\n", nr_pages, PAGES_FOR_IO, free); return free > nr_pages + PAGES_FOR_IO; Loading Loading @@ -1961,20 +1963,20 @@ asmlinkage __visible int swsusp_save(void) { unsigned int nr_pages, nr_highmem; printk(KERN_INFO "PM: Creating hibernation image:\n"); pr_info("Creating hibernation image:\n"); drain_local_pages(NULL); nr_pages = count_data_pages(); nr_highmem = count_highmem_pages(); printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem); pr_info("Need to copy %u pages\n", nr_pages + nr_highmem); if (!enough_free_mem(nr_pages, nr_highmem)) { printk(KERN_ERR "PM: Not enough free memory\n"); pr_err("Not enough free memory\n"); return -ENOMEM; } if (swsusp_alloc(©_bm, nr_pages, nr_highmem)) { printk(KERN_ERR "PM: Memory allocation failed\n"); pr_err("Memory allocation failed\n"); return -ENOMEM; } Loading @@ -1995,8 +1997,7 @@ asmlinkage __visible int swsusp_save(void) nr_copy_pages = nr_pages; nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE); printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n", nr_pages); pr_info("Hibernation image created (%d pages copied)\n", nr_pages); return 0; } Loading Loading @@ -2170,7 +2171,7 @@ static int check_header(struct swsusp_info *info) if (!reason && info->num_physpages != get_num_physpages()) reason = "memory size"; if (reason) { printk(KERN_ERR "PM: Image mismatch: %s\n", reason); pr_err("Image mismatch: %s\n", reason); return -EPERM; } return 0; Loading