aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2010-05-27 19:38:37 -0400
committerMarcel Holtmann <marcel@holtmann.org>2010-07-21 13:39:06 -0400
commitd1d10d783089cc26a14be92fc12fccda9aa6593a (patch)
tree109f208c61617a703993ac21a40d71d2e646c44b /drivers/bluetooth
parent2d0a03460a8a0c611843500735096ff799aa8510 (diff)
Bluetooth: Process interrupt in main thread of btmrvl driver as well
When driver is sending a command or data and the firmware is also sending a sleep event, sometimes it is observed that driver will continue to send the command/data to firmware right after processing sleep event. Once sleep event is processed driver is not supposed to send anything because firmware is in sleep state after that. Previously interrupt processing was done in SDIO interrupt callback handler. Now it is done in btmrvl driver main thread to solve the cross-sending properly. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/btmrvl_drv.h1
-rw-r--r--drivers/bluetooth/btmrvl_main.c5
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c97
3 files changed, 55 insertions, 48 deletions
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index bed0ba63023..872cb6cfcd0 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -76,6 +76,7 @@ struct btmrvl_private {
76 int (*hw_host_to_card) (struct btmrvl_private *priv, 76 int (*hw_host_to_card) (struct btmrvl_private *priv,
77 u8 *payload, u16 nb); 77 u8 *payload, u16 nb);
78 int (*hw_wakeup_firmware) (struct btmrvl_private *priv); 78 int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
79 int (*hw_process_int_status) (struct btmrvl_private *priv);
79 spinlock_t driver_lock; /* spinlock used by driver */ 80 spinlock_t driver_lock; /* spinlock used by driver */
80#ifdef CONFIG_DEBUG_FS 81#ifdef CONFIG_DEBUG_FS
81 void *debugfs_data; 82 void *debugfs_data;
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index ee37ef0caee..0d32ec82e9b 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -502,14 +502,17 @@ static int btmrvl_service_main_thread(void *data)
502 spin_lock_irqsave(&priv->driver_lock, flags); 502 spin_lock_irqsave(&priv->driver_lock, flags);
503 if (adapter->int_count) { 503 if (adapter->int_count) {
504 adapter->int_count = 0; 504 adapter->int_count = 0;
505 spin_unlock_irqrestore(&priv->driver_lock, flags);
506 priv->hw_process_int_status(priv);
505 } else if (adapter->ps_state == PS_SLEEP && 507 } else if (adapter->ps_state == PS_SLEEP &&
506 !skb_queue_empty(&adapter->tx_queue)) { 508 !skb_queue_empty(&adapter->tx_queue)) {
507 spin_unlock_irqrestore(&priv->driver_lock, flags); 509 spin_unlock_irqrestore(&priv->driver_lock, flags);
508 adapter->wakeup_tries++; 510 adapter->wakeup_tries++;
509 priv->hw_wakeup_firmware(priv); 511 priv->hw_wakeup_firmware(priv);
510 continue; 512 continue;
513 } else {
514 spin_unlock_irqrestore(&priv->driver_lock, flags);
511 } 515 }
512 spin_unlock_irqrestore(&priv->driver_lock, flags);
513 516
514 if (adapter->ps_state == PS_SLEEP) 517 if (adapter->ps_state == PS_SLEEP)
515 continue; 518 continue;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 47f0f917dec..182e55345d6 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -47,6 +47,7 @@
47 * module_exit function is called. 47 * module_exit function is called.
48 */ 48 */
49static u8 user_rmmod; 49static u8 user_rmmod;
50static u8 sdio_ireg;
50 51
51static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { 52static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
52 .helper = "sd8688_helper.bin", 53 .helper = "sd8688_helper.bin",
@@ -555,78 +556,79 @@ exit:
555 return ret; 556 return ret;
556} 557}
557 558
558static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) 559static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
559{ 560{
560 int ret; 561 ulong flags;
561 u8 sdio_ireg = 0; 562 u8 ireg;
562 struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; 563 struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
563 564
564 *ireg = 0; 565 spin_lock_irqsave(&priv->driver_lock, flags);
565 566 ireg = sdio_ireg;
566 sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); 567 sdio_ireg = 0;
567 if (ret) { 568 spin_unlock_irqrestore(&priv->driver_lock, flags);
568 BT_ERR("sdio_readb: read int status register failed");
569 ret = -EIO;
570 goto done;
571 }
572
573 if (sdio_ireg != 0) {
574 /*
575 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
576 * Clear the interrupt status register and re-enable the
577 * interrupt.
578 */
579 BT_DBG("sdio_ireg = 0x%x", sdio_ireg);
580
581 sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
582 UP_LD_HOST_INT_STATUS),
583 HOST_INTSTATUS_REG, &ret);
584 if (ret) {
585 BT_ERR("sdio_writeb: clear int status register "
586 "failed");
587 ret = -EIO;
588 goto done;
589 }
590 }
591 569
592 if (sdio_ireg & DN_LD_HOST_INT_STATUS) { 570 sdio_claim_host(card->func);
571 if (ireg & DN_LD_HOST_INT_STATUS) {
593 if (priv->btmrvl_dev.tx_dnld_rdy) 572 if (priv->btmrvl_dev.tx_dnld_rdy)
594 BT_DBG("tx_done already received: " 573 BT_DBG("tx_done already received: "
595 " int_status=0x%x", sdio_ireg); 574 " int_status=0x%x", ireg);
596 else 575 else
597 priv->btmrvl_dev.tx_dnld_rdy = true; 576 priv->btmrvl_dev.tx_dnld_rdy = true;
598 } 577 }
599 578
600 if (sdio_ireg & UP_LD_HOST_INT_STATUS) 579 if (ireg & UP_LD_HOST_INT_STATUS)
601 btmrvl_sdio_card_to_host(priv); 580 btmrvl_sdio_card_to_host(priv);
602 581
603 *ireg = sdio_ireg; 582 sdio_release_host(card->func);
604
605 ret = 0;
606 583
607done: 584 return 0;
608 return ret;
609} 585}
610 586
611static void btmrvl_sdio_interrupt(struct sdio_func *func) 587static void btmrvl_sdio_interrupt(struct sdio_func *func)
612{ 588{
613 struct btmrvl_private *priv; 589 struct btmrvl_private *priv;
614 struct hci_dev *hcidev;
615 struct btmrvl_sdio_card *card; 590 struct btmrvl_sdio_card *card;
591 ulong flags;
616 u8 ireg = 0; 592 u8 ireg = 0;
593 int ret;
617 594
618 card = sdio_get_drvdata(func); 595 card = sdio_get_drvdata(func);
619 if (card && card->priv) { 596 if (!card || !card->priv) {
620 priv = card->priv; 597 BT_ERR("sbi_interrupt(%p) card or priv is "
621 hcidev = priv->btmrvl_dev.hcidev; 598 "NULL, card=%p\n", func, card);
599 return;
600 }
622 601
623 if (btmrvl_sdio_get_int_status(priv, &ireg)) 602 priv = card->priv;
624 BT_ERR("reading HOST_INT_STATUS_REG failed");
625 else
626 BT_DBG("HOST_INT_STATUS_REG %#x", ireg);
627 603
628 btmrvl_interrupt(priv); 604 ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
605 if (ret) {
606 BT_ERR("sdio_readb: read int status register failed");
607 return;
629 } 608 }
609
610 if (ireg != 0) {
611 /*
612 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
613 * Clear the interrupt status register and re-enable the
614 * interrupt.
615 */
616 BT_DBG("ireg = 0x%x", ireg);
617
618 sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
619 UP_LD_HOST_INT_STATUS),
620 HOST_INTSTATUS_REG, &ret);
621 if (ret) {
622 BT_ERR("sdio_writeb: clear int status register failed");
623 return;
624 }
625 }
626
627 spin_lock_irqsave(&priv->driver_lock, flags);
628 sdio_ireg |= ireg;
629 spin_unlock_irqrestore(&priv->driver_lock, flags);
630
631 btmrvl_interrupt(priv);
630} 632}
631 633
632static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) 634static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
@@ -930,6 +932,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
930 /* Initialize the interface specific function pointers */ 932 /* Initialize the interface specific function pointers */
931 priv->hw_host_to_card = btmrvl_sdio_host_to_card; 933 priv->hw_host_to_card = btmrvl_sdio_host_to_card;
932 priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; 934 priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
935 priv->hw_process_int_status = btmrvl_sdio_process_int_status;
933 936
934 if (btmrvl_register_hdev(priv)) { 937 if (btmrvl_register_hdev(priv)) {
935 BT_ERR("Register hdev failed!"); 938 BT_ERR("Register hdev failed!");