Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+15 −14
Original line number Diff line number Diff line
@@ -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)
{
	struct brcmf_core *buscore;
	u32 addr;
	unsigned long val;
	int n, ret;
	int ret;

	buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
	addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
@@ -2452,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
	val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
	bus->sdcnt.f1regdata++;
	if (ret != 0)
		val = 0;
		return ret;

	val &= bus->hostintmask;
	atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
@@ -2461,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
	if (val) {
		brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
		bus->sdcnt.f1regdata++;
	}

	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);
		atomic_orr(val, &bus->intstatus);
	}

	return ret;
@@ -2479,7 +2482,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
	unsigned long intstatus;
	uint txlimit = bus->txbound;	/* Tx frames to send before resched */
	uint framecnt;			/* Temporary counter of tx/rx frames */
	int err = 0, n;
	int err = 0;

	brcmf_dbg(TRACE, "Enter\n");

@@ -2583,10 +2586,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
	}

	/* Keep still-pending events for next scheduling */
	if (intstatus) {
		for_each_set_bit(n, &intstatus, 32)
			set_bit(n, (unsigned long *)&bus->intstatus.counter);
	}
	if (intstatus)
		atomic_orr(intstatus, &bus->intstatus);

	brcmf_sdio_clrintr(bus);