aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorCorentin Chary <corentincj@iksaif.net>2011-02-06 07:28:29 -0500
committerMatthew Garrett <mjg@redhat.com>2011-03-28 06:05:15 -0400
commit279f8f95493c9aaa0a85520c863ccba87c4bf930 (patch)
tree02b1b68a797e1b5094f557b92f881d090893a7ba /drivers/platform
parentafa7c886578ce264d9b66d4bcb1fea51fac47925 (diff)
eeepc-wmi: serialize access to wmi method
\AMW0.WMBC, which is the main method that we use, is not reentrant. When wireless hotpluging is enabled, toggling the status of the wireless device using WMBC will trigger a notification and the notification handler need to call WMBC again to get the new status of the device, this will trigger the following error: ACPI Error (dswload-0802): [_T_0] Namespace lookup failure, AE_ALREADY_EXISTS ACPI Exception: AE_ALREADY_EXISTS, During name lookup/catalog (20100428/psloop-231) ACPI Error (psparse-0537): Method parse/execution failed [\AMW0.WMBC] (Node f7023b88), AE_ALREADY_EXISTS ACPI: Marking method WMBC as Serialized because of AE_ALREADY_EXISTS error Since there is currently no way to tell the acpi subsystem to mark a method as serialized, we do it in eeepc-wmi. Of course, we could let the first call fail, and then it would work, but it doesn't seems really clean, and it will make the first WMBC call return a random value. This patch was tested on EeePc 1000H with a RaLink RT2860 wireless card using the rt2800pci driver. rt2860sta driver seems to deadlock when we remove the pci device... Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/eeepc-wmi.c78
1 files changed, 72 insertions, 6 deletions
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 01bc2b3da98a..eb4c0ce88ac1 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -137,6 +137,9 @@ struct eeepc_wmi {
137 137
138 struct hotplug_slot *hotplug_slot; 138 struct hotplug_slot *hotplug_slot;
139 struct mutex hotplug_lock; 139 struct mutex hotplug_lock;
140 struct mutex wmi_lock;
141 struct workqueue_struct *hotplug_workqueue;
142 struct work_struct hotplug_work;
140 143
141 struct eeepc_wmi_debug debug; 144 struct eeepc_wmi_debug debug;
142}; 145};
@@ -370,15 +373,19 @@ static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc)
370{ 373{
371 struct pci_dev *dev; 374 struct pci_dev *dev;
372 struct pci_bus *bus; 375 struct pci_bus *bus;
373 bool blocked = eeepc_wlan_rfkill_blocked(eeepc); 376 bool blocked;
374 bool absent; 377 bool absent;
375 u32 l; 378 u32 l;
376 379
377 if (eeepc->wlan_rfkill) 380 mutex_lock(&eeepc->wmi_lock);
378 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); 381 blocked = eeepc_wlan_rfkill_blocked(eeepc);
382 mutex_unlock(&eeepc->wmi_lock);
379 383
380 mutex_lock(&eeepc->hotplug_lock); 384 mutex_lock(&eeepc->hotplug_lock);
381 385
386 if (eeepc->wlan_rfkill)
387 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
388
382 if (eeepc->hotplug_slot) { 389 if (eeepc->hotplug_slot) {
383 bus = pci_find_bus(0, 1); 390 bus = pci_find_bus(0, 1);
384 if (!bus) { 391 if (!bus) {
@@ -435,7 +442,14 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
435 if (event != ACPI_NOTIFY_BUS_CHECK) 442 if (event != ACPI_NOTIFY_BUS_CHECK)
436 return; 443 return;
437 444
438 eeepc_rfkill_hotplug(eeepc); 445 /*
446 * We can't call directly eeepc_rfkill_hotplug because most
447 * of the time WMBC is still being executed and not reetrant.
448 * There is currently no way to tell ACPICA that we want this
449 * method to be serialized, we schedule a eeepc_rfkill_hotplug
450 * call later, in a safer context.
451 */
452 queue_work(eeepc->hotplug_workqueue, &eeepc->hotplug_work);
439} 453}
440 454
441static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, 455static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc,
@@ -508,6 +522,14 @@ static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
508 .get_power_status = eeepc_get_adapter_status, 522 .get_power_status = eeepc_get_adapter_status,
509}; 523};
510 524
525static void eeepc_hotplug_work(struct work_struct *work)
526{
527 struct eeepc_wmi *eeepc;
528
529 eeepc = container_of(work, struct eeepc_wmi, hotplug_work);
530 eeepc_rfkill_hotplug(eeepc);
531}
532
511static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) 533static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc)
512{ 534{
513 int ret = -ENOMEM; 535 int ret = -ENOMEM;
@@ -518,6 +540,13 @@ static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc)
518 return -ENODEV; 540 return -ENODEV;
519 } 541 }
520 542
543 eeepc->hotplug_workqueue =
544 create_singlethread_workqueue("hotplug_workqueue");
545 if (!eeepc->hotplug_workqueue)
546 goto error_workqueue;
547
548 INIT_WORK(&eeepc->hotplug_work, eeepc_hotplug_work);
549
521 eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); 550 eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
522 if (!eeepc->hotplug_slot) 551 if (!eeepc->hotplug_slot)
523 goto error_slot; 552 goto error_slot;
@@ -547,6 +576,8 @@ error_info:
547 kfree(eeepc->hotplug_slot); 576 kfree(eeepc->hotplug_slot);
548 eeepc->hotplug_slot = NULL; 577 eeepc->hotplug_slot = NULL;
549error_slot: 578error_slot:
579 destroy_workqueue(eeepc->hotplug_workqueue);
580error_workqueue:
550 return ret; 581 return ret;
551} 582}
552 583
@@ -575,6 +606,34 @@ static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
575 rfkill_set_sw_state(rfkill, !(retval & 0x1)); 606 rfkill_set_sw_state(rfkill, !(retval & 0x1));
576} 607}
577 608
609static int eeepc_rfkill_wlan_set(void *data, bool blocked)
610{
611 struct eeepc_wmi *eeepc = data;
612 int ret;
613
614 /*
615 * This handler is enabled only if hotplug is enabled.
616 * In this case, the eeepc_wmi_set_devstate() will
617 * trigger a wmi notification and we need to wait
618 * this call to finish before being able to call
619 * any wmi method
620 */
621 mutex_lock(&eeepc->wmi_lock);
622 ret = eeepc_rfkill_set((void *)(long)EEEPC_WMI_DEVID_WLAN, blocked);
623 mutex_unlock(&eeepc->wmi_lock);
624 return ret;
625}
626
627static void eeepc_rfkill_wlan_query(struct rfkill *rfkill, void *data)
628{
629 eeepc_rfkill_query(rfkill, (void *)(long)EEEPC_WMI_DEVID_WLAN);
630}
631
632static const struct rfkill_ops eeepc_rfkill_wlan_ops = {
633 .set_block = eeepc_rfkill_wlan_set,
634 .query = eeepc_rfkill_wlan_query,
635};
636
578static const struct rfkill_ops eeepc_rfkill_ops = { 637static const struct rfkill_ops eeepc_rfkill_ops = {
579 .set_block = eeepc_rfkill_set, 638 .set_block = eeepc_rfkill_set,
580 .query = eeepc_rfkill_query, 639 .query = eeepc_rfkill_query,
@@ -603,8 +662,12 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
603 if (!retval || retval == 0x00060000) 662 if (!retval || retval == 0x00060000)
604 return -ENODEV; 663 return -ENODEV;
605 664
606 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, 665 if (dev_id == EEEPC_WMI_DEVID_WLAN && eeepc->hotplug_wireless)
607 &eeepc_rfkill_ops, (void *)(long)dev_id); 666 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
667 &eeepc_rfkill_wlan_ops, eeepc);
668 else
669 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
670 &eeepc_rfkill_ops, (void *)(long)dev_id);
608 671
609 if (!*rfkill) 672 if (!*rfkill)
610 return -EINVAL; 673 return -EINVAL;
@@ -636,6 +699,8 @@ static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
636 eeepc_rfkill_hotplug(eeepc); 699 eeepc_rfkill_hotplug(eeepc);
637 if (eeepc->hotplug_slot) 700 if (eeepc->hotplug_slot)
638 pci_hp_deregister(eeepc->hotplug_slot); 701 pci_hp_deregister(eeepc->hotplug_slot);
702 if (eeepc->hotplug_workqueue)
703 destroy_workqueue(eeepc->hotplug_workqueue);
639 704
640 if (eeepc->bluetooth_rfkill) { 705 if (eeepc->bluetooth_rfkill) {
641 rfkill_unregister(eeepc->bluetooth_rfkill); 706 rfkill_unregister(eeepc->bluetooth_rfkill);
@@ -654,6 +719,7 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
654 int result = 0; 719 int result = 0;
655 720
656 mutex_init(&eeepc->hotplug_lock); 721 mutex_init(&eeepc->hotplug_lock);
722 mutex_init(&eeepc->wmi_lock);
657 723
658 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, 724 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
659 "eeepc-wlan", RFKILL_TYPE_WLAN, 725 "eeepc-wlan", RFKILL_TYPE_WLAN,