aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2015-01-25 14:31:31 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-01-29 02:58:54 -0500
commit69d03ee0b709a282f81e9f81c1359cffe1edcd2b (patch)
tree454532da01623c1e81b2f6fbacf2df8dc164cb02 /drivers/net/wireless/brcm80211
parent5ef1e604194ee629c5d9fd6b9a4d3c424cfd2a84 (diff)
brcmfmac: prevent possible deadlock on resuming SDIO device.
When the system is resumed a deadlock can occur when DPC gets entered before resume is complete. This patch fixes this by properly checking the suspend state outside the claim_host code block. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/brcm80211')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c33
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c18
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.h2
3 files changed, 18 insertions, 35 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 00ba90b89455..8ba60f6f4915 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -97,25 +97,6 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
97{ 97{
98} 98}
99 99
100static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
101{
102 bool is_err = false;
103#ifdef CONFIG_PM_SLEEP
104 is_err = atomic_read(&sdiodev->suspend);
105#endif
106 return is_err;
107}
108
109static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
110 wait_queue_head_t *wq)
111{
112#ifdef CONFIG_PM_SLEEP
113 int retry = 0;
114 while (atomic_read(&sdiodev->suspend) && retry++ != 30)
115 wait_event_timeout(*wq, false, HZ/100);
116#endif
117}
118
119int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) 100int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
120{ 101{
121 int ret = 0; 102 int ret = 0;
@@ -244,10 +225,6 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
244 brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", 225 brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
245 write, fn, addr, regsz); 226 write, fn, addr, regsz);
246 227
247 brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
248 if (brcmf_sdiod_pm_resume_error(sdiodev))
249 return -EIO;
250
251 /* only allow byte access on F0 */ 228 /* only allow byte access on F0 */
252 if (WARN_ON(regsz > 1 && !fn)) 229 if (WARN_ON(regsz > 1 && !fn))
253 return -EINVAL; 230 return -EINVAL;
@@ -462,10 +439,6 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
462 unsigned int req_sz; 439 unsigned int req_sz;
463 int err; 440 int err;
464 441
465 brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
466 if (brcmf_sdiod_pm_resume_error(sdiodev))
467 return -EIO;
468
469 /* Single skb use the standard mmc interface */ 442 /* Single skb use the standard mmc interface */
470 req_sz = pkt->len + 3; 443 req_sz = pkt->len + 3;
471 req_sz &= (uint)~3; 444 req_sz &= (uint)~3;
@@ -516,10 +489,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
516 if (!pktlist->qlen) 489 if (!pktlist->qlen)
517 return -EINVAL; 490 return -EINVAL;
518 491
519 brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
520 if (brcmf_sdiod_pm_resume_error(sdiodev))
521 return -EIO;
522
523 target_list = pktlist; 492 target_list = pktlist;
524 /* for host with broken sg support, prepare a page aligned list */ 493 /* for host with broken sg support, prepare a page aligned list */
525 __skb_queue_head_init(&local_list); 494 __skb_queue_head_init(&local_list);
@@ -1077,8 +1046,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
1077#endif 1046#endif
1078 1047
1079 atomic_set(&sdiodev->suspend, false); 1048 atomic_set(&sdiodev->suspend, false);
1080 init_waitqueue_head(&sdiodev->request_word_wait);
1081 init_waitqueue_head(&sdiodev->request_buffer_wait);
1082 1049
1083 brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); 1050 brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
1084 err = brcmf_sdiod_probe(sdiodev); 1051 err = brcmf_sdiod_probe(sdiodev);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index 99a37765888d..2c4f0ccd3b70 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -2609,6 +2609,21 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
2609 return ret; 2609 return ret;
2610} 2610}
2611 2611
2612static int brcmf_sdio_pm_resume_wait(struct brcmf_sdio_dev *sdiodev)
2613{
2614#ifdef CONFIG_PM_SLEEP
2615 int retry;
2616
2617 /* Wait for possible resume to complete */
2618 retry = 0;
2619 while ((atomic_read(&sdiodev->suspend)) && (retry++ != 50))
2620 msleep(20);
2621 if (atomic_read(&sdiodev->suspend))
2622 return -EIO;
2623#endif
2624 return 0;
2625}
2626
2612static void brcmf_sdio_dpc(struct brcmf_sdio *bus) 2627static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
2613{ 2628{
2614 u32 newstatus = 0; 2629 u32 newstatus = 0;
@@ -2619,6 +2634,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
2619 2634
2620 brcmf_dbg(TRACE, "Enter\n"); 2635 brcmf_dbg(TRACE, "Enter\n");
2621 2636
2637 if (brcmf_sdio_pm_resume_wait(bus->sdiodev))
2638 return;
2639
2622 sdio_claim_host(bus->sdiodev->func[1]); 2640 sdio_claim_host(bus->sdiodev->func[1]);
2623 2641
2624 /* If waiting for HTAVAIL, check status */ 2642 /* If waiting for HTAVAIL, check status */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
index 8eb42620129c..82494df541d4 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
@@ -169,8 +169,6 @@ struct brcmf_sdio_dev {
169 u32 sbwad; /* Save backplane window address */ 169 u32 sbwad; /* Save backplane window address */
170 struct brcmf_sdio *bus; 170 struct brcmf_sdio *bus;
171 atomic_t suspend; /* suspend flag */ 171 atomic_t suspend; /* suspend flag */
172 wait_queue_head_t request_word_wait;
173 wait_queue_head_t request_buffer_wait;
174 struct device *dev; 172 struct device *dev;
175 struct brcmf_bus *bus_if; 173 struct brcmf_bus *bus_if;
176 struct brcmfmac_sdio_platform_data *pdata; 174 struct brcmfmac_sdio_platform_data *pdata;