diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2014-03-06 04:16:12 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-03-06 14:29:58 -0500 |
commit | 5cbb9c285bdcc14ee381120dab7e23a81060f1c0 (patch) | |
tree | fa65f4a61ef1a7ab8569710564610abdeed29a43 /drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |
parent | 561e722201e41e304936b8a2aaa282c46ad4f393 (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.c | 29 |
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 | ||
2442 | static 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 | |||
2442 | static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) | 2451 | static 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 | ||