提交 07e84aa9 编写于 作者: A Alan Jenkins 提交者: Len Brown

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: NAlan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: NCorentin Chary <corentincj@iksaif.net>
Signed-off-by: NLen Brown <len.brown@intel.com>
上级 dcf443b5
...@@ -667,37 +667,37 @@ static void eeepc_rfkill_hotplug(void) ...@@ -667,37 +667,37 @@ static void eeepc_rfkill_hotplug(void)
struct pci_bus *bus; struct pci_bus *bus;
bool blocked = eeepc_wlan_rfkill_blocked(); bool blocked = eeepc_wlan_rfkill_blocked();
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); if (ehotk->wlan_rfkill)
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
mutex_lock(&ehotk->hotplug_lock); mutex_lock(&ehotk->hotplug_lock);
if (ehotk->hotplug_slot == NULL) if (ehotk->hotplug_slot) {
goto out_unlock; bus = pci_find_bus(0, 1);
if (!bus) {
bus = pci_find_bus(0, 1); pr_warning("Unable to find PCI bus 1?\n");
if (!bus) {
pr_warning("Unable to find PCI bus 1?\n");
goto out_unlock;
}
if (!blocked) {
dev = pci_get_slot(bus, 0);
if (dev) {
/* Device already present */
pci_dev_put(dev);
goto out_unlock; goto out_unlock;
} }
dev = pci_scan_single_device(bus, 0);
if (dev) { if (!blocked) {
pci_bus_assign_resources(bus); dev = pci_get_slot(bus, 0);
if (pci_bus_add_device(dev)) if (dev) {
pr_err("Unable to hotplug wifi\n"); /* Device already present */
} pci_dev_put(dev);
} else { goto out_unlock;
dev = pci_get_slot(bus, 0); }
if (dev) { dev = pci_scan_single_device(bus, 0);
pci_remove_bus_device(dev); if (dev) {
pci_dev_put(dev); pci_bus_assign_resources(bus);
if (pci_bus_add_device(dev))
pr_err("Unable to hotplug wifi\n");
}
} else {
dev = pci_get_slot(bus, 0);
if (dev) {
pci_remove_bus_device(dev);
pci_dev_put(dev);
}
} }
} }
...@@ -1029,14 +1029,22 @@ static void eeepc_rfkill_exit(void) ...@@ -1029,14 +1029,22 @@ static void eeepc_rfkill_exit(void)
{ {
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
if (ehotk->wlan_rfkill) if (ehotk->wlan_rfkill) {
rfkill_unregister(ehotk->wlan_rfkill); rfkill_unregister(ehotk->wlan_rfkill);
ehotk->wlan_rfkill = NULL;
}
/*
* Refresh pci hotplug in case the rfkill state was changed after
* eeepc_unregister_rfkill_notifier()
*/
eeepc_rfkill_hotplug();
if (ehotk->hotplug_slot)
pci_hp_deregister(ehotk->hotplug_slot);
if (ehotk->bluetooth_rfkill) if (ehotk->bluetooth_rfkill)
rfkill_unregister(ehotk->bluetooth_rfkill); rfkill_unregister(ehotk->bluetooth_rfkill);
if (ehotk->wwan3g_rfkill) if (ehotk->wwan3g_rfkill)
rfkill_unregister(ehotk->wwan3g_rfkill); rfkill_unregister(ehotk->wwan3g_rfkill);
if (ehotk->hotplug_slot)
pci_hp_deregister(ehotk->hotplug_slot);
} }
static void eeepc_input_exit(void) static void eeepc_input_exit(void)
...@@ -1104,9 +1112,6 @@ static int eeepc_rfkill_init(struct device *dev) ...@@ -1104,9 +1112,6 @@ static int eeepc_rfkill_init(struct device *dev)
mutex_init(&ehotk->hotplug_lock); mutex_init(&ehotk->hotplug_lock);
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
result = eeepc_new_rfkill(&ehotk->wlan_rfkill, result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
"eeepc-wlan", dev, "eeepc-wlan", dev,
RFKILL_TYPE_WLAN, CM_ASL_WLAN); RFKILL_TYPE_WLAN, CM_ASL_WLAN);
...@@ -1136,6 +1141,14 @@ static int eeepc_rfkill_init(struct device *dev) ...@@ -1136,6 +1141,14 @@ static int eeepc_rfkill_init(struct device *dev)
if (result == -EBUSY) if (result == -EBUSY)
result = 0; result = 0;
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
/*
* Refresh pci hotplug in case the rfkill state was changed during
* setup.
*/
eeepc_rfkill_hotplug();
exit: exit:
if (result && result != -ENODEV) if (result && result != -ENODEV)
eeepc_rfkill_exit(); eeepc_rfkill_exit();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册