mirror of https://gitee.com/openkylin/linux.git
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-mmc
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-mmc: [MMC] Don't check READY_FOR_DATA when reading [MMC] MMC_CAP_BYTEBLOCK flag for non-log2 block sizes capable hosts [MMC] Add multi block-write capability [MMC] Remove data->blksz_bits member [MMC] Convert mmci to use data->blksz rather than data->blksz_bits
This commit is contained in:
commit
fecf3404f4
|
@ -822,6 +822,7 @@ static int at91_mci_probe(struct platform_device *pdev)
|
||||||
mmc->f_min = 375000;
|
mmc->f_min = 375000;
|
||||||
mmc->f_max = 25000000;
|
mmc->f_max = 25000000;
|
||||||
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||||
|
mmc->caps = MMC_CAP_BYTEBLOCK;
|
||||||
|
|
||||||
host = mmc_priv(mmc);
|
host = mmc_priv(mmc);
|
||||||
host->mmc = mmc;
|
host->mmc = mmc;
|
||||||
|
|
|
@ -956,7 +956,7 @@ static int imxmci_probe(struct platform_device *pdev)
|
||||||
mmc->f_min = 150000;
|
mmc->f_min = 150000;
|
||||||
mmc->f_max = CLK_RATE/2;
|
mmc->f_max = CLK_RATE/2;
|
||||||
mmc->ocr_avail = MMC_VDD_32_33;
|
mmc->ocr_avail = MMC_VDD_32_33;
|
||||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
|
||||||
|
|
||||||
/* MMC core transfer sizes tunable parameters */
|
/* MMC core transfer sizes tunable parameters */
|
||||||
mmc->max_hw_segs = 64;
|
mmc->max_hw_segs = 64;
|
||||||
|
|
|
@ -996,7 +996,6 @@ static void mmc_read_scrs(struct mmc_host *host)
|
||||||
|
|
||||||
mmc_set_data_timeout(&data, card, 0);
|
mmc_set_data_timeout(&data, card, 0);
|
||||||
|
|
||||||
data.blksz_bits = 3;
|
|
||||||
data.blksz = 1 << 3;
|
data.blksz = 1 << 3;
|
||||||
data.blocks = 1;
|
data.blocks = 1;
|
||||||
data.flags = MMC_DATA_READ;
|
data.flags = MMC_DATA_READ;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/mmc/card.h>
|
#include <linux/mmc/card.h>
|
||||||
#include <linux/mmc/host.h>
|
#include <linux/mmc/host.h>
|
||||||
#include <linux/mmc/protocol.h>
|
#include <linux/mmc/protocol.h>
|
||||||
|
#include <linux/mmc/host.h>
|
||||||
|
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||||
do {
|
do {
|
||||||
struct mmc_blk_request brq;
|
struct mmc_blk_request brq;
|
||||||
struct mmc_command cmd;
|
struct mmc_command cmd;
|
||||||
|
u32 readcmd, writecmd;
|
||||||
|
|
||||||
memset(&brq, 0, sizeof(struct mmc_blk_request));
|
memset(&brq, 0, sizeof(struct mmc_blk_request));
|
||||||
brq.mrq.cmd = &brq.cmd;
|
brq.mrq.cmd = &brq.cmd;
|
||||||
|
@ -172,7 +174,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||||
|
|
||||||
brq.cmd.arg = req->sector << 9;
|
brq.cmd.arg = req->sector << 9;
|
||||||
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||||
brq.data.blksz_bits = md->block_bits;
|
|
||||||
brq.data.blksz = 1 << md->block_bits;
|
brq.data.blksz = 1 << md->block_bits;
|
||||||
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
|
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
|
||||||
brq.stop.opcode = MMC_STOP_TRANSMISSION;
|
brq.stop.opcode = MMC_STOP_TRANSMISSION;
|
||||||
|
@ -181,20 +182,31 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||||
|
|
||||||
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
|
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
|
||||||
|
|
||||||
if (rq_data_dir(req) == READ) {
|
/*
|
||||||
brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
|
* If the host doesn't support multiple block writes, force
|
||||||
brq.data.flags |= MMC_DATA_READ;
|
* block writes to single block.
|
||||||
} else {
|
*/
|
||||||
brq.cmd.opcode = MMC_WRITE_BLOCK;
|
if (rq_data_dir(req) != READ &&
|
||||||
brq.data.flags |= MMC_DATA_WRITE;
|
!(card->host->caps & MMC_CAP_MULTIWRITE))
|
||||||
brq.data.blocks = 1;
|
brq.data.blocks = 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (brq.data.blocks > 1) {
|
if (brq.data.blocks > 1) {
|
||||||
brq.data.flags |= MMC_DATA_MULTI;
|
brq.data.flags |= MMC_DATA_MULTI;
|
||||||
brq.mrq.stop = &brq.stop;
|
brq.mrq.stop = &brq.stop;
|
||||||
|
readcmd = MMC_READ_MULTIPLE_BLOCK;
|
||||||
|
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
|
||||||
} else {
|
} 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;
|
||||||
|
} else {
|
||||||
|
brq.cmd.opcode = writecmd;
|
||||||
|
brq.data.flags |= MMC_DATA_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
brq.data.sg = mq->sg;
|
brq.data.sg = mq->sg;
|
||||||
|
@ -219,27 +231,29 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||||
goto cmd_err;
|
goto cmd_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
if (rq_data_dir(req) != READ) {
|
||||||
int err;
|
do {
|
||||||
|
int err;
|
||||||
|
|
||||||
cmd.opcode = MMC_SEND_STATUS;
|
cmd.opcode = MMC_SEND_STATUS;
|
||||||
cmd.arg = card->rca << 16;
|
cmd.arg = card->rca << 16;
|
||||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||||
err = mmc_wait_for_cmd(card->host, &cmd, 5);
|
err = mmc_wait_for_cmd(card->host, &cmd, 5);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "%s: error %d requesting status\n",
|
printk(KERN_ERR "%s: error %d requesting status\n",
|
||||||
req->rq_disk->disk_name, err);
|
req->rq_disk->disk_name, err);
|
||||||
goto cmd_err;
|
goto cmd_err;
|
||||||
}
|
}
|
||||||
} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
|
} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (cmd.resp[0] & ~0x00000900)
|
if (cmd.resp[0] & ~0x00000900)
|
||||||
printk(KERN_ERR "%s: status = %08x\n",
|
printk(KERN_ERR "%s: status = %08x\n",
|
||||||
req->rq_disk->disk_name, cmd.resp[0]);
|
req->rq_disk->disk_name, cmd.resp[0]);
|
||||||
if (mmc_decode_status(cmd.resp))
|
if (mmc_decode_status(cmd.resp))
|
||||||
goto cmd_err;
|
goto cmd_err;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A block was successfully transferred.
|
* A block was successfully transferred.
|
||||||
|
|
|
@ -69,12 +69,13 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
|
||||||
unsigned int datactrl, timeout, irqmask;
|
unsigned int datactrl, timeout, irqmask;
|
||||||
unsigned long long clks;
|
unsigned long long clks;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
int blksz_bits;
|
||||||
|
|
||||||
DBG(host, "blksz %04x blks %04x flags %08x\n",
|
DBG(host, "blksz %04x blks %04x flags %08x\n",
|
||||||
1 << data->blksz_bits, data->blocks, data->flags);
|
data->blksz, data->blocks, data->flags);
|
||||||
|
|
||||||
host->data = data;
|
host->data = data;
|
||||||
host->size = data->blocks << data->blksz_bits;
|
host->size = data->blksz;
|
||||||
host->data_xfered = 0;
|
host->data_xfered = 0;
|
||||||
|
|
||||||
mmci_init_sg(host, data);
|
mmci_init_sg(host, data);
|
||||||
|
@ -88,7 +89,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
|
||||||
writel(timeout, base + MMCIDATATIMER);
|
writel(timeout, base + MMCIDATATIMER);
|
||||||
writel(host->size, base + MMCIDATALENGTH);
|
writel(host->size, base + MMCIDATALENGTH);
|
||||||
|
|
||||||
datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
|
blksz_bits = ffs(data->blksz) - 1;
|
||||||
|
BUG_ON(1 << blksz_bits != data->blksz);
|
||||||
|
|
||||||
|
datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
|
||||||
if (data->flags & MMC_DATA_READ) {
|
if (data->flags & MMC_DATA_READ) {
|
||||||
datactrl |= MCI_DPSM_DIRECTION;
|
datactrl |= MCI_DPSM_DIRECTION;
|
||||||
irqmask = MCI_RXFIFOHALFFULLMASK;
|
irqmask = MCI_RXFIFOHALFFULLMASK;
|
||||||
|
@ -145,7 +149,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
|
||||||
unsigned int status)
|
unsigned int status)
|
||||||
{
|
{
|
||||||
if (status & MCI_DATABLOCKEND) {
|
if (status & MCI_DATABLOCKEND) {
|
||||||
host->data_xfered += 1 << data->blksz_bits;
|
host->data_xfered += data->blksz;
|
||||||
}
|
}
|
||||||
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
|
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
|
||||||
if (status & MCI_DATACRCFAIL)
|
if (status & MCI_DATACRCFAIL)
|
||||||
|
@ -505,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
|
||||||
mmc->f_min = (host->mclk + 511) / 512;
|
mmc->f_min = (host->mclk + 511) / 512;
|
||||||
mmc->f_max = min(host->mclk, fmax);
|
mmc->f_max = min(host->mclk, fmax);
|
||||||
mmc->ocr_avail = plat->ocr_mask;
|
mmc->ocr_avail = plat->ocr_mask;
|
||||||
|
mmc->caps = MMC_CAP_MULTIWRITE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can do SGIO
|
* We can do SGIO
|
||||||
|
|
|
@ -1034,13 +1034,14 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
|
||||||
host->irq = pdev->resource[1].start;
|
host->irq = pdev->resource[1].start;
|
||||||
host->base = (void __iomem*)IO_ADDRESS(r->start);
|
host->base = (void __iomem*)IO_ADDRESS(r->start);
|
||||||
|
|
||||||
if (minfo->wire4)
|
|
||||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
|
||||||
|
|
||||||
mmc->ops = &mmc_omap_ops;
|
mmc->ops = &mmc_omap_ops;
|
||||||
mmc->f_min = 400000;
|
mmc->f_min = 400000;
|
||||||
mmc->f_max = 24000000;
|
mmc->f_max = 24000000;
|
||||||
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
|
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
|
||||||
|
mmc->caps = MMC_CAP_BYTEBLOCK;
|
||||||
|
|
||||||
|
if (minfo->wire4)
|
||||||
|
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||||
|
|
||||||
/* Use scatterlist DMA to reduce per-transfer costs.
|
/* Use scatterlist DMA to reduce per-transfer costs.
|
||||||
* NOTE max_seg_size assumption that small blocks aren't
|
* NOTE max_seg_size assumption that small blocks aren't
|
||||||
|
|
|
@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
|
||||||
mmc->ops = &sdhci_ops;
|
mmc->ops = &sdhci_ops;
|
||||||
mmc->f_min = host->max_clk / 256;
|
mmc->f_min = host->max_clk / 256;
|
||||||
mmc->f_max = host->max_clk;
|
mmc->f_max = host->max_clk;
|
||||||
mmc->caps = MMC_CAP_4_BIT_DATA;
|
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
|
||||||
|
|
||||||
mmc->ocr_avail = 0;
|
mmc->ocr_avail = 0;
|
||||||
if (caps & SDHCI_CAN_VDD_330)
|
if (caps & SDHCI_CAN_VDD_330)
|
||||||
|
|
|
@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
|
||||||
mmc->f_min = 375000;
|
mmc->f_min = 375000;
|
||||||
mmc->f_max = 24000000;
|
mmc->f_max = 24000000;
|
||||||
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||||
mmc->caps = MMC_CAP_4_BIT_DATA;
|
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
|
||||||
|
|
||||||
spin_lock_init(&host->lock);
|
spin_lock_init(&host->lock);
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,8 @@ struct mmc_host {
|
||||||
unsigned long caps; /* Host capabilities */
|
unsigned long caps; /* Host capabilities */
|
||||||
|
|
||||||
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
|
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
|
||||||
|
#define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */
|
||||||
|
#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */
|
||||||
|
|
||||||
/* host specific block data */
|
/* host specific block data */
|
||||||
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
|
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
|
||||||
|
|
|
@ -68,7 +68,6 @@ struct mmc_command {
|
||||||
struct mmc_data {
|
struct mmc_data {
|
||||||
unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
|
unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
|
||||||
unsigned int timeout_clks; /* data timeout (in clocks) */
|
unsigned int timeout_clks; /* data timeout (in clocks) */
|
||||||
unsigned int blksz_bits; /* data block size */
|
|
||||||
unsigned int blksz; /* data block size */
|
unsigned int blksz; /* data block size */
|
||||||
unsigned int blocks; /* number of blocks */
|
unsigned int blocks; /* number of blocks */
|
||||||
unsigned int error; /* data error */
|
unsigned int error; /* data error */
|
||||||
|
|
Loading…
Reference in New Issue