Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e38e8a07 authored by Bob Moore's avatar Bob Moore Committed by Andi Kleen
Browse files

Make GPE disable more robust

Implemented another change for the GPE disable. We now perform a
read-change-write of the enable register instead of simply writing out the
cached enable mask. This will prevent inadvertent enabling of GPEs if a rogue
GPE is received during initialization (before GPE handlers are installed.)

http://bugzilla.kernel.org/show_bug.cgi?id=6217



Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
parent 87dc5e32
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
		return_ACPI_STATUS(status);
	}

	/* Mark wake-disabled or HW disable, or both */
	/* Clear the appropriate enabled flags for this GPE */

	switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
	case ACPI_GPE_TYPE_WAKE:
@@ -273,13 +273,23 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
		/* Disable the requested runtime GPE */

		ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);

		/* fallthrough */
		break;

	default:
		acpi_hw_write_gpe_enable_reg(gpe_event_info);
		break;
	}

	/*
	 * Even if we don't know the GPE type, make sure that we always
	 * disable it. low_disable_gpe will just clear the enable bit for this
	 * GPE and write it. It will not write out the current GPE enable mask,
	 * since this may inadvertently enable GPEs too early, if a rogue GPE has
	 * come in during ACPICA initialization - possibly as a result of AML or
	 * other code that has enabled the GPE.
	 */
	status = acpi_hw_low_disable_gpe(gpe_event_info);
	return_ACPI_STATUS(status);

	return_ACPI_STATUS(AE_OK);
}

+49 −1
Original line number Diff line number Diff line
@@ -53,6 +53,54 @@ static acpi_status
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
				struct acpi_gpe_block_info *gpe_block);

/******************************************************************************
 *
 * FUNCTION:	acpi_hw_low_disable_gpe
 *
 * PARAMETERS:	gpe_event_info	    - Info block for the GPE to be disabled
 *
 * RETURN:	Status
 *
 * DESCRIPTION: Disable a single GPE in the enable register.
 *
 ******************************************************************************/

acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
	struct acpi_gpe_register_info *gpe_register_info;
	acpi_status status;
	u32 enable_mask;

	/* Get the info block for the entire GPE register */

	gpe_register_info = gpe_event_info->register_info;
	if (!gpe_register_info) {
		return (AE_NOT_EXIST);
	}

	/* Get current value of the enable register that contains this GPE */

	status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask,
					&gpe_register_info->enable_address);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	/* Clear just the bit that corresponds to this GPE */

	ACPI_CLEAR_BIT(enable_mask,
		       ((u32) 1 <<
			(gpe_event_info->gpe_number -
			 gpe_register_info->base_gpe_number)));

	/* Write the updated enable mask */

	status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask,
					 &gpe_register_info->enable_address);

	return (status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_write_gpe_enable_reg
+2 −0
Original line number Diff line number Diff line
@@ -87,6 +87,8 @@ acpi_status acpi_hw_clear_acpi_status(void);
/*
 * hwgpe - GPE support
 */
acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);

acpi_status
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);