Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ed5a133 authored by Rupesh Tatiya's avatar Rupesh Tatiya
Browse files

Bluetooth: Protect request_firmware with a semaphore for btusb



If btusb_probe gets called during system suspend/resume,
request_firmware call will fail sometimes as userspace processes
that help in request_firmware are frozen as a part of suspend.

Change-Id: I51c6fc0221e56e9dfa507aee0c26005e805a9e78
Signed-off-by: default avatarRupesh Tatiya <rtatiya@codeaurora.org>
parent f81d0b1f
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -452,6 +452,9 @@ static int ath3k_set_normal_mode(struct usb_device *udev)
			NULL, 0, USB_CTRL_SET_TIMEOUT);
}

DECLARE_RWSEM(btusb_pm_sem);
EXPORT_SYMBOL(btusb_pm_sem);

static int ath3k_load_patch(struct usb_device *udev,
						struct ath3k_version *version)
{
@@ -471,10 +474,9 @@ static int ath3k_load_patch(struct usb_device *udev,

	if ((fw_state == ATH3K_PATCH_UPDATE) ||
		(fw_state == ATH3K_PATCH_SYSCFG_UPDATE)) {
		BT_INFO("%s: Patch already downloaded(fw_state: %d)", __func__,
			fw_state);
		BT_INFO("Patch already downloaded(fw_state: %d)", fw_state);
		return 0;
	}
	} else
		BT_DBG("Downloading RamPatch(fw_state: %d)", fw_state);

	switch (version->rom_version) {
@@ -497,11 +499,14 @@ static int ath3k_load_patch(struct usb_device *udev,
		break;
	}

	down_read(&btusb_pm_sem);
	ret = request_firmware(&firmware, filename, &udev->dev);
	if (ret < 0) {
		BT_ERR("Patch file not found %s", filename);
		up_read(&btusb_pm_sem);
		return ret;
	}
	up_read(&btusb_pm_sem);

	if ((version->rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(version->rom_version == ROME3_0_USB_CHIP_VERSION)) {
+2 −0
Original line number Diff line number Diff line
@@ -25,3 +25,5 @@ struct ath3k_version {
int get_rome_version(struct usb_device *udev, struct ath3k_version *version);
int rome_download(struct usb_device *udev, struct ath3k_version *version);

extern struct rw_semaphore btusb_pm_sem;
+49 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/suspend.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -2295,6 +2296,29 @@ done:
}
#endif

static unsigned long btusb_pm_flags;
#define BTUSB_PM_SUSPEND	(1)
static int btusb_pm_notify(struct notifier_block *b,
				unsigned long event, void *p)
{
	switch (event) {
	case PM_SUSPEND_PREPARE:
		set_bit(BTUSB_PM_SUSPEND, &btusb_pm_flags);
		down_write(&btusb_pm_sem);
		break;
	case PM_POST_SUSPEND:
		up_write(&btusb_pm_sem);
		clear_bit(BTUSB_PM_SUSPEND, &btusb_pm_flags);
		break;
	}

	return NOTIFY_DONE;
}

static struct notifier_block btusb_pm_notifier = {
	.notifier_call = btusb_pm_notify,
};

static struct usb_driver btusb_driver = {
	.name		= "btusb",
	.probe		= btusb_probe,
@@ -2308,7 +2332,31 @@ static struct usb_driver btusb_driver = {
	.disable_hub_initiated_lpm = 1,
};

module_usb_driver(btusb_driver);
static int __init btusb_driver_init(void)
{
	int ret = 0;

	ret = usb_register(&btusb_driver);
	/* ignore return value */
	register_pm_notifier(&btusb_pm_notifier);
	return ret;
}
module_init(btusb_driver_init);

static void __exit btusb_driver_exit(void)
{
	unregister_pm_notifier(&btusb_pm_notifier);
	/*
	 * If unregister gets called before resume notification, we need to
	 * release the semaphore to avoid deadlock.
	 */
	if (test_bit(BTUSB_PM_SUSPEND, &btusb_pm_flags)) {
		up_write(&btusb_pm_sem);
		clear_bit(BTUSB_PM_SUSPEND, &btusb_pm_flags);
	}
	usb_deregister(&btusb_driver);
}
module_exit(btusb_driver_exit);

module_param(disable_scofix, bool, 0644);
MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");