Skip to content

Commit

Permalink
brcmfmac: decrease the range of SDIO access lock
Browse files Browse the repository at this point in the history
Semaphore sdsem which protects consecutive SDIO bus access is used
to lock down unnecessary wide range. Decrease the locking range
provides the capability of parallel processing.

Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Franky Lin authored and John W. Linville committed Nov 14, 2012
1 parent dd43a01 commit 7cdf57d
Showing 1 changed file with 34 additions and 28 deletions.
62 changes: 34 additions & 28 deletions drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
* read directly into the chained packet, or allocate a large
* packet and and copy into the chain.
*/
down(&bus->sdsem);
if (usechain) {
errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
bus->sdiodev->sbwad,
Expand All @@ -1295,6 +1296,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
dlen);
errcode = -1;
}
up(&bus->sdsem);
bus->sdcnt.f2rxdata++;

/* On failure, kill the superframe, allow a couple retries */
Expand Down Expand Up @@ -1399,11 +1401,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
pfirst->prev);
}
/* sent any remaining packets up */
if (bus->glom.qlen) {
up(&bus->sdsem);
if (bus->glom.qlen)
brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
down(&bus->sdsem);
}

bus->sdcnt.rxglomframes++;
bus->sdcnt.rxglompkts += bus->glom.qlen;
Expand Down Expand Up @@ -1586,6 +1585,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)

rd->len_left = rd->len;
/* read header first for unknow frame length */
down(&bus->sdsem);
if (!rd->len) {
sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
bus->sdiodev->sbwad,
Expand All @@ -1598,6 +1598,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
sdret);
bus->sdcnt.rx_hdrfail++;
brcmf_sdbrcm_rxfail(bus, true, true);
up(&bus->sdsem);
continue;
}

Expand All @@ -1607,6 +1608,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)

if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
BRCMF_SDIO_FT_NORMAL)) {
up(&bus->sdsem);
if (!bus->rxpending)
break;
else
Expand All @@ -1622,6 +1624,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
rd->len_nxtfrm = 0;
/* treat all packet as event if we don't know */
rd->channel = SDPCM_EVENT_CHANNEL;
up(&bus->sdsem);
continue;
}
rd->len_left = rd->len > BRCMF_FIRSTREAD ?
Expand All @@ -1639,6 +1642,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
bus->sdiodev->bus_if->dstats.rx_dropped++;
brcmf_sdbrcm_rxfail(bus, false,
RETRYCHAN(rd->channel));
up(&bus->sdsem);
continue;
}
skb_pull(pkt, head_read);
Expand All @@ -1647,6 +1651,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, pkt);
bus->sdcnt.f2rxdata++;
up(&bus->sdsem);

if (sdret < 0) {
brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n",
Expand Down Expand Up @@ -1749,10 +1754,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
continue;
}

/* Unlock during rx call */
up(&bus->sdsem);
brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
down(&bus->sdsem);
}

rxcount = maxframes - rxleft;
Expand All @@ -1772,9 +1774,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
static void
brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar)
{
up(&bus->sdsem);
wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2);
down(&bus->sdsem);
return;
}

Expand Down Expand Up @@ -1879,6 +1879,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
if (len & (ALIGNMENT - 1))
len = roundup(len, ALIGNMENT);

down(&bus->sdsem);
ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, pkt);
bus->sdcnt.f2txdata++;
Expand Down Expand Up @@ -1906,15 +1907,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
}

}
up(&bus->sdsem);
if (ret == 0)
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;

done:
/* restore pkt buffer pointer before calling tx complete routine */
skb_pull(pkt, SDPCM_HDRLEN + pad);
up(&bus->sdsem);
brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
down(&bus->sdsem);

if (free_pkt)
brcmu_pkt_buf_free_skb(pkt);
Expand Down Expand Up @@ -1955,9 +1955,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
/* Check device status, signal pending interrupt */
down(&bus->sdsem);
ret = r_sdreg32(bus, &intstatus,
offsetof(struct sdpcmd_regs,
intstatus));
up(&bus->sdsem);
bus->sdcnt.f2txdata++;
if (ret != 0)
break;
Expand Down Expand Up @@ -2028,6 +2030,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)

/* Turn off the backplane clock (only) */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
up(&bus->sdsem);

/* Clear the data packet queues */
brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
Expand All @@ -2046,8 +2049,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
/* Reset some F2 state stuff */
bus->rxskip = false;
bus->tx_seq = bus->rx_seq = 0;

up(&bus->sdsem);
}

#ifdef CONFIG_BRCMFMAC_SDIO_OOB
Expand Down Expand Up @@ -2216,6 +2217,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
intstatus |= brcmf_sdbrcm_hostmail(bus);
}

up(&bus->sdsem);

/* Generally don't ask for these, can get CRC errors... */
if (intstatus & I_WR_OOSYNC) {
brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
Expand Down Expand Up @@ -2262,6 +2265,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
(bus->clkstate == CLK_AVAIL)) {
int i;

down(&bus->sdsem);
err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,
(u32) bus->ctrl_frame_len);
Expand Down Expand Up @@ -2295,6 +2299,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
} else {
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
}
up(&bus->sdsem);
bus->ctrl_frame_stat = false;
brcmf_sdbrcm_wait_event_wakeup(bus);
}
Expand Down Expand Up @@ -2326,8 +2331,6 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
bus->activity = false;
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
}

up(&bus->sdsem);
}

static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
Expand Down Expand Up @@ -2618,11 +2621,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)

/* precondition: IS_ALIGNED((unsigned long)frame, 2) */

/* Need to lock here to protect txseq and SDIO tx calls */
down(&bus->sdsem);

/* Make sure backplane clock is on */
down(&bus->sdsem);
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
up(&bus->sdsem);

/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
*(__le16 *) frame = cpu_to_le16((u16) msglen);
Expand Down Expand Up @@ -2664,7 +2666,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
frame, min_t(u16, len, 16), "TxHdr:\n");

do {
down(&bus->sdsem);
ret = brcmf_tx_frame(bus, frame, len);
up(&bus->sdsem);
} while (ret < 0 && retries++ < TXRETRIES);
}

Expand All @@ -2674,13 +2678,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);

bus->activity = false;
down(&bus->sdsem);
brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
up(&bus->sdsem);
} else {
spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
}

up(&bus->sdsem);

if (ret)
bus->sdcnt.tx_ctlerrs++;
else
Expand Down Expand Up @@ -2710,8 +2714,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
* Read last word in socram to determine
* address of sdpcm_shared structure
*/
down(&bus->sdsem);
rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
(u8 *)&addr_le, 4);
up(&bus->sdsem);
if (rv < 0)
return rv;

Expand Down Expand Up @@ -2834,12 +2840,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
return 0;

down(&bus->sdsem);
error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
sizeof(struct brcmf_trap_info));
if (error < 0)
return error;

nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
up(&bus->sdsem);
if (nbytes < 0)
return nbytes;

Expand Down Expand Up @@ -2885,6 +2893,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
return 0;
}

down(&bus->sdsem);
if (sh->assert_file_addr != 0) {
error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
(u8 *)file, 80);
Expand All @@ -2897,6 +2906,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
if (error < 0)
return error;
}
up(&bus->sdsem);

res = scnprintf(buf, sizeof(buf),
"dongle assert: %s:%d: assert(%s)\n",
Expand All @@ -2909,9 +2919,7 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
int error;
struct sdpcm_shared sh;

down(&bus->sdsem);
error = brcmf_sdio_readshared(bus, &sh);
up(&bus->sdsem);

if (error < 0)
return error;
Expand All @@ -2938,7 +2946,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
if (pos != 0)
return 0;

down(&bus->sdsem);
error = brcmf_sdio_readshared(bus, &sh);
if (error < 0)
goto done;
Expand All @@ -2955,7 +2962,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
error += nbytes;
*ppos += error;
done:
up(&bus->sdsem);
return error;
}

Expand Down Expand Up @@ -3511,8 +3517,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)

brcmf_dbg(TIMER, "Enter\n");

down(&bus->sdsem);

/* Poll period: check device if appropriate. */
if (bus->poll && (++bus->polltick >= bus->pollrate)) {
u32 intstatus = 0;
Expand Down Expand Up @@ -3561,11 +3565,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) {
bus->console.count -= bus->console_interval;
down(&bus->sdsem);
/* Make sure backplane clock is on */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
if (brcmf_sdbrcm_readconsole(bus) < 0)
/* stop on error */
bus->console_interval = 0;
up(&bus->sdsem);
}
}
#endif /* DEBUG */
Expand All @@ -3578,13 +3584,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
bus->activity = false;
brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
} else {
down(&bus->sdsem);
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
up(&bus->sdsem);
}
}
}

up(&bus->sdsem);

return (atomic_read(&bus->ipend) > 0);
}

Expand Down

0 comments on commit 7cdf57d

Please sign in to comment.