Skip to content

Commit 76dfdc2

Browse files
committed
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"
3 parents cac7f24 + 5287078 + 7914900 commit 76dfdc2

File tree

2 files changed

+75
-26
lines changed

2 files changed

+75
-26
lines changed

drivers/acpi/ec.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
126126
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
127127
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
128128
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
129+
static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
129130

130131
/* --------------------------------------------------------------------------
131132
* Transaction Management
@@ -236,13 +237,8 @@ static bool advance_transaction(struct acpi_ec *ec)
236237
}
237238
return wakeup;
238239
} else {
239-
/*
240-
* There is firmware refusing to respond QR_EC when SCI_EVT
241-
* is not set, for which case, we complete the QR_EC
242-
* without issuing it to the firmware.
243-
* https://bugzilla.kernel.org/show_bug.cgi?id=86211
244-
*/
245-
if (!(status & ACPI_EC_FLAG_SCI) &&
240+
if (EC_FLAGS_QUERY_HANDSHAKE &&
241+
!(status & ACPI_EC_FLAG_SCI) &&
246242
(t->command == ACPI_EC_COMMAND_QUERY)) {
247243
t->flags |= ACPI_EC_COMMAND_POLL;
248244
t->rdata[t->ri++] = 0x00;
@@ -334,13 +330,13 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
334330
pr_debug("***** Command(%s) started *****\n",
335331
acpi_ec_cmd_string(t->command));
336332
start_transaction(ec);
337-
spin_unlock_irqrestore(&ec->lock, tmp);
338-
ret = ec_poll(ec);
339-
spin_lock_irqsave(&ec->lock, tmp);
340333
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
341334
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
342335
pr_debug("***** Event stopped *****\n");
343336
}
337+
spin_unlock_irqrestore(&ec->lock, tmp);
338+
ret = ec_poll(ec);
339+
spin_lock_irqsave(&ec->lock, tmp);
344340
pr_debug("***** Command(%s) stopped *****\n",
345341
acpi_ec_cmd_string(t->command));
346342
ec->curr = NULL;
@@ -1011,6 +1007,18 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
10111007
return 0;
10121008
}
10131009

1010+
/*
1011+
* Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
1012+
* which case, we complete the QR_EC without issuing it to the firmware.
1013+
* https://bugzilla.kernel.org/show_bug.cgi?id=86211
1014+
*/
1015+
static int ec_flag_query_handshake(const struct dmi_system_id *id)
1016+
{
1017+
pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
1018+
EC_FLAGS_QUERY_HANDSHAKE = 1;
1019+
return 0;
1020+
}
1021+
10141022
/*
10151023
* On some hardware it is necessary to clear events accumulated by the EC during
10161024
* 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 = {
10851093
{
10861094
ec_clear_on_resume, "Samsung hardware", {
10871095
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
1096+
{
1097+
ec_flag_query_handshake, "Acer hardware", {
1098+
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
10881099
{},
10891100
};
10901101

drivers/acpi/scan.c

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,53 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
141141
return len;
142142
}
143143

144+
/*
145+
* acpi_companion_match() - Can we match via ACPI companion device
146+
* @dev: Device in question
147+
*
148+
* Check if the given device has an ACPI companion and if that companion has
149+
* a valid list of PNP IDs, and if the device is the first (primary) physical
150+
* device associated with it.
151+
*
152+
* If multiple physical devices are attached to a single ACPI companion, we need
153+
* to be careful. The usage scenario for this kind of relationship is that all
154+
* of the physical devices in question use resources provided by the ACPI
155+
* companion. A typical case is an MFD device where all the sub-devices share
156+
* the parent's ACPI companion. In such cases we can only allow the primary
157+
* (first) physical device to be matched with the help of the companion's PNP
158+
* IDs.
159+
*
160+
* Additional physical devices sharing the ACPI companion can still use
161+
* resources available from it but they will be matched normally using functions
162+
* provided by their bus types (and analogously for their modalias).
163+
*/
164+
static bool acpi_companion_match(const struct device *dev)
165+
{
166+
struct acpi_device *adev;
167+
bool ret;
168+
169+
adev = ACPI_COMPANION(dev);
170+
if (!adev)
171+
return false;
172+
173+
if (list_empty(&adev->pnp.ids))
174+
return false;
175+
176+
mutex_lock(&adev->physical_node_lock);
177+
if (list_empty(&adev->physical_node_list)) {
178+
ret = false;
179+
} else {
180+
const struct acpi_device_physical_node *node;
181+
182+
node = list_first_entry(&adev->physical_node_list,
183+
struct acpi_device_physical_node, node);
184+
ret = node->dev == dev;
185+
}
186+
mutex_unlock(&adev->physical_node_lock);
187+
188+
return ret;
189+
}
190+
144191
/*
145192
* Creates uevent modalias field for ACPI enumerated devices.
146193
* 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,
149196
*/
150197
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
151198
{
152-
struct acpi_device *acpi_dev;
153199
int len;
154200

155-
acpi_dev = ACPI_COMPANION(dev);
156-
if (!acpi_dev)
157-
return -ENODEV;
158-
159-
/* Fall back to bus specific way of modalias exporting */
160-
if (list_empty(&acpi_dev->pnp.ids))
201+
if (!acpi_companion_match(dev))
161202
return -ENODEV;
162203

163204
if (add_uevent_var(env, "MODALIAS="))
164205
return -ENOMEM;
165-
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
206+
len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
166207
sizeof(env->buf) - env->buflen);
167208
if (len <= 0)
168209
return len;
@@ -179,18 +220,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
179220
*/
180221
int acpi_device_modalias(struct device *dev, char *buf, int size)
181222
{
182-
struct acpi_device *acpi_dev;
183223
int len;
184224

185-
acpi_dev = ACPI_COMPANION(dev);
186-
if (!acpi_dev)
225+
if (!acpi_companion_match(dev))
187226
return -ENODEV;
188227

189-
/* Fall back to bus specific way of modalias exporting */
190-
if (list_empty(&acpi_dev->pnp.ids))
191-
return -ENODEV;
192-
193-
len = create_modalias(acpi_dev, buf, size -1);
228+
len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
194229
if (len <= 0)
195230
return len;
196231
buf[len++] = '\n';
@@ -853,6 +888,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
853888
if (!ids || !handle || acpi_bus_get_device(handle, &adev))
854889
return NULL;
855890

891+
if (!acpi_companion_match(dev))
892+
return NULL;
893+
856894
return __acpi_match_device(adev, ids);
857895
}
858896
EXPORT_SYMBOL_GPL(acpi_match_device);

0 commit comments

Comments
 (0)