xref: /linux/drivers/acpi/x86/s2idle.c (revision 316863cb62fe7aaea30e7ef8e6481f1ba414b044)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Architecture-specific ACPI-based support for suspend-to-idle.
4   *
5   * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
6   * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
7   * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
8   *
9   * On platforms supporting the Low Power S0 Idle interface there is an ACPI
10   * device object with the PNP0D80 compatible device ID (System Power Management
11   * Controller) and a specific _DSM method under it.  That method, if present,
12   * can be used to indicate to the platform that the OS is transitioning into a
13   * low-power state in which certain types of activity are not desirable or that
14   * it is leaving such a state, which allows the platform to adjust its operation
15   * mode accordingly.
16   */
17  
18  #include <linux/acpi.h>
19  #include <linux/device.h>
20  #include <linux/dmi.h>
21  #include <linux/suspend.h>
22  
23  #include "../sleep.h"
24  
25  #ifdef CONFIG_SUSPEND
26  
27  static bool sleep_no_lps0 __read_mostly;
28  module_param(sleep_no_lps0, bool, 0644);
29  MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface");
30  
31  static const struct acpi_device_id lps0_device_ids[] = {
32  	{"PNP0D80", },
33  	{"", },
34  };
35  
36  /* Microsoft platform agnostic UUID */
37  #define ACPI_LPS0_DSM_UUID_MICROSOFT      "11e00d56-ce64-47ce-837b-1f898f9aa461"
38  
39  #define ACPI_LPS0_DSM_UUID	"c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
40  
41  #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS	1
42  #define ACPI_LPS0_SCREEN_OFF	3
43  #define ACPI_LPS0_SCREEN_ON	4
44  #define ACPI_LPS0_ENTRY		5
45  #define ACPI_LPS0_EXIT		6
46  #define ACPI_LPS0_MS_ENTRY      7
47  #define ACPI_LPS0_MS_EXIT       8
48  
49  /* AMD */
50  #define ACPI_LPS0_DSM_UUID_AMD      "e3f32452-febc-43ce-9039-932122d37721"
51  #define ACPI_LPS0_ENTRY_AMD         2
52  #define ACPI_LPS0_EXIT_AMD          3
53  #define ACPI_LPS0_SCREEN_OFF_AMD    4
54  #define ACPI_LPS0_SCREEN_ON_AMD     5
55  
56  static acpi_handle lps0_device_handle;
57  static guid_t lps0_dsm_guid;
58  static int lps0_dsm_func_mask;
59  
60  static guid_t lps0_dsm_guid_microsoft;
61  static int lps0_dsm_func_mask_microsoft;
62  static int lps0_dsm_state;
63  
64  /* Device constraint entry structure */
65  struct lpi_device_info {
66  	char *name;
67  	int enabled;
68  	union acpi_object *package;
69  };
70  
71  /* Constraint package structure */
72  struct lpi_device_constraint {
73  	int uid;
74  	int min_dstate;
75  	int function_states;
76  };
77  
78  struct lpi_constraints {
79  	acpi_handle handle;
80  	int min_dstate;
81  };
82  
83  /* AMD Constraint package structure */
84  struct lpi_device_constraint_amd {
85  	char *name;
86  	int enabled;
87  	int function_states;
88  	int min_dstate;
89  };
90  
91  static LIST_HEAD(lps0_s2idle_devops_head);
92  
93  static struct lpi_constraints *lpi_constraints_table;
94  static int lpi_constraints_table_size;
95  static int rev_id;
96  
97  #define for_each_lpi_constraint(entry)						\
98  	for (int i = 0;								\
99  	     entry = &lpi_constraints_table[i], i < lpi_constraints_table_size;	\
100  	     i++)
101  
102  static void lpi_device_get_constraints_amd(void)
103  {
104  	union acpi_object *out_obj;
105  	int i, j, k;
106  
107  	out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
108  					  rev_id, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
109  					  NULL, ACPI_TYPE_PACKAGE);
110  
111  	acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
112  			  out_obj ? "successful" : "failed");
113  
114  	if (!out_obj)
115  		return;
116  
117  	for (i = 0; i < out_obj->package.count; i++) {
118  		union acpi_object *package = &out_obj->package.elements[i];
119  
120  		if (package->type == ACPI_TYPE_PACKAGE) {
121  			if (lpi_constraints_table) {
122  				acpi_handle_err(lps0_device_handle,
123  						"Duplicate constraints list\n");
124  				goto free_acpi_buffer;
125  			}
126  
127  			lpi_constraints_table = kcalloc(package->package.count,
128  							sizeof(*lpi_constraints_table),
129  							GFP_KERNEL);
130  
131  			if (!lpi_constraints_table)
132  				goto free_acpi_buffer;
133  
134  			acpi_handle_debug(lps0_device_handle,
135  					  "LPI: constraints list begin:\n");
136  
137  			for (j = 0; j < package->package.count; j++) {
138  				union acpi_object *info_obj = &package->package.elements[j];
139  				struct lpi_device_constraint_amd dev_info = {};
140  				struct lpi_constraints *list;
141  				acpi_status status;
142  
143  				list = &lpi_constraints_table[lpi_constraints_table_size];
144  
145  				for (k = 0; k < info_obj->package.count; k++) {
146  					union acpi_object *obj = &info_obj->package.elements[k];
147  
148  					switch (k) {
149  					case 0:
150  						dev_info.enabled = obj->integer.value;
151  						break;
152  					case 1:
153  						dev_info.name = obj->string.pointer;
154  						break;
155  					case 2:
156  						dev_info.function_states = obj->integer.value;
157  						break;
158  					case 3:
159  						dev_info.min_dstate = obj->integer.value;
160  						break;
161  					}
162  				}
163  
164  				acpi_handle_debug(lps0_device_handle,
165  						  "Name:%s, Enabled: %d, States: %d, MinDstate: %d\n",
166  						  dev_info.name,
167  						  dev_info.enabled,
168  						  dev_info.function_states,
169  						  dev_info.min_dstate);
170  
171  				if (!dev_info.enabled || !dev_info.name ||
172  				    !dev_info.min_dstate)
173  					continue;
174  
175  				status = acpi_get_handle(NULL, dev_info.name, &list->handle);
176  				if (ACPI_FAILURE(status))
177  					continue;
178  
179  				list->min_dstate = dev_info.min_dstate;
180  
181  				lpi_constraints_table_size++;
182  			}
183  		}
184  	}
185  
186  	acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n");
187  
188  free_acpi_buffer:
189  	ACPI_FREE(out_obj);
190  }
191  
192  static void lpi_device_get_constraints(void)
193  {
194  	union acpi_object *out_obj;
195  	int i;
196  
197  	out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
198  					  1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
199  					  NULL, ACPI_TYPE_PACKAGE);
200  
201  	acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
202  			  out_obj ? "successful" : "failed");
203  
204  	if (!out_obj)
205  		return;
206  
207  	lpi_constraints_table = kcalloc(out_obj->package.count,
208  					sizeof(*lpi_constraints_table),
209  					GFP_KERNEL);
210  	if (!lpi_constraints_table)
211  		goto free_acpi_buffer;
212  
213  	acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n");
214  
215  	for (i = 0; i < out_obj->package.count; i++) {
216  		struct lpi_constraints *constraint;
217  		acpi_status status;
218  		union acpi_object *package = &out_obj->package.elements[i];
219  		struct lpi_device_info info = { };
220  		int package_count = 0, j;
221  
222  		if (!package)
223  			continue;
224  
225  		for (j = 0; j < package->package.count; j++) {
226  			union acpi_object *element =
227  					&(package->package.elements[j]);
228  
229  			switch (element->type) {
230  			case ACPI_TYPE_INTEGER:
231  				info.enabled = element->integer.value;
232  				break;
233  			case ACPI_TYPE_STRING:
234  				info.name = element->string.pointer;
235  				break;
236  			case ACPI_TYPE_PACKAGE:
237  				package_count = element->package.count;
238  				info.package = element->package.elements;
239  				break;
240  			}
241  		}
242  
243  		if (!info.enabled || !info.package || !info.name)
244  			continue;
245  
246  		constraint = &lpi_constraints_table[lpi_constraints_table_size];
247  
248  		status = acpi_get_handle(NULL, info.name, &constraint->handle);
249  		if (ACPI_FAILURE(status))
250  			continue;
251  
252  		acpi_handle_debug(lps0_device_handle,
253  				  "index:%d Name:%s\n", i, info.name);
254  
255  		constraint->min_dstate = -1;
256  
257  		for (j = 0; j < package_count; j++) {
258  			union acpi_object *info_obj = &info.package[j];
259  			union acpi_object *cnstr_pkg;
260  			union acpi_object *obj;
261  			struct lpi_device_constraint dev_info;
262  
263  			switch (info_obj->type) {
264  			case ACPI_TYPE_INTEGER:
265  				/* version */
266  				break;
267  			case ACPI_TYPE_PACKAGE:
268  				if (info_obj->package.count < 2)
269  					break;
270  
271  				cnstr_pkg = info_obj->package.elements;
272  				obj = &cnstr_pkg[0];
273  				dev_info.uid = obj->integer.value;
274  				obj = &cnstr_pkg[1];
275  				dev_info.min_dstate = obj->integer.value;
276  
277  				acpi_handle_debug(lps0_device_handle,
278  					"uid:%d min_dstate:%s\n",
279  					dev_info.uid,
280  					acpi_power_state_string(dev_info.min_dstate));
281  
282  				constraint->min_dstate = dev_info.min_dstate;
283  				break;
284  			}
285  		}
286  
287  		if (constraint->min_dstate < 0) {
288  			acpi_handle_debug(lps0_device_handle,
289  					  "Incomplete constraint defined\n");
290  			continue;
291  		}
292  
293  		lpi_constraints_table_size++;
294  	}
295  
296  	acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n");
297  
298  free_acpi_buffer:
299  	ACPI_FREE(out_obj);
300  }
301  
302  /**
303   * acpi_get_lps0_constraint - Get the LPS0 constraint for a device.
304   * @adev: Device to get the constraint for.
305   *
306   * The LPS0 constraint is the shallowest (minimum) power state in which the
307   * device can be so as to allow the platform as a whole to achieve additional
308   * energy conservation by utilizing a system-wide low-power state.
309   *
310   * Returns:
311   *  - ACPI power state value of the constraint for @adev on success.
312   *  - Otherwise, ACPI_STATE_UNKNOWN.
313   */
314  int acpi_get_lps0_constraint(struct acpi_device *adev)
315  {
316  	struct lpi_constraints *entry;
317  
318  	for_each_lpi_constraint(entry) {
319  		if (adev->handle == entry->handle)
320  			return entry->min_dstate;
321  	}
322  
323  	return ACPI_STATE_UNKNOWN;
324  }
325  
326  static void lpi_check_constraints(void)
327  {
328  	struct lpi_constraints *entry;
329  
330  	for_each_lpi_constraint(entry) {
331  		struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle);
332  
333  		if (!adev)
334  			continue;
335  
336  		acpi_handle_debug(entry->handle,
337  			"LPI: required min power state:%s current power state:%s\n",
338  			acpi_power_state_string(entry->min_dstate),
339  			acpi_power_state_string(adev->power.state));
340  
341  		if (!adev->flags.power_manageable) {
342  			acpi_handle_info(entry->handle, "LPI: Device not power manageable\n");
343  			entry->handle = NULL;
344  			continue;
345  		}
346  
347  		if (adev->power.state < entry->min_dstate)
348  			acpi_handle_info(entry->handle,
349  				"LPI: Constraint not met; min power state:%s current power state:%s\n",
350  				acpi_power_state_string(entry->min_dstate),
351  				acpi_power_state_string(adev->power.state));
352  	}
353  }
354  
355  static bool acpi_s2idle_vendor_amd(void)
356  {
357  	return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
358  }
359  
360  static const char *acpi_sleep_dsm_state_to_str(unsigned int state)
361  {
362  	if (lps0_dsm_func_mask_microsoft || !acpi_s2idle_vendor_amd()) {
363  		switch (state) {
364  		case ACPI_LPS0_SCREEN_OFF:
365  			return "screen off";
366  		case ACPI_LPS0_SCREEN_ON:
367  			return "screen on";
368  		case ACPI_LPS0_ENTRY:
369  			return "lps0 entry";
370  		case ACPI_LPS0_EXIT:
371  			return "lps0 exit";
372  		case ACPI_LPS0_MS_ENTRY:
373  			return "lps0 ms entry";
374  		case ACPI_LPS0_MS_EXIT:
375  			return "lps0 ms exit";
376  		}
377  	} else {
378  		switch (state) {
379  		case ACPI_LPS0_SCREEN_ON_AMD:
380  			return "screen on";
381  		case ACPI_LPS0_SCREEN_OFF_AMD:
382  			return "screen off";
383  		case ACPI_LPS0_ENTRY_AMD:
384  			return "lps0 entry";
385  		case ACPI_LPS0_EXIT_AMD:
386  			return "lps0 exit";
387  		}
388  	}
389  
390  	return "unknown";
391  }
392  
393  static void acpi_sleep_run_lps0_dsm(unsigned int func, unsigned int func_mask, guid_t dsm_guid)
394  {
395  	union acpi_object *out_obj;
396  
397  	if (!(func_mask & (1 << func)))
398  		return;
399  
400  	out_obj = acpi_evaluate_dsm(lps0_device_handle, &dsm_guid,
401  					rev_id, func, NULL);
402  	ACPI_FREE(out_obj);
403  
404  	lps0_dsm_state = func;
405  	if (pm_debug_messages_on) {
406  		acpi_handle_info(lps0_device_handle,
407  				"%s transitioned to state %s\n",
408  				 out_obj ? "Successfully" : "Failed to",
409  				 acpi_sleep_dsm_state_to_str(lps0_dsm_state));
410  	}
411  }
412  
413  
414  static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *dsm_guid)
415  {
416  	union acpi_object *obj;
417  	int ret = -EINVAL;
418  
419  	guid_parse(uuid, dsm_guid);
420  
421  	/* Check if the _DSM is present and as expected. */
422  	obj = acpi_evaluate_dsm_typed(handle, dsm_guid, rev, 0, NULL, ACPI_TYPE_BUFFER);
423  	if (!obj || obj->buffer.length == 0 || obj->buffer.length > sizeof(u32)) {
424  		acpi_handle_debug(handle,
425  				"_DSM UUID %s rev %d function 0 evaluation failed\n", uuid, rev);
426  		goto out;
427  	}
428  
429  	ret = *(int *)obj->buffer.pointer;
430  	acpi_handle_debug(handle, "_DSM UUID %s rev %d function mask: 0x%x\n", uuid, rev, ret);
431  
432  out:
433  	ACPI_FREE(obj);
434  	return ret;
435  }
436  
437  struct amd_lps0_hid_device_data {
438  	const bool check_off_by_one;
439  };
440  
441  static const struct amd_lps0_hid_device_data amd_picasso = {
442  	.check_off_by_one = true,
443  };
444  
445  static const struct amd_lps0_hid_device_data amd_cezanne = {
446  	.check_off_by_one = false,
447  };
448  
449  static const struct acpi_device_id amd_hid_ids[] = {
450  	{"AMD0004",	(kernel_ulong_t)&amd_picasso,	},
451  	{"AMD0005",	(kernel_ulong_t)&amd_picasso,	},
452  	{"AMDI0005",	(kernel_ulong_t)&amd_picasso,	},
453  	{"AMDI0006",	(kernel_ulong_t)&amd_cezanne,	},
454  	{}
455  };
456  
457  static int lps0_device_attach(struct acpi_device *adev,
458  			      const struct acpi_device_id *not_used)
459  {
460  	if (lps0_device_handle)
461  		return 0;
462  
463  	lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle,
464  						    ACPI_LPS0_DSM_UUID_MICROSOFT, 0,
465  						    &lps0_dsm_guid_microsoft);
466  	if (acpi_s2idle_vendor_amd()) {
467  		static const struct acpi_device_id *dev_id;
468  		const struct amd_lps0_hid_device_data *data;
469  
470  		for (dev_id = &amd_hid_ids[0]; dev_id->id[0]; dev_id++)
471  			if (acpi_dev_hid_uid_match(adev, dev_id->id, NULL))
472  				break;
473  		if (dev_id->id[0])
474  			data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data;
475  		else
476  			data = &amd_cezanne;
477  		lps0_dsm_func_mask = validate_dsm(adev->handle,
478  					ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
479  		if (lps0_dsm_func_mask > 0x3 && data->check_off_by_one) {
480  			lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
481  			acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
482  					  ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
483  		} else if (lps0_dsm_func_mask_microsoft > 0 && rev_id) {
484  			lps0_dsm_func_mask_microsoft = -EINVAL;
485  			acpi_handle_debug(adev->handle, "_DSM Using AMD method\n");
486  		}
487  	} else {
488  		rev_id = 1;
489  		lps0_dsm_func_mask = validate_dsm(adev->handle,
490  					ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid);
491  		if (lps0_dsm_func_mask > 0 && lps0_dsm_func_mask_microsoft > 0) {
492  			unsigned int func_mask;
493  
494  			/*
495  			 * Log a message if the _DSM function sets for two
496  			 * different UUIDs overlap.
497  			 */
498  			func_mask = lps0_dsm_func_mask & lps0_dsm_func_mask_microsoft;
499  			if (func_mask)
500  				acpi_handle_info(adev->handle,
501  						 "Duplicate LPS0 _DSM functions (mask: 0x%x)\n",
502  						 func_mask);
503  		}
504  	}
505  
506  	if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0)
507  		return 0; //function evaluation failed
508  
509  	lps0_device_handle = adev->handle;
510  
511  	if (acpi_s2idle_vendor_amd())
512  		lpi_device_get_constraints_amd();
513  	else
514  		lpi_device_get_constraints();
515  
516  	/*
517  	 * Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set in
518  	 * the FADT and the default suspend mode was not set from the command
519  	 * line.
520  	 */
521  	if ((acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) &&
522  	    mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) {
523  		mem_sleep_current = PM_SUSPEND_TO_IDLE;
524  		pr_info("Low-power S0 idle used by default for system suspend\n");
525  	}
526  
527  	/*
528  	 * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
529  	 * EC GPE to be enabled while suspended for certain wakeup devices to
530  	 * work, so mark it as wakeup-capable.
531  	 */
532  	acpi_ec_mark_gpe_for_wake();
533  
534  	return 0;
535  }
536  
537  static struct acpi_scan_handler lps0_handler = {
538  	.ids = lps0_device_ids,
539  	.attach = lps0_device_attach,
540  };
541  
542  int acpi_s2idle_prepare_late(void)
543  {
544  	struct acpi_s2idle_dev_ops *handler;
545  
546  	if (!lps0_device_handle || sleep_no_lps0)
547  		return 0;
548  
549  	if (pm_debug_messages_on)
550  		lpi_check_constraints();
551  
552  	/* Screen off */
553  	if (lps0_dsm_func_mask > 0)
554  		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
555  					ACPI_LPS0_SCREEN_OFF_AMD :
556  					ACPI_LPS0_SCREEN_OFF,
557  					lps0_dsm_func_mask, lps0_dsm_guid);
558  
559  	if (lps0_dsm_func_mask_microsoft > 0)
560  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
561  				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
562  
563  	/* LPS0 entry */
564  	if (lps0_dsm_func_mask > 0 && acpi_s2idle_vendor_amd())
565  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
566  					lps0_dsm_func_mask, lps0_dsm_guid);
567  
568  	if (lps0_dsm_func_mask_microsoft > 0) {
569  		/* Modern Standby entry */
570  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
571  				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
572  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
573  				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
574  	}
575  
576  	if (lps0_dsm_func_mask > 0 && !acpi_s2idle_vendor_amd())
577  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
578  					lps0_dsm_func_mask, lps0_dsm_guid);
579  
580  	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
581  		if (handler->prepare)
582  			handler->prepare();
583  	}
584  
585  	return 0;
586  }
587  
588  void acpi_s2idle_check(void)
589  {
590  	struct acpi_s2idle_dev_ops *handler;
591  
592  	if (!lps0_device_handle || sleep_no_lps0)
593  		return;
594  
595  	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
596  		if (handler->check)
597  			handler->check();
598  	}
599  }
600  
601  void acpi_s2idle_restore_early(void)
602  {
603  	struct acpi_s2idle_dev_ops *handler;
604  
605  	if (!lps0_device_handle || sleep_no_lps0)
606  		return;
607  
608  	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node)
609  		if (handler->restore)
610  			handler->restore();
611  
612  	/* LPS0 exit */
613  	if (lps0_dsm_func_mask > 0)
614  		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
615  					ACPI_LPS0_EXIT_AMD :
616  					ACPI_LPS0_EXIT,
617  					lps0_dsm_func_mask, lps0_dsm_guid);
618  
619  	if (lps0_dsm_func_mask_microsoft > 0) {
620  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
621  				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
622  		/* Modern Standby exit */
623  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
624  				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
625  	}
626  
627  	/* Screen on */
628  	if (lps0_dsm_func_mask_microsoft > 0)
629  		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
630  				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
631  	if (lps0_dsm_func_mask > 0)
632  		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
633  					ACPI_LPS0_SCREEN_ON_AMD :
634  					ACPI_LPS0_SCREEN_ON,
635  					lps0_dsm_func_mask, lps0_dsm_guid);
636  }
637  
638  static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
639  	.begin = acpi_s2idle_begin,
640  	.prepare = acpi_s2idle_prepare,
641  	.prepare_late = acpi_s2idle_prepare_late,
642  	.check = acpi_s2idle_check,
643  	.wake = acpi_s2idle_wake,
644  	.restore_early = acpi_s2idle_restore_early,
645  	.restore = acpi_s2idle_restore,
646  	.end = acpi_s2idle_end,
647  };
648  
649  void __init acpi_s2idle_setup(void)
650  {
651  	acpi_scan_add_handler(&lps0_handler);
652  	s2idle_set_ops(&acpi_s2idle_ops_lps0);
653  }
654  
655  int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg)
656  {
657  	unsigned int sleep_flags;
658  
659  	if (!lps0_device_handle || sleep_no_lps0)
660  		return -ENODEV;
661  
662  	sleep_flags = lock_system_sleep();
663  	list_add(&arg->list_node, &lps0_s2idle_devops_head);
664  	unlock_system_sleep(sleep_flags);
665  
666  	return 0;
667  }
668  EXPORT_SYMBOL_GPL(acpi_register_lps0_dev);
669  
670  void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg)
671  {
672  	unsigned int sleep_flags;
673  
674  	if (!lps0_device_handle || sleep_no_lps0)
675  		return;
676  
677  	sleep_flags = lock_system_sleep();
678  	list_del(&arg->list_node);
679  	unlock_system_sleep(sleep_flags);
680  }
681  EXPORT_SYMBOL_GPL(acpi_unregister_lps0_dev);
682  
683  #endif /* CONFIG_SUSPEND */
684