diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 22:35:52 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 22:35:52 +0100 |
commit | e531cdf50a8a0fb7a4d51c06e52097bd01e9bf7c (patch) | |
tree | 55a0b1f8116f4d4800b7f3b0d5422cb12f0397fd /drivers/mmc/host/sdhci.c | |
parent | Merge tag 'md/4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md (diff) | |
parent | mmc: sdhci-of-at91: fix wake-up issue when using runtime pm (diff) | |
download | linux-e531cdf50a8a0fb7a4d51c06e52097bd01e9bf7c.tar.xz linux-e531cdf50a8a0fb7a4d51c06e52097bd01e9bf7c.zip |
Merge tag 'mmc-v4.6' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Fix ABI regression of MMC BLK ioctl
- Remove the unused MMC_DATA_STREAM flag
- Enable asynchronous system PM for the host device
- Minor fixes and clean-ups
SDHCI host:
Throughout the years, the numbers of SDHCI variants have increased
and so has also the numbers of SDHCI callbacks/quirks. The purpose
of these callbacks/quirks were to enable SDHCI to deal with variant
specific requirements, but unfortunate this method didn't scale.
Instead we have ended up with a mess. Not only did the code become
suboptimal but also highly fragile.
Lately many discussions of how to move forward with SDHCI has taken
place at the MMC mailing list. Step by step, we aim to turn
SDHCI's common code into a set of library functions. This will
enable for optimizations and allow some of the existing callbacks
and quirks to be removed, which also should help to make the code
less fragile.
Therefore I am also really pleased to announce that Adrian Hunter
(Intel) has volunteered to step in as the maintainer for SDHCI.
Future wise, I hope the community around SDHCI will continue to
grow and that this release cycle can be the starting point of
moving SDHCI into a better shape. As a matter of fact, already in
this cycle the re-factoring has begun, but of course there are also
fixes and new features included. Some highlights:
- sdhci-iproc: Add support for Broadcom's BCM2835 eMMC IP
- sdhci-acpi: Add support for QCOM controllers
- sdhci-pic32: Add new SDHCI variant for PIC32MZDA
Other hosts:
- atmel-mci: Fix a NULL pointer dereference
- mediatek: Add SD write-protect support
- mmc_spi: Fix card detect in GPIO case
- tmio/sdhi: Add r8a7795 support
- tmio/sdhi: Some fixes and clean-ups
- dw_mmc: Add HW reset support
- dw_mmc: Some fixes and clean-ups
- sunxi: Add support for MMC DDR52 mode"
* tag 'mmc-v4.6' of git://git.linaro.org/people/ulf.hansson/mmc: (123 commits)
mmc: sdhci-of-at91: fix wake-up issue when using runtime pm
mmc: sdhci-pci: Do not set DMA mask in enable_dma()
mmc: sdhci-acpi: Remove enable_dma() hook
mmc: sdhci: Set DMA mask when adding host
mmc: block: fix ABI regression of mmc_blk_ioctl
mmc: atmel-mci: Check pdata for NULL before dereferencing it at DMA config
mmc: core: remove redundant memset of sdio_read_cccr
mmc: core: remove redundant memset of mmc_decode_cid
mmc: of_mmc_spi: fix unused warning
mmc: sdhci-of-arasan: add phy support for sdhci-of-arasan
mmc: sdhci-of-arasan: fix missing sdhci_pltfm_free for err handling
mmc: sdhci-of-arasan: remove disable clk_ahb from sdhci_arasan_resume
Documentation: bindings: add description of phy for sdhci-of-arasan
mmc: sdhci: Fix override of timeout clk wrt max_busy_timeout
mmc: mmci: Remove unnecessary header file
mmc: sdhci-acpi: add QCOM controllers
mmc: tegra: implement memcomp pad calibration
mmc: mediatek: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch
mmc: mediatek: Change signal voltage error to dev_dbg()
mmc: sh_mmcif, tmio: Use ARCH_RENESAS
...
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 500 |
1 files changed, 239 insertions, 261 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index add9fdfd1d8f..8670f162dec7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -53,8 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); -static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data); static int sdhci_do_get_cd(struct sdhci_host *host); #ifdef CONFIG_PM @@ -428,6 +426,31 @@ static void sdhci_transfer_pio(struct sdhci_host *host) DBG("PIO transfer complete.\n"); } +static int sdhci_pre_dma_transfer(struct sdhci_host *host, + struct mmc_data *data, int cookie) +{ + int sg_count; + + /* + * If the data buffers are already mapped, return the previous + * dma_map_sg() result. + */ + if (data->host_cookie == COOKIE_PRE_MAPPED) + return data->sg_count; + + sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + + if (sg_count == 0) + return -ENOSPC; + + data->sg_count = sg_count; + data->host_cookie = cookie; + + return sg_count; +} + static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); @@ -462,41 +485,22 @@ static void sdhci_adma_mark_end(void *desc) dma_desc->cmd |= cpu_to_le16(ADMA2_END); } -static int sdhci_adma_table_pre(struct sdhci_host *host, - struct mmc_data *data) +static void sdhci_adma_table_pre(struct sdhci_host *host, + struct mmc_data *data, int sg_count) { - int direction; - - void *desc; - void *align; - dma_addr_t addr; - dma_addr_t align_addr; - int len, offset; - struct scatterlist *sg; - int i; - char *buffer; unsigned long flags; + dma_addr_t addr, align_addr; + void *desc, *align; + char *buffer; + int len, offset, i; /* * The spec does not specify endianness of descriptor table. * We currently guess that it is LE. */ - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - - host->align_addr = dma_map_single(mmc_dev(host->mmc), - host->align_buffer, host->align_buffer_sz, direction); - if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) - goto fail; - BUG_ON(host->align_addr & SDHCI_ADMA2_MASK); - - host->sg_count = sdhci_pre_dma_transfer(host, data); - if (host->sg_count < 0) - goto unmap_align; + host->sg_count = sg_count; desc = host->adma_table; align = host->align_buffer; @@ -508,10 +512,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, len = sg_dma_len(sg); /* - * The SDHCI specification states that ADMA - * addresses must be 32-bit aligned. If they - * aren't, then we use a bounce buffer for - * the (up to three) bytes that screw up the + * The SDHCI specification states that ADMA addresses must + * be 32-bit aligned. If they aren't, then we use a bounce + * buffer for the (up to three) bytes that screw up the * alignment. */ offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) & @@ -555,92 +558,56 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, } if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { - /* - * Mark the last descriptor as the terminating descriptor - */ + /* Mark the last descriptor as the terminating descriptor */ if (desc != host->adma_table) { desc -= host->desc_sz; sdhci_adma_mark_end(desc); } } else { - /* - * Add a terminating entry. - */ - - /* nop, end, valid */ + /* Add a terminating entry - nop, end, valid */ sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); } - - /* - * Resync align buffer as we might have changed it. - */ - if (data->flags & MMC_DATA_WRITE) { - dma_sync_single_for_device(mmc_dev(host->mmc), - host->align_addr, host->align_buffer_sz, direction); - } - - return 0; - -unmap_align: - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - host->align_buffer_sz, direction); -fail: - return -EINVAL; } static void sdhci_adma_table_post(struct sdhci_host *host, struct mmc_data *data) { - int direction; - struct scatterlist *sg; int i, size; void *align; char *buffer; unsigned long flags; - bool has_unaligned; - - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - host->align_buffer_sz, direction); + if (data->flags & MMC_DATA_READ) { + bool has_unaligned = false; - /* Do a quick scan of the SG list for any unaligned mappings */ - has_unaligned = false; - for_each_sg(data->sg, sg, host->sg_count, i) - if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { - has_unaligned = true; - break; - } + /* Do a quick scan of the SG list for any unaligned mappings */ + for_each_sg(data->sg, sg, host->sg_count, i) + if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { + has_unaligned = true; + break; + } - if (has_unaligned && data->flags & MMC_DATA_READ) { - dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); + if (has_unaligned) { + dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, + data->sg_len, DMA_FROM_DEVICE); - align = host->align_buffer; + align = host->align_buffer; - for_each_sg(data->sg, sg, host->sg_count, i) { - if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { - size = SDHCI_ADMA2_ALIGN - - (sg_dma_address(sg) & SDHCI_ADMA2_MASK); + for_each_sg(data->sg, sg, host->sg_count, i) { + if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { + size = SDHCI_ADMA2_ALIGN - + (sg_dma_address(sg) & SDHCI_ADMA2_MASK); - buffer = sdhci_kmap_atomic(sg, &flags); - memcpy(buffer, align, size); - sdhci_kunmap_atomic(buffer, &flags); + buffer = sdhci_kmap_atomic(sg, &flags); + memcpy(buffer, align, size); + sdhci_kunmap_atomic(buffer, &flags); - align += SDHCI_ADMA2_ALIGN; + align += SDHCI_ADMA2_ALIGN; + } } } } - - if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); - data->host_cookie = COOKIE_UNMAPPED; - } } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) @@ -666,9 +633,20 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) if (!data) target_timeout = cmd->busy_timeout * 1000; else { - target_timeout = data->timeout_ns / 1000; - if (host->clock) - target_timeout += data->timeout_clks / host->clock; + target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); + if (host->clock && data->timeout_clks) { + unsigned long long val; + + /* + * data->timeout_clks is in units of clock cycles. + * host->clock is in Hz. target_timeout is in us. + * Hence, us = 1000000 * cycles / Hz. Round up. + */ + val = 1000000 * data->timeout_clks; + if (do_div(val, host->clock)) + target_timeout++; + target_timeout += val; + } } /* @@ -729,7 +707,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) { u8 ctrl; struct mmc_data *data = cmd->data; - int ret; WARN_ON(host->data); @@ -748,63 +725,48 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) host->data_early = 0; host->data->bytes_xfered = 0; - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) - host->flags |= SDHCI_REQ_USE_DMA; - - /* - * FIXME: This doesn't account for merging when mapping the - * scatterlist. - */ - if (host->flags & SDHCI_REQ_USE_DMA) { - int broken, i; + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { struct scatterlist *sg; + unsigned int length_mask, offset_mask; + int i; + + host->flags |= SDHCI_REQ_USE_DMA; - broken = 0; + /* + * FIXME: This doesn't account for merging when mapping the + * scatterlist. + * + * The assumption here being that alignment and lengths are + * the same after DMA mapping to device address space. + */ + length_mask = 0; + offset_mask = 0; if (host->flags & SDHCI_USE_ADMA) { - if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - broken = 1; + if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) { + length_mask = 3; + /* + * As we use up to 3 byte chunks to work + * around alignment problems, we need to + * check the offset as well. + */ + offset_mask = 3; + } } else { if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) - broken = 1; + length_mask = 3; + if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) + offset_mask = 3; } - if (unlikely(broken)) { + if (unlikely(length_mask | offset_mask)) { for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->length & 0x3) { + if (sg->length & length_mask) { DBG("Reverting to PIO because of transfer size (%d)\n", - sg->length); + sg->length); host->flags &= ~SDHCI_REQ_USE_DMA; break; } - } - } - } - - /* - * The assumption here being that alignment is the same after - * translation to device address space. - */ - if (host->flags & SDHCI_REQ_USE_DMA) { - int broken, i; - struct scatterlist *sg; - - broken = 0; - if (host->flags & SDHCI_USE_ADMA) { - /* - * As we use 3 byte chunks to work around - * alignment problems, we need to check this - * quirk. - */ - if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - broken = 1; - } else { - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) - broken = 1; - } - - if (unlikely(broken)) { - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 0x3) { + if (sg->offset & offset_mask) { DBG("Reverting to PIO because of bad alignment\n"); host->flags &= ~SDHCI_REQ_USE_DMA; break; @@ -814,39 +776,27 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } if (host->flags & SDHCI_REQ_USE_DMA) { - if (host->flags & SDHCI_USE_ADMA) { - ret = sdhci_adma_table_pre(host, data); - if (ret) { - /* - * This only happens when someone fed - * us an invalid request. - */ - WARN_ON(1); - host->flags &= ~SDHCI_REQ_USE_DMA; - } else { - sdhci_writel(host, host->adma_addr, - SDHCI_ADMA_ADDRESS); - if (host->flags & SDHCI_USE_64_BIT_DMA) - sdhci_writel(host, - (u64)host->adma_addr >> 32, - SDHCI_ADMA_ADDRESS_HI); - } - } else { - int sg_cnt; + int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED); - sg_cnt = sdhci_pre_dma_transfer(host, data); - if (sg_cnt <= 0) { - /* - * This only happens when someone fed - * us an invalid request. - */ - WARN_ON(1); - host->flags &= ~SDHCI_REQ_USE_DMA; - } else { - WARN_ON(sg_cnt != 1); - sdhci_writel(host, sg_dma_address(data->sg), - SDHCI_DMA_ADDRESS); - } + if (sg_cnt <= 0) { + /* + * This only happens when someone fed + * us an invalid request. + */ + WARN_ON(1); + host->flags &= ~SDHCI_REQ_USE_DMA; + } else if (host->flags & SDHCI_USE_ADMA) { + sdhci_adma_table_pre(host, data, sg_cnt); + + sdhci_writel(host, host->adma_addr, SDHCI_ADMA_ADDRESS); + if (host->flags & SDHCI_USE_64_BIT_DMA) + sdhci_writel(host, + (u64)host->adma_addr >> 32, + SDHCI_ADMA_ADDRESS_HI); + } else { + WARN_ON(sg_cnt != 1); + sdhci_writel(host, sg_dma_address(data->sg), + SDHCI_DMA_ADDRESS); } } @@ -946,19 +896,9 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; - if (host->flags & SDHCI_REQ_USE_DMA) { - if (host->flags & SDHCI_USE_ADMA) - sdhci_adma_table_post(host, data); - else { - if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - data->host_cookie = COOKIE_UNMAPPED; - } - } - } + if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) == + (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) + sdhci_adma_table_post(host, data); /* * The specification states that the block count register must @@ -1003,6 +943,9 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) WARN_ON(host->cmd); + /* Initially, a command has no error */ + cmd->error = 0; + /* Wait max 10 ms */ timeout = 10; @@ -1097,8 +1040,6 @@ static void sdhci_finish_command(struct sdhci_host *host) } } - host->cmd->error = 0; - /* Finished CMD23, now send actual command. */ if (host->cmd == host->mrq->sbc) { host->cmd = NULL; @@ -2114,39 +2055,12 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct sdhci_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; - if (host->flags & SDHCI_REQ_USE_DMA) { - if (data->host_cookie == COOKIE_GIVEN || - data->host_cookie == COOKIE_MAPPED) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - data->host_cookie = COOKIE_UNMAPPED; - } -} - -static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data) -{ - int sg_count; - - if (data->host_cookie == COOKIE_MAPPED) { - data->host_cookie = COOKIE_GIVEN; - return data->sg_count; - } + if (data->host_cookie != COOKIE_UNMAPPED) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); - WARN_ON(data->host_cookie == COOKIE_GIVEN); - - sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (sg_count == 0) - return -ENOSPC; - - data->sg_count = sg_count; - data->host_cookie = COOKIE_MAPPED; - - return sg_count; + data->host_cookie = COOKIE_UNMAPPED; } static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, @@ -2157,7 +2071,7 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, mrq->data->host_cookie = COOKIE_UNMAPPED; if (host->flags & SDHCI_REQ_USE_DMA) - sdhci_pre_dma_transfer(host, mrq->data); + sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED); } static void sdhci_card_event(struct mmc_host *mmc) @@ -2238,6 +2152,22 @@ static void sdhci_tasklet_finish(unsigned long param) mrq = host->mrq; /* + * Always unmap the data buffers if they were mapped by + * sdhci_prepare_data() whenever we finish with a request. + * This avoids leaking DMA mappings on error. + */ + if (host->flags & SDHCI_REQ_USE_DMA) { + struct mmc_data *data = mrq->data; + + if (data && data->host_cookie == COOKIE_MAPPED) { + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + (data->flags & MMC_DATA_READ) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + data->host_cookie = COOKIE_UNMAPPED; + } + } + + /* * The controller needs a reset of internal state machines * upon error conditions. */ @@ -2322,13 +2252,30 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) return; } - if (intmask & SDHCI_INT_TIMEOUT) - host->cmd->error = -ETIMEDOUT; - else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | - SDHCI_INT_INDEX)) - host->cmd->error = -EILSEQ; + if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | + SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) { + if (intmask & SDHCI_INT_TIMEOUT) + host->cmd->error = -ETIMEDOUT; + else + host->cmd->error = -EILSEQ; + + /* + * If this command initiates a data phase and a response + * CRC error is signalled, the card can start transferring + * data - the card may have received the command without + * error. We must not terminate the mmc_request early. + * + * If the card did not receive the command or returned an + * error which prevented it sending data, the data phase + * will time out. + */ + if (host->cmd->data && + (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) == + SDHCI_INT_CRC) { + host->cmd = NULL; + return; + } - if (host->cmd->error) { tasklet_schedule(&host->finish_tasklet); return; } @@ -2857,6 +2804,36 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, EXPORT_SYMBOL_GPL(sdhci_alloc_host); +static int sdhci_set_dma_mask(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc_dev(mmc); + int ret = -EINVAL; + + if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) + host->flags &= ~SDHCI_USE_64_BIT_DMA; + + /* Try 64-bit mask if hardware is capable of it */ + if (host->flags & SDHCI_USE_64_BIT_DMA) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) { + pr_warn("%s: Failed to set 64-bit DMA mask.\n", + mmc_hostname(mmc)); + host->flags &= ~SDHCI_USE_64_BIT_DMA; + } + } + + /* 32-bit mask as default & fallback */ + if (ret) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + pr_warn("%s: Failed to set 32-bit DMA mask.\n", + mmc_hostname(mmc)); + } + + return ret; +} + int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; @@ -2928,17 +2905,21 @@ int sdhci_add_host(struct sdhci_host *host) * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to * implement. */ - if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) + if (caps[0] & SDHCI_CAN_64BIT) host->flags |= SDHCI_USE_64_BIT_DMA; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if (host->ops->enable_dma) { - if (host->ops->enable_dma(host)) { - pr_warn("%s: No suitable DMA available - falling back to PIO\n", - mmc_hostname(mmc)); - host->flags &= - ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); - } + ret = sdhci_set_dma_mask(host); + + if (!ret && host->ops->enable_dma) + ret = host->ops->enable_dma(host); + + if (ret) { + pr_warn("%s: No suitable DMA available - falling back to PIO\n", + mmc_hostname(mmc)); + host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); + + ret = 0; } } @@ -2947,6 +2928,9 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_SDMA; if (host->flags & SDHCI_USE_ADMA) { + dma_addr_t dma; + void *buf; + /* * The DMA descriptor table size is calculated as the maximum * number of segments times 2, to allow for an alignment @@ -2962,33 +2946,27 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_ADMA2_32_DESC_SZ; host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; } - host->adma_table = dma_alloc_coherent(mmc_dev(mmc), - host->adma_table_sz, - &host->adma_addr, - GFP_KERNEL); + host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN; - host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); - if (!host->adma_table || !host->align_buffer) { - if (host->adma_table) - dma_free_coherent(mmc_dev(mmc), - host->adma_table_sz, - host->adma_table, - host->adma_addr); - kfree(host->align_buffer); + buf = dma_alloc_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, &dma, GFP_KERNEL); + if (!buf) { pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - host->adma_table = NULL; - host->align_buffer = NULL; - } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) { + } else if ((dma + host->align_buffer_sz) & + (SDHCI_ADMA2_DESC_ALIGN - 1)) { pr_warn("%s: unable to allocate aligned ADMA descriptor\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, - host->adma_table, host->adma_addr); - kfree(host->align_buffer); - host->adma_table = NULL; - host->align_buffer = NULL; + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, buf, dma); + } else { + host->align_buffer = buf; + host->align_addr = dma; + + host->adma_table = buf + host->align_buffer_sz; + host->adma_addr = dma + host->align_buffer_sz; } } @@ -3072,14 +3050,14 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT) host->timeout_clk *= 1000; + if (override_timeout_clk) + host->timeout_clk = override_timeout_clk; + mmc->max_busy_timeout = host->ops->get_max_timeout_count ? host->ops->get_max_timeout_count(host) : 1 << 27; mmc->max_busy_timeout /= host->timeout_clk; } - if (override_timeout_clk) - host->timeout_clk = override_timeout_clk; - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; @@ -3449,10 +3427,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); - if (host->adma_table) - dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, - host->adma_table, host->adma_addr); - kfree(host->align_buffer); + if (host->align_buffer) + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, host->align_buffer, + host->align_addr); host->adma_table = NULL; host->align_buffer = NULL; |