Commit 5cbb9c28 authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville

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: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarDaniel (Deognyoun) Kim <dekim@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 561e7222
...@@ -2439,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) ...@@ -2439,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
} }
} }
static void atomic_orr(int val, atomic_t *v)
{
int old_val;
old_val = atomic_read(v);
while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
old_val = atomic_read(v);
}
static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
{ {
struct brcmf_core *buscore; struct brcmf_core *buscore;
u32 addr; u32 addr;
unsigned long val; unsigned long val;
int n, ret; int ret;
buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
...@@ -2452,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) ...@@ -2452,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
bus->sdcnt.f1regdata++; bus->sdcnt.f1regdata++;
if (ret != 0) if (ret != 0)
val = 0; return ret;
val &= bus->hostintmask; val &= bus->hostintmask;
atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
...@@ -2461,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) ...@@ -2461,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
if (val) { if (val) {
brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
bus->sdcnt.f1regdata++; bus->sdcnt.f1regdata++;
} atomic_orr(val, &bus->intstatus);
if (ret) {
atomic_set(&bus->intstatus, 0);
} else if (val) {
for_each_set_bit(n, &val, 32)
set_bit(n, (unsigned long *)&bus->intstatus.counter);
} }
return ret; return ret;
...@@ -2479,7 +2482,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) ...@@ -2479,7 +2482,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
unsigned long intstatus; unsigned long intstatus;
uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint txlimit = bus->txbound; /* Tx frames to send before resched */
uint framecnt; /* Temporary counter of tx/rx frames */ uint framecnt; /* Temporary counter of tx/rx frames */
int err = 0, n; int err = 0;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
...@@ -2583,10 +2586,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) ...@@ -2583,10 +2586,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
} }
/* Keep still-pending events for next scheduling */ /* Keep still-pending events for next scheduling */
if (intstatus) { if (intstatus)
for_each_set_bit(n, &intstatus, 32) atomic_orr(intstatus, &bus->intstatus);
set_bit(n, (unsigned long *)&bus->intstatus.counter);
}
brcmf_sdio_clrintr(bus); brcmf_sdio_clrintr(bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment