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

Commit 76dfdc2c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branches 'acpi-scan' and 'acpi-ec'

* acpi-scan:
  ACPI: Use ACPI companion to match only the first physical device

* acpi-ec:
  ACPI / EC: Fix regression due to conflicting firmware behavior between Samsung and Acer.
  Revert "ACPI / EC: Add support to disallow QR_EC to be issued before completing previous QR_EC"
Loading
Loading
Loading
Loading
+21 −10
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */

/* --------------------------------------------------------------------------
 *                           Transaction Management
@@ -236,13 +237,8 @@ static bool advance_transaction(struct acpi_ec *ec)
		}
		return wakeup;
	} else {
		/*
		 * There is firmware refusing to respond QR_EC when SCI_EVT
		 * is not set, for which case, we complete the QR_EC
		 * without issuing it to the firmware.
		 * https://bugzilla.kernel.org/show_bug.cgi?id=86211
		 */
		if (!(status & ACPI_EC_FLAG_SCI) &&
		if (EC_FLAGS_QUERY_HANDSHAKE &&
		    !(status & ACPI_EC_FLAG_SCI) &&
		    (t->command == ACPI_EC_COMMAND_QUERY)) {
			t->flags |= ACPI_EC_COMMAND_POLL;
			t->rdata[t->ri++] = 0x00;
@@ -334,13 +330,13 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
	pr_debug("***** Command(%s) started *****\n",
		 acpi_ec_cmd_string(t->command));
	start_transaction(ec);
	spin_unlock_irqrestore(&ec->lock, tmp);
	ret = ec_poll(ec);
	spin_lock_irqsave(&ec->lock, tmp);
	if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
		pr_debug("***** Event stopped *****\n");
	}
	spin_unlock_irqrestore(&ec->lock, tmp);
	ret = ec_poll(ec);
	spin_lock_irqsave(&ec->lock, tmp);
	pr_debug("***** Command(%s) stopped *****\n",
		 acpi_ec_cmd_string(t->command));
	ec->curr = NULL;
@@ -1011,6 +1007,18 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
	return 0;
}

/*
 * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
 * which case, we complete the QR_EC without issuing it to the firmware.
 * https://bugzilla.kernel.org/show_bug.cgi?id=86211
 */
static int ec_flag_query_handshake(const struct dmi_system_id *id)
{
	pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
	EC_FLAGS_QUERY_HANDSHAKE = 1;
	return 0;
}

/*
 * On some hardware it is necessary to clear events accumulated by the EC during
 * sleep. These ECs stop reporting GPEs until they are manually polled, if too
@@ -1085,6 +1093,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
	{
	ec_clear_on_resume, "Samsung hardware", {
	DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
	{
	ec_flag_query_handshake, "Acer hardware", {
	DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
	{},
};

+54 −16
Original line number Diff line number Diff line
@@ -141,6 +141,53 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
	return len;
}

/*
 * acpi_companion_match() - Can we match via ACPI companion device
 * @dev: Device in question
 *
 * Check if the given device has an ACPI companion and if that companion has
 * a valid list of PNP IDs, and if the device is the first (primary) physical
 * device associated with it.
 *
 * If multiple physical devices are attached to a single ACPI companion, we need
 * to be careful.  The usage scenario for this kind of relationship is that all
 * of the physical devices in question use resources provided by the ACPI
 * companion.  A typical case is an MFD device where all the sub-devices share
 * the parent's ACPI companion.  In such cases we can only allow the primary
 * (first) physical device to be matched with the help of the companion's PNP
 * IDs.
 *
 * Additional physical devices sharing the ACPI companion can still use
 * resources available from it but they will be matched normally using functions
 * provided by their bus types (and analogously for their modalias).
 */
static bool acpi_companion_match(const struct device *dev)
{
	struct acpi_device *adev;
	bool ret;

	adev = ACPI_COMPANION(dev);
	if (!adev)
		return false;

	if (list_empty(&adev->pnp.ids))
		return false;

	mutex_lock(&adev->physical_node_lock);
	if (list_empty(&adev->physical_node_list)) {
		ret = false;
	} else {
		const struct acpi_device_physical_node *node;

		node = list_first_entry(&adev->physical_node_list,
					struct acpi_device_physical_node, node);
		ret = node->dev == dev;
	}
	mutex_unlock(&adev->physical_node_lock);

	return ret;
}

/*
 * Creates uevent modalias field for ACPI enumerated devices.
 * Because the other buses does not support ACPI HIDs & CIDs.
@@ -149,20 +196,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
 */
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
{
	struct acpi_device *acpi_dev;
	int len;

	acpi_dev = ACPI_COMPANION(dev);
	if (!acpi_dev)
		return -ENODEV;

	/* Fall back to bus specific way of modalias exporting */
	if (list_empty(&acpi_dev->pnp.ids))
	if (!acpi_companion_match(dev))
		return -ENODEV;

	if (add_uevent_var(env, "MODALIAS="))
		return -ENOMEM;
	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
	len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
				sizeof(env->buf) - env->buflen);
	if (len <= 0)
		return len;
@@ -179,18 +220,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
 */
int acpi_device_modalias(struct device *dev, char *buf, int size)
{
	struct acpi_device *acpi_dev;
	int len;

	acpi_dev = ACPI_COMPANION(dev);
	if (!acpi_dev)
	if (!acpi_companion_match(dev))
		return -ENODEV;

	/* Fall back to bus specific way of modalias exporting */
	if (list_empty(&acpi_dev->pnp.ids))
		return -ENODEV;

	len = create_modalias(acpi_dev, buf, size -1);
	len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
	if (len <= 0)
		return len;
	buf[len++] = '\n';
@@ -853,6 +888,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
	if (!ids || !handle || acpi_bus_get_device(handle, &adev))
		return NULL;

	if (!acpi_companion_match(dev))
		return NULL;

	return __acpi_match_device(adev, ids);
}
EXPORT_SYMBOL_GPL(acpi_match_device);