Pull ACPI and power management fixes from Rafael Wysocki: "These are regression fixes (ACPI hotplug, cpufreq, hibernation, ACPI LPSS driver), fixes for stuff that never worked correctly (ACPI GPIO support in some cases and a wrong sign of an error code in the ACPI core in one place), and one blacklist item for ACPI backlight handling. Specifics: - Revert of a recent hibernation core commit that introduced a NULL pointer dereference during resume for at least one user (Rafael J Wysocki). - Fix for the ACPI LPSS (Low-Power Subsystem) driver to disable asynchronous PM callback execution for LPSS devices during system suspend/resume (introduced in 3.16) which turns out to break ordering expectations on some systems. From Fu Zhonghui. - cpufreq core fix related to the handling of sysfs nodes during system suspend/resume that has been broken for intel_pstate since 3.15 from Lan Tianyu. - Restore the generation of "online" uevents for ACPI container devices that was removed in 3.14, but some user space utilities turn out to need them (Rafael J Wysocki). - The cpufreq core fails to release a lock in an error code path after changes made in 3.14. Fix from Prarit Bhargava. - ACPICA and ACPI/GPIO fixes to make the handling of ACPI GPIO operation regions (which means AML using GPIOs) work correctly in all cases from Bob Moore and Srinivas Pandruvada. - Fix for a wrong sign of the ACPI core's create_modalias() return value in case of an error from Mika Westerberg. - ACPI backlight blacklist entry for ThinkPad X201s from Aaron Lu" * tag 'pm+acpi-3.17-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: Revert "PM / Hibernate: Iterate over set bits instead of PFNs in swsusp_free()" gpio / ACPI: Use pin index and bit length ACPICA: Update to GPIO region handler interface. ACPI / platform / LPSS: disable async suspend/resume of LPSS devices cpufreq: release policy->rwsem on error cpufreq: fix cpufreq suspend/resume for intel_pstate ACPI / scan: Correct error return value of create_modalias() ACPI / video: disable native backlight for ThinkPad X201s ACPI / hotplug: Generate online uevents for ACPI containers
Unified · Split
| @@ -419,7 +419,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev, · 418 unmodified lines | ||
| 419 | 419 | adev->driver_data = pdata; |
| 420 | 420 | pdev = acpi_create_platform_device(adev); |
| 421 | 421 | if (!IS_ERR_OR_NULL(pdev)) { |
| 422 | − device_enable_async_suspend(&pdev->dev); | |
| 423 | 422 | return 1; |
| 424 | 423 | } |
| 425 | 424 | |
| @@ -254,6 +254,7 @@ struct acpi_create_field_info { · 253 unmodified lines | ||
| 254 | 254 | u32 field_bit_position; |
| 255 | 255 | u32 field_bit_length; |
| 256 | 256 | u16 resource_length; |
| 257 | + u16 pin_number_index; | |
| 257 | 258 | u8 field_flags; |
| 258 | 259 | u8 attribute; |
| 259 | 260 | u8 field_type; |
| @@ -264,6 +264,7 @@ struct acpi_object_region_field { · 263 unmodified lines | ||
| 264 | 264 | ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; |
| 265 | 265 | union acpi_operand_object *region_obj; /* Containing op_region object */ |
| 266 | 266 | u8 *resource_buffer; /* resource_template for serial regions/fields */ |
| 267 | + u16 pin_number_index; /* Index relative to previous Connection/Template */ | |
| 267 | 268 | }; |
| 268 | 269 | |
| 269 | 270 | struct acpi_object_bank_field { |
| @@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, · 359 unmodified lines | ||
| 360 | 360 | */ |
| 361 | 361 | info->resource_buffer = NULL; |
| 362 | 362 | info->connection_node = NULL; |
| 363 | + info->pin_number_index = 0; | |
| 363 | 364 | |
| 364 | 365 | /* |
| 365 | 366 | * A Connection() is either an actual resource descriptor (buffer) |
| @@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, · 71 unmodified lines | ||
| 437 | 438 | } |
| 438 | 439 | |
| 439 | 440 | info->field_bit_position += info->field_bit_length; |
| 441 | + info->pin_number_index++; /* Index relative to previous Connection() */ | |
| 440 | 442 | break; |
| 441 | 443 | |
| 442 | 444 | default: |
| @@ -142,6 +142,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, · 141 unmodified lines | ||
| 142 | 142 | union acpi_operand_object *region_obj2; |
| 143 | 143 | void *region_context = NULL; |
| 144 | 144 | struct acpi_connection_info *context; |
| 145 | + acpi_physical_address address; | |
| 145 | 146 | |
| 146 | 147 | ACPI_FUNCTION_TRACE(ev_address_space_dispatch); |
| 147 | 148 | |
| @@ -231,25 +232,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, · 83 unmodified lines | ||
| 231 | 232 | /* We have everything we need, we can invoke the address space handler */ |
| 232 | 233 | |
| 233 | 234 | handler = handler_desc->address_space.handler; |
| 234 | − | |
| 235 | − ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, | |
| 236 | − "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", | |
| 237 | − ®ion_obj->region.handler->address_space, handler, | |
| 238 | − ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + | |
| 239 | − region_offset), | |
| 240 | − acpi_ut_get_region_name(region_obj->region. | |
| 241 | − space_id))); | |
| 235 | + address = (region_obj->region.address + region_offset); | |
| 242 | 236 | |
| 243 | 237 | /* |
| 244 | 238 | * Special handling for generic_serial_bus and general_purpose_io: |
| 245 | 239 | * There are three extra parameters that must be passed to the |
| 246 | 240 | * handler via the context: |
| 247 | − * 1) Connection buffer, a resource template from Connection() op. | |
| 248 | − * 2) Length of the above buffer. | |
| 249 | − * 3) Actual access length from the access_as() op. | |
| 241 | + * 1) Connection buffer, a resource template from Connection() op | |
| 242 | + * 2) Length of the above buffer | |
| 243 | + * 3) Actual access length from the access_as() op | |
| 244 | + * | |
| 245 | + * In addition, for general_purpose_io, the Address and bit_width fields | |
| 246 | + * are defined as follows: | |
| 247 | + * 1) Address is the pin number index of the field (bit offset from | |
| 248 | + * the previous Connection) | |
| 249 | + * 2) bit_width is the actual bit length of the field (number of pins) | |
| 250 | 250 | */ |
| 251 | − if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || | |
| 252 | − (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) && | |
| 251 | + if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && | |
| 253 | 252 | context && field_obj) { |
| 254 | 253 | |
| 255 | 254 | /* Get the Connection (resource_template) buffer */ |
| @@ -258,6 +257,24 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, · 2 unmodified lines | ||
| 258 | 257 | context->length = field_obj->field.resource_length; |
| 259 | 258 | context->access_length = field_obj->field.access_length; |
| 260 | 259 | } |
| 260 | + if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) && | |
| 261 | + context && field_obj) { | |
| 262 | + | |
| 263 | + /* Get the Connection (resource_template) buffer */ | |
| 264 | + | |
| 265 | + context->connection = field_obj->field.resource_buffer; | |
| 266 | + context->length = field_obj->field.resource_length; | |
| 267 | + context->access_length = field_obj->field.access_length; | |
| 268 | + address = field_obj->field.pin_number_index; | |
| 269 | + bit_width = field_obj->field.bit_length; | |
| 270 | + } | |
| 271 | + | |
| 272 | + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, | |
| 273 | + "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", | |
| 274 | + ®ion_obj->region.handler->address_space, handler, | |
| 275 | + ACPI_FORMAT_NATIVE_UINT(address), | |
| 276 | + acpi_ut_get_region_name(region_obj->region. | |
| 277 | + space_id))); | |
| 261 | 278 | |
| 262 | 279 | if (!(handler_desc->address_space.handler_flags & |
| 263 | 280 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { |
| @@ -271,9 +288,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, · 7 unmodified lines | ||
| 271 | 288 | |
| 272 | 289 | /* Call the handler */ |
| 273 | 290 | |
| 274 | − status = handler(function, | |
| 275 | − (region_obj->region.address + region_offset), | |
| 276 | − bit_width, value, context, | |
| 291 | + status = handler(function, address, bit_width, value, context, | |
| 277 | 292 | region_obj2->extra.region_context); |
| 278 | 293 | |
| 279 | 294 | if (ACPI_FAILURE(status)) { |
| @@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, · 252 unmodified lines | ||
| 253 | 253 | buffer = &buffer_desc->integer.value; |
| 254 | 254 | } |
| 255 | 255 | |
| 256 | + if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && | |
| 257 | + (obj_desc->field.region_obj->region.space_id == | |
| 258 | + ACPI_ADR_SPACE_GPIO)) { | |
| 259 | + /* | |
| 260 | + * For GPIO (general_purpose_io), the Address will be the bit offset | |
| 261 | + * from the previous Connection() operator, making it effectively a | |
| 262 | + * pin number index. The bit_length is the length of the field, which | |
| 263 | + * is thus the number of pins. | |
| 264 | + */ | |
| 265 | + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, | |
| 266 | + "GPIO FieldRead [FROM]: Pin %u Bits %u\n", | |
| 267 | + obj_desc->field.pin_number_index, | |
| 268 | + obj_desc->field.bit_length)); | |
| 269 | + | |
| 270 | + /* Lock entire transaction if requested */ | |
| 271 | + | |
| 272 | + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); | |
| 273 | + | |
| 274 | + /* Perform the write */ | |
| 275 | + | |
| 276 | + status = acpi_ex_access_region(obj_desc, 0, | |
| 277 | + (u64 *)buffer, ACPI_READ); | |
| 278 | + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); | |
| 279 | + if (ACPI_FAILURE(status)) { | |
| 280 | + acpi_ut_remove_reference(buffer_desc); | |
| 281 | + } else { | |
| 282 | + *ret_buffer_desc = buffer_desc; | |
| 283 | + } | |
| 284 | + return_ACPI_STATUS(status); | |
| 285 | + } | |
| 286 | + | |
| 256 | 287 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
| 257 | 288 | "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", |
| 258 | 289 | obj_desc, obj_desc->common.type, buffer, |
| @@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, · 154 unmodified lines | ||
| 413 | 444 | |
| 414 | 445 | *result_desc = buffer_desc; |
| 415 | 446 | return_ACPI_STATUS(status); |
| 447 | + } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && | |
| 448 | + (obj_desc->field.region_obj->region.space_id == | |
| 449 | + ACPI_ADR_SPACE_GPIO)) { | |
| 450 | + /* | |
| 451 | + * For GPIO (general_purpose_io), we will bypass the entire field | |
| 452 | + * mechanism and handoff the bit address and bit width directly to | |
| 453 | + * the handler. The Address will be the bit offset | |
| 454 | + * from the previous Connection() operator, making it effectively a | |
| 455 | + * pin number index. The bit_length is the length of the field, which | |
| 456 | + * is thus the number of pins. | |
| 457 | + */ | |
| 458 | + if (source_desc->common.type != ACPI_TYPE_INTEGER) { | |
| 459 | + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | |
| 460 | + } | |
| 461 | + | |
| 462 | + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, | |
| 463 | + "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", | |
| 464 | + acpi_ut_get_type_name(source_desc->common. | |
| 465 | + type), | |
| 466 | + source_desc->common.type, | |
| 467 | + (u32)source_desc->integer.value, | |
| 468 | + obj_desc->field.pin_number_index, | |
| 469 | + obj_desc->field.bit_length)); | |
| 470 | + | |
| 471 | + buffer = &source_desc->integer.value; | |
| 472 | + | |
| 473 | + /* Lock entire transaction if requested */ | |
| 474 | + | |
| 475 | + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); | |
| 476 | + | |
| 477 | + /* Perform the write */ | |
| 478 | + | |
| 479 | + status = acpi_ex_access_region(obj_desc, 0, | |
| 480 | + (u64 *)buffer, ACPI_WRITE); | |
| 481 | + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); | |
| 482 | + return_ACPI_STATUS(status); | |
| 416 | 483 | } |
| 417 | 484 | |
| 418 | 485 | /* Get a pointer to the data to be written */ |
| @@ -484,6 +484,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) · 483 unmodified lines | ||
| 484 | 484 | obj_desc->field.resource_length = info->resource_length; |
| 485 | 485 | } |
| 486 | 486 | |
| 487 | + obj_desc->field.pin_number_index = info->pin_number_index; | |
| 488 | + | |
| 487 | 489 | /* Allow full data read from EC address space */ |
| 488 | 490 | |
| 489 | 491 | if ((obj_desc->field.region_obj->region.space_id == |
| @@ -99,6 +99,13 @@ static void container_device_detach(struct acpi_device *adev) · 98 unmodified lines | ||
| 99 | 99 | device_unregister(dev); |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | +static void container_device_online(struct acpi_device *adev) | |
| 103 | +{ | |
| 104 | + struct device *dev = acpi_driver_data(adev); | |
| 105 | + | |
| 106 | + kobject_uevent(&dev->kobj, KOBJ_ONLINE); | |
| 107 | +} | |
| 108 | + | |
| 102 | 109 | static struct acpi_scan_handler container_handler = { |
| 103 | 110 | .ids = container_device_ids, |
| 104 | 111 | .attach = container_device_attach, |
| @@ -106,6 +113,7 @@ static struct acpi_scan_handler container_handler = { · 1 unmodified line | ||
| 106 | 113 | .hotplug = { |
| 107 | 114 | .enabled = true, |
| 108 | 115 | .demand_offline = true, |
| 116 | + .notify_online = container_device_online, | |
| 109 | 117 | }, |
| 110 | 118 | }; |
| 111 | 119 | |
| @@ -130,7 +130,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, · 129 unmodified lines | ||
| 130 | 130 | list_for_each_entry(id, &acpi_dev->pnp.ids, list) { |
| 131 | 131 | count = snprintf(&modalias[len], size, "%s:", id->id); |
| 132 | 132 | if (count < 0) |
| 133 | − return EINVAL; | |
| 133 | + return -EINVAL; | |
| 134 | 134 | if (count >= size) |
| 135 | 135 | return -ENOMEM; |
| 136 | 136 | len += count; |
| @@ -2189,6 +2189,9 @@ static void acpi_bus_attach(struct acpi_device *device) · 2052 unmodified lines | ||
| 2189 | 2189 | ok: |
| 2190 | 2190 | list_for_each_entry(child, &device->children, node) |
| 2191 | 2191 | acpi_bus_attach(child); |
| 2192 | + | |
| 2193 | + if (device->handler && device->handler->hotplug.notify_online) | |
| 2194 | + device->handler->hotplug.notify_online(device); | |
| 2192 | 2195 | } |
| 2193 | 2196 | |
| 2194 | 2197 | /** |
| @@ -750,6 +750,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { · 749 unmodified lines | ||
| 750 | 750 | DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"), |
| 751 | 751 | }, |
| 752 | 752 | }, |
| 753 | + { | |
| 754 | + .callback = video_disable_native_backlight, | |
| 755 | + .ident = "ThinkPad X201s", | |
| 756 | + .matches = { | |
| 757 | + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | |
| 758 | + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"), | |
| 759 | + }, | |
| 760 | + }, | |
| 753 | 761 | |
| 754 | 762 | /* The native backlight controls do not work on some older machines */ |
| 755 | 763 | { |
| @@ -1289,6 +1289,8 @@ err_get_freq: · 1288 unmodified lines | ||
| 1289 | 1289 | per_cpu(cpufreq_cpu_data, j) = NULL; |
| 1290 | 1290 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
| 1291 | 1291 | |
| 1292 | + up_write(&policy->rwsem); | |
| 1293 | + | |
| 1292 | 1294 | if (cpufreq_driver->exit) |
| 1293 | 1295 | cpufreq_driver->exit(policy); |
| 1294 | 1296 | err_set_policy_cpu: |
| @@ -1656,6 +1658,8 @@ void cpufreq_suspend(void) · 361 unmodified lines | ||
| 1656 | 1658 | if (!cpufreq_driver) |
| 1657 | 1659 | return; |
| 1658 | 1660 | |
| 1661 | + cpufreq_suspended = true; | |
| 1662 | + | |
| 1659 | 1663 | if (!has_target()) |
| 1660 | 1664 | return; |
| 1661 | 1665 | |
| @@ -1670,8 +1674,6 @@ void cpufreq_suspend(void) · 8 unmodified lines | ||
| 1670 | 1674 | pr_err("%s: Failed to suspend driver: %p\n", __func__, |
| 1671 | 1675 | policy); |
| 1672 | 1676 | } |
| 1673 | − | |
| 1674 | − cpufreq_suspended = true; | |
| 1675 | 1677 | } |
| 1676 | 1678 | |
| 1677 | 1679 | /** |
| @@ -1687,13 +1689,13 @@ void cpufreq_resume(void) · 9 unmodified lines | ||
| 1687 | 1689 | if (!cpufreq_driver) |
| 1688 | 1690 | return; |
| 1689 | 1691 | |
| 1692 | + cpufreq_suspended = false; | |
| 1693 | + | |
| 1690 | 1694 | if (!has_target()) |
| 1691 | 1695 | return; |
| 1692 | 1696 | |
| 1693 | 1697 | pr_debug("%s: Resuming Governors\n", __func__); |
| 1694 | 1698 | |
| 1695 | − cpufreq_suspended = false; | |
| 1696 | − | |
| 1697 | 1699 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { |
| 1698 | 1700 | if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) |
| 1699 | 1701 | pr_err("%s: Failed to resume driver: %p\n", __func__, |
| @@ -377,8 +377,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, · 376 unmodified lines | ||
| 377 | 377 | struct gpio_chip *chip = achip->chip; |
| 378 | 378 | struct acpi_resource_gpio *agpio; |
| 379 | 379 | struct acpi_resource *ares; |
| 380 | + int pin_index = (int)address; | |
| 380 | 381 | acpi_status status; |
| 381 | 382 | bool pull_up; |
| 383 | + int length; | |
| 382 | 384 | int i; |
| 383 | 385 | |
| 384 | 386 | status = acpi_buffer_to_resource(achip->conn_info.connection, |
| @@ -400,7 +402,8 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, · 15 unmodified lines | ||
| 400 | 402 | return AE_BAD_PARAMETER; |
| 401 | 403 | } |
| 402 | 404 | |
| 403 | − for (i = 0; i < agpio->pin_table_length; i++) { | |
| 405 | + length = min(agpio->pin_table_length, (u16)(pin_index + bits)); | |
| 406 | + for (i = pin_index; i < length; ++i) { | |
| 404 | 407 | unsigned pin = agpio->pin_table[i]; |
| 405 | 408 | struct acpi_gpio_connection *conn; |
| 406 | 409 | struct gpio_desc *desc; |
| @@ -118,6 +118,7 @@ struct acpi_device; · 117 unmodified lines | ||
| 118 | 118 | struct acpi_hotplug_profile { |
| 119 | 119 | struct kobject kobj; |
| 120 | 120 | int (*scan_dependent)(struct acpi_device *adev); |
| 121 | + void (*notify_online)(struct acpi_device *adev); | |
| 121 | 122 | bool enabled:1; |
| 122 | 123 | bool demand_offline:1; |
| 123 | 124 | }; |
| @@ -725,14 +725,6 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) · 724 unmodified lines | ||
| 725 | 725 | clear_bit(bit, addr); |
| 726 | 726 | } |
| 727 | 727 | |
| 728 | −static void memory_bm_clear_current(struct memory_bitmap *bm) | |
| 729 | −{ | |
| 730 | − int bit; | |
| 731 | − | |
| 732 | − bit = max(bm->cur.node_bit - 1, 0); | |
| 733 | − clear_bit(bit, bm->cur.node->data); | |
| 734 | −} | |
| 735 | − | |
| 736 | 728 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) |
| 737 | 729 | { |
| 738 | 730 | void *addr; |
| @@ -1341,35 +1333,23 @@ static struct memory_bitmap copy_bm; · 602 unmodified lines | ||
| 1341 | 1333 | |
| 1342 | 1334 | void swsusp_free(void) |
| 1343 | 1335 | { |
| 1344 | − unsigned long fb_pfn, fr_pfn; | |
| 1345 | − | |
| 1346 | − memory_bm_position_reset(forbidden_pages_map); | |
| 1347 | − memory_bm_position_reset(free_pages_map); | |
| 1348 | − | |
| 1349 | −loop: | |
| 1350 | − fr_pfn = memory_bm_next_pfn(free_pages_map); | |
| 1351 | − fb_pfn = memory_bm_next_pfn(forbidden_pages_map); | |
| 1352 | − | |
| 1353 | − /* | |
| 1354 | − * Find the next bit set in both bitmaps. This is guaranteed to | |
| 1355 | − * terminate when fb_pfn == fr_pfn == BM_END_OF_MAP. | |
| 1356 | − */ | |
| 1357 | − do { | |
| 1358 | − if (fb_pfn < fr_pfn) | |
| 1359 | − fb_pfn = memory_bm_next_pfn(forbidden_pages_map); | |
| 1360 | − if (fr_pfn < fb_pfn) | |
| 1361 | − fr_pfn = memory_bm_next_pfn(free_pages_map); | |
| 1362 | − } while (fb_pfn != fr_pfn); | |
| 1363 | − | |
| 1364 | − if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) { | |
| 1365 | − struct page *page = pfn_to_page(fr_pfn); | |
| 1336 | + struct zone *zone; | |
| 1337 | + unsigned long pfn, max_zone_pfn; | |
| 1366 | 1338 | |
| 1367 | − memory_bm_clear_current(forbidden_pages_map); | |
| 1368 | − memory_bm_clear_current(free_pages_map); | |
| 1369 | − __free_page(page); | |
| 1370 | − goto loop; | |
| 1339 | + for_each_populated_zone(zone) { | |
| 1340 | + max_zone_pfn = zone_end_pfn(zone); | |
| 1341 | + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) | |
| 1342 | + if (pfn_valid(pfn)) { | |
| 1343 | + struct page *page = pfn_to_page(pfn); | |
| 1344 | + | |
| 1345 | + if (swsusp_page_is_forbidden(page) && | |
| 1346 | + swsusp_page_is_free(page)) { | |
| 1347 | + swsusp_unset_page_forbidden(page); | |
| 1348 | + swsusp_unset_page_free(page); | |
| 1349 | + __free_page(page); | |
| 1350 | + } | |
| 1351 | + } | |
| 1371 | 1352 | } |
| 1372 | − | |
| 1373 | 1353 | nr_copy_pages = 0; |
| 1374 | 1354 | nr_meta_pages = 0; |
| 1375 | 1355 | restore_pblist = NULL; |