summaryrefslogtreecommitdiff
path: root/target/device/Atmel/arch-avr32/kernel-patches-2.6.22.10/linux-2.6.22.10-502-atmel_mci-fix-two-subtle-but-deadly-races.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/device/Atmel/arch-avr32/kernel-patches-2.6.22.10/linux-2.6.22.10-502-atmel_mci-fix-two-subtle-but-deadly-races.patch')
-rw-r--r--target/device/Atmel/arch-avr32/kernel-patches-2.6.22.10/linux-2.6.22.10-502-atmel_mci-fix-two-subtle-but-deadly-races.patch438
1 files changed, 0 insertions, 438 deletions
diff --git a/target/device/Atmel/arch-avr32/kernel-patches-2.6.22.10/linux-2.6.22.10-502-atmel_mci-fix-two-subtle-but-deadly-races.patch b/target/device/Atmel/arch-avr32/kernel-patches-2.6.22.10/linux-2.6.22.10-502-atmel_mci-fix-two-subtle-but-deadly-races.patch
deleted file mode 100644
index be99b8346..000000000
--- a/target/device/Atmel/arch-avr32/kernel-patches-2.6.22.10/linux-2.6.22.10-502-atmel_mci-fix-two-subtle-but-deadly-races.patch
+++ /dev/null
@@ -1,438 +0,0 @@
-From: Haavard Skinnemoen <hskinnemoen@atmel.com>
-Subject: [PATCH 2/2] atmel_mci: Fix two subtle but deadly races
-
-This patch fixes two possible races in the atmel_mci driver, at least
-one of which may cause card probing to fail.
-
-The first one may happen if a command fails and the next command is
-queued before the controller is ready to accept a new one. Fix this by
-not enabling error interrupts for commands and instead do any error
-handling when the CMDRDY bit has been set.
-
-The second one may happen after a successful read data transfer where
-then next command is queued after the DMA transfer is complete, but
-before the whole data transfer from the card is complete (i.e. the
-card is still sending CRC, for example.) Fix this by waiting for the
-NOTBUSY bit to be set before considering the request to be done. This
-will also ensure that we actually see any CRC failures before
-completing the request.
-
-Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 172 +++++++++++++-----------------------------
- 1 files changed, 54 insertions(+), 118 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 1dc91b4..45323c9 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -28,20 +28,15 @@
-
- #define DRIVER_NAME "atmel_mci"
-
--#define MCI_CMD_ERROR_FLAGS (MCI_BIT(RINDE) | MCI_BIT(RDIRE) | \
-- MCI_BIT(RCRCE) | MCI_BIT(RENDE) | \
-- MCI_BIT(RTOE))
- #define MCI_DATA_ERROR_FLAGS (MCI_BIT(DCRCE) | MCI_BIT(DTOE) | \
- MCI_BIT(OVRE) | MCI_BIT(UNRE))
-
- enum {
- EVENT_CMD_COMPLETE = 0,
-- EVENT_CMD_ERROR,
- EVENT_DATA_COMPLETE,
- EVENT_DATA_ERROR,
- EVENT_STOP_SENT,
- EVENT_STOP_COMPLETE,
-- EVENT_STOP_ERROR,
- EVENT_DMA_ERROR,
- EVENT_CARD_DETECT,
- };
-@@ -61,13 +56,14 @@ struct atmel_mci {
- struct mmc_command *cmd;
- struct mmc_data *data;
-
-+ u32 cmd_status;
-+ u32 data_status;
-+ u32 stop_status;
- u32 stop_cmdr;
-- u32 stop_iflags;
-
- struct tasklet_struct tasklet;
- unsigned long pending_events;
- unsigned long completed_events;
-- u32 error_status;
-
- int present;
- int detect_pin;
-@@ -99,8 +95,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- /* Test bit macros for completed events */
- #define mci_cmd_is_complete(host) \
- test_bit(EVENT_CMD_COMPLETE, &host->completed_events)
--#define mci_cmd_error_is_complete(host) \
-- test_bit(EVENT_CMD_ERROR, &host->completed_events)
- #define mci_data_is_complete(host) \
- test_bit(EVENT_DATA_COMPLETE, &host->completed_events)
- #define mci_data_error_is_complete(host) \
-@@ -109,8 +103,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- test_bit(EVENT_STOP_SENT, &host->completed_events)
- #define mci_stop_is_complete(host) \
- test_bit(EVENT_STOP_COMPLETE, &host->completed_events)
--#define mci_stop_error_is_complete(host) \
-- test_bit(EVENT_STOP_ERROR, &host->completed_events)
- #define mci_dma_error_is_complete(host) \
- test_bit(EVENT_DMA_ERROR, &host->completed_events)
- #define mci_card_detect_is_complete(host) \
-@@ -119,8 +111,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- /* Test and clear bit macros for pending events */
- #define mci_clear_cmd_is_pending(host) \
- test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
--#define mci_clear_cmd_error_is_pending(host) \
-- test_and_clear_bit(EVENT_CMD_ERROR, &host->pending_events)
- #define mci_clear_data_is_pending(host) \
- test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
- #define mci_clear_data_error_is_pending(host) \
-@@ -129,8 +119,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- test_and_clear_bit(EVENT_STOP_SENT, &host->pending_events)
- #define mci_clear_stop_is_pending(host) \
- test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
--#define mci_clear_stop_error_is_pending(host) \
-- test_and_clear_bit(EVENT_STOP_ERROR, &host->pending_events)
- #define mci_clear_dma_error_is_pending(host) \
- test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)
- #define mci_clear_card_detect_is_pending(host) \
-@@ -139,8 +127,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- /* Test and set bit macros for completed events */
- #define mci_set_cmd_is_completed(host) \
- test_and_set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
--#define mci_set_cmd_error_is_completed(host) \
-- test_and_set_bit(EVENT_CMD_ERROR, &host->completed_events)
- #define mci_set_data_is_completed(host) \
- test_and_set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
- #define mci_set_data_error_is_completed(host) \
-@@ -149,8 +135,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- test_and_set_bit(EVENT_STOP_SENT, &host->completed_events)
- #define mci_set_stop_is_completed(host) \
- test_and_set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
--#define mci_set_stop_error_is_completed(host) \
-- test_and_set_bit(EVENT_STOP_ERROR, &host->completed_events)
- #define mci_set_dma_error_is_completed(host) \
- test_and_set_bit(EVENT_DMA_ERROR, &host->completed_events)
- #define mci_set_card_detect_is_completed(host) \
-@@ -159,8 +143,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- /* Set bit macros for completed events */
- #define mci_set_cmd_complete(host) \
- set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
--#define mci_set_cmd_error_complete(host) \
-- set_bit(EVENT_CMD_ERROR, &host->completed_events)
- #define mci_set_data_complete(host) \
- set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
- #define mci_set_data_error_complete(host) \
-@@ -169,8 +151,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- set_bit(EVENT_STOP_SENT, &host->completed_events)
- #define mci_set_stop_complete(host) \
- set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
--#define mci_set_stop_error_complete(host) \
-- set_bit(EVENT_STOP_ERROR, &host->completed_events)
- #define mci_set_dma_error_complete(host) \
- set_bit(EVENT_DMA_ERROR, &host->completed_events)
- #define mci_set_card_detect_complete(host) \
-@@ -179,8 +159,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- /* Set bit macros for pending events */
- #define mci_set_cmd_pending(host) \
- set_bit(EVENT_CMD_COMPLETE, &host->pending_events)
--#define mci_set_cmd_error_pending(host) \
-- set_bit(EVENT_CMD_ERROR, &host->pending_events)
- #define mci_set_data_pending(host) \
- set_bit(EVENT_DATA_COMPLETE, &host->pending_events)
- #define mci_set_data_error_pending(host) \
-@@ -189,8 +167,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- set_bit(EVENT_STOP_SENT, &host->pending_events)
- #define mci_set_stop_pending(host) \
- set_bit(EVENT_STOP_COMPLETE, &host->pending_events)
--#define mci_set_stop_error_pending(host) \
-- set_bit(EVENT_STOP_ERROR, &host->pending_events)
- #define mci_set_dma_error_pending(host) \
- set_bit(EVENT_DMA_ERROR, &host->pending_events)
- #define mci_set_card_detect_pending(host) \
-@@ -199,8 +175,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- /* Clear bit macros for pending events */
- #define mci_clear_cmd_pending(host) \
- clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
--#define mci_clear_cmd_error_pending(host) \
-- clear_bit(EVENT_CMD_ERROR, &host->pending_events)
- #define mci_clear_data_pending(host) \
- clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
- #define mci_clear_data_error_pending(host) \
-@@ -209,8 +183,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
- clear_bit(EVENT_STOP_SENT, &host->pending_events)
- #define mci_clear_stop_pending(host) \
- clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
--#define mci_clear_stop_error_pending(host) \
-- clear_bit(EVENT_STOP_ERROR, &host->pending_events)
- #define mci_clear_dma_error_pending(host) \
- clear_bit(EVENT_DMA_ERROR, &host->pending_events)
- #define mci_clear_card_detect_pending(host) \
-@@ -471,20 +443,16 @@ static void atmci_set_timeout(struct atmel_mci *host,
- }
-
- /*
-- * Return mask with interrupt flags to be handled for this command.
-+ * Return mask with command flags to be enabled for this command.
- */
- static u32 atmci_prepare_command(struct mmc_host *mmc,
-- struct mmc_command *cmd,
-- u32 *cmd_flags)
-+ struct mmc_command *cmd)
- {
- u32 cmdr;
-- u32 iflags;
-
- cmd->error = MMC_ERR_NONE;
-
-- cmdr = 0;
-- BUG_ON(MCI_BFEXT(CMDNB, cmdr) != 0);
-- cmdr = MCI_BFINS(CMDNB, cmd->opcode, cmdr);
-+ cmdr = MCI_BF(CMDNB, cmd->opcode);
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136)
-@@ -503,16 +471,11 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
- if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
- cmdr |= MCI_BIT(OPDCMD);
-
-- iflags = MCI_BIT(CMDRDY) | MCI_CMD_ERROR_FLAGS;
-- if (!(cmd->flags & MMC_RSP_CRC))
-- iflags &= ~MCI_BIT(RCRCE);
--
- dev_dbg(&mmc->class_dev,
- "cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n",
- cmd->opcode, cmd->arg, cmd->flags, (unsigned long)cmdr);
-
-- *cmd_flags = cmdr;
-- return iflags;
-+ return cmdr;
- }
-
- static void atmci_start_command(struct atmel_mci *host,
-@@ -596,13 +559,13 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
- host->pending_events = 0;
- host->completed_events = 0;
-
-- iflags = atmci_prepare_command(mmc, mrq->cmd, &cmdflags);
-+ iflags = MCI_BIT(CMDRDY);
-+ cmdflags = atmci_prepare_command(mmc, mrq->cmd);
-
- if (mrq->stop) {
-- BUG_ON(!data);
-+ WARN_ON(!data);
-
-- host->stop_iflags = atmci_prepare_command(mmc, mrq->stop,
-- &host->stop_cmdr);
-+ host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
- host->stop_cmdr |= MCI_BF(TRCMD, MCI_TRCMD_STOP_TRANS);
- if (!(data->flags & MMC_DATA_WRITE))
- host->stop_cmdr |= MCI_BIT(TRDIR);
-@@ -716,7 +679,7 @@ static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data,
- struct atmel_mci *host = mmc_priv(mmc);
-
- atmci_start_command(host, data->stop, host->stop_cmdr | flags);
-- mci_writel(host, IER, host->stop_iflags);
-+ mci_writel(host, IER, MCI_BIT(CMDRDY));
- }
-
- static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data)
-@@ -735,18 +698,30 @@ static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data)
- atmci_request_end(host->mmc, data->mrq);
- }
-
--static void atmci_command_error(struct mmc_host *mmc,
-- struct mmc_command *cmd,
-- u32 status)
-+static void atmci_command_complete(struct atmel_mci *host,
-+ struct mmc_command *cmd, u32 status)
- {
-- dev_dbg(&mmc->class_dev, "command error: status=0x%08x\n", status);
--
- if (status & MCI_BIT(RTOE))
- cmd->error = MMC_ERR_TIMEOUT;
-- else if (status & MCI_BIT(RCRCE))
-+ else if ((cmd->flags & MMC_RSP_CRC)
-+ && (status & MCI_BIT(RCRCE)))
- cmd->error = MMC_ERR_BADCRC;
-- else
-+ else if (status & (MCI_BIT(RINDE) | MCI_BIT(RDIRE) | MCI_BIT(RENDE)))
- cmd->error = MMC_ERR_FAILED;
-+
-+ if (cmd->error != MMC_ERR_NONE) {
-+ dev_dbg(&host->mmc->class_dev,
-+ "command error: op=0x%x status=0x%08x\n",
-+ cmd->opcode, status);
-+
-+ if (cmd->data) {
-+ dma_stop_request(host->dma.req.req.dmac,
-+ host->dma.req.req.channel);
-+ mci_writel(host, IDR, MCI_BIT(NOTBUSY)
-+ | MCI_DATA_ERROR_FLAGS);
-+ host->data = NULL;
-+ }
-+ }
- }
-
- static void atmci_tasklet_func(unsigned long priv)
-@@ -761,38 +736,16 @@ static void atmci_tasklet_func(unsigned long priv)
- host->pending_events, host->completed_events,
- mci_readl(host, IMR));
-
-- if (mci_clear_cmd_error_is_pending(host)) {
-- struct mmc_command *cmd;
--
-- mci_set_cmd_error_complete(host);
-- mci_clear_cmd_pending(host);
-- cmd = host->mrq->cmd;
--
-- if (cmd->data) {
-- dma_stop_request(host->dma.req.req.dmac,
-- host->dma.req.req.channel);
-- host->data = NULL;
-- }
--
-- atmci_command_error(mmc, cmd, host->error_status);
-- atmci_request_end(mmc, cmd->mrq);
-- }
-- if (mci_clear_stop_error_is_pending(host)) {
-- mci_set_stop_error_complete(host);
-- mci_clear_stop_pending(host);
-- atmci_command_error(mmc, host->mrq->stop,
-- host->error_status);
-- if (!host->data)
-- atmci_request_end(mmc, host->mrq);
-- }
- if (mci_clear_cmd_is_pending(host)) {
- mci_set_cmd_complete(host);
-- if (!mrq->data || mci_data_is_complete(host)
-+ atmci_command_complete(host, mrq->cmd, host->cmd_status);
-+ if (!host->data || mci_data_is_complete(host)
- || mci_data_error_is_complete(host))
- atmci_request_end(mmc, mrq);
- }
- if (mci_clear_stop_is_pending(host)) {
- mci_set_stop_complete(host);
-+ atmci_command_complete(host, mrq->stop, host->stop_status);
- if (mci_data_is_complete(host)
- || mci_data_error_is_complete(host))
- atmci_request_end(mmc, mrq);
-@@ -815,7 +768,7 @@ static void atmci_tasklet_func(unsigned long priv)
- atmci_data_complete(host, data);
- }
- if (mci_clear_data_error_is_pending(host)) {
-- u32 status = host->error_status;
-+ u32 status = host->data_status;
-
- mci_set_data_error_complete(host);
- mci_clear_data_pending(host);
-@@ -858,10 +811,8 @@ static void atmci_tasklet_func(unsigned long priv)
-
- /* Clean up queue if present */
- if (mrq) {
-- if (!mci_cmd_is_complete(host)
-- && !mci_cmd_error_is_complete(host)) {
-+ if (!mci_cmd_is_complete(host))
- mrq->cmd->error = MMC_ERR_TIMEOUT;
-- }
- if (mrq->data && !mci_data_is_complete(host)
- && !mci_data_error_is_complete(host)) {
- dma_stop_request(host->dma.req.req.dmac,
-@@ -869,10 +820,8 @@ static void atmci_tasklet_func(unsigned long priv)
- host->data->error = MMC_ERR_TIMEOUT;
- atmci_data_complete(host, data);
- }
-- if (mrq->stop && !mci_stop_is_complete(host)
-- && !mci_stop_error_is_complete(host)) {
-+ if (mrq->stop && !mci_stop_is_complete(host))
- mrq->stop->error = MMC_ERR_TIMEOUT;
-- }
-
- host->cmd = NULL;
- atmci_request_end(mmc, mrq);
-@@ -895,13 +844,16 @@ static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
- cmd->resp[2] = mci_readl(host, RSPR);
- cmd->resp[3] = mci_readl(host, RSPR);
-
-- mci_writel(host, IDR, MCI_BIT(CMDRDY) | MCI_CMD_ERROR_FLAGS);
-+ mci_writel(host, IDR, MCI_BIT(CMDRDY));
- host->cmd = NULL;
-
-- if (mci_stop_sent_is_complete(host))
-+ if (mci_stop_sent_is_complete(host)) {
-+ host->stop_status = status;
- mci_set_stop_pending(host);
-- else
-+ } else {
-+ host->cmd_status = status;
- mci_set_cmd_pending(host);
-+ }
-
- tasklet_schedule(&host->tasklet);
- }
-@@ -920,18 +872,16 @@ static void atmci_xfer_complete(struct dma_request *_req)
- if (data->stop && !mci_set_stop_sent_is_completed(host))
- send_stop_cmd(host->mmc, data, 0);
-
-- if (data->flags & MMC_DATA_READ) {
-- mci_writel(host, IDR, MCI_DATA_ERROR_FLAGS);
-- mci_set_data_pending(host);
-- tasklet_schedule(&host->tasklet);
-- } else {
-- /*
-- * For the WRITE case, wait for NOTBUSY. This function
-- * is called when everything has been written to the
-- * controller, not when the card is done programming.
-- */
-- mci_writel(host, IER, MCI_BIT(NOTBUSY));
-- }
-+ /*
-+ * Regardless of what the documentation says, we have to wait
-+ * for NOTBUSY even after block read operations.
-+ *
-+ * When the DMA transfer is complete, the controller may still
-+ * be reading the CRC from the card, i.e. the data transfer is
-+ * still in progress and we haven't seen all the potential
-+ * error bits yet.
-+ */
-+ mci_writel(host, IER, MCI_BIT(NOTBUSY));
- }
-
- static void atmci_dma_error(struct dma_request *_req)
-@@ -963,24 +913,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- pending = status & mask;
-
- do {
-- if (pending & MCI_CMD_ERROR_FLAGS) {
-- mci_writel(host, IDR, (MCI_BIT(CMDRDY)
-- | MCI_BIT(NOTBUSY)
-- | MCI_CMD_ERROR_FLAGS
-- | MCI_DATA_ERROR_FLAGS));
-- host->error_status = status;
-- host->cmd = NULL;
-- if (mci_stop_sent_is_complete(host))
-- mci_set_stop_error_pending(host);
-- else
-- mci_set_cmd_error_pending(host);
-- tasklet_schedule(&host->tasklet);
-- break;
-- }
- if (pending & MCI_DATA_ERROR_FLAGS) {
- mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
- | MCI_DATA_ERROR_FLAGS));
-- host->error_status = status;
-+ host->data_status = status;
- mci_set_data_error_pending(host);
- tasklet_schedule(&host->tasklet);
- break;
---
-1.5.3.2
-
-_______________________________________________
-Kernel mailing list
-Kernel@avr32linux.org
-http://duppen.flaskehals.net/cgi-bin/mailman/listinfo/kernel