patch-2.4.25 linux-2.4.25/drivers/acpi/hardware/hwsleep.c

Next file: linux-2.4.25/drivers/acpi/hardware/hwtimer.c
Previous file: linux-2.4.25/drivers/acpi/hardware/hwregs.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/drivers/acpi/hardware/hwsleep.c linux-2.4.25/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -181,6 +181,13 @@
 		return_ACPI_STATUS (status);
 	}
 
+	/* Set the system indicators to show the desired sleep state. */
+
+	status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL);
+	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+		 ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+	}
+
 	return_ACPI_STATUS (AE_OK);
 }
 
@@ -220,30 +227,31 @@
 		return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
 	}
 
-
 	sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
 	sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
 
-	/* Clear wake status */
+	if (sleep_state != ACPI_STATE_S5) {
+		/* Clear wake status */
 
-	status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
-	}
+		status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+		if (ACPI_FAILURE (status)) {
+			return_ACPI_STATUS (status);
+		}
 
-	status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
-	}
+		status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
+		if (ACPI_FAILURE (status)) {
+			return_ACPI_STATUS (status);
+		}
 
-	/* Disable BM arbitration */
+		/* Disable BM arbitration */
 
-	status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+		status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+		if (ACPI_FAILURE (status)) {
+			return_ACPI_STATUS (status);
+		}
 	}
 
-	status = acpi_hw_disable_non_wakeup_gpes();
+	status = acpi_hw_disable_non_wakeup_gpes ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -266,6 +274,11 @@
 	PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
 	PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
 
+	/*
+	 * We split the writes of SLP_TYP and SLP_EN to workaround
+	 * poorly implemented hardware.
+	 */
+
 	/* Write #1: fill in SLP_TYP data */
 
 	status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
@@ -297,13 +310,15 @@
 		return_ACPI_STATUS (status);
 	}
 
-	/*
-	 * Wait a second, then try again. This is to get S4/5 to work on all machines.
-	 */
 	if (sleep_state > ACPI_STATE_S3) {
 		/*
+		 * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that
+		 * we are still executing!)
+		 *
+		 * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines.
+		 *
 		 * We wait so long to allow chipsets that poll this reg very slowly to
-		 * still read the right value. Ideally, this entire block would go
+		 * still read the right value. Ideally, this block would go
 		 * away entirely.
 		 */
 		acpi_os_stall (10000000);
@@ -354,12 +369,23 @@
 
 	ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios");
 
-	acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
-	acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
 
-	acpi_hw_disable_non_wakeup_gpes();
+	status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	status = acpi_hw_disable_non_wakeup_gpes ();
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
 
-	ACPI_FLUSH_CPU_CACHE();
+	ACPI_FLUSH_CPU_CACHE ();
 
 	status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8);
 
@@ -389,16 +415,56 @@
 
 acpi_status
 acpi_leave_sleep_state (
-	u8                          sleep_state)
+	u8                              sleep_state)
 {
-	struct acpi_object_list     arg_list;
-	union acpi_object           arg;
-	acpi_status                 status;
+	struct acpi_object_list         arg_list;
+	union acpi_object               arg;
+	acpi_status                     status;
+	struct acpi_bit_register_info   *sleep_type_reg_info;
+	struct acpi_bit_register_info   *sleep_enable_reg_info;
+	u32                             PM1Acontrol;
+	u32                             PM1Bcontrol;
 
 
 	ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state");
 
 
+	/*
+	 * Set SLP_TYPE and SLP_EN to state S0.
+	 * This is unclear from the ACPI Spec, but it is required
+	 * by some machines.
+	 */
+	status = acpi_get_sleep_type_data (ACPI_STATE_S0,
+			  &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b);
+	if (ACPI_SUCCESS (status)) {
+		sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
+		sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
+
+		/* Get current value of PM1A control */
+
+		status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+				 ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+		if (ACPI_SUCCESS (status)) {
+			/* Clear SLP_EN and SLP_TYP fields */
+
+			PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
+					   sleep_enable_reg_info->access_bit_mask);
+			PM1Bcontrol = PM1Acontrol;
+
+			/* Insert SLP_TYP bits */
+
+			PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
+			PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
+
+			/* Just ignore any errors */
+
+			(void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+					  ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+			(void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+					  ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+		}
+	}
+
 	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
 
 	acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
@@ -407,12 +473,17 @@
 
 	arg_list.count = 1;
 	arg_list.pointer = &arg;
-
 	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = sleep_state;
 
 	/* Ignore any errors from these methods */
 
+	arg.integer.value = 0;
+	status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL);
+	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+		ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+	}
+
+	arg.integer.value = sleep_state;
 	status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL);
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
@@ -425,13 +496,13 @@
 
 	/* _WAK returns stuff - do we want to look at it? */
 
-	status = acpi_hw_enable_non_wakeup_gpes();
+	status = acpi_hw_enable_non_wakeup_gpes ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
 
-	/* Disable BM arbitration */
-	status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK);
+	/* Enable BM arbitration */
 
+	status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK);
 	return_ACPI_STATUS (status);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)