aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/sdio.c')
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c140
1 files changed, 87 insertions, 53 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 9475e2d0d0b7..4febee723495 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -49,11 +49,13 @@ struct ath6kl_sdio {
49 /* scatter request list head */ 49 /* scatter request list head */
50 struct list_head scat_req; 50 struct list_head scat_req;
51 51
52 /* Avoids disabling irq while the interrupts being handled */
53 struct mutex mtx_irq;
54
52 spinlock_t scat_lock; 55 spinlock_t scat_lock;
53 bool scatter_enabled; 56 bool scatter_enabled;
54 57
55 bool is_disabled; 58 bool is_disabled;
56 atomic_t irq_handling;
57 const struct sdio_device_id *id; 59 const struct sdio_device_id *id;
58 struct work_struct wr_async_work; 60 struct work_struct wr_async_work;
59 struct list_head wr_asyncq; 61 struct list_head wr_asyncq;
@@ -460,8 +462,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
460 ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); 462 ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
461 463
462 ar_sdio = sdio_get_drvdata(func); 464 ar_sdio = sdio_get_drvdata(func);
463 atomic_set(&ar_sdio->irq_handling, 1); 465 mutex_lock(&ar_sdio->mtx_irq);
464
465 /* 466 /*
466 * Release the host during interrups so we can pick it back up when 467 * Release the host during interrups so we can pick it back up when
467 * we process commands. 468 * we process commands.
@@ -470,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
470 471
471 status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); 472 status = ath6kl_hif_intr_bh_handler(ar_sdio->ar);
472 sdio_claim_host(ar_sdio->func); 473 sdio_claim_host(ar_sdio->func);
473 atomic_set(&ar_sdio->irq_handling, 0); 474 mutex_unlock(&ar_sdio->mtx_irq);
474 WARN_ON(status && status != -ECANCELED); 475 WARN_ON(status && status != -ECANCELED);
475} 476}
476 477
@@ -578,17 +579,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
578 579
579 sdio_claim_host(ar_sdio->func); 580 sdio_claim_host(ar_sdio->func);
580 581
581 /* Mask our function IRQ */ 582 mutex_lock(&ar_sdio->mtx_irq);
582 while (atomic_read(&ar_sdio->irq_handling)) {
583 sdio_release_host(ar_sdio->func);
584 schedule_timeout(HZ / 10);
585 sdio_claim_host(ar_sdio->func);
586 }
587 583
588 ret = sdio_release_irq(ar_sdio->func); 584 ret = sdio_release_irq(ar_sdio->func);
589 if (ret) 585 if (ret)
590 ath6kl_err("Failed to release sdio irq: %d\n", ret); 586 ath6kl_err("Failed to release sdio irq: %d\n", ret);
591 587
588 mutex_unlock(&ar_sdio->mtx_irq);
589
592 sdio_release_host(ar_sdio->func); 590 sdio_release_host(ar_sdio->func);
593} 591}
594 592
@@ -772,7 +770,6 @@ static int ath6kl_sdio_config(struct ath6kl *ar)
772 if (ret) { 770 if (ret) {
773 ath6kl_err("Set sdio block size %d failed: %d)\n", 771 ath6kl_err("Set sdio block size %d failed: %d)\n",
774 HIF_MBOX_BLOCK_SIZE, ret); 772 HIF_MBOX_BLOCK_SIZE, ret);
775 sdio_release_host(func);
776 goto out; 773 goto out;
777 } 774 }
778 775
@@ -782,7 +779,7 @@ out:
782 return ret; 779 return ret;
783} 780}
784 781
785static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) 782static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar)
786{ 783{
787 struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 784 struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
788 struct sdio_func *func = ar_sdio->func; 785 struct sdio_func *func = ar_sdio->func;
@@ -793,60 +790,95 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
793 790
794 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags); 791 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
795 792
796 if (!(flags & MMC_PM_KEEP_POWER) || 793 if (!(flags & MMC_PM_WAKE_SDIO_IRQ) ||
797 (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) { 794 !(flags & MMC_PM_KEEP_POWER))
798 /* as host doesn't support keep power we need to cut power */ 795 return -EINVAL;
799 return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
800 NULL);
801 }
802 796
803 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 797 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
804 if (ret) { 798 if (ret) {
805 printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", 799 ath6kl_err("set sdio keep pwr flag failed: %d\n", ret);
806 ret);
807 return ret; 800 return ret;
808 } 801 }
809 802
810 if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
811 goto deepsleep;
812
813 /* sdio irq wakes up host */ 803 /* sdio irq wakes up host */
804 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
805 if (ret)
806 ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
807
808 return ret;
809}
810
811static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
812{
813 struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
814 struct sdio_func *func = ar_sdio->func;
815 mmc_pm_flag_t flags;
816 int ret;
814 817
815 if (ar->state == ATH6KL_STATE_SCHED_SCAN) { 818 if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
819 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
820
821 ret = ath6kl_set_sdio_pm_caps(ar);
822 if (ret)
823 goto cut_pwr;
824
816 ret = ath6kl_cfg80211_suspend(ar, 825 ret = ath6kl_cfg80211_suspend(ar,
817 ATH6KL_CFG_SUSPEND_SCHED_SCAN, 826 ATH6KL_CFG_SUSPEND_SCHED_SCAN,
818 NULL); 827 NULL);
819 if (ret) { 828 if (ret)
820 ath6kl_warn("Schedule scan suspend failed: %d", ret); 829 goto cut_pwr;
821 return ret; 830
822 } 831 return 0;
832 }
833
834 if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
835 (!ar->suspend_mode && wow)) {
823 836
824 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); 837 ret = ath6kl_set_sdio_pm_caps(ar);
825 if (ret) 838 if (ret)
826 ath6kl_warn("set sdio wake irq flag failed: %d\n", ret); 839 goto cut_pwr;
827 840
828 return ret; 841 ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
842 if (ret)
843 goto cut_pwr;
844
845 return 0;
829 } 846 }
830 847
831 if (wow) { 848 if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
849 !ar->suspend_mode) {
850
851 flags = sdio_get_host_pm_caps(func);
852 if (!(flags & MMC_PM_KEEP_POWER))
853 goto cut_pwr;
854
855 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
856 if (ret)
857 goto cut_pwr;
858
832 /* 859 /*
833 * The host sdio controller is capable of keep power and 860 * Workaround to support Deep Sleep with MSM, set the host pm
834 * sdio irq wake up at this point. It's fine to continue 861 * flag as MMC_PM_WAKE_SDIO_IRQ to allow SDCC deiver to disable
835 * wow suspend operation. 862 * the sdc2_clock and internally allows MSM to enter
863 * TCXO shutdown properly.
836 */ 864 */
837 ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); 865 if ((flags & MMC_PM_WAKE_SDIO_IRQ)) {
838 if (ret) 866 ret = sdio_set_host_pm_flags(func,
839 return ret; 867 MMC_PM_WAKE_SDIO_IRQ);
868 if (ret)
869 goto cut_pwr;
870 }
840 871
841 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); 872 ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
873 NULL);
842 if (ret) 874 if (ret)
843 ath6kl_err("set sdio wake irq flag failed: %d\n", ret); 875 goto cut_pwr;
844 876
845 return ret; 877 return 0;
846 } 878 }
847 879
848deepsleep: 880cut_pwr:
849 return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL); 881 return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
850} 882}
851 883
852static int ath6kl_sdio_resume(struct ath6kl *ar) 884static int ath6kl_sdio_resume(struct ath6kl *ar)
@@ -1253,6 +1285,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
1253 spin_lock_init(&ar_sdio->scat_lock); 1285 spin_lock_init(&ar_sdio->scat_lock);
1254 spin_lock_init(&ar_sdio->wr_async_lock); 1286 spin_lock_init(&ar_sdio->wr_async_lock);
1255 mutex_init(&ar_sdio->dma_buffer_mutex); 1287 mutex_init(&ar_sdio->dma_buffer_mutex);
1288 mutex_init(&ar_sdio->mtx_irq);
1256 1289
1257 INIT_LIST_HEAD(&ar_sdio->scat_req); 1290 INIT_LIST_HEAD(&ar_sdio->scat_req);
1258 INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); 1291 INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
@@ -1263,7 +1296,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
1263 for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) 1296 for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
1264 ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); 1297 ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
1265 1298
1266 ar = ath6kl_core_alloc(&ar_sdio->func->dev); 1299 ar = ath6kl_core_create(&ar_sdio->func->dev);
1267 if (!ar) { 1300 if (!ar) {
1268 ath6kl_err("Failed to alloc ath6kl core\n"); 1301 ath6kl_err("Failed to alloc ath6kl core\n");
1269 ret = -ENOMEM; 1302 ret = -ENOMEM;
@@ -1293,7 +1326,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
1293 return ret; 1326 return ret;
1294 1327
1295err_core_alloc: 1328err_core_alloc:
1296 ath6kl_core_free(ar_sdio->ar); 1329 ath6kl_core_destroy(ar_sdio->ar);
1297err_dma: 1330err_dma:
1298 kfree(ar_sdio->dma_buffer); 1331 kfree(ar_sdio->dma_buffer);
1299err_hif: 1332err_hif:
@@ -1316,6 +1349,7 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
1316 cancel_work_sync(&ar_sdio->wr_async_work); 1349 cancel_work_sync(&ar_sdio->wr_async_work);
1317 1350
1318 ath6kl_core_cleanup(ar_sdio->ar); 1351 ath6kl_core_cleanup(ar_sdio->ar);
1352 ath6kl_core_destroy(ar_sdio->ar);
1319 1353
1320 kfree(ar_sdio->dma_buffer); 1354 kfree(ar_sdio->dma_buffer);
1321 kfree(ar_sdio); 1355 kfree(ar_sdio);
@@ -1332,7 +1366,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
1332MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); 1366MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
1333 1367
1334static struct sdio_driver ath6kl_sdio_driver = { 1368static struct sdio_driver ath6kl_sdio_driver = {
1335 .name = "ath6kl", 1369 .name = "ath6kl_sdio",
1336 .id_table = ath6kl_sdio_devices, 1370 .id_table = ath6kl_sdio_devices,
1337 .probe = ath6kl_sdio_probe, 1371 .probe = ath6kl_sdio_probe,
1338 .remove = ath6kl_sdio_remove, 1372 .remove = ath6kl_sdio_remove,
@@ -1362,19 +1396,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
1362MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); 1396MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
1363MODULE_LICENSE("Dual BSD/GPL"); 1397MODULE_LICENSE("Dual BSD/GPL");
1364 1398
1365MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE); 1399MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_OTP_FILE);
1366MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE); 1400MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_FIRMWARE_FILE);
1367MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE); 1401MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_PATCH_FILE);
1368MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE); 1402MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE);
1369MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE); 1403MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE);
1370MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE); 1404MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_OTP_FILE);
1371MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE); 1405MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_FIRMWARE_FILE);
1372MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE); 1406MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_PATCH_FILE);
1373MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE); 1407MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE);
1374MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE); 1408MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE);
1375MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE); 1409MODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE);
1376MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); 1410MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
1377MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); 1411MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
1378MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); 1412MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE);
1379MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); 1413MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
1380MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); 1414MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);