aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2014-03-06 04:16:12 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-03-06 14:29:58 -0500
commit5cbb9c285bdcc14ee381120dab7e23a81060f1c0 (patch)
treefa65f4a61ef1a7ab8569710564610abdeed29a43 /drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
parent561e722201e41e304936b8a2aaa282c46ad4f393 (diff)
brcmfmac: Use atomic functions for intstatus update.
The intstatus in sdio code can be updated from different threads. To protect intstatus access, atomic functions are used. One of them is set_bit, but this function is not guaranteed atomic on all platforms. The loop was replaced with local created OR function. 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: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c29
1 files changed, 15 insertions, 14 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 70bab5e089eb..a111b6fbbeba 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -2439,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
2439 } 2439 }
2440} 2440}
2441 2441
2442static void atomic_orr(int val, atomic_t *v)
2443{
2444 int old_val;
2445
2446 old_val = atomic_read(v);
2447 while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
2448 old_val = atomic_read(v);
2449}
2450
2442static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) 2451static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
2443{ 2452{
2444 struct brcmf_core *buscore; 2453 struct brcmf_core *buscore;
2445 u32 addr; 2454 u32 addr;
2446 unsigned long val; 2455 unsigned long val;
2447 int n, ret; 2456 int ret;
2448 2457
2449 buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); 2458 buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
2450 addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); 2459 addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
@@ -2452,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
2452 val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); 2461 val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
2453 bus->sdcnt.f1regdata++; 2462 bus->sdcnt.f1regdata++;
2454 if (ret != 0) 2463 if (ret != 0)
2455 val = 0; 2464 return ret;
2456 2465
2457 val &= bus->hostintmask; 2466 val &= bus->hostintmask;
2458 atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); 2467 atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
@@ -2461,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
2461 if (val) { 2470 if (val) {
2462 brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); 2471 brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
2463 bus->sdcnt.f1regdata++; 2472 bus->sdcnt.f1regdata++;
2464 } 2473 atomic_orr(val, &bus->intstatus);
2465
2466 if (ret) {
2467 atomic_set(&bus->intstatus, 0);
2468 } else if (val) {
2469 for_each_set_bit(n, &val, 32)
2470 set_bit(n, (unsigned long *)&bus->intstatus.counter);
2471 } 2474 }
2472 2475
2473 return ret; 2476 return ret;
@@ -2479,7 +2482,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
2479 unsigned long intstatus; 2482 unsigned long intstatus;
2480 uint txlimit = bus->txbound; /* Tx frames to send before resched */ 2483 uint txlimit = bus->txbound; /* Tx frames to send before resched */
2481 uint framecnt; /* Temporary counter of tx/rx frames */ 2484 uint framecnt; /* Temporary counter of tx/rx frames */
2482 int err = 0, n; 2485 int err = 0;
2483 2486
2484 brcmf_dbg(TRACE, "Enter\n"); 2487 brcmf_dbg(TRACE, "Enter\n");
2485 2488
@@ -2583,10 +2586,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
2583 } 2586 }
2584 2587
2585 /* Keep still-pending events for next scheduling */ 2588 /* Keep still-pending events for next scheduling */
2586 if (intstatus) { 2589 if (intstatus)
2587 for_each_set_bit(n, &intstatus, 32) 2590 atomic_orr(intstatus, &bus->intstatus);
2588 set_bit(n, (unsigned long *)&bus->intstatus.counter);
2589 }
2590 2591
2591 brcmf_sdio_clrintr(bus); 2592 brcmf_sdio_clrintr(bus);
2592 2593