All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

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

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"
......@@ -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},
{},
};
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment