Commit 76dfdc2c6ed8cd9dde0d18091c2cf41b1e378be4
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
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"
Showing 2 changed files Side-by-side Diff
drivers/acpi/ec.c
... | ... | @@ -126,6 +126,7 @@ |
126 | 126 | static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ |
127 | 127 | static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ |
128 | 128 | 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 */ | |
129 | 130 | |
130 | 131 | /* -------------------------------------------------------------------------- |
131 | 132 | * Transaction Management |
... | ... | @@ -236,13 +237,8 @@ |
236 | 237 | } |
237 | 238 | return wakeup; |
238 | 239 | } 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) && | |
246 | 242 | (t->command == ACPI_EC_COMMAND_QUERY)) { |
247 | 243 | t->flags |= ACPI_EC_COMMAND_POLL; |
248 | 244 | t->rdata[t->ri++] = 0x00; |
249 | 245 | |
... | ... | @@ -334,13 +330,13 @@ |
334 | 330 | pr_debug("***** Command(%s) started *****\n", |
335 | 331 | acpi_ec_cmd_string(t->command)); |
336 | 332 | start_transaction(ec); |
337 | - spin_unlock_irqrestore(&ec->lock, tmp); | |
338 | - ret = ec_poll(ec); | |
339 | - spin_lock_irqsave(&ec->lock, tmp); | |
340 | 333 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { |
341 | 334 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
342 | 335 | pr_debug("***** Event stopped *****\n"); |
343 | 336 | } |
337 | + spin_unlock_irqrestore(&ec->lock, tmp); | |
338 | + ret = ec_poll(ec); | |
339 | + spin_lock_irqsave(&ec->lock, tmp); | |
344 | 340 | pr_debug("***** Command(%s) stopped *****\n", |
345 | 341 | acpi_ec_cmd_string(t->command)); |
346 | 342 | ec->curr = NULL; |
... | ... | @@ -1012,6 +1008,18 @@ |
1012 | 1008 | } |
1013 | 1009 | |
1014 | 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 | + | |
1022 | +/* | |
1015 | 1023 | * On some hardware it is necessary to clear events accumulated by the EC during |
1016 | 1024 | * sleep. These ECs stop reporting GPEs until they are manually polled, if too |
1017 | 1025 | * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) |
... | ... | @@ -1085,6 +1093,9 @@ |
1085 | 1093 | { |
1086 | 1094 | ec_clear_on_resume, "Samsung hardware", { |
1087 | 1095 | 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}, | |
1088 | 1099 | {}, |
1089 | 1100 | }; |
1090 | 1101 |
drivers/acpi/scan.c
... | ... | @@ -142,6 +142,53 @@ |
142 | 142 | } |
143 | 143 | |
144 | 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 | + | |
191 | +/* | |
145 | 192 | * Creates uevent modalias field for ACPI enumerated devices. |
146 | 193 | * Because the other buses does not support ACPI HIDs & CIDs. |
147 | 194 | * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: |
148 | 195 | |
149 | 196 | |
150 | 197 | |
... | ... | @@ -149,20 +196,14 @@ |
149 | 196 | */ |
150 | 197 | int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) |
151 | 198 | { |
152 | - struct acpi_device *acpi_dev; | |
153 | 199 | int len; |
154 | 200 | |
155 | - acpi_dev = ACPI_COMPANION(dev); | |
156 | - if (!acpi_dev) | |
201 | + if (!acpi_companion_match(dev)) | |
157 | 202 | return -ENODEV; |
158 | 203 | |
159 | - /* Fall back to bus specific way of modalias exporting */ | |
160 | - if (list_empty(&acpi_dev->pnp.ids)) | |
161 | - return -ENODEV; | |
162 | - | |
163 | 204 | if (add_uevent_var(env, "MODALIAS=")) |
164 | 205 | 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], | |
166 | 207 | sizeof(env->buf) - env->buflen); |
167 | 208 | if (len <= 0) |
168 | 209 | return len; |
169 | 210 | |
170 | 211 | |
... | ... | @@ -179,18 +220,12 @@ |
179 | 220 | */ |
180 | 221 | int acpi_device_modalias(struct device *dev, char *buf, int size) |
181 | 222 | { |
182 | - struct acpi_device *acpi_dev; | |
183 | 223 | int len; |
184 | 224 | |
185 | - acpi_dev = ACPI_COMPANION(dev); | |
186 | - if (!acpi_dev) | |
225 | + if (!acpi_companion_match(dev)) | |
187 | 226 | return -ENODEV; |
188 | 227 | |
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); | |
194 | 229 | if (len <= 0) |
195 | 230 | return len; |
196 | 231 | buf[len++] = '\n'; |
... | ... | @@ -851,6 +886,9 @@ |
851 | 886 | acpi_handle handle = ACPI_HANDLE(dev); |
852 | 887 | |
853 | 888 | if (!ids || !handle || acpi_bus_get_device(handle, &adev)) |
889 | + return NULL; | |
890 | + | |
891 | + if (!acpi_companion_match(dev)) | |
854 | 892 | return NULL; |
855 | 893 | |
856 | 894 | return __acpi_match_device(adev, ids); |