Bluetooth: hci_bcm: Validate IRQ before using it

The ->close, ->suspend and ->resume hooks assume presence of a valid IRQ
if the device is wakeup capable.  However it's entirely possible that
wakeup was enabled by some other entity besides this driver and in this
case the user will get a WARN splat if no valid IRQ was found.  Avoid by
checking if the IRQ is valid, i.e. > 0.

Case in point:  On recent MacBook Pros, the Bluetooth device lacks an
IRQ (because host wakeup is handled by the SMC, independently of the
operating system), but it does possess a _PRW method (which specifies
the SMC's GPE as wake event).  The ACPI core therefore automatically
marks the physical Bluetooth device wakeup capable upon binding it to
its ACPI companion:

device_set_wakeup_capable+0x96/0xb0
acpi_bind_one+0x28a/0x310
acpi_platform_notify+0x20/0xa0
device_add+0x215/0x690
serdev_device_add+0x57/0xf0
acpi_serdev_add_device+0xc9/0x110
acpi_ns_walk_namespace+0x131/0x280
acpi_walk_namespace+0xf5/0x13d
serdev_controller_add+0x6f/0x110
serdev_tty_port_register+0x98/0xf0
tty_port_register_device_attr_serdev+0x3a/0x70
uart_add_one_port+0x268/0x500
serial8250_register_8250_port+0x32e/0x490
dw8250_probe+0x46c/0x720
platform_drv_probe+0x35/0x90
driver_probe_device+0x300/0x450
bus_for_each_drv+0x67/0xb0
__device_attach+0xde/0x160
bus_probe_device+0x9c/0xb0
device_add+0x448/0x690
platform_device_add+0x10e/0x260
mfd_add_device+0x392/0x4c0
mfd_add_devices+0xb1/0x110
intel_lpss_probe+0x2a9/0x610 [intel_lpss]
intel_lpss_pci_probe+0x7a/0xa8 [intel_lpss_pci]

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
[lukas: fix up ->suspend and ->resume as well, add commit message]
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Ronald Tschalär 2018-01-10 16:32:10 +01:00 committed by Marcel Holtmann
parent 3e81a4ca51
commit 4a59f1fab9
1 changed files with 3 additions and 3 deletions

View File

@ -377,7 +377,7 @@ static int bcm_close(struct hci_uart *hu)
pm_runtime_disable(bdev->dev); pm_runtime_disable(bdev->dev);
pm_runtime_set_suspended(bdev->dev); pm_runtime_set_suspended(bdev->dev);
if (device_can_wakeup(bdev->dev)) { if (bdev->irq > 0) {
devm_free_irq(bdev->dev, bdev->irq, bdev); devm_free_irq(bdev->dev, bdev->irq, bdev);
device_init_wakeup(bdev->dev, false); device_init_wakeup(bdev->dev, false);
} }
@ -623,7 +623,7 @@ static int bcm_suspend(struct device *dev)
if (pm_runtime_active(dev)) if (pm_runtime_active(dev))
bcm_suspend_device(dev); bcm_suspend_device(dev);
if (device_may_wakeup(dev)) { if (device_may_wakeup(dev) && bdev->irq > 0) {
error = enable_irq_wake(bdev->irq); error = enable_irq_wake(bdev->irq);
if (!error) if (!error)
bt_dev_dbg(bdev, "BCM irq: enabled"); bt_dev_dbg(bdev, "BCM irq: enabled");
@ -653,7 +653,7 @@ static int bcm_resume(struct device *dev)
if (!bdev->hu) if (!bdev->hu)
goto unlock; goto unlock;
if (device_may_wakeup(dev)) { if (device_may_wakeup(dev) && bdev->irq > 0) {
disable_irq_wake(bdev->irq); disable_irq_wake(bdev->irq);
bt_dev_dbg(bdev, "BCM irq: disabled"); bt_dev_dbg(bdev, "BCM irq: disabled");
} }