diff options
author | Laura Abbott <labbott@fedoraproject.org> | 2015-09-01 15:03:08 -0700 |
---|---|---|
committer | Laura Abbott <labbott@fedoraproject.org> | 2015-09-01 15:59:56 -0700 |
commit | d07b889185195409a6090ed3e12fff475b4258f4 (patch) | |
tree | c2b98784a9c45c2ba5420c4a256c03d1c1c2e125 /mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch | |
parent | 07775e21b6d0c7b9c2251deb8cb5ef3052a38c6e (diff) | |
download | kernel-d07b889185195409a6090ed3e12fff475b4258f4.tar.gz kernel-d07b889185195409a6090ed3e12fff475b4258f4.tar.xz kernel-d07b889185195409a6090ed3e12fff475b4258f4.zip |
Linux v4.2
This is a squashed patch of the history from F22 + the 4.2 rebase
Diffstat (limited to 'mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch')
-rw-r--r-- | mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch b/mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch new file mode 100644 index 000000000..c755534a0 --- /dev/null +++ b/mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch @@ -0,0 +1,203 @@ +From: Haibo Chen <haibo.chen@freescale.com> +Date: Tue, 25 Aug 2015 10:02:11 +0800 +Subject: [PATCH] mmc: sdhci: fix dma memory leak in sdhci_pre_req() + +Currently one mrq->data maybe execute dma_map_sg() twice +when mmc subsystem prepare over one new request, and the +following log show up: + sdhci[sdhci_pre_dma_transfer] invalid cookie: 24, next-cookie 25 + +In this condition, mrq->date map a dma-memory(1) in sdhci_pre_req +for the first time, and map another dma-memory(2) in sdhci_prepare_data +for the second time. But driver only unmap the dma-memory(2), and +dma-memory(1) never unmapped, which cause the dma memory leak issue. + +This patch use another method to map the dma memory for the mrq->data +which can fix this dma memory leak issue. + +Fixes: commit 348487cb28e66b0 ("mmc: sdhci: use pipeline mmc requests to improve performance") +Cc: stable@vger.kernel.org # 4.0+ +Reported-and-tested-by: Jiri Slaby <jslaby@suse.cz> +Signed-off-by: Haibo Chen <haibo.chen@freescale.com> +--- + drivers/mmc/host/sdhci.c | 67 ++++++++++++++++++------------------------------ + drivers/mmc/host/sdhci.h | 8 +++--- + 2 files changed, 29 insertions(+), 46 deletions(-) + +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 1dbe932..ea10ebc 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -54,8 +54,7 @@ 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, +- struct sdhci_host_next *next); ++ struct mmc_data *data); + static int sdhci_do_get_cd(struct sdhci_host *host); + + #ifdef CONFIG_PM +@@ -496,7 +495,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, + goto fail; + BUG_ON(host->align_addr & host->align_mask); + +- host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); ++ host->sg_count = sdhci_pre_dma_transfer(host, data); + if (host->sg_count < 0) + goto unmap_align; + +@@ -635,9 +634,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, + } + } + +- if (!data->host_cookie) ++ 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) +@@ -833,7 +834,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) + } else { + int sg_cnt; + +- sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); ++ sg_cnt = sdhci_pre_dma_transfer(host, data); + if (sg_cnt <= 0) { + /* + * This only happens when someone fed +@@ -949,11 +950,13 @@ static void sdhci_finish_data(struct sdhci_host *host) + if (host->flags & SDHCI_USE_ADMA) + sdhci_adma_table_post(host, data); + else { +- if (!data->host_cookie) ++ 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; ++ } + } + } + +@@ -2097,49 +2100,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, + struct mmc_data *data = mrq->data; + + if (host->flags & SDHCI_REQ_USE_DMA) { +- if (data->host_cookie) ++ 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); +- mrq->data->host_cookie = 0; ++ data->host_cookie = COOKIE_UNMAPPED; + } + } + + static int sdhci_pre_dma_transfer(struct sdhci_host *host, +- struct mmc_data *data, +- struct sdhci_host_next *next) ++ struct mmc_data *data) + { + int sg_count; + +- if (!next && data->host_cookie && +- data->host_cookie != host->next_data.cookie) { +- pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", +- __func__, data->host_cookie, host->next_data.cookie); +- data->host_cookie = 0; ++ if (data->host_cookie == COOKIE_MAPPED) { ++ data->host_cookie = COOKIE_GIVEN; ++ return data->sg_count; + } + +- /* Check if next job is already prepared */ +- if (next || +- (!next && data->host_cookie != host->next_data.cookie)) { +- 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); +- +- } else { +- sg_count = host->next_data.sg_count; +- host->next_data.sg_count = 0; +- } ++ 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 -EINVAL; ++ return -ENOSPC; + +- if (next) { +- next->sg_count = sg_count; +- data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; +- } else +- host->sg_count = sg_count; ++ data->sg_count = sg_count; ++ data->host_cookie = COOKIE_MAPPED; + + return sg_count; + } +@@ -2149,16 +2139,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, + { + struct sdhci_host *host = mmc_priv(mmc); + +- if (mrq->data->host_cookie) { +- mrq->data->host_cookie = 0; +- return; +- } ++ mrq->data->host_cookie = COOKIE_UNMAPPED; + + if (host->flags & SDHCI_REQ_USE_DMA) +- if (sdhci_pre_dma_transfer(host, +- mrq->data, +- &host->next_data) < 0) +- mrq->data->host_cookie = 0; ++ sdhci_pre_dma_transfer(host, mrq->data); + } + + static void sdhci_card_event(struct mmc_host *mmc) +@@ -3030,7 +3014,6 @@ int sdhci_add_host(struct sdhci_host *host) + host->max_clk = host->ops->get_max_clock(host); + } + +- host->next_data.cookie = 1; + /* + * In case of Host Controller v3.00, find out whether clock + * multiplier is supported. +diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h +index 5521d29..a9512a4 100644 +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc { + */ + #define SDHCI_MAX_SEGS 128 + +-struct sdhci_host_next { +- unsigned int sg_count; +- s32 cookie; ++enum sdhci_cookie { ++ COOKIE_UNMAPPED, ++ COOKIE_MAPPED, ++ COOKIE_GIVEN, + }; + + struct sdhci_host { +@@ -503,7 +504,6 @@ struct sdhci_host { + unsigned int tuning_mode; /* Re-tuning mode supported by host */ + #define SDHCI_TUNING_MODE_1 0 + +- struct sdhci_host_next next_data; + unsigned long private[0] ____cacheline_aligned; + }; + |