Skip to content

Commit 8bfa7e1

Browse files
l1kholtmann
authored andcommitted
Bluetooth: hci_bcm: Handle errors properly
A significant portion of this driver lacks error handling. As a first step, add error paths to bcm_gpio_set_power(), bcm_open(), bcm_close(), bcm_suspend_device(), bcm_resume_device(), bcm_resume(), bcm_probe() and bcm_serdev_probe(). (I've also scrutinized bcm_suspend() but think it's fine as is.) Those are all the functions accessing the device wake and shutdown GPIO. On Apple Macs the pins are accessed through ACPI methods, which may fail for various reasons, hence proper error handling is necessary. Non-Macs access the pins directly, which may fail as well but the GPIO core does not yet pass back errors to consumers. Cc: Frédéric Danis <[email protected]> Cc: Hans de Goede <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Lukas Wunner <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 8353b4a commit 8bfa7e1

File tree

1 file changed

+75
-16
lines changed

1 file changed

+75
-16
lines changed

drivers/bluetooth/hci_bcm.c

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -197,18 +197,35 @@ static bool bcm_device_exists(struct bcm_device *device)
197197

198198
static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
199199
{
200-
if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled)
201-
clk_prepare_enable(dev->clk);
200+
int err;
202201

203-
dev->set_shutdown(dev, powered);
204-
dev->set_device_wakeup(dev, powered);
202+
if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled) {
203+
err = clk_prepare_enable(dev->clk);
204+
if (err)
205+
return err;
206+
}
207+
208+
err = dev->set_shutdown(dev, powered);
209+
if (err)
210+
goto err_clk_disable;
211+
212+
err = dev->set_device_wakeup(dev, powered);
213+
if (err)
214+
goto err_revert_shutdown;
205215

206216
if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled)
207217
clk_disable_unprepare(dev->clk);
208218

209219
dev->clk_enabled = powered;
210220

211221
return 0;
222+
223+
err_revert_shutdown:
224+
dev->set_shutdown(dev, !powered);
225+
err_clk_disable:
226+
if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled)
227+
clk_disable_unprepare(dev->clk);
228+
return err;
212229
}
213230

214231
#ifdef CONFIG_PM
@@ -331,6 +348,7 @@ static int bcm_open(struct hci_uart *hu)
331348
{
332349
struct bcm_data *bcm;
333350
struct list_head *p;
351+
int err;
334352

335353
bt_dev_dbg(hu->hdev, "hu %p", hu);
336354

@@ -345,7 +363,10 @@ static int bcm_open(struct hci_uart *hu)
345363
mutex_lock(&bcm_device_lock);
346364

347365
if (hu->serdev) {
348-
serdev_device_open(hu->serdev);
366+
err = serdev_device_open(hu->serdev);
367+
if (err)
368+
goto err_free;
369+
349370
bcm->dev = serdev_device_get_drvdata(hu->serdev);
350371
goto out;
351372
}
@@ -373,17 +394,30 @@ static int bcm_open(struct hci_uart *hu)
373394
if (bcm->dev) {
374395
hu->init_speed = bcm->dev->init_speed;
375396
hu->oper_speed = bcm->dev->oper_speed;
376-
bcm_gpio_set_power(bcm->dev, true);
397+
err = bcm_gpio_set_power(bcm->dev, true);
398+
if (err)
399+
goto err_unset_hu;
377400
}
378401

379402
mutex_unlock(&bcm_device_lock);
380403
return 0;
404+
405+
err_unset_hu:
406+
#ifdef CONFIG_PM
407+
bcm->dev->hu = NULL;
408+
#endif
409+
err_free:
410+
mutex_unlock(&bcm_device_lock);
411+
hu->priv = NULL;
412+
kfree(bcm);
413+
return err;
381414
}
382415

383416
static int bcm_close(struct hci_uart *hu)
384417
{
385418
struct bcm_data *bcm = hu->priv;
386419
struct bcm_device *bdev = NULL;
420+
int err;
387421

388422
bt_dev_dbg(hu->hdev, "hu %p", hu);
389423

@@ -407,8 +441,11 @@ static int bcm_close(struct hci_uart *hu)
407441
pm_runtime_disable(bdev->dev);
408442
}
409443

410-
bcm_gpio_set_power(bdev, false);
411-
pm_runtime_set_suspended(bdev->dev);
444+
err = bcm_gpio_set_power(bdev, false);
445+
if (err)
446+
bt_dev_err(hu->hdev, "Failed to power down");
447+
else
448+
pm_runtime_set_suspended(bdev->dev);
412449
}
413450
mutex_unlock(&bcm_device_lock);
414451

@@ -588,6 +625,7 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
588625
static int bcm_suspend_device(struct device *dev)
589626
{
590627
struct bcm_device *bdev = dev_get_drvdata(dev);
628+
int err;
591629

592630
bt_dev_dbg(bdev, "");
593631

@@ -599,7 +637,15 @@ static int bcm_suspend_device(struct device *dev)
599637
}
600638

601639
/* Suspend the device */
602-
bdev->set_device_wakeup(bdev, false);
640+
err = bdev->set_device_wakeup(bdev, false);
641+
if (err) {
642+
if (bdev->is_suspended && bdev->hu) {
643+
bdev->is_suspended = false;
644+
hci_uart_set_flow_control(bdev->hu, false);
645+
}
646+
return -EBUSY;
647+
}
648+
603649
bt_dev_dbg(bdev, "suspend, delaying 15 ms");
604650
mdelay(15);
605651

@@ -609,10 +655,16 @@ static int bcm_suspend_device(struct device *dev)
609655
static int bcm_resume_device(struct device *dev)
610656
{
611657
struct bcm_device *bdev = dev_get_drvdata(dev);
658+
int err;
612659

613660
bt_dev_dbg(bdev, "");
614661

615-
bdev->set_device_wakeup(bdev, true);
662+
err = bdev->set_device_wakeup(bdev, true);
663+
if (err) {
664+
dev_err(dev, "Failed to power up\n");
665+
return err;
666+
}
667+
616668
bt_dev_dbg(bdev, "resume, delaying 15 ms");
617669
mdelay(15);
618670

@@ -666,6 +718,7 @@ static int bcm_suspend(struct device *dev)
666718
static int bcm_resume(struct device *dev)
667719
{
668720
struct bcm_device *bdev = dev_get_drvdata(dev);
721+
int err = 0;
669722

670723
bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);
671724

@@ -685,14 +738,16 @@ static int bcm_resume(struct device *dev)
685738
bt_dev_dbg(bdev, "BCM irq: disabled");
686739
}
687740

688-
bcm_resume_device(dev);
741+
err = bcm_resume_device(dev);
689742

690743
unlock:
691744
mutex_unlock(&bcm_device_lock);
692745

693-
pm_runtime_disable(dev);
694-
pm_runtime_set_active(dev);
695-
pm_runtime_enable(dev);
746+
if (!err) {
747+
pm_runtime_disable(dev);
748+
pm_runtime_set_active(dev);
749+
pm_runtime_enable(dev);
750+
}
696751

697752
return 0;
698753
}
@@ -923,7 +978,9 @@ static int bcm_probe(struct platform_device *pdev)
923978
list_add_tail(&dev->list, &bcm_device_list);
924979
mutex_unlock(&bcm_device_lock);
925980

926-
bcm_gpio_set_power(dev, false);
981+
ret = bcm_gpio_set_power(dev, false);
982+
if (ret)
983+
dev_err(&pdev->dev, "Failed to power down\n");
927984

928985
return 0;
929986
}
@@ -1025,7 +1082,9 @@ static int bcm_serdev_probe(struct serdev_device *serdev)
10251082
if (err)
10261083
return err;
10271084

1028-
bcm_gpio_set_power(bcmdev, false);
1085+
err = bcm_gpio_set_power(bcmdev, false);
1086+
if (err)
1087+
dev_err(&serdev->dev, "Failed to power down\n");
10291088

10301089
return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto);
10311090
}

0 commit comments

Comments
 (0)