brcmfmac: determine host controller related variables during probe

Instead of determining the limits for scatter-gather MMC transfer
request upon each transmit it is now determined during the probe
of the SDIO function.

Reviewed-by: Franky Lin <frankyl@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Arend van Spriel 2013-10-15 15:44:49 +02:00 committed by John W. Linville
parent 3f782744f9
commit 71201496cf
3 changed files with 28 additions and 16 deletions

View File

@ -26,7 +26,6 @@
#include <linux/mmc/sdio.h> #include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/brcmfmac-sdio.h> #include <linux/platform_data/brcmfmac-sdio.h>
#include <defs.h> #include <defs.h>
@ -331,7 +330,7 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
bool write, u32 addr, struct sk_buff_head *pktlist) bool write, u32 addr, struct sk_buff_head *pktlist)
{ {
unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset; unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;
unsigned int max_blks, max_req_sz, orig_offset, dst_offset; unsigned int max_req_sz, orig_offset, dst_offset;
unsigned short max_seg_cnt, seg_sz; unsigned short max_seg_cnt, seg_sz;
unsigned char *pkt_data, *orig_data, *dst_data; unsigned char *pkt_data, *orig_data, *dst_data;
struct sk_buff *pkt_next = NULL, *local_pkt_next; struct sk_buff *pkt_next = NULL, *local_pkt_next;
@ -341,7 +340,6 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
struct mmc_data mmc_dat; struct mmc_data mmc_dat;
struct sg_table st; struct sg_table st;
struct scatterlist *sgl; struct scatterlist *sgl;
struct mmc_host *host;
int ret = 0; int ret = 0;
if (!pktlist->qlen) if (!pktlist->qlen)
@ -398,17 +396,10 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
target_list = &local_list; target_list = &local_list;
} }
host = sdiodev->func[fn]->card->host;
func_blk_sz = sdiodev->func[fn]->cur_blksize; func_blk_sz = sdiodev->func[fn]->cur_blksize;
/* Blocks per command is limited by host count, host transfer max_req_sz = sdiodev->max_request_size;
* size and the maximum for IO_RW_EXTENDED of 511 blocks. max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count,
*/ target_list->qlen);
max_blks = min_t(unsigned int, host->max_blk_count, 511u);
max_req_sz = min_t(unsigned int, host->max_req_size,
max_blks * func_blk_sz);
max_seg_cnt = min_t(unsigned short, host->max_segs,
SG_MAX_SINGLE_ALLOC);
max_seg_cnt = min_t(unsigned short, max_seg_cnt, target_list->qlen);
seg_sz = target_list->qlen; seg_sz = target_list->qlen;
pkt_offset = 0; pkt_offset = 0;
pkt_next = target_list->next; pkt_next = target_list->next;
@ -429,8 +420,8 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
while (pkt_next != (struct sk_buff *)target_list) { while (pkt_next != (struct sk_buff *)target_list) {
pkt_data = pkt_next->data + pkt_offset; pkt_data = pkt_next->data + pkt_offset;
sg_data_sz = pkt_next->len - pkt_offset; sg_data_sz = pkt_next->len - pkt_offset;
if (sg_data_sz > host->max_seg_size) if (sg_data_sz > sdiodev->max_segment_size)
sg_data_sz = host->max_seg_size; sg_data_sz = sdiodev->max_segment_size;
if (sg_data_sz > max_req_sz - req_sz) if (sg_data_sz > max_req_sz - req_sz)
sg_data_sz = max_req_sz - req_sz; sg_data_sz = max_req_sz - req_sz;
@ -476,7 +467,7 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
addr += req_sz; addr += req_sz;
mmc_set_data_timeout(&mmc_dat, sdiodev->func[fn]->card); mmc_set_data_timeout(&mmc_dat, sdiodev->func[fn]->card);
mmc_wait_for_req(host, &mmc_req); mmc_wait_for_req(sdiodev->func[fn]->card->host, &mmc_req);
ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error; ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
if (ret != 0) { if (ret != 0) {

View File

@ -21,6 +21,7 @@
#include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> /* request_irq() */ #include <linux/sched.h> /* request_irq() */
@ -315,6 +316,8 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
int err; int err;
struct brcmf_sdio_dev *sdiodev; struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if; struct brcmf_bus *bus_if;
struct mmc_host *host;
uint max_blocks;
brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class); brcmf_dbg(SDIO, "Class=%x\n", func->class);
@ -361,6 +364,20 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
brcmf_err("F2 error, probe failed %d...\n", err); brcmf_err("F2 error, probe failed %d...\n", err);
goto fail; goto fail;
} }
/*
* determine host related variables after brcmf_sdio_probe()
* as func->cur_blksize is properly set and F2 init has been
* completed successfully.
*/
host = func->card->host;
sdiodev->sg_support = host->max_segs > 1;
max_blocks = min_t(uint, host->max_blk_count, 511u);
sdiodev->max_request_size = min_t(uint, host->max_req_size,
max_blocks * func->cur_blksize);
sdiodev->max_segment_count = min_t(uint, host->max_segs,
SG_MAX_SINGLE_ALLOC);
sdiodev->max_segment_size = host->max_seg_size;
brcmf_dbg(SDIO, "F2 init completed...\n"); brcmf_dbg(SDIO, "F2 init completed...\n");
return 0; return 0;

View File

@ -178,6 +178,10 @@ struct brcmf_sdio_dev {
bool irq_en; /* irq enable flags */ bool irq_en; /* irq enable flags */
spinlock_t irq_en_lock; spinlock_t irq_en_lock;
bool irq_wake; /* irq wake enable flags */ bool irq_wake; /* irq wake enable flags */
bool sg_support;
uint max_request_size;
ushort max_segment_count;
uint max_segment_size;
}; };
/* Register/deregister interrupt handler. */ /* Register/deregister interrupt handler. */