diff options
author | Bob Moore <robert.moore@intel.com> | 2012-06-28 22:04:17 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-07-14 11:17:29 -0400 |
commit | 5816b3430c4b5f31d9c35af1da7be721c9518137 (patch) | |
tree | 6d5877c622f05f65cab4040771a6654a5fbf47b3 /drivers/acpi/acpica/evxfgpe.c | |
parent | e40d5940396aa4002feeab8323224b5c7f84246c (diff) |
ACPICA: Add support for implicit notify on multiple devices
Adds basic support to allow multiple devices to be implicitly
notified.
This change is partially derived from original commit 981858b("ACPI /
ACPICA: Implicit notify for multiple devices") by Rafael.
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jung-uk Kim <jkim@freebsd.org>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/evxfgpe.c')
-rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 106 |
1 files changed, 69 insertions, 37 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 86f9b343ebd4..2ce44099eb84 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c | |||
@@ -197,12 +197,12 @@ acpi_status | |||
197 | acpi_setup_gpe_for_wake(acpi_handle wake_device, | 197 | acpi_setup_gpe_for_wake(acpi_handle wake_device, |
198 | acpi_handle gpe_device, u32 gpe_number) | 198 | acpi_handle gpe_device, u32 gpe_number) |
199 | { | 199 | { |
200 | acpi_status status = AE_BAD_PARAMETER; | 200 | acpi_status status; |
201 | struct acpi_gpe_event_info *gpe_event_info; | 201 | struct acpi_gpe_event_info *gpe_event_info; |
202 | struct acpi_namespace_node *device_node; | 202 | struct acpi_namespace_node *device_node; |
203 | struct acpi_gpe_notify_object *notify_object; | 203 | struct acpi_gpe_notify_info *notify; |
204 | struct acpi_gpe_notify_info *new_notify; | ||
204 | acpi_cpu_flags flags; | 205 | acpi_cpu_flags flags; |
205 | u8 gpe_dispatch_mask; | ||
206 | 206 | ||
207 | ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); | 207 | ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); |
208 | 208 | ||
@@ -216,63 +216,95 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, | |||
216 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 216 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
217 | } | 217 | } |
218 | 218 | ||
219 | /* Handle root object case */ | ||
220 | |||
221 | if (wake_device == ACPI_ROOT_OBJECT) { | ||
222 | device_node = acpi_gbl_root_node; | ||
223 | } else { | ||
224 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); | ||
225 | } | ||
226 | |||
227 | /* Validate WakeDevice is of type Device */ | ||
228 | |||
229 | if (device_node->type != ACPI_TYPE_DEVICE) { | ||
230 | return_ACPI_STATUS (AE_BAD_PARAMETER); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Allocate a new notify object up front, in case it is needed. | ||
235 | * Memory allocation while holding a spinlock is a big no-no | ||
236 | * on some hosts. | ||
237 | */ | ||
238 | new_notify = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_notify_info)); | ||
239 | if (!new_notify) { | ||
240 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
241 | } | ||
242 | |||
219 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 243 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
220 | 244 | ||
221 | /* Ensure that we have a valid GPE number */ | 245 | /* Ensure that we have a valid GPE number */ |
222 | 246 | ||
223 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); | 247 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); |
224 | if (!gpe_event_info) { | 248 | if (!gpe_event_info) { |
249 | status = AE_BAD_PARAMETER; | ||
225 | goto unlock_and_exit; | 250 | goto unlock_and_exit; |
226 | } | 251 | } |
227 | 252 | ||
228 | if (wake_device == ACPI_ROOT_OBJECT) { | ||
229 | goto out; | ||
230 | } | ||
231 | |||
232 | /* | 253 | /* |
233 | * If there is no method or handler for this GPE, then the | 254 | * If there is no method or handler for this GPE, then the |
234 | * wake_device will be notified whenever this GPE fires (aka | 255 | * wake_device will be notified whenever this GPE fires. This is |
235 | * "implicit notify") Note: The GPE is assumed to be | 256 | * known as an "implicit notify". Note: The GPE is assumed to be |
236 | * level-triggered (for windows compatibility). | 257 | * level-triggered (for windows compatibility). |
237 | */ | 258 | */ |
238 | gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK; | 259 | if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == |
239 | if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE | 260 | ACPI_GPE_DISPATCH_NONE) { |
240 | && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) { | 261 | /* |
241 | goto out; | 262 | * This is the first device for implicit notify on this GPE. |
242 | } | 263 | * Just set the flags here, and enter the NOTIFY block below. |
243 | 264 | */ | |
244 | /* Validate wake_device is of type Device */ | 265 | gpe_event_info->flags = |
245 | 266 | (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); | |
246 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); | ||
247 | if (device_node->type != ACPI_TYPE_DEVICE) { | ||
248 | goto unlock_and_exit; | ||
249 | } | 267 | } |
250 | 268 | ||
251 | if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) { | 269 | /* |
252 | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | | 270 | * If we already have an implicit notify on this GPE, add |
253 | ACPI_GPE_LEVEL_TRIGGERED); | 271 | * this device to the notify list. |
254 | gpe_event_info->dispatch.device.node = device_node; | 272 | */ |
255 | gpe_event_info->dispatch.device.next = NULL; | 273 | if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == |
256 | } else { | 274 | ACPI_GPE_DISPATCH_NOTIFY) { |
257 | /* There are multiple devices to notify implicitly. */ | 275 | |
258 | 276 | /* Ensure that the device is not already in the list */ | |
259 | notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object)); | 277 | |
260 | if (!notify_object) { | 278 | notify = gpe_event_info->dispatch.notify_list; |
261 | status = AE_NO_MEMORY; | 279 | while (notify) { |
262 | goto unlock_and_exit; | 280 | if (notify->device_node == device_node) { |
281 | status = AE_ALREADY_EXISTS; | ||
282 | goto unlock_and_exit; | ||
283 | } | ||
284 | notify = notify->next; | ||
263 | } | 285 | } |
264 | 286 | ||
265 | notify_object->node = device_node; | 287 | /* Add this device to the notify list for this GPE */ |
266 | notify_object->next = gpe_event_info->dispatch.device.next; | 288 | |
267 | gpe_event_info->dispatch.device.next = notify_object; | 289 | new_notify->device_node = device_node; |
290 | new_notify->next = gpe_event_info->dispatch.notify_list; | ||
291 | gpe_event_info->dispatch.notify_list = new_notify; | ||
292 | new_notify = NULL; | ||
268 | } | 293 | } |
269 | 294 | ||
270 | out: | 295 | /* Mark the GPE as a possible wake event */ |
296 | |||
271 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; | 297 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; |
272 | status = AE_OK; | 298 | status = AE_OK; |
273 | 299 | ||
274 | unlock_and_exit: | 300 | unlock_and_exit: |
275 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 301 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
302 | |||
303 | /* Delete the notify object if it was not used above */ | ||
304 | |||
305 | if (new_notify) { | ||
306 | ACPI_FREE(new_notify); | ||
307 | } | ||
276 | return_ACPI_STATUS(status); | 308 | return_ACPI_STATUS(status); |
277 | } | 309 | } |
278 | ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) | 310 | ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) |