Skip to content

Commit

Permalink
brcm80211: fmac: separate receiving skb chain from other receive path
Browse files Browse the repository at this point in the history
In the receive path the buffer used to store the receive data from the
device can be a chain of sk_buff. It has been separated to allow the
use of skb queues.

Reported-by: Johannes Berg <johannes@sipsolutions.net>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Alwin Beukers <alwin@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Arend van Spriel authored and John W. Linville committed Nov 28, 2011
1 parent 3030794 commit 5adfeb6
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 77 deletions.
116 changes: 97 additions & 19 deletions drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,12 @@ bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
return sdiodev->regfail;
}

int
brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags,
u8 *buf, uint nbytes, struct sk_buff *pkt)
static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
uint flags, uint width, u32 *addr)
{
int status;
uint incr_fix;
uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;

brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);

/* Async not implemented yet */
if (flags & SDIO_REQ_ASYNC)
return -ENOTSUPP;
Expand All @@ -247,29 +240,114 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
sdiodev->sbwad = bar0;
}

addr &= SBSDIO_SB_OFT_ADDR_MASK;
*addr &= SBSDIO_SB_OFT_ADDR_MASK;

if (width == 4)
*addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;

return 0;
}

int
brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes)
{
struct sk_buff *mypkt;
int err;

mypkt = brcmu_pkt_buf_get_skb(nbytes);
if (!mypkt) {
brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
nbytes);
return -EIO;
}

err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
if (!err)
memcpy(buf, mypkt->data, nbytes);

brcmu_pkt_buf_free_skb(mypkt);
return err;
}

int
brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt)
{
uint incr_fix;
uint width;
int err = 0;

brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);

width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
if (err)
return err;

incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
fn, addr, width, 0, NULL, pkt);

return err;
}

int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq)
{
uint incr_fix;
uint width;
int err = 0;

brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);

width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
if (err)
return err;

status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
fn, addr, width, nbytes, buf, pkt);
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
pktq);

return status;
return err;
}

int
brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt)
uint flags, u8 *buf, uint nbytes)
{
struct sk_buff *mypkt;
int err;

mypkt = brcmu_pkt_buf_get_skb(nbytes);
if (!mypkt) {
brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
nbytes);
return -EIO;
}

memcpy(mypkt->data, buf, nbytes);
err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);

brcmu_pkt_buf_free_skb(mypkt);
return err;

}

int
brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt)
{
uint incr_fix;
uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;

brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);

/* Async not implemented yet */
if (flags & SDIO_REQ_ASYNC)
Expand All @@ -291,7 +369,7 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;

return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
addr, width, nbytes, buf, pkt);
addr, width, 0, NULL, pkt);
}

int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
Expand Down
97 changes: 72 additions & 25 deletions drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,79 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
return err_ret;
}

/* precondition: host controller is claimed */
static int
brcmf_sdioh_request_data(struct brcmf_sdio_dev *sdiodev, uint write, bool fifo,
uint func, uint addr, struct sk_buff *pkt, uint pktlen)
{
int err_ret = 0;

if ((write) && (!fifo)) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pkt->data)), pktlen);
} else if (write) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pkt->data)), pktlen);
} else if (fifo) {
err_ret = sdio_readsb(sdiodev->func[func],
((u8 *) (pkt->data)), addr, pktlen);
} else {
err_ret = sdio_memcpy_fromio(sdiodev->func[func],
((u8 *) (pkt->data)),
addr, pktlen);
}

return err_ret;
}

static int
brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
uint write, uint func, uint addr,
struct sk_buff *pkt)
{
bool fifo = (fix_inc == SDIOH_DATA_FIX);
int err_ret = 0;
uint pkt_len = pkt->len;

brcmf_dbg(TRACE, "Enter\n");

brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait);
if (brcmf_pm_resume_error(sdiodev))
return -EIO;

/* Claim host controller */
sdio_claim_host(sdiodev->func[func]);

pkt_len += 3;
pkt_len &= 0xFFFFFFFC;

err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
addr, pkt, pkt_len);
if (err_ret) {
brcmf_dbg(ERROR, "%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
write ? "TX" : "RX", pkt, addr, pkt_len, err_ret);
} else {
brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pkt, addr, pkt_len);
}

/* Release host controller */
sdio_release_host(sdiodev->func[func]);

brcmf_dbg(TRACE, "Exit\n");
return err_ret;
}

int
brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
uint write, uint func, uint addr,
struct sk_buff_head *pktq)
{
bool fifo = (fix_inc == SDIOH_DATA_FIX);
u32 SGCount = 0;
int err_ret = 0;

struct sk_buff *pnext;
struct sk_buff *pkt;

brcmf_dbg(TRACE, "Enter\n");

Expand All @@ -223,43 +286,27 @@ brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,

/* Claim host controller */
sdio_claim_host(sdiodev->func[func]);
for (pnext = pkt; pnext; pnext = pnext->next) {
uint pkt_len = pnext->len;

skb_queue_walk(pktq, pkt) {
uint pkt_len = pkt->len;
pkt_len += 3;
pkt_len &= 0xFFFFFFFC;

if ((write) && (!fifo)) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pnext->data)),
pkt_len);
} else if (write) {
err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pnext->data)),
pkt_len);
} else if (fifo) {
err_ret = sdio_readsb(sdiodev->func[func],
((u8 *) (pnext->data)),
addr, pkt_len);
} else {
err_ret = sdio_memcpy_fromio(sdiodev->func[func],
((u8 *) (pnext->data)),
addr, pkt_len);
}

err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
addr, pkt, pkt_len);
if (err_ret) {
brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
write ? "TX" : "RX", pnext, SGCount, addr,
write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len, err_ret);
} else {
brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pnext, SGCount, addr,
write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len);
}

if (!fifo)
addr += pkt_len;
SGCount++;

SGCount++;
}

/* Release host controller */
Expand Down
Loading

0 comments on commit 5adfeb6

Please sign in to comment.