Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: au1xmmc: raise segment size limit. mmc_block: use proper sg iterators mmc: properly iterate over sg list in debug check mmc_test: Revert "mmc_test: test oversized sg lists" sdhci: check correct return value sdhci: disable DMA for req, not completely sdhci: handle bug in JMB38x for sizes < 4 bytes
This commit is contained in:
Коммит
b2bbf43e60
|
@ -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_blk_data *md = mq->data;
|
||||||
struct mmc_card *card = md->queue.card;
|
struct mmc_card *card = md->queue.card;
|
||||||
struct mmc_blk_request brq;
|
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);
|
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);
|
mmc_queue_bounce_pre(mq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust the sg list so it is the same size as the
|
||||||
|
* request.
|
||||||
|
*/
|
||||||
if (brq.data.blocks !=
|
if (brq.data.blocks !=
|
||||||
(req->nr_sectors >> (md->block_bits - 9))) {
|
(req->nr_sectors >> (md->block_bits - 9))) {
|
||||||
data_size = brq.data.blocks * brq.data.blksz;
|
data_size = brq.data.blocks * brq.data.blksz;
|
||||||
for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
|
for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
|
||||||
data_size -= mq->sg[sg_pos].length;
|
data_size -= sg->length;
|
||||||
if (data_size <= 0) {
|
if (data_size <= 0) {
|
||||||
mq->sg[sg_pos].length += data_size;
|
sg->length += data_size;
|
||||||
sg_pos++;
|
i++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
brq.data.sg_len = sg_pos;
|
brq.data.sg_len = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmc_wait_for_req(card->host, &brq.mrq);
|
mmc_wait_for_req(card->host, &brq.mrq);
|
||||||
|
|
|
@ -388,16 +388,14 @@ static int mmc_test_transfer(struct mmc_test_card *test,
|
||||||
int ret, i;
|
int ret, i;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
BUG_ON(blocks * blksz > BUFFER_SIZE);
|
|
||||||
|
|
||||||
if (write) {
|
if (write) {
|
||||||
for (i = 0;i < blocks * blksz;i++)
|
for (i = 0;i < blocks * blksz;i++)
|
||||||
test->scratch[i] = i;
|
test->scratch[i] = i;
|
||||||
} else {
|
} else {
|
||||||
memset(test->scratch, 0, blocks * blksz);
|
memset(test->scratch, 0, BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
local_irq_save(flags);
|
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);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
ret = mmc_test_set_blksize(test, blksz);
|
ret = mmc_test_set_blksize(test, blksz);
|
||||||
|
@ -444,7 +442,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
local_irq_save(flags);
|
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);
|
local_irq_restore(flags);
|
||||||
for (i = 0;i < blocks * blksz;i++) {
|
for (i = 0;i < blocks * blksz;i++) {
|
||||||
if (test->scratch[i] != (u8)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;
|
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
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
|
||||||
static int mmc_test_write_high(struct mmc_test_card *test)
|
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,
|
.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
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -121,6 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_MMC_DEBUG
|
#ifdef CONFIG_MMC_DEBUG
|
||||||
unsigned int i, sz;
|
unsigned int i, sz;
|
||||||
|
struct scatterlist *sg;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
|
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
|
#ifdef CONFIG_MMC_DEBUG
|
||||||
sz = 0;
|
sz = 0;
|
||||||
for (i = 0;i < mrq->data->sg_len;i++)
|
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
|
||||||
sz += mrq->data->sg[i].length;
|
sz += sg->length;
|
||||||
BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
|
BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,13 @@
|
||||||
|
|
||||||
/* Hardware definitions */
|
/* Hardware definitions */
|
||||||
#define AU1XMMC_DESCRIPTOR_COUNT 1
|
#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 | \
|
#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 | \
|
MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
|
||||||
|
|
|
@ -143,7 +143,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
|
||||||
chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
|
chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
|
||||||
SDHCI_QUIRK_32BIT_DMA_SIZE |
|
SDHCI_QUIRK_32BIT_DMA_SIZE |
|
||||||
SDHCI_QUIRK_32BIT_ADMA_SIZE |
|
SDHCI_QUIRK_32BIT_ADMA_SIZE |
|
||||||
SDHCI_QUIRK_RESET_AFTER_REQUEST;
|
SDHCI_QUIRK_RESET_AFTER_REQUEST |
|
||||||
|
SDHCI_QUIRK_BROKEN_SMALL_PIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -278,6 +278,15 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
|
||||||
else
|
else
|
||||||
mask = SDHCI_SPACE_AVAILABLE;
|
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) {
|
while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
|
||||||
if (host->data->flags & MMC_DATA_READ)
|
if (host->data->flags & MMC_DATA_READ)
|
||||||
sdhci_read_block_pio(host);
|
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_addr = dma_map_single(mmc_dev(host->mmc),
|
||||||
host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
|
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;
|
goto unmap_entries;
|
||||||
BUG_ON(host->adma_addr & 0x3);
|
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.
|
* us an invalid request.
|
||||||
*/
|
*/
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
host->flags &= ~SDHCI_USE_DMA;
|
host->flags &= ~SDHCI_REQ_USE_DMA;
|
||||||
} else {
|
} else {
|
||||||
writel(host->adma_addr,
|
writel(host->adma_addr,
|
||||||
host->ioaddr + SDHCI_ADMA_ADDRESS);
|
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.
|
* us an invalid request.
|
||||||
*/
|
*/
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
host->flags &= ~SDHCI_USE_DMA;
|
host->flags &= ~SDHCI_REQ_USE_DMA;
|
||||||
} else {
|
} else {
|
||||||
WARN_ON(sg_cnt != 1);
|
WARN_ON(sg_cnt != 1);
|
||||||
writel(sg_dma_address(data->sg),
|
writel(sg_dma_address(data->sg),
|
||||||
|
|
|
@ -206,6 +206,8 @@ struct sdhci_host {
|
||||||
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11)
|
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11)
|
||||||
/* Controller provides an incorrect timeout value for transfers */
|
/* Controller provides an incorrect timeout value for transfers */
|
||||||
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
|
#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 */
|
int irq; /* Device IRQ */
|
||||||
void __iomem * ioaddr; /* Mapped address */
|
void __iomem * ioaddr; /* Mapped address */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче