aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Jenkins <alan-jenkins@tuffmail.co.uk>2009-08-28 08:56:34 -0400
committerLen Brown <len.brown@intel.com>2009-08-28 15:21:11 -0400
commit07e84aa98f6b3a7278d3267f6f657955ed3eb973 (patch)
treee3f9b3a8fea9ab26e84bb1e7ef93a9db2a883951 /drivers
parentdcf443b5813074031a45b05ad9c57da98bcae329 (diff)
eeepc-laptop: fix pci hotplug race on load and unload
Wifi rfkill state changes can race with pci hotplug cleanup. A simple fix is to refresh the hotplug state just before deregistering the pci hotplug slot. There is also potential for a hotplug notification to fire too early during setup, while the structures it uses are still being initialised. (This could only happen if the BIOS performs hotplug itself; a bug triggered by removing the battery while hibernated). Avoid this by registering the notifier later. The same refresh mechanism is used to handle rfkill state changes which can now race with registration. Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/eeepc-laptop.c77
1 files changed, 45 insertions, 32 deletions
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 179010386981..8dd86f73b844 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -667,37 +667,37 @@ static void eeepc_rfkill_hotplug(void)
667 struct pci_bus *bus; 667 struct pci_bus *bus;
668 bool blocked = eeepc_wlan_rfkill_blocked(); 668 bool blocked = eeepc_wlan_rfkill_blocked();
669 669
670 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); 670 if (ehotk->wlan_rfkill)
671 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
671 672
672 mutex_lock(&ehotk->hotplug_lock); 673 mutex_lock(&ehotk->hotplug_lock);
673 674
674 if (ehotk->hotplug_slot == NULL) 675 if (ehotk->hotplug_slot) {
675 goto out_unlock; 676 bus = pci_find_bus(0, 1);
676 677 if (!bus) {
677 bus = pci_find_bus(0, 1); 678 pr_warning("Unable to find PCI bus 1?\n");
678 if (!bus) {
679 pr_warning("Unable to find PCI bus 1?\n");
680 goto out_unlock;
681 }
682
683 if (!blocked) {
684 dev = pci_get_slot(bus, 0);
685 if (dev) {
686 /* Device already present */
687 pci_dev_put(dev);
688 goto out_unlock; 679 goto out_unlock;
689 } 680 }
690 dev = pci_scan_single_device(bus, 0); 681
691 if (dev) { 682 if (!blocked) {
692 pci_bus_assign_resources(bus); 683 dev = pci_get_slot(bus, 0);
693 if (pci_bus_add_device(dev)) 684 if (dev) {
694 pr_err("Unable to hotplug wifi\n"); 685 /* Device already present */
695 } 686 pci_dev_put(dev);
696 } else { 687 goto out_unlock;
697 dev = pci_get_slot(bus, 0); 688 }
698 if (dev) { 689 dev = pci_scan_single_device(bus, 0);
699 pci_remove_bus_device(dev); 690 if (dev) {
700 pci_dev_put(dev); 691 pci_bus_assign_resources(bus);
692 if (pci_bus_add_device(dev))
693 pr_err("Unable to hotplug wifi\n");
694 }
695 } else {
696 dev = pci_get_slot(bus, 0);
697 if (dev) {
698 pci_remove_bus_device(dev);
699 pci_dev_put(dev);
700 }
701 } 701 }
702 } 702 }
703 703
@@ -1029,14 +1029,22 @@ static void eeepc_rfkill_exit(void)
1029{ 1029{
1030 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 1030 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
1031 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 1031 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
1032 if (ehotk->wlan_rfkill) 1032 if (ehotk->wlan_rfkill) {
1033 rfkill_unregister(ehotk->wlan_rfkill); 1033 rfkill_unregister(ehotk->wlan_rfkill);
1034 ehotk->wlan_rfkill = NULL;
1035 }
1036 /*
1037 * Refresh pci hotplug in case the rfkill state was changed after
1038 * eeepc_unregister_rfkill_notifier()
1039 */
1040 eeepc_rfkill_hotplug();
1041 if (ehotk->hotplug_slot)
1042 pci_hp_deregister(ehotk->hotplug_slot);
1043
1034 if (ehotk->bluetooth_rfkill) 1044 if (ehotk->bluetooth_rfkill)
1035 rfkill_unregister(ehotk->bluetooth_rfkill); 1045 rfkill_unregister(ehotk->bluetooth_rfkill);
1036 if (ehotk->wwan3g_rfkill) 1046 if (ehotk->wwan3g_rfkill)
1037 rfkill_unregister(ehotk->wwan3g_rfkill); 1047 rfkill_unregister(ehotk->wwan3g_rfkill);
1038 if (ehotk->hotplug_slot)
1039 pci_hp_deregister(ehotk->hotplug_slot);
1040} 1048}
1041 1049
1042static void eeepc_input_exit(void) 1050static void eeepc_input_exit(void)
@@ -1104,9 +1112,6 @@ static int eeepc_rfkill_init(struct device *dev)
1104 1112
1105 mutex_init(&ehotk->hotplug_lock); 1113 mutex_init(&ehotk->hotplug_lock);
1106 1114
1107 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1108 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1109
1110 result = eeepc_new_rfkill(&ehotk->wlan_rfkill, 1115 result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
1111 "eeepc-wlan", dev, 1116 "eeepc-wlan", dev,
1112 RFKILL_TYPE_WLAN, CM_ASL_WLAN); 1117 RFKILL_TYPE_WLAN, CM_ASL_WLAN);
@@ -1136,6 +1141,14 @@ static int eeepc_rfkill_init(struct device *dev)
1136 if (result == -EBUSY) 1141 if (result == -EBUSY)
1137 result = 0; 1142 result = 0;
1138 1143
1144 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1145 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1146 /*
1147 * Refresh pci hotplug in case the rfkill state was changed during
1148 * setup.
1149 */
1150 eeepc_rfkill_hotplug();
1151
1139exit: 1152exit:
1140 if (result && result != -ENODEV) 1153 if (result && result != -ENODEV)
1141 eeepc_rfkill_exit(); 1154 eeepc_rfkill_exit();