diff options
-rw-r--r-- | drivers/mmc/card/block.c | 17 | ||||
-rw-r--r-- | drivers/mmc/card/mmc_test.c | 85 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 5 | ||||
-rw-r--r-- | drivers/mmc/host/au1xmmc.c | 8 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 3 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 15 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 2 |
7 files changed, 40 insertions, 95 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 66e5a5487c2..86dbb366415 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -213,7 +213,8 @@ 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, sg_pos, data_size; + int ret = 1, data_size, i; + struct scatterlist *sg; mmc_claim_host(card->host); @@ -267,18 +268,22 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_queue_bounce_pre(mq); + /* + * Adjust the sg list so it is the same size as the + * request. + */ 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; + for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) { + data_size -= sg->length; if (data_size <= 0) { - mq->sg[sg_pos].length += data_size; - sg_pos++; + sg->length += data_size; + i++; break; } } - brq.data.sg_len = sg_pos; + brq.data.sg_len = i; } mmc_wait_for_req(card->host, &brq.mrq); diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index a067fe43630..f26b01d811a 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -388,16 +388,14 @@ static int mmc_test_transfer(struct mmc_test_card *test, int ret, i; unsigned long flags; - BUG_ON(blocks * blksz > BUFFER_SIZE); - if (write) { for (i = 0;i < blocks * blksz;i++) test->scratch[i] = i; } else { - memset(test->scratch, 0, blocks * blksz); + memset(test->scratch, 0, BUFFER_SIZE); } local_irq_save(flags); - sg_copy_from_buffer(sg, sg_len, test->scratch, blocks * blksz); + sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); local_irq_restore(flags); ret = mmc_test_set_blksize(test, blksz); @@ -444,7 +442,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, } } else { local_irq_save(flags); - sg_copy_to_buffer(sg, sg_len, test->scratch, blocks * blksz); + sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); local_irq_restore(flags); for (i = 0;i < blocks * blksz;i++) { if (test->scratch[i] != (u8)i) @@ -805,69 +803,6 @@ static int mmc_test_multi_xfersize_read(struct mmc_test_card *test) return 0; } -static int mmc_test_bigsg_write(struct mmc_test_card *test) -{ - int ret; - unsigned int size; - struct scatterlist sg; - - if (test->card->host->max_blk_count == 1) - return RESULT_UNSUP_HOST; - - size = PAGE_SIZE * 2; - size = min(size, test->card->host->max_req_size); - size = min(size, test->card->host->max_seg_size); - size = min(size, test->card->host->max_blk_count * 512); - - memset(test->buffer, 0, BUFFER_SIZE); - - if (size < 1024) - return RESULT_UNSUP_HOST; - - sg_init_table(&sg, 1); - sg_init_one(&sg, test->buffer, BUFFER_SIZE); - - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); - if (ret) - return ret; - - return 0; -} - -static int mmc_test_bigsg_read(struct mmc_test_card *test) -{ - int ret, i; - unsigned int size; - struct scatterlist sg; - - if (test->card->host->max_blk_count == 1) - return RESULT_UNSUP_HOST; - - size = PAGE_SIZE * 2; - size = min(size, test->card->host->max_req_size); - size = min(size, test->card->host->max_seg_size); - size = min(size, test->card->host->max_blk_count * 512); - - if (size < 1024) - return RESULT_UNSUP_HOST; - - memset(test->buffer, 0xCD, BUFFER_SIZE); - - sg_init_table(&sg, 1); - sg_init_one(&sg, test->buffer, BUFFER_SIZE); - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); - if (ret) - return ret; - - /* mmc_test_transfer() doesn't check for read overflows */ - for (i = size;i < BUFFER_SIZE;i++) { - if (test->buffer[i] != 0xCD) - return RESULT_FAIL; - } - - return 0; -} - #ifdef CONFIG_HIGHMEM static int mmc_test_write_high(struct mmc_test_card *test) @@ -1071,20 +1006,6 @@ static const struct mmc_test_case mmc_test_cases[] = { .run = mmc_test_multi_xfersize_read, }, - { - .name = "Over-sized SG list write", - .prepare = mmc_test_prepare_write, - .run = mmc_test_bigsg_write, - .cleanup = mmc_test_cleanup, - }, - - { - .name = "Over-sized SG list read", - .prepare = mmc_test_prepare_read, - .run = mmc_test_bigsg_read, - .cleanup = mmc_test_cleanup, - }, - #ifdef CONFIG_HIGHMEM { diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3ee5b8c3b5c..044d84eeed7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -121,6 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { #ifdef CONFIG_MMC_DEBUG unsigned int i, sz; + struct scatterlist *sg; #endif pr_debug("%s: starting CMD%u arg %08x flags %08x\n", @@ -156,8 +157,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) #ifdef CONFIG_MMC_DEBUG sz = 0; - for (i = 0;i < mrq->data->sg_len;i++) - sz += mrq->data->sg[i].length; + for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) + sz += sg->length; BUG_ON(sz != mrq->data->blocks * mrq->data->blksz); #endif diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 99b20917cc0..d3f55615c09 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -61,7 +61,13 @@ /* Hardware definitions */ #define AU1XMMC_DESCRIPTOR_COUNT 1 -#define AU1XMMC_DESCRIPTOR_SIZE 2048 + +/* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */ +#ifdef CONFIG_SOC_AU1100 +#define AU1XMMC_DESCRIPTOR_SIZE 0x0000ffff +#else /* Au1200 */ +#define AU1XMMC_DESCRIPTOR_SIZE 0x003fffff +#endif #define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index deb607c52c0..fcb14c2346c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -143,7 +143,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip) chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | - SDHCI_QUIRK_RESET_AFTER_REQUEST; + SDHCI_QUIRK_RESET_AFTER_REQUEST | + SDHCI_QUIRK_BROKEN_SMALL_PIO; } /* diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5f95e10229b..e3a8133560a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -278,6 +278,15 @@ static void sdhci_transfer_pio(struct sdhci_host *host) else mask = SDHCI_SPACE_AVAILABLE; + /* + * Some controllers (JMicron JMB38x) mess up the buffer bits + * for transfers < 4 bytes. As long as it is just one block, + * we can ignore the bits. + */ + if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) && + (host->data->blocks == 1)) + mask = ~0; + while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { if (host->data->flags & MMC_DATA_READ) sdhci_read_block_pio(host); @@ -439,7 +448,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, host->adma_addr = dma_map_single(mmc_dev(host->mmc), host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); - if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) + if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr)) goto unmap_entries; BUG_ON(host->adma_addr & 0x3); @@ -645,7 +654,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) * us an invalid request. */ WARN_ON(1); - host->flags &= ~SDHCI_USE_DMA; + host->flags &= ~SDHCI_REQ_USE_DMA; } else { writel(host->adma_addr, host->ioaddr + SDHCI_ADMA_ADDRESS); @@ -664,7 +673,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) * us an invalid request. */ WARN_ON(1); - host->flags &= ~SDHCI_USE_DMA; + host->flags &= ~SDHCI_REQ_USE_DMA; } else { WARN_ON(sg_cnt != 1); writel(sg_dma_address(data->sg), diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e354faee5df..197d4a05f4a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -206,6 +206,8 @@ struct sdhci_host { #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) /* Controller provides an incorrect timeout value for transfers */ #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) +/* Controller has an issue with buffer bits for small transfers */ +#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ |