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"
This commit is contained in:
commit
76dfdc2c6e
2 changed files with 75 additions and 26 deletions
|
@ -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_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_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_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
|
* Transaction Management
|
||||||
|
@ -236,13 +237,8 @@ static bool advance_transaction(struct acpi_ec *ec)
|
||||||
}
|
}
|
||||||
return wakeup;
|
return wakeup;
|
||||||
} else {
|
} else {
|
||||||
/*
|
if (EC_FLAGS_QUERY_HANDSHAKE &&
|
||||||
* There is firmware refusing to respond QR_EC when SCI_EVT
|
!(status & ACPI_EC_FLAG_SCI) &&
|
||||||
* 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) &&
|
|
||||||
(t->command == ACPI_EC_COMMAND_QUERY)) {
|
(t->command == ACPI_EC_COMMAND_QUERY)) {
|
||||||
t->flags |= ACPI_EC_COMMAND_POLL;
|
t->flags |= ACPI_EC_COMMAND_POLL;
|
||||||
t->rdata[t->ri++] = 0x00;
|
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",
|
pr_debug("***** Command(%s) started *****\n",
|
||||||
acpi_ec_cmd_string(t->command));
|
acpi_ec_cmd_string(t->command));
|
||||||
start_transaction(ec);
|
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) {
|
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
|
||||||
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
||||||
pr_debug("***** Event stopped *****\n");
|
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",
|
pr_debug("***** Command(%s) stopped *****\n",
|
||||||
acpi_ec_cmd_string(t->command));
|
acpi_ec_cmd_string(t->command));
|
||||||
ec->curr = NULL;
|
ec->curr = NULL;
|
||||||
|
@ -1011,6 +1007,18 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
|
||||||
return 0;
|
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
|
* 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
|
* 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", {
|
ec_clear_on_resume, "Samsung hardware", {
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
|
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;
|
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.
|
* Creates uevent modalias field for ACPI enumerated devices.
|
||||||
* Because the other buses does not support ACPI HIDs & CIDs.
|
* 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)
|
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
|
||||||
{
|
{
|
||||||
struct acpi_device *acpi_dev;
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
acpi_dev = ACPI_COMPANION(dev);
|
if (!acpi_companion_match(dev))
|
||||||
if (!acpi_dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/* Fall back to bus specific way of modalias exporting */
|
|
||||||
if (list_empty(&acpi_dev->pnp.ids))
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (add_uevent_var(env, "MODALIAS="))
|
if (add_uevent_var(env, "MODALIAS="))
|
||||||
return -ENOMEM;
|
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);
|
sizeof(env->buf) - env->buflen);
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return len;
|
return len;
|
||||||
|
@ -179,18 +220,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
|
||||||
*/
|
*/
|
||||||
int acpi_device_modalias(struct device *dev, char *buf, int size)
|
int acpi_device_modalias(struct device *dev, char *buf, int size)
|
||||||
{
|
{
|
||||||
struct acpi_device *acpi_dev;
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
acpi_dev = ACPI_COMPANION(dev);
|
if (!acpi_companion_match(dev))
|
||||||
if (!acpi_dev)
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* Fall back to bus specific way of modalias exporting */
|
len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
|
||||||
if (list_empty(&acpi_dev->pnp.ids))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
len = create_modalias(acpi_dev, buf, size -1);
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return len;
|
return len;
|
||||||
buf[len++] = '\n';
|
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))
|
if (!ids || !handle || acpi_bus_get_device(handle, &adev))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!acpi_companion_match(dev))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return __acpi_match_device(adev, ids);
|
return __acpi_match_device(adev, ids);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_match_device);
|
EXPORT_SYMBOL_GPL(acpi_match_device);
|
||||||
|
|
Loading…
Add table
Reference in a new issue