Skip to content

Commit

Permalink
mmc: block: add member in mmc queue struct to hold request data
Browse files Browse the repository at this point in the history
The way the request data is organized in the mmc queue struct, it only
allows processing of one request at a time.  This patch adds a new struct
to hold mmc queue request data such as sg list, request, blk request and
bounce buffers, and updates any functions depending on the mmc queue
struct. This prepares for using multiple active requests in one mmc queue.

Signed-off-by: Per Forlin <per.forlin@linaro.org>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Venkatraman S <svenkatr@ti.com>
Tested-by: Sourav Poddar <sourav.poddar@ti.com>
Tested-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
  • Loading branch information
Per Forlin authored and Chris Ball committed Jul 20, 2011
1 parent bf04333 commit 97868a2
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 128 deletions.
109 changes: 51 additions & 58 deletions drivers/mmc/card/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,14 +427,6 @@ static const struct block_device_operations mmc_bdops = {
#endif
};

struct mmc_blk_request {
struct mmc_request mrq;
struct mmc_command sbc;
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_data data;
};

static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md)
{
Expand Down Expand Up @@ -824,7 +816,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq;
struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
int ret = 1, disable_multi = 0, retry = 0;

/*
Expand All @@ -839,60 +831,60 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
do {
u32 readcmd, writecmd;

memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
memset(brq, 0, sizeof(struct mmc_blk_request));
brq->mrq.cmd = &brq->cmd;
brq->mrq.data = &brq->data;

brq.cmd.arg = blk_rq_pos(req);
brq->cmd.arg = blk_rq_pos(req);
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 512;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
brq.data.blocks = blk_rq_sectors(req);
brq->cmd.arg <<= 9;
brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
brq->data.blksz = 512;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
brq->data.blocks = blk_rq_sectors(req);

/*
* The block layer doesn't support all sector count
* restrictions, so we need to be prepared for too big
* requests.
*/
if (brq.data.blocks > card->host->max_blk_count)
brq.data.blocks = card->host->max_blk_count;
if (brq->data.blocks > card->host->max_blk_count)
brq->data.blocks = card->host->max_blk_count;

/*
* After a read error, we redo the request one sector at a time
* in order to accurately determine which sectors can be read
* successfully.
*/
if (disable_multi && brq.data.blocks > 1)
brq.data.blocks = 1;
if (disable_multi && brq->data.blocks > 1)
brq->data.blocks = 1;

if (brq.data.blocks > 1 || do_rel_wr) {
if (brq->data.blocks > 1 || do_rel_wr) {
/* SPI multiblock writes terminate using a special
* token, not a STOP_TRANSMISSION request.
*/
if (!mmc_host_is_spi(card->host) ||
rq_data_dir(req) == READ)
brq.mrq.stop = &brq.stop;
brq->mrq.stop = &brq->stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else {
brq.mrq.stop = NULL;
brq->mrq.stop = NULL;
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
}
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = readcmd;
brq.data.flags |= MMC_DATA_READ;
brq->cmd.opcode = readcmd;
brq->data.flags |= MMC_DATA_READ;
} else {
brq.cmd.opcode = writecmd;
brq.data.flags |= MMC_DATA_WRITE;
brq->cmd.opcode = writecmd;
brq->data.flags |= MMC_DATA_WRITE;
}

if (do_rel_wr)
mmc_apply_rel_rw(&brq, card, req);
mmc_apply_rel_rw(brq, card, req);

/*
* Pre-defined multi-block transfers are preferable to
Expand All @@ -914,44 +906,44 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
*/

if ((md->flags & MMC_BLK_CMD23) &&
mmc_op_multi(brq.cmd.opcode) &&
mmc_op_multi(brq->cmd.opcode) &&
(do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
brq.sbc.arg = brq.data.blocks |
brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
brq->sbc.arg = brq->data.blocks |
(do_rel_wr ? (1 << 31) : 0);
brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
brq.mrq.sbc = &brq.sbc;
brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
brq->mrq.sbc = &brq->sbc;
}

mmc_set_data_timeout(&brq.data, card);
mmc_set_data_timeout(&brq->data, card);

brq.data.sg = mq->sg;
brq.data.sg_len = mmc_queue_map_sg(mq);
brq->data.sg = mq->mqrq_cur->sg;
brq->data.sg_len = mmc_queue_map_sg(mq, mq->mqrq_cur);

/*
* Adjust the sg list so it is the same size as the
* request.
*/
if (brq.data.blocks != blk_rq_sectors(req)) {
int i, data_size = brq.data.blocks << 9;
if (brq->data.blocks != blk_rq_sectors(req)) {
int i, data_size = brq->data.blocks << 9;
struct scatterlist *sg;

for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
data_size -= sg->length;
if (data_size <= 0) {
sg->length += data_size;
i++;
break;
}
}
brq.data.sg_len = i;
brq->data.sg_len = i;
}

mmc_queue_bounce_pre(mq);
mmc_queue_bounce_pre(mq->mqrq_cur);

mmc_wait_for_req(card->host, &brq.mrq);
mmc_wait_for_req(card->host, &brq->mrq);

mmc_queue_bounce_post(mq);
mmc_queue_bounce_post(mq->mqrq_cur);

/*
* sbc.error indicates a problem with the set block count
Expand All @@ -963,8 +955,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
* stop.error indicates a problem with the stop command. Data
* may have been transferred, or may still be transferring.
*/
if (brq.sbc.error || brq.cmd.error || brq.stop.error) {
switch (mmc_blk_cmd_recovery(card, req, &brq)) {
if (brq->sbc.error || brq->cmd.error || brq->stop.error) {
switch (mmc_blk_cmd_recovery(card, req, brq)) {
case ERR_RETRY:
if (retry++ < 5)
continue;
Expand All @@ -980,9 +972,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
* initial command - such as address errors. No data
* has been transferred.
*/
if (brq.cmd.resp[0] & CMD_ERRORS) {
if (brq->cmd.resp[0] & CMD_ERRORS) {
pr_err("%s: r/w command failed, status = %#x\n",
req->rq_disk->disk_name, brq.cmd.resp[0]);
req->rq_disk->disk_name, brq->cmd.resp[0]);
goto cmd_abort;
}

Expand All @@ -1009,15 +1001,15 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
(R1_CURRENT_STATE(status) == R1_STATE_PRG));
}

if (brq.data.error) {
if (brq->data.error) {
pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
req->rq_disk->disk_name, brq.data.error,
req->rq_disk->disk_name, brq->data.error,
(unsigned)blk_rq_pos(req),
(unsigned)blk_rq_sectors(req),
brq.cmd.resp[0], brq.stop.resp[0]);
brq->cmd.resp[0], brq->stop.resp[0]);

if (rq_data_dir(req) == READ) {
if (brq.data.blocks > 1) {
if (brq->data.blocks > 1) {
/* Redo read one sector at a time */
pr_warning("%s: retrying using single block read\n",
req->rq_disk->disk_name);
Expand All @@ -1031,7 +1023,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
* read a single sector.
*/
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, -EIO, brq.data.blksz);
ret = __blk_end_request(req, -EIO,
brq->data.blksz);
spin_unlock_irq(&md->lock);
continue;
} else {
Expand All @@ -1043,7 +1036,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
* A block was successfully transferred.
*/
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
} while (ret);

Expand All @@ -1069,7 +1062,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
}
} else {
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
}

Expand Down
Loading

0 comments on commit 97868a2

Please sign in to comment.