diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/at91_mci.c | 13 | ||||
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 18 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.c | 207 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 9 | ||||
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 139 | ||||
-rw-r--r-- | drivers/mmc/host/msm_sdcc.h | 8 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 12 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 31 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pxa.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 54 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 9 | ||||
-rw-r--r-- | drivers/mmc/host/sh_mmcif.c | 429 | ||||
-rw-r--r-- | drivers/mmc/host/ushc.c | 30 |
14 files changed, 727 insertions, 238 deletions
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 591ab540b407..d3e6a962f423 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -69,6 +69,7 @@ #include <linux/highmem.h> #include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> #include <asm/io.h> #include <asm/irq.h> @@ -493,10 +494,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command else if (data->flags & MMC_DATA_WRITE) cmdr |= AT91_MCI_TRCMD_START; - if (data->flags & MMC_DATA_STREAM) - cmdr |= AT91_MCI_TRTYP_STREAM; - if (data->blocks > 1) - cmdr |= AT91_MCI_TRTYP_MULTIPLE; + if (cmd->opcode == SD_IO_RW_EXTENDED) { + cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; + } else { + if (data->flags & MMC_DATA_STREAM) + cmdr |= AT91_MCI_TRTYP_STREAM; + if (data->blocks > 1) + cmdr |= AT91_MCI_TRTYP_MULTIPLE; + } } else { block_length = 0; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 301351a5d838..ad2a7a032cdf 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -26,6 +26,7 @@ #include <linux/stat.h> #include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> #include <mach/atmel-mci.h> #include <linux/atmel-mci.h> @@ -532,12 +533,17 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, data = cmd->data; if (data) { cmdr |= MCI_CMDR_START_XFER; - if (data->flags & MMC_DATA_STREAM) - cmdr |= MCI_CMDR_STREAM; - else if (data->blocks > 1) - cmdr |= MCI_CMDR_MULTI_BLOCK; - else - cmdr |= MCI_CMDR_BLOCK; + + if (cmd->opcode == SD_IO_RW_EXTENDED) { + cmdr |= MCI_CMDR_SDIO_BLOCK; + } else { + if (data->flags & MMC_DATA_STREAM) + cmdr |= MCI_CMDR_STREAM; + else if (data->blocks > 1) + cmdr |= MCI_CMDR_MULTI_BLOCK; + else + cmdr |= MCI_CMDR_BLOCK; + } if (data->flags & MMC_DATA_READ) cmdr |= MCI_CMDR_TRDIR_READ; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 87b4fc6c98c2..563022825667 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -19,6 +19,7 @@ #include <linux/highmem.h> #include <linux/log2.h> #include <linux/mmc/host.h> +#include <linux/mmc/card.h> #include <linux/amba/bus.h> #include <linux/clk.h> #include <linux/scatterlist.h> @@ -45,6 +46,12 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY * is asserted (likewise for RX) + * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware + * and will not work at all. + * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when + * using DMA. + * @sdio: variant supports SDIO + * @st_clkdiv: true if using a ST-specific clock divider algorithm */ struct variant_data { unsigned int clkreg; @@ -52,6 +59,10 @@ struct variant_data { unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; + bool broken_blockend; + bool broken_blockend_dma; + bool sdio; + bool st_clkdiv; }; static struct variant_data variant_arm = { @@ -65,6 +76,8 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, + .broken_blockend_dma = true, + .sdio = true, }; static struct variant_data variant_ux500 = { @@ -73,7 +86,11 @@ static struct variant_data variant_ux500 = { .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, + .broken_blockend = true, + .sdio = true, + .st_clkdiv = true, }; + /* * This must be called with host->lock held */ @@ -86,7 +103,22 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (desired >= host->mclk) { clk = MCI_CLK_BYPASS; host->cclk = host->mclk; + } else if (variant->st_clkdiv) { + /* + * DB8500 TRM says f = mclk / (clkdiv + 2) + * => clkdiv = (mclk / f) - 2 + * Round the divider up so we don't exceed the max + * frequency + */ + clk = DIV_ROUND_UP(host->mclk, desired) - 2; + if (clk >= 256) + clk = 255; + host->cclk = host->mclk / (clk + 2); } else { + /* + * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) + * => clkdiv = mclk / (2 * f) - 1 + */ clk = host->mclk / (2 * desired) - 1; if (clk >= 256) clk = 255; @@ -129,10 +161,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) spin_lock(&host->lock); } +static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) +{ + void __iomem *base = host->base; + + if (host->singleirq) { + unsigned int mask0 = readl(base + MMCIMASK0); + + mask0 &= ~MCI_IRQ1MASK; + mask0 |= mask; + + writel(mask0, base + MMCIMASK0); + } + + writel(mask, base + MMCIMASK1); +} + static void mmci_stop_data(struct mmci_host *host) { writel(0, host->base + MMCIDATACTRL); - writel(0, host->base + MMCIMASK1); + mmci_set_mask1(host, 0); host->data = NULL; } @@ -162,6 +210,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; host->data_xfered = 0; + host->blockend = false; + host->dataend = false; mmci_init_sg(host, data); @@ -196,9 +246,14 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } + /* The ST Micro variants has a special bit to enable SDIO */ + if (variant->sdio && host->mmc->card) + if (mmc_card_sdio(host->mmc->card)) + datactrl |= MCI_ST_DPSM_SDIOEN; + writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); - writel(irqmask, base + MMCIMASK1); + mmci_set_mask1(host, irqmask); } static void @@ -233,20 +288,9 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { - if (status & MCI_DATABLOCKEND) { - host->data_xfered += data->blksz; -#ifdef CONFIG_ARCH_U300 - /* - * On the U300 some signal or other is - * badly routed so that a data write does - * not properly terminate with a MCI_DATAEND - * status flag. This quirk will make writes - * work again. - */ - if (data->flags & MMC_DATA_WRITE) - status |= MCI_DATAEND; -#endif - } + struct variant_data *variant = host->variant; + + /* First check for errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); if (status & MCI_DATACRCFAIL) @@ -255,7 +299,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -ETIMEDOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) data->error = -EIO; - status |= MCI_DATAEND; + + /* Force-complete the transaction */ + host->blockend = true; + host->dataend = true; /* * We hit an error condition. Ensure that any data @@ -273,9 +320,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, local_irq_restore(flags); } } - if (status & MCI_DATAEND) { + + /* + * On ARM variants in PIO mode, MCI_DATABLOCKEND + * is always sent first, and we increase the + * transfered number of bytes for that IRQ. Then + * MCI_DATAEND follows and we conclude the transaction. + * + * On the Ux500 single-IRQ variant MCI_DATABLOCKEND + * doesn't seem to immediately clear from the status, + * so we can't use it keep count when only one irq is + * used because the irq will hit for other reasons, and + * then the flag is still up. So we use the MCI_DATAEND + * IRQ at the end of the entire transfer because + * MCI_DATABLOCKEND is broken. + * + * In the U300, the IRQs can arrive out-of-order, + * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, + * so for this case we use the flags "blockend" and + * "dataend" to make sure both IRQs have arrived before + * concluding the transaction. (This does not apply + * to the Ux500 which doesn't fire MCI_DATABLOCKEND + * at all.) In DMA mode it suffers from the same problem + * as the Ux500. + */ + if (status & MCI_DATABLOCKEND) { + /* + * Just being a little over-cautious, we do not + * use this progressive update if the hardware blockend + * flag is unreliable: since it can stay high between + * IRQs it will corrupt the transfer counter. + */ + if (!variant->broken_blockend) + host->data_xfered += data->blksz; + host->blockend = true; + } + + if (status & MCI_DATAEND) + host->dataend = true; + + /* + * On variants with broken blockend we shall only wait for dataend, + * on others we must sync with the blockend signal since they can + * appear out-of-order. + */ + if (host->dataend && (host->blockend || variant->broken_blockend)) { mmci_stop_data(host); + /* Reset these flags */ + host->blockend = false; + host->dataend = false; + + /* + * Variants with broken blockend flags need to handle the + * end of the entire transfer here. + */ + if (variant->broken_blockend && !data->error) + host->data_xfered += data->blksz * data->blocks; + if (!data->stop) { mmci_request_end(host, data->mrq); } else { @@ -356,7 +458,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); - writesl(base + MMCIFIFO, ptr, count >> 2); + /* + * The ST Micro variant for SDIO transfer sizes + * less then 8 bytes should have clock H/W flow + * control disabled. + */ + if (variant->sdio && + mmc_card_sdio(host->mmc->card)) { + if (count < 8) + writel(readl(host->base + MMCICLOCK) & + ~variant->clkreg_enable, + host->base + MMCICLOCK); + else + writel(readl(host->base + MMCICLOCK) | + variant->clkreg_enable, + host->base + MMCICLOCK); + } + + /* + * SDIO especially may want to send something that is + * not divisible by 4 (as opposed to card sectors + * etc), and the FIFO only accept full 32-bit writes. + * So compensate by adding +3 on the count, a single + * byte become a 32bit write, 7 bytes will be two + * 32bit writes etc. + */ + writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); ptr += count; remain -= count; @@ -437,7 +564,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * "any data available" mode. */ if (status & MCI_RXACTIVE && host->size < variant->fifosize) - writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); /* * If we run out of data, disable the data IRQs; this @@ -446,7 +573,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * stops us racing with our data end IRQ. */ if (host->size == 0) { - writel(0, base + MMCIMASK1); + mmci_set_mask1(host, 0); writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); } @@ -469,6 +596,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) struct mmc_data *data; status = readl(host->base + MMCISTATUS); + + if (host->singleirq) { + if (status & readl(host->base + MMCIMASK1)) + mmci_pio_irq(irq, dev_id); + + status &= ~MCI_IRQ1MASK; + } + status &= readl(host->base + MMCIMASK0); writel(status, host->base + MMCICLEAR); @@ -635,6 +770,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; + unsigned int mask; int ret; /* must have platform data */ @@ -806,20 +942,30 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (ret) goto unmap; - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); - if (ret) - goto irq0_free; + if (dev->irq[1] == NO_IRQ) + host->singleirq = true; + else { + ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, + DRIVER_NAME " (pio)", host); + if (ret) + goto irq0_free; + } - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + mask = MCI_IRQENABLE; + /* Don't use the datablockend flag if it's broken */ + if (variant->broken_blockend) + mask &= ~MCI_DATABLOCKEND; - amba_set_drvdata(dev, mmc); + writel(mask, host->base + MMCIMASK0); - mmc_add_host(mmc); + amba_set_drvdata(dev, mmc); - dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n", - mmc_hostname(mmc), amba_rev(dev), amba_config(dev), + dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n", + mmc_hostname(mmc), amba_part(dev), amba_rev(dev), (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); + mmc_add_host(mmc); + return 0; irq0_free: @@ -864,7 +1010,8 @@ static int __devexit mmci_remove(struct amba_device *dev) writel(0, host->base + MMCIDATACTRL); free_irq(dev->irq[0], host); - free_irq(dev->irq[1], host); + if (!host->singleirq) + free_irq(dev->irq[1], host); if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 4ae887fc0189..df06f01aac89 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -139,6 +139,11 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) +/* These interrupts are directed to IRQ1 when two IRQ lines are available */ +#define MCI_IRQ1MASK \ + (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ + MCI_TXFIFOHALFEMPTYMASK) + #define NR_SG 16 struct clk; @@ -154,6 +159,7 @@ struct mmci_host { int gpio_cd; int gpio_wp; int gpio_cd_irq; + bool singleirq; unsigned int data_xfered; @@ -171,6 +177,9 @@ struct mmci_host { struct timer_list timer; unsigned int oldstat; + bool blockend; + bool dataend; + /* pio stuff */ struct sg_mapping_iter sg_miter; unsigned int size; diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 1290d14c5839..5decfd0bd61d 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -44,6 +44,7 @@ #include <mach/mmc.h> #include <mach/msm_iomap.h> #include <mach/dma.h> +#include <mach/clk.h> #include "msm_sdcc.h" @@ -126,6 +127,40 @@ static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c); +static void msmsdcc_reset_and_restore(struct msmsdcc_host *host) +{ + u32 mci_clk = 0; + u32 mci_mask0 = 0; + int ret = 0; + + /* Save the controller state */ + mci_clk = readl(host->base + MMCICLOCK); + mci_mask0 = readl(host->base + MMCIMASK0); + + /* Reset the controller */ + ret = clk_reset(host->clk, CLK_RESET_ASSERT); + if (ret) + pr_err("%s: Clock assert failed at %u Hz with err %d\n", + mmc_hostname(host->mmc), host->clk_rate, ret); + + ret = clk_reset(host->clk, CLK_RESET_DEASSERT); + if (ret) + pr_err("%s: Clock deassert failed at %u Hz with err %d\n", + mmc_hostname(host->mmc), host->clk_rate, ret); + + pr_info("%s: Controller has been re-initialiazed\n", + mmc_hostname(host->mmc)); + + /* Restore the contoller state */ + writel(host->pwr, host->base + MMCIPOWER); + writel(mci_clk, host->base + MMCICLOCK); + writel(mci_mask0, host->base + MMCIMASK0); + ret = clk_set_rate(host->clk, host->clk_rate); + if (ret) + pr_err("%s: Failed to set clk rate %u Hz (%d)\n", + mmc_hostname(host->mmc), host->clk_rate, ret); +} + static void msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) { @@ -155,7 +190,7 @@ static void msmsdcc_stop_data(struct msmsdcc_host *host) { host->curr.data = NULL; - host->curr.got_dataend = host->curr.got_datablkend = 0; + host->curr.got_dataend = 0; } uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) @@ -189,42 +224,42 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) } static void -msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, - unsigned int result, - struct msm_dmov_errdata *err) +msmsdcc_dma_complete_tlet(unsigned long data) { - struct msmsdcc_dma_data *dma_data = - container_of(cmd, struct msmsdcc_dma_data, hdr); - struct msmsdcc_host *host = dma_data->host; + struct msmsdcc_host *host = (struct msmsdcc_host *)data; unsigned long flags; struct mmc_request *mrq; + struct msm_dmov_errdata err; spin_lock_irqsave(&host->lock, flags); host->dma.active = 0; + err = host->dma.err; mrq = host->curr.mrq; BUG_ON(!mrq); WARN_ON(!mrq->data); - if (!(result & DMOV_RSLT_VALID)) { + if (!(host->dma.result & DMOV_RSLT_VALID)) { pr_err("msmsdcc: Invalid DataMover result\n"); goto out; } - if (result & DMOV_RSLT_DONE) { + if (host->dma.result & DMOV_RSLT_DONE) { host->curr.data_xfered = host->curr.xfer_size; } else { /* Error or flush */ - if (result & DMOV_RSLT_ERROR) + if (host->dma.result & DMOV_RSLT_ERROR) pr_err("%s: DMA error (0x%.8x)\n", - mmc_hostname(host->mmc), result); - if (result & DMOV_RSLT_FLUSH) + mmc_hostname(host->mmc), host->dma.result); + if (host->dma.result & DMOV_RSLT_FLUSH) pr_err("%s: DMA channel flushed (0x%.8x)\n", - mmc_hostname(host->mmc), result); - if (err) - pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", - err->flush[0], err->flush[1], err->flush[2], - err->flush[3], err->flush[4], err->flush[5]); + mmc_hostname(host->mmc), host->dma.result); + + pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", + err.flush[0], err.flush[1], err.flush[2], + err.flush[3], err.flush[4], err.flush[5]); + + msmsdcc_reset_and_restore(host); if (!mrq->data->error) mrq->data->error = -EIO; } @@ -242,8 +277,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, host->dma.sg = NULL; host->dma.busy = 0; - if ((host->curr.got_dataend && host->curr.got_datablkend) - || mrq->data->error) { + if (host->curr.got_dataend || mrq->data->error) { /* * If we've already gotten our DATAEND / DATABLKEND @@ -273,6 +307,22 @@ out: return; } +static void +msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, + unsigned int result, + struct msm_dmov_errdata *err) +{ + struct msmsdcc_dma_data *dma_data = + container_of(cmd, struct msmsdcc_dma_data, hdr); + struct msmsdcc_host *host = dma_data->host; + + dma_data->result = result; + if (err) + memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata)); + + tasklet_schedule(&host->dma_tlet); +} + static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) { if (host->dma.channel == -1) @@ -424,6 +474,11 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host, (cmd->opcode == 53)) *c |= MCI_CSPM_DATCMD; + if (host->prog_scan && (cmd->opcode == 12)) { + *c |= MCI_CPSM_PROGENA; + host->prog_enable = true; + } + if (cmd == cmd->mrq->stop) *c |= MCI_CSPM_MCIABORT; @@ -450,7 +505,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, host->curr.xfer_remain = host->curr.xfer_size; host->curr.data_xfered = 0; host->curr.got_dataend = 0; - host->curr.got_datablkend = 0; memset(&host->pio, 0, sizeof(host->pio)); @@ -494,6 +548,8 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, host->cmd_c = c; } msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); + if (data->flags & MMC_DATA_WRITE) + host->prog_scan = true; } else { msmsdcc_writel(host, timeout, MMCIDATATIMER); @@ -555,6 +611,9 @@ msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) uint32_t *ptr = (uint32_t *) buffer; int count = 0; + if (remain % 4) + remain = ((remain >> 2) + 1) << 2; + while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); ptr++; @@ -575,13 +634,14 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, char *ptr = buffer; do { - unsigned int count, maxcnt; + unsigned int count, maxcnt, sz; maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; count = min(remain, maxcnt); - writesl(base + MMCIFIFO, ptr, count >> 2); + sz = count % 4 ? (count >> 2) + 1 : (count >> 2); + writesl(base + MMCIFIFO, ptr, sz); ptr += count; remain -= count; @@ -702,10 +762,26 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else if (host->curr.data) { /* Non DMA */ + msmsdcc_reset_and_restore(host); msmsdcc_stop_data(host); msmsdcc_request_end(host, cmd->mrq); - } else /* host->data == NULL */ - msmsdcc_request_end(host, cmd->mrq); + } else { /* host->data == NULL */ + if (!cmd->error && host->prog_enable) { + if (status & MCI_PROGDONE) { + host->prog_scan = false; + host->prog_enable = false; + msmsdcc_request_end(host, cmd->mrq); + } else { + host->curr.cmd = cmd; + } + } else { + if (host->prog_enable) { + host->prog_scan = false; + host->prog_enable = false; + } + msmsdcc_request_end(host, cmd->mrq); + } + } } else if (cmd->data) if (!(cmd->data->flags & MMC_DATA_READ)) msmsdcc_start_data(host, cmd->data, @@ -719,7 +795,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, struct mmc_data *data = host->curr.data; if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | - MCI_CMDTIMEOUT) && host->curr.cmd) { + MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) { msmsdcc_do_cmdirq(host, status); } @@ -735,6 +811,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else { + msmsdcc_reset_and_restore(host); if (host->curr.data) msmsdcc_stop_data(host); if (!data->stop) @@ -748,14 +825,10 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, if (!host->curr.got_dataend && (status & MCI_DATAEND)) host->curr.got_dataend = 1; - if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) - host->curr.got_datablkend = 1; - /* * If DMA is still in progress, we complete via the completion handler */ - if (host->curr.got_dataend && host->curr.got_datablkend && - !host->dma.busy) { + if (host->curr.got_dataend && !host->dma.busy) { /* * There appears to be an issue in the controller where * if you request a small block transfer (< fifo size), @@ -792,8 +865,7 @@ msmsdcc_irq(int irq, void *dev_id) do { status = msmsdcc_readl(host, MMCISTATUS); - status &= (msmsdcc_readl(host, MMCIMASK0) | - MCI_DATABLOCKENDMASK); + status &= msmsdcc_readl(host, MMCIMASK0); msmsdcc_writel(host, status, MMCICLEAR); if (status & MCI_SDIOINTR) @@ -1118,6 +1190,9 @@ msmsdcc_probe(struct platform_device *pdev) host->dmares = dmares; spin_lock_init(&host->lock); + tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet, + (unsigned long)host); + /* * Setup DMA */ diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index ff2b0f74f6f4..939557af266d 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -138,7 +138,7 @@ #define MCI_IRQENABLE \ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK) + MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) /* * The size of the FIFO in bytes. @@ -172,6 +172,8 @@ struct msmsdcc_dma_data { struct msmsdcc_host *host; int busy; /* Set if DM is busy */ int active; + unsigned int result; + struct msm_dmov_errdata err; }; struct msmsdcc_pio_data { @@ -188,7 +190,6 @@ struct msmsdcc_curr_req { unsigned int xfer_remain; /* Bytes remaining to send */ unsigned int data_xfered; /* Bytes acked by BLKEND irq */ int got_dataend; - int got_datablkend; int user_pages; }; @@ -235,6 +236,7 @@ struct msmsdcc_host { int cmdpoll; struct msmsdcc_stats stats; + struct tasklet_struct dma_tlet; /* Command parameters */ unsigned int cmd_timeout; unsigned int cmd_pio_irqmask; @@ -242,6 +244,8 @@ struct msmsdcc_host { struct mmc_command *cmd_cmd; u32 cmd_c; + bool prog_scan; + bool prog_enable; }; #endif diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9e136bbd2b61..078fdf11af03 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1002,7 +1002,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * Monitor a 0->1 transition first */ if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) { - while ((!(OMAP_HSMMC_READ(host, SYSCTL) & bit)) + while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit)) && (i++ < limit)) cpu_relax(); } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 2e9cca19c90b..9b82910b9dbb 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -17,6 +17,7 @@ #include <linux/clk.h> #include <linux/mmc/host.h> #include <linux/mmc/sdhci-pltfm.h> +#include <mach/hardware.h> #include "sdhci.h" #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -112,6 +113,13 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd clk_enable(clk); pltfm_host->clk = clk; + if (cpu_is_mx35() || cpu_is_mx51()) + host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + + /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */ + if (cpu_is_mx25() || cpu_is_mx35()) + host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; + return 0; } @@ -133,10 +141,8 @@ static struct sdhci_ops sdhci_esdhc_ops = { }; struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK - | SDHCI_QUIRK_BROKEN_ADMA, + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA, /* ADMA has issues. Might be fixable */ - /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */ .ops = &sdhci_esdhc_ops, .init = esdhc_pltfm_init, .exit = esdhc_pltfm_exit, diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 55746bac2f44..3d9c2460d437 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -149,11 +149,11 @@ static const struct sdhci_pci_fixes sdhci_cafe = { * ADMA operation is disabled for Moorestown platform due to * hardware bugs. */ -static int mrst_hc1_probe(struct sdhci_pci_chip *chip) +static int mrst_hc_probe(struct sdhci_pci_chip *chip) { /* - * slots number is fixed here for MRST as SDIO3 is never used and has - * hardware bugs. + * slots number is fixed here for MRST as SDIO3/5 are never used and + * have hardware bugs. */ chip->num_slots = 1; return 0; @@ -163,9 +163,9 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, }; -static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = { +static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, - .probe = mrst_hc1_probe, + .probe = mrst_hc_probe, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { @@ -538,7 +538,15 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_INTEL_MRST_SD1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1, + .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, + }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_MRST_SD2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, }, { @@ -637,6 +645,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) { struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; + mmc_pm_flag_t slot_pm_flags; mmc_pm_flag_t pm_flags = 0; int i, ret; @@ -657,7 +666,11 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) return ret; } - pm_flags |= slot->host->mmc->pm_flags; + slot_pm_flags = slot->host->mmc->pm_flags; + if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) + sdhci_enable_irq_wakeups(slot->host); + + pm_flags |= slot_pm_flags; } if (chip->fixes && chip->fixes->suspend) { @@ -671,8 +684,10 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); if (pm_flags & MMC_PM_KEEP_POWER) { - if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) + if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) { + pci_pme_active(pdev, true); pci_enable_wake(pdev, PCI_D3hot, 1); + } pci_set_power_state(pdev, PCI_D3hot); } else { pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c index fc406ac5d193..5a61208cbc66 100644 --- a/drivers/mmc/host/sdhci-pxa.c +++ b/drivers/mmc/host/sdhci-pxa.c @@ -141,6 +141,10 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev) if (pdata->quirks) host->quirks |= pdata->quirks; + /* If slot design supports 8 bit data, indicate this to MMC. */ + if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "failed to add host\n"); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 782c0ee3c925..a25db426c910 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1185,17 +1185,31 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - if (ios->bus_width == MMC_BUS_WIDTH_8) - ctrl |= SDHCI_CTRL_8BITBUS; - else - ctrl &= ~SDHCI_CTRL_8BITBUS; + /* + * If your platform has 8-bit width support but is not a v3 controller, + * or if it requires special setup code, you should implement that in + * platform_8bit_width(). + */ + if (host->ops->platform_8bit_width) + host->ops->platform_8bit_width(host, ios->bus_width); + else { + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + if (ios->bus_width == MMC_BUS_WIDTH_8) { + ctrl &= ~SDHCI_CTRL_4BITBUS; + if (host->version >= SDHCI_SPEC_300) + ctrl |= SDHCI_CTRL_8BITBUS; + } else { + if (host->version >= SDHCI_SPEC_300) + ctrl &= ~SDHCI_CTRL_8BITBUS; + if (ios->bus_width == MMC_BUS_WIDTH_4) + ctrl |= SDHCI_CTRL_4BITBUS; + else + ctrl &= ~SDHCI_CTRL_4BITBUS; + } + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + } - if (ios->bus_width == MMC_BUS_WIDTH_4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if ((ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_MMC_HS) @@ -1681,6 +1695,16 @@ int sdhci_resume_host(struct sdhci_host *host) EXPORT_SYMBOL_GPL(sdhci_resume_host); +void sdhci_enable_irq_wakeups(struct sdhci_host *host) +{ + u8 val; + val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); + val |= SDHCI_WAKE_ON_INT; + sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); +} + +EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); + #endif /* CONFIG_PM */ /*****************************************************************************\ @@ -1845,11 +1869,19 @@ int sdhci_add_host(struct sdhci_host *host) mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; + mmc->f_max = host->max_clk; mmc->caps |= MMC_CAP_SDIO_IRQ; + /* + * A controller may support 8-bit width, but the board itself + * might not have the pins brought out. Boards that support + * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in + * their platform code before calling sdhci_add_host(), and we + * won't assume 8-bit width for hosts without that CAP. + */ if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + mmc->caps |= MMC_CAP_4_BIT_DATA; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index b7b8a3b28b01..e42d7f00c060 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -76,7 +76,7 @@ #define SDHCI_CTRL_ADMA1 0x08 #define SDHCI_CTRL_ADMA32 0x10 #define SDHCI_CTRL_ADMA64 0x18 -#define SDHCI_CTRL_8BITBUS 0x20 +#define SDHCI_CTRL_8BITBUS 0x20 #define SDHCI_POWER_CONTROL 0x29 #define SDHCI_POWER_ON 0x01 @@ -87,6 +87,9 @@ #define SDHCI_BLOCK_GAP_CONTROL 0x2A #define SDHCI_WAKE_UP_CONTROL 0x2B +#define SDHCI_WAKE_ON_INT 0x01 +#define SDHCI_WAKE_ON_INSERT 0x02 +#define SDHCI_WAKE_ON_REMOVE 0x04 #define SDHCI_CLOCK_CONTROL 0x2C #define SDHCI_DIVIDER_SHIFT 8 @@ -152,6 +155,7 @@ #define SDHCI_CLOCK_BASE_SHIFT 8 #define SDHCI_MAX_BLOCK_MASK 0x00030000 #define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_8BIT 0x00040000 #define SDHCI_CAN_DO_ADMA2 0x00080000 #define SDHCI_CAN_DO_ADMA1 0x00100000 #define SDHCI_CAN_DO_HISPD 0x00200000 @@ -212,6 +216,8 @@ struct sdhci_ops { unsigned int (*get_max_clock)(struct sdhci_host *host); unsigned int (*get_min_clock)(struct sdhci_host *host); unsigned int (*get_timeout_clock)(struct sdhci_host *host); + int (*platform_8bit_width)(struct sdhci_host *host, + int width); void (*platform_send_init_74_clocks)(struct sdhci_host *host, u8 power_mode); unsigned int (*get_ro)(struct sdhci_host *host); @@ -317,6 +323,7 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead); #ifdef CONFIG_PM extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); extern int sdhci_resume_host(struct sdhci_host *host); +extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif #endif /* __SDHCI_HW_H */ diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index ddd09840520b..12884c270171 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -16,16 +16,19 @@ * */ +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> -#include <linux/mmc/host.h> +#include <linux/dmaengine.h> #include <linux/mmc/card.h> #include <linux/mmc/core.h> +#include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/clk.h> #include <linux/mmc/sh_mmcif.h> +#include <linux/pagemap.h> +#include <linux/platform_device.h> #define DRIVER_NAME "sh_mmcif" #define DRIVER_VERSION "2010-04-28" @@ -62,25 +65,6 @@ /* CE_BLOCK_SET */ #define BLOCK_SIZE_MASK 0x0000ffff -/* CE_CLK_CTRL */ -#define CLK_ENABLE (1 << 24) /* 1: output mmc clock */ -#define CLK_CLEAR ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16)) -#define CLK_SUP_PCLK ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16)) -#define SRSPTO_256 ((1 << 13) | (0 << 12)) /* resp timeout */ -#define SRBSYTO_29 ((1 << 11) | (1 << 10) | \ - (1 << 9) | (1 << 8)) /* resp busy timeout */ -#define SRWDTO_29 ((1 << 7) | (1 << 6) | \ - (1 << 5) | (1 << 4)) /* read/write timeout */ -#define SCCSTO_29 ((1 << 3) | (1 << 2) | \ - (1 << 1) | (1 << 0)) /* ccs timeout */ - -/* CE_BUF_ACC */ -#define BUF_ACC_DMAWEN (1 << 25) -#define BUF_ACC_DMAREN (1 << 24) -#define BUF_ACC_BUSW_32 (0 << 17) -#define BUF_ACC_BUSW_16 (1 << 17) -#define BUF_ACC_ATYP (1 << 16) - /* CE_INT */ #define INT_CCSDE (1 << 29) #define INT_CMD12DRE (1 << 26) @@ -165,10 +149,6 @@ STS2_AC12BSYTO | STS2_RSPBSYTO | \ STS2_AC12RSPTO | STS2_RSPTO) -/* CE_VERSION */ -#define SOFT_RST_ON (1 << 31) -#define SOFT_RST_OFF (0 << 31) - #define CLKDEV_EMMC_DATA 52000000 /* 52MHz */ #define CLKDEV_MMC_DATA 20000000 /* 20MHz */ #define CLKDEV_INIT 400000 /* 400 KHz */ @@ -176,18 +156,21 @@ struct sh_mmcif_host { struct mmc_host *mmc; struct mmc_data *data; - struct mmc_command *cmd; struct platform_device *pd; struct clk *hclk; unsigned int clk; int bus_width; - u16 wait_int; - u16 sd_error; + bool sd_error; long timeout; void __iomem *addr; - wait_queue_head_t intr_wait; -}; + struct completion intr_wait; + /* DMA support */ + struct dma_chan *chan_rx; + struct dma_chan *chan_tx; + struct completion dma_complete; + unsigned int dma_sglen; +}; static inline void sh_mmcif_bitset(struct sh_mmcif_host *host, unsigned int reg, u32 val) @@ -201,6 +184,188 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, writel(~val & readl(host->addr + reg), host->addr + reg); } +static void mmcif_dma_complete(void *arg) +{ + struct sh_mmcif_host *host = arg; + dev_dbg(&host->pd->dev, "Command completed\n"); + + if (WARN(!host->data, "%s: NULL data in DMA completion!\n", + dev_name(&host->pd->dev))) + return; + + if (host->data->flags & MMC_DATA_READ) + dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen, + DMA_FROM_DEVICE); + else + dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen, + DMA_TO_DEVICE); + + complete(&host->dma_complete); +} + +static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) +{ + struct scatterlist *sg = host->data->sg; + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *chan = host->chan_rx; + dma_cookie_t cookie = -EINVAL; + int ret; + + ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_FROM_DEVICE); + if (ret > 0) { + host->dma_sglen = ret; + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + } + + if (desc) { + desc->callback = mmcif_dma_complete; + desc->callback_param = host; + cookie = desc->tx_submit(desc); + if (cookie < 0) { + desc = NULL; + ret = cookie; + } else { + sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN); + chan->device->device_issue_pending(chan); + } + } + dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", + __func__, host->data->sg_len, ret, cookie); + + if (!desc) { + /* DMA failed, fall back to PIO */ + if (ret >= 0) + ret = -EIO; + host->chan_rx = NULL; + host->dma_sglen = 0; + dma_release_channel(chan); + /* Free the Tx channel too */ + chan = host->chan_tx; + if (chan) { + host->chan_tx = NULL; + dma_release_channel(chan); + } + dev_warn(&host->pd->dev, + "DMA failed: %d, falling back to PIO\n", ret); + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + } + + dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, + desc, cookie, host->data->sg_len); +} + +static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) +{ + struct scatterlist *sg = host->data->sg; + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *chan = host->chan_tx; + dma_cookie_t cookie = -EINVAL; + int ret; + + ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_TO_DEVICE); + if (ret > 0) { + host->dma_sglen = ret; + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + } + + if (desc) { + desc->callback = mmcif_dma_complete; + desc->callback_param = host; + cookie = desc->tx_submit(desc); + if (cookie < 0) { + desc = NULL; + ret = cookie; + } else { + sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN); + chan->device->device_issue_pending(chan); + } + } + dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", + __func__, host->data->sg_len, ret, cookie); + + if (!desc) { + /* DMA failed, fall back to PIO */ + if (ret >= 0) + ret = -EIO; + host->chan_tx = NULL; + host->dma_sglen = 0; + dma_release_channel(chan); + /* Free the Rx channel too */ + chan = host->chan_rx; + if (chan) { + host->chan_rx = NULL; + dma_release_channel(chan); + } + dev_warn(&host->pd->dev, + "DMA failed: %d, falling back to PIO\n", ret); + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + } + + dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d\n", __func__, + desc, cookie); +} + +static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) +{ + dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); + chan->private = arg; + return true; +} + +static void sh_mmcif_request_dma(struct sh_mmcif_host *host, + struct sh_mmcif_plat_data *pdata) +{ + host->dma_sglen = 0; + + /* We can only either use DMA for both Tx and Rx or not use it at all */ + if (pdata->dma) { + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, + &pdata->dma->chan_priv_tx); + dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, + host->chan_tx); + + if (!host->chan_tx) + return; + + host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, + &pdata->dma->chan_priv_rx); + dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, + host->chan_rx); + + if (!host->chan_rx) { + dma_release_channel(host->chan_tx); + host->chan_tx = NULL; + return; + } + + init_completion(&host->dma_complete); + } +} + +static void sh_mmcif_release_dma(struct sh_mmcif_host *host) +{ + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + /* Descriptors are freed automatically */ + if (host->chan_tx) { + struct dma_chan *chan = host->chan_tx; + host->chan_tx = NULL; + dma_release_channel(chan); + } + if (host->chan_rx) { + struct dma_chan *chan = host->chan_rx; + host->chan_rx = NULL; + dma_release_channel(chan); + } + + host->dma_sglen = 0; +} static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) { @@ -239,13 +404,12 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) u32 state1, state2; int ret, timeout = 10000000; - host->sd_error = 0; - host->wait_int = 0; + host->sd_error = false; state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); - pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1); - pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2); + dev_dbg(&host->pd->dev, "ERR HOST_STS1 = %08x\n", state1); + dev_dbg(&host->pd->dev, "ERR HOST_STS2 = %08x\n", state2); if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); @@ -253,8 +417,8 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) while (1) { timeout--; if (timeout < 0) { - pr_err(DRIVER_NAME": Forceed end of " \ - "command sequence timeout err\n"); + dev_err(&host->pd->dev, + "Forceed end of command sequence timeout err\n"); return -EIO; } if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) @@ -263,18 +427,18 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) mdelay(1); } sh_mmcif_sync_reset(host); - pr_debug(DRIVER_NAME": Forced end of command sequence\n"); + dev_dbg(&host->pd->dev, "Forced end of command sequence\n"); return -EIO; } if (state2 & STS2_CRC_ERR) { - pr_debug(DRIVER_NAME": Happened CRC error\n"); + dev_dbg(&host->pd->dev, ": Happened CRC error\n"); ret = -EIO; } else if (state2 & STS2_TIMEOUT_ERR) { - pr_debug(DRIVER_NAME": Happened Timeout error\n"); + dev_dbg(&host->pd->dev, ": Happened Timeout error\n"); ret = -ETIMEDOUT; } else { - pr_debug(DRIVER_NAME": Happened End/Index error\n"); + dev_dbg(&host->pd->dev, ": Happened End/Index error\n"); ret = -EIO; } return ret; @@ -287,17 +451,13 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host, long time; u32 blocksize, i, *p = sg_virt(data->sg); - host->wait_int = 0; - /* buf read enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); - if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) return sh_mmcif_error_manage(host); - host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) @@ -305,13 +465,11 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host, /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); - if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) return sh_mmcif_error_manage(host); - host->wait_int = 0; return 0; } @@ -326,19 +484,15 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host, MMCIF_CE_BLOCK_SET); for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); - host->wait_int = 0; for (sec = 0; sec < data->sg->length / blocksize; sec++) { sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); /* buf read enable */ - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); - if (host->wait_int != 1 && - (time == 0 || host->sd_error != 0)) + if (time <= 0 || host->sd_error) return sh_mmcif_error_manage(host); - host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); @@ -356,17 +510,14 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host, long time; u32 blocksize, i, *p = sg_virt(data->sg); - host->wait_int = 0; sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); /* buf write enable */ - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); - if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) return sh_mmcif_error_manage(host); - host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) @@ -375,13 +526,11 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host, /* buffer write end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); - if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) return sh_mmcif_error_manage(host); - host->wait_int = 0; return 0; } @@ -397,19 +546,15 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host, for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); - host->wait_int = 0; for (sec = 0; sec < data->sg->length / blocksize; sec++) { sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); /* buf write enable*/ - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); - if (host->wait_int != 1 && - (time == 0 || host->sd_error != 0)) + if (time <= 0 || host->sd_error) return sh_mmcif_error_manage(host); - host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); @@ -457,7 +602,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, tmp |= CMD_SET_RTYP_17B; break; default: - pr_err(DRIVER_NAME": Not support type response.\n"); + dev_err(&host->pd->dev, "Unsupported response type.\n"); break; } switch (opc) { @@ -485,7 +630,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, tmp |= CMD_SET_DATW_8; break; default: - pr_err(DRIVER_NAME": Not support bus width.\n"); + dev_err(&host->pd->dev, "Unsupported bus width.\n"); break; } } @@ -513,10 +658,10 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, return opc = ((opc << 24) | tmp); } -static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, +static int sh_mmcif_data_trans(struct sh_mmcif_host *host, struct mmc_request *mrq, u32 opc) { - u32 ret; + int ret; switch (opc) { case MMC_READ_MULTIPLE_BLOCK: @@ -533,7 +678,7 @@ static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, ret = sh_mmcif_single_read(host, mrq); break; default: - pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc); + dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc); ret = -EINVAL; break; } @@ -547,8 +692,6 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, int ret = 0, mask = 0; u32 opc = cmd->opcode; - host->cmd = cmd; - switch (opc) { /* respons busy check */ case MMC_SWITCH: @@ -579,13 +722,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); /* set arg */ sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); - host->wait_int = 0; /* set cmd */ sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || host->sd_error == 1, host->timeout); - if (host->wait_int != 1 && time == 0) { + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0) { cmd->error = sh_mmcif_error_manage(host); return; } @@ -597,26 +739,34 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, cmd->error = -ETIMEDOUT; break; default: - pr_debug("%s: Cmd(d'%d) err\n", - DRIVER_NAME, cmd->opcode); + dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n", + cmd->opcode); cmd->error = sh_mmcif_error_manage(host); break; } - host->sd_error = 0; - host->wait_int = 0; + host->sd_error = false; return; } if (!(cmd->flags & MMC_RSP_PRESENT)) { - cmd->error = ret; - host->wait_int = 0; + cmd->error = 0; return; } - if (host->wait_int == 1) { - sh_mmcif_get_response(host, cmd); - host->wait_int = 0; - } + sh_mmcif_get_response(host, cmd); if (host->data) { - ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); + if (!host->dma_sglen) { + ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); + } else { + long time = + wait_for_completion_interruptible_timeout(&host->dma_complete, + host->timeout); + if (!time) + ret = -ETIMEDOUT; + else if (time < 0) + ret = time; + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, + BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + host->dma_sglen = 0; + } if (ret < 0) mrq->data->bytes_xfered = 0; else @@ -636,20 +786,18 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); else { - pr_err(DRIVER_NAME": not support stop cmd\n"); + dev_err(&host->pd->dev, "unsupported stop cmd\n"); cmd->error = sh_mmcif_error_manage(host); return; } - time = wait_event_interruptible_timeout(host->intr_wait, - host->wait_int == 1 || - host->sd_error == 1, host->timeout); - if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) { + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) { cmd->error = sh_mmcif_error_manage(host); return; } sh_mmcif_get_cmd12response(host, cmd); - host->wait_int = 0; cmd->error = 0; } @@ -676,6 +824,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) break; } host->data = mrq->data; + if (mrq->data) { + if (mrq->data->flags & MMC_DATA_READ) { + if (host->chan_rx) + sh_mmcif_start_dma_rx(host); + } else { + if (host->chan_tx) + sh_mmcif_start_dma_tx(host); + } + } sh_mmcif_start_cmd(host, mrq, mrq->cmd); host->data = NULL; @@ -735,7 +892,7 @@ static void sh_mmcif_detect(struct mmc_host *mmc) static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; - u32 state = 0; + u32 state; int err = 0; state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); @@ -774,17 +931,19 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } else { - pr_debug("%s: Not support int\n", DRIVER_NAME); + dev_dbg(&host->pd->dev, "Not support int\n"); sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } if (err) { - host->sd_error = 1; - pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state); + host->sd_error = true; + dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } - host->wait_int = 1; - wake_up(&host->intr_wait); + if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) + complete(&host->intr_wait); + else + dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); return IRQ_HANDLED; } @@ -793,8 +952,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; struct mmc_host *mmc; - struct sh_mmcif_host *host = NULL; - struct sh_mmcif_plat_data *pd = NULL; + struct sh_mmcif_host *host; + struct sh_mmcif_plat_data *pd; struct resource *res; void __iomem *reg; char clk_name[8]; @@ -802,7 +961,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); if (irq[0] < 0 || irq[1] < 0) { - pr_err(DRIVER_NAME": Get irq error\n"); + dev_err(&pdev->dev, "Get irq error\n"); return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -815,7 +974,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) dev_err(&pdev->dev, "ioremap error.\n"); return -ENOMEM; } - pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data); + pd = pdev->dev.platform_data; if (!pd) { dev_err(&pdev->dev, "sh_mmcif plat data error.\n"); ret = -ENXIO; @@ -842,7 +1001,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) host->clk = clk_get_rate(host->hclk); host->pd = pdev; - init_waitqueue_head(&host->intr_wait); + init_completion(&host->intr_wait); mmc->ops = &sh_mmcif_ops; mmc->f_max = host->clk; @@ -858,33 +1017,37 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) mmc->caps = MMC_CAP_MMC_HIGHSPEED; if (pd->caps) mmc->caps |= pd->caps; - mmc->max_segs = 128; + mmc->max_segs = 32; mmc->max_blk_size = 512; - mmc->max_blk_count = 65535; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs; + mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; mmc->max_seg_size = mmc->max_req_size; sh_mmcif_sync_reset(host); platform_set_drvdata(pdev, host); + + /* See if we also get DMA */ + sh_mmcif_request_dma(host, pd); + mmc_add_host(mmc); ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); if (ret) { - pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n"); + dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); goto clean_up2; } ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host); if (ret) { free_irq(irq[0], host); - pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n"); + dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); goto clean_up2; } sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); sh_mmcif_detect(host->mmc); - pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION); - pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME, + dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); + dev_dbg(&pdev->dev, "chip ver H'%04x\n", sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; @@ -903,20 +1066,22 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) struct sh_mmcif_host *host = platform_get_drvdata(pdev); int irq[2]; - sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - - irq[0] = platform_get_irq(pdev, 0); - irq[1] = platform_get_irq(pdev, 1); + mmc_remove_host(host->mmc); + sh_mmcif_release_dma(host); if (host->addr) iounmap(host->addr); - platform_set_drvdata(pdev, NULL); - mmc_remove_host(host->mmc); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); + + irq[0] = platform_get_irq(pdev, 0); + irq[1] = platform_get_irq(pdev, 1); free_irq(irq[0], host); free_irq(irq[1], host); + platform_set_drvdata(pdev, NULL); + clk_disable(host->hclk); mmc_free_host(host->mmc); @@ -947,5 +1112,5 @@ module_exit(sh_mmcif_exit); MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS(DRIVER_NAME); +MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>"); diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index b4ead4a13c98..f8f65df9b017 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -425,7 +425,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id struct usb_device *usb_dev = interface_to_usbdev(intf); struct mmc_host *mmc; struct ushc_data *ushc; - int ret = -ENOMEM; + int ret; mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev); if (mmc == NULL) @@ -462,11 +462,15 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id mmc->max_blk_count = 511; ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->int_urb == NULL) + if (ushc->int_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL); - if (ushc->int_data == NULL) + if (ushc->int_data == NULL) { + ret = -ENOMEM; goto err; + } usb_fill_int_urb(ushc->int_urb, ushc->usb_dev, usb_rcvintpipe(usb_dev, intf->cur_altsetting->endpoint[0].desc.bEndpointAddress), @@ -475,11 +479,15 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id intf->cur_altsetting->endpoint[0].desc.bInterval); ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->cbw_urb == NULL) + if (ushc->cbw_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL); - if (ushc->cbw == NULL) + if (ushc->cbw == NULL) { + ret = -ENOMEM; goto err; + } ushc->cbw->signature = USHC_CBW_SIGNATURE; usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2), @@ -487,15 +495,21 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id cbw_callback, ushc); ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->data_urb == NULL) + if (ushc->data_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->csw_urb == NULL) + if (ushc->csw_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL); - if (ushc->csw == NULL) + if (ushc->csw == NULL) { + ret = -ENOMEM; goto err; + } usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6), ushc->csw, sizeof(struct ushc_csw), csw_callback, ushc); |