mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
MMC core:
- Prevent potential use-after-free for SDIO IRQ work - Fix OF node reference leak on card add failure - Fix memory lea when the port table is full for sdio_uart MMC host: - hsq: Fix use-after-free in retry work - mmci: Fix use-after-free in busy-timeout work - mmc_spi: Reset bytes_xfered before retrying CRC failures - mxcmmc: Cancel data work and watchdog on remove - rtsx_pci_sdmmc: Ignore broken write-protect on ThinkPad X260 - sdhci_am654: A couple of fixes for the tuning sequence - sdhci-of-aspeed: Remove children before releasing SDC resources - sh_mmcif: Initialize IRQ-thread mutex before requesting interrupt MEMSTICK: - ms_block: Destroy io_queue workqueue on removal -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmqtI4oQHHVsZmhAa2Vy bmVsLm9yZwAKCRD+JoQlc1iMKcjwD/91lyNP8fb8cxorEtmkiNt63Sb+glVEnobW aOlXS23GuV9ZsPw7kKEEfZ4EWCOTEZ86Lj0OMzlpXE8dxYHGlu0qG97uxSiJ4wux LQ0+OR5ljqDN48BWrn3wWsJ1YLfM4xXL7XukiCEuxLU9jwlbPHNjtY8c0+JqMapH D1yE7tH7/ZPJuYwKt9DJlx5DKg0BTiRn/7j+o3IETNyuBP05ZzrUjNdgQW8DVawg 2uR0GCZ268Asd7XhnywvLXbeg5jxRAEVMGVjEzn2CY5uY0YyUW9ye9e+TpbNqpYf OA2MnYiTNpcRIiI3Z8R5vrhGxMpqFd5hFdIUE64O5gnjSyrBKeo9SSw4huXlLvac xjdBYmtLxSQjIgvZaEG4hl12lJt/snLJODTEq690zei9oWCUnCKzZaargLFPcDje 0J8HwPYStynI0nc2Jc4oGZEGGwgvSmFPk15JtMEdmJb3eIwOfzGLA1ky9+5VEVCC zzMifnvnseAJwz+iAaJYxkED3Gd4t/jm4n8XIihddsKBQHAbMtGhUmhSzNnzD6NF xgscpv8s8SKExwS6X+6f/SBZD4VoF9b1JDhJ+fVUJDQ1Dsgv9AyT/bl8gDBHPNwr JHflPaQhc3hM9RppdcZnW3KSCu3DCJ04XaoHy6m5zKWZHUBEAtxujHA5u373Wv89 StY7v7d7UQ== =KPXN -----END PGP SIGNATURE----- Merge tag 'mmc-v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC/MEMSTICK fixes from Ulf Hansson: "MMC core: - Prevent potential use-after-free for SDIO IRQ work - Fix OF node reference leak on card add failure - Fix memory lea when the port table is full for sdio_uart MMC host: - hsq: Fix use-after-free in retry work - mmci: Fix use-after-free in busy-timeout work - mmc_spi: Reset bytes_xfered before retrying CRC failures - mxcmmc: Cancel data work and watchdog on remove - rtsx_pci_sdmmc: Ignore broken write-protect on ThinkPad X260 - sdhci_am654: A couple of fixes for the tuning sequence - sdhci-of-aspeed: Remove children before releasing SDC resources - sh_mmcif: Initialize IRQ-thread mutex before requesting interrupt MEMSTICK: - ms_block: Destroy io_queue workqueue on removal * tag 'mmc-v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: mmc: sdhci-of-aspeed: Remove children before releasing SDC resources mmc: sh_mmcif: initialize IRQ-thread mutex before requesting interrupt mmc: core: Fix OF node reference leak on card add failure mmc: rtsx_pci_sdmmc: ignore broken write-protect on ThinkPad X260 mmc: sdio_uart: fix xmit_fifo leak when the port table is full mmc: spi: reset bytes_xfered before retrying CRC failures mmc: sdhci_am654: Fallback to DT-provided itap delay on DDR50 tuning failure mmc: sdhci_am654: Clear ITAPDLY on tuning failure mmc: sdhci_am654: Reset command and data lines on failed tuning mmc: sdhci_am654: Move tuning_loop to local variable mmc: hsq: Fix use-after-free in retry work mmc: mxcmmc: cancel data work and watchdog on remove mmc: mmci: Fix use-after-free in busy-timeout work mmc: core: Cancel SDIO IRQ work before freeing host memstick: ms_block: destroy io_queue workqueue on removal
This commit is contained in:
commit
8cb0606271
|
|
@ -2204,6 +2204,8 @@ static void msb_remove(struct memstick_dev *card)
|
|||
msb_data_clear(msb);
|
||||
mutex_unlock(&msb_disk_lock);
|
||||
|
||||
destroy_workqueue(msb->io_queue);
|
||||
|
||||
put_disk(msb->disk);
|
||||
memstick_set_drvdata(card, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -417,8 +417,8 @@ void mmc_remove_card(struct mmc_card *card)
|
|||
mmc_hostname(card->host), card->rca);
|
||||
}
|
||||
device_del(&card->dev);
|
||||
of_node_put(card->dev.of_node);
|
||||
}
|
||||
of_node_put(card->dev.of_node);
|
||||
|
||||
if (host->cqe_enabled) {
|
||||
host->cqe_ops->cqe_disable(host);
|
||||
|
|
|
|||
|
|
@ -698,6 +698,7 @@ EXPORT_SYMBOL(mmc_remove_host);
|
|||
void mmc_free_host(struct mmc_host *host)
|
||||
{
|
||||
cancel_delayed_work_sync(&host->detect);
|
||||
cancel_work_sync(&host->sdio_irq_work);
|
||||
mmc_pwrseq_free(host);
|
||||
put_device(&host->class_dev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
|
|||
}
|
||||
spin_unlock(&sdio_uart_table_lock);
|
||||
|
||||
if (ret)
|
||||
kfifo_free(&port->xmit_fifo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* Author: Baolin Wang <baolin.wang@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/devm-helpers.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -345,6 +346,7 @@ static const struct mmc_cqe_ops mmc_hsq_ops = {
|
|||
|
||||
int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
hsq->num_slots = HSQ_NUM_SLOTS;
|
||||
hsq->next_tag = HSQ_INVALID_TAG;
|
||||
|
|
@ -363,7 +365,11 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
|
|||
for (i = 0; i < HSQ_NUM_SLOTS; i++)
|
||||
hsq->tag_slot[i] = HSQ_INVALID_TAG;
|
||||
|
||||
INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
|
||||
ret = devm_work_autocancel(mmc_dev(mmc), &hsq->retry_work,
|
||||
mmc_hsq_retry_handler);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&hsq->lock);
|
||||
init_waitqueue_head(&hsq->wait_queue);
|
||||
|
||||
|
|
|
|||
|
|
@ -952,6 +952,7 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
status = mmc_spi_command_send(host, mrq, &stop, 0);
|
||||
crc_retry--;
|
||||
mrq->data->error = 0;
|
||||
mrq->data->bytes_xfered = 0;
|
||||
goto crc_recover;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2511,6 +2511,9 @@ static void mmci_remove(struct amba_device *dev)
|
|||
writel(0, host->base + MMCICOMMAND);
|
||||
writel(0, host->base + MMCIDATACTRL);
|
||||
|
||||
if (variant->busy_detect)
|
||||
disable_delayed_work_sync(&host->ux500_busy_timeout_work);
|
||||
|
||||
mmci_dma_release(host);
|
||||
clk_disable_unprepare(host->clk);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1173,6 +1173,10 @@ static void mxcmci_remove(struct platform_device *pdev)
|
|||
|
||||
mmc_remove_host(mmc);
|
||||
|
||||
devm_free_irq(&pdev->dev, platform_get_irq(pdev, 0), host);
|
||||
cancel_work_sync(&host->datawork);
|
||||
timer_delete_sync(&host->watchdog);
|
||||
|
||||
if (host->pdata && host->pdata->exit)
|
||||
host->pdata->exit(&pdev->dev, mmc);
|
||||
|
||||
|
|
|
|||
|
|
@ -1425,6 +1425,11 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host)
|
|||
mmc->caps = mmc->caps | MMC_CAP_AGGRESSIVE_PM;
|
||||
mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
|
||||
MMC_CAP2_NO_SDIO;
|
||||
|
||||
if (pcr->pci->device == 0x522a &&
|
||||
pcr->pci->subsystem_vendor == PCI_VENDOR_ID_LENOVO &&
|
||||
pcr->pci->subsystem_device == 0x504a)
|
||||
mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
|
||||
mmc->max_current_330 = 400;
|
||||
mmc->max_current_180 = 800;
|
||||
mmc->ops = &realtek_pci_sdmmc_ops;
|
||||
|
|
|
|||
|
|
@ -560,12 +560,14 @@ static int aspeed_sdc_probe(struct platform_device *pdev)
|
|||
cpdev = of_platform_device_create(child, NULL, &pdev->dev);
|
||||
if (!cpdev) {
|
||||
ret = -ENODEV;
|
||||
goto err_clk;
|
||||
goto err_children;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_children:
|
||||
device_for_each_child_reverse(&pdev->dev, NULL, of_platform_device_destroy);
|
||||
err_clk:
|
||||
clk_disable_unprepare(sdc->clk);
|
||||
return ret;
|
||||
|
|
@ -575,6 +577,7 @@ static void aspeed_sdc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
device_for_each_child_reverse(&pdev->dev, NULL, of_platform_device_destroy);
|
||||
clk_disable_unprepare(sdc->clk);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ static const struct timing_data td[] = {
|
|||
NULL,
|
||||
MMC_CAP_UHS_SDR104},
|
||||
[MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50",
|
||||
NULL,
|
||||
"ti,itap-del-sel-ddr50",
|
||||
MMC_CAP_UHS_DDR50},
|
||||
[MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52",
|
||||
"ti,itap-del-sel-ddr52",
|
||||
|
|
@ -144,6 +144,8 @@ struct sdhci_am654_data {
|
|||
u32 otap_del_sel[ARRAY_SIZE(td)];
|
||||
u32 itap_del_sel[ARRAY_SIZE(td)];
|
||||
u32 itap_del_ena[ARRAY_SIZE(td)];
|
||||
u32 itap_del_sel_dt_ddr50;
|
||||
u32 itap_del_ena_dt_ddr50;
|
||||
int clkbuf_sel;
|
||||
int trm_icp;
|
||||
int drv_strength;
|
||||
|
|
@ -151,7 +153,6 @@ struct sdhci_am654_data {
|
|||
u32 flags;
|
||||
u32 quirks;
|
||||
bool dll_enable;
|
||||
u32 tuning_loop;
|
||||
|
||||
#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
|
||||
#define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1)
|
||||
|
|
@ -443,15 +444,13 @@ static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
int err = sdhci_execute_tuning(mmc, opcode);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* Tuning data remains in the buffer after tuning.
|
||||
* Do a command and data reset to get rid of it
|
||||
*/
|
||||
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
|
||||
|
|
@ -530,7 +529,6 @@ static int sdhci_am654_do_tuning(struct sdhci_host *host,
|
|||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||
unsigned char timing = host->mmc->ios.timing;
|
||||
struct window fail_window[ITAPDLY_LENGTH];
|
||||
struct device *dev = mmc_dev(host->mmc);
|
||||
u8 curr_pass, itap;
|
||||
|
|
@ -539,11 +537,8 @@ static int sdhci_am654_do_tuning(struct sdhci_host *host,
|
|||
|
||||
memset(fail_window, 0, sizeof(fail_window));
|
||||
|
||||
/* Enable ITAPDLY */
|
||||
sdhci_am654->itap_del_ena[timing] = 0x1;
|
||||
|
||||
for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
|
||||
sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);
|
||||
sdhci_am654_write_itapdly(sdhci_am654, itap, 0x1);
|
||||
|
||||
curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL);
|
||||
|
||||
|
|
@ -576,20 +571,36 @@ static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host,
|
|||
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||
unsigned char timing = host->mmc->ios.timing;
|
||||
struct device *dev = mmc_dev(host->mmc);
|
||||
unsigned int tuning_loop = 0;
|
||||
int itapdly;
|
||||
|
||||
do {
|
||||
itapdly = sdhci_am654_do_tuning(host, opcode);
|
||||
if (itapdly >= 0)
|
||||
break;
|
||||
} while (++sdhci_am654->tuning_loop < RETRY_TUNING_MAX);
|
||||
} while (++tuning_loop < RETRY_TUNING_MAX);
|
||||
|
||||
if (itapdly < 0) {
|
||||
dev_err(dev, "Failed to find itapdly, fail tuning\n");
|
||||
if (timing == MMC_TIMING_UHS_DDR50) {
|
||||
dev_dbg(dev, "Failed DDR50 tuning, fallback to DT ITAP\n");
|
||||
sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel_dt_ddr50;
|
||||
sdhci_am654->itap_del_ena[timing] = sdhci_am654->itap_del_ena_dt_ddr50;
|
||||
} else {
|
||||
dev_err(dev, "Failed to find itapdly, fail tuning\n");
|
||||
sdhci_am654->itap_del_ena[timing] = 0;
|
||||
sdhci_am654->itap_del_sel[timing] = 0;
|
||||
}
|
||||
|
||||
sdhci_am654_write_itapdly(sdhci_am654,
|
||||
sdhci_am654->itap_del_sel[timing],
|
||||
sdhci_am654->itap_del_ena[timing]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Passed tuning, final itapdly=%d\n", itapdly);
|
||||
|
||||
/* Enable ITAPDLY */
|
||||
sdhci_am654->itap_del_ena[timing] = 0x1;
|
||||
sdhci_am654_write_itapdly(sdhci_am654, itapdly, sdhci_am654->itap_del_ena[timing]);
|
||||
/* Save ITAPDLY */
|
||||
sdhci_am654->itap_del_sel[timing] = itapdly;
|
||||
|
|
@ -758,6 +769,11 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
|
|||
}
|
||||
}
|
||||
|
||||
sdhci_am654->itap_del_sel_dt_ddr50 =
|
||||
sdhci_am654->itap_del_sel[MMC_TIMING_UHS_DDR50];
|
||||
sdhci_am654->itap_del_ena_dt_ddr50 =
|
||||
sdhci_am654->itap_del_ena[MMC_TIMING_UHS_DDR50];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -806,9 +822,6 @@ static int sdhci_am654_init(struct sdhci_host *host)
|
|||
regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK,
|
||||
TUNINGFORSDR50_MASK);
|
||||
|
||||
/* Use to re-execute tuning */
|
||||
sdhci_am654->tuning_loop = 0;
|
||||
|
||||
ret = sdhci_setup_host(host);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -1461,6 +1461,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
|
|||
host->pd = pdev;
|
||||
|
||||
spin_lock_init(&host->lock);
|
||||
mutex_init(&host->thread_lock);
|
||||
|
||||
mmc->ops = &sh_mmcif_ops;
|
||||
sh_mmcif_init_ocr(host);
|
||||
|
|
@ -1515,8 +1516,6 @@ static int sh_mmcif_probe(struct platform_device *pdev)
|
|||
goto err_clk;
|
||||
}
|
||||
|
||||
mutex_init(&host->thread_lock);
|
||||
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret < 0)
|
||||
goto err_clk;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user