Skip to content

Commit

Permalink
mmc: cull sg list to match mmc request size
Browse files Browse the repository at this point in the history
mmc layer may introduce additional (compared to block layer) limits on
request size. Culling of the sg list to match adjusted request size
simplifies the handling of such cases in the low level driver, allowing
it to skip block count checks while processing sg entries.

(fixes for wbsd and sdhci by Pierre Ossman)

Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
  • Loading branch information
Alex Dubov authored and Pierre Ossman committed May 1, 2007
1 parent dc87c39 commit 14d836e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 129 deletions.
16 changes: 15 additions & 1 deletion drivers/mmc/mmc_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static int mmc_blk_issue_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;
int ret = 1;
int ret = 1, sg_pos, data_size;

if (mmc_card_claim_host(card))
goto flush_queue;
Expand Down Expand Up @@ -283,6 +283,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.sg = mq->sg;
brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);

if (brq.data.blocks !=
(req->nr_sectors >> (md->block_bits - 9))) {
data_size = brq.data.blocks * brq.data.blksz;
for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
data_size -= mq->sg[sg_pos].length;
if (data_size <= 0) {
mq->sg[sg_pos].length += data_size;
sg_pos++;
break;
}
}
brq.data.sg_len = sg_pos;
}

mmc_wait_for_req(card->host, &brq.mrq);
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write command\n",
Expand Down
24 changes: 7 additions & 17 deletions drivers/mmc/sdhci.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -247,14 +247,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = min(blksize, 4);
}

size = min(host->size, host->remain);
size = min(size, chunk_remain);
size = min(host->remain, chunk_remain);

chunk_remain -= size;
blksize -= size;
host->offset += size;
host->remain -= size;
host->size -= size;

while (size) {
*buffer = data & 0xFF;
buffer++;
Expand Down Expand Up @@ -289,14 +288,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
buffer = sdhci_sg_to_buffer(host) + host->offset;

while (blksize) {
size = min(host->size, host->remain);
size = min(size, chunk_remain);
size = min(host->remain, chunk_remain);

chunk_remain -= size;
blksize -= size;
host->offset += size;
host->remain -= size;
host->size -= size;

while (size) {
data >>= 8;
data |= (u32)*buffer << 24;
Expand Down Expand Up @@ -325,7 +323,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host)

BUG_ON(!host->data);

if (host->size == 0)
if (host->num_sg == 0)
return;

if (host->data->flags & MMC_DATA_READ)
Expand All @@ -339,10 +337,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
else
sdhci_write_block_pio(host);

if (host->size == 0)
if (host->num_sg == 0)
break;

BUG_ON(host->num_sg == 0);
}

DBG("PIO transfer complete.\n");
Expand Down Expand Up @@ -408,8 +404,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)

writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
} else {
host->size = data->blksz * data->blocks;

host->cur_sg = data->sg;
host->num_sg = data->sg_len;

Expand Down Expand Up @@ -473,10 +467,6 @@ static void sdhci_finish_data(struct sdhci_host *host)
"though there were blocks left.\n",
mmc_hostname(host->mmc));
data->error = MMC_ERR_FAILED;
} else if (host->size != 0) {
printk(KERN_ERR "%s: %d bytes were left untransferred.\n",
mmc_hostname(host->mmc), host->size);
data->error = MMC_ERR_FAILED;
}

DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
Expand Down
4 changes: 1 addition & 3 deletions drivers/mmc/sdhci.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -187,8 +187,6 @@ struct sdhci_host {
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */

int size; /* Remaining bytes in transfer */

char slot_descr[20]; /* Name for reservations */

int irq; /* Device IRQ */
Expand Down
Loading

0 comments on commit 14d836e

Please sign in to comment.