@@ -81,25 +81,23 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host)
}
#ifdef DEBUG
+static inline void sd_print_reg(struct realtek_pci_sdmmc *host, u16 reg)
+{
+ u8 val;
+ if (rtsx_pci_read_register(host->pcr, reg, &val) < 0)
+ dev_dbg(sdmmc_dev(host), "read 0x%04x failed\n", reg);
+ else
+ dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", reg, val);
+}
+
static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
{
- struct rtsx_pcr *pcr = host->pcr;
u16 i;
- u8 *ptr;
-
- /* Print SD host internal registers */
- rtsx_pci_init_cmd(pcr);
- for (i = 0xFDA0; i <= 0xFDAE; i++)
- rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
- for (i = 0xFD52; i <= 0xFD69; i++)
- rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
- rtsx_pci_send_cmd(pcr, 100);
- ptr = rtsx_pci_get_cmd_data(pcr);
for (i = 0xFDA0; i <= 0xFDAE; i++)
- dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
+ sd_print_reg(host, i);
for (i = 0xFD52; i <= 0xFD69; i++)
- dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
+ sd_print_reg(host, i);
}
#else
#define sd_print_debug_regs(host)
@@ -125,19 +123,27 @@ static void sd_request_timeout(unsigned long host_addr)
spin_lock_irqsave(&host->lock, flags);
if (!host->mrq) {
- dev_err(sdmmc_dev(host), "error: no request exist\n");
- goto out;
+ dev_err(sdmmc_dev(host), "error: request not exist\n");
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
}
- if (host->cmd)
+ if (host->cmd && host->data)
+ dev_err(sdmmc_dev(host), "error: cmd and data conflict\n");
+
+ if (host->cmd) {
host->cmd->error = -ETIMEDOUT;
- if (host->data)
- host->data->error = -ETIMEDOUT;
+ dev_dbg(sdmmc_dev(host), "timeout for cmd %d\n",
+ host->cmd->opcode);
+ tasklet_schedule(&host->cmd_tasklet);
+ }
- dev_dbg(sdmmc_dev(host), "timeout for request\n");
+ if (host->data) {
+ host->data->error = -ETIMEDOUT;
+ dev_dbg(sdmmc_dev(host), "timeout for data transfer\n");
+ tasklet_schedule(&host->data_tasklet);
+ }
-out:
- tasklet_schedule(&host->finish_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -157,7 +163,8 @@ static void sd_finish_request(unsigned long host_addr)
mrq = host->mrq;
if (!mrq) {
dev_err(sdmmc_dev(host), "error: no request need finish\n");
- goto out;
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
}
cmd = mrq->cmd;
@@ -167,11 +174,6 @@ static void sd_finish_request(unsigned long host_addr)
(mrq->stop && mrq->stop->error) ||
(cmd && cmd->error) || (data && data->error);
- if (any_error) {
- rtsx_pci_stop_cmd(pcr);
- sd_clear_error(host);
- }
-
if (data) {
if (any_error)
data->bytes_xfered = 0;
@@ -188,7 +190,6 @@ static void sd_finish_request(unsigned long host_addr)
host->cmd = NULL;
host->data = NULL;
-out:
spin_unlock_irqrestore(&host->lock, flags);
mutex_unlock(&pcr->pcr_mutex);
mmc_request_done(host->mmc, mrq);
@@ -373,8 +374,11 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
if (cmd->opcode == SD_SWITCH_VOLTAGE) {
err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
0xFF, SD_CLK_TOGGLE_EN);
- if (err < 0)
+ if (err < 0) {
+ rtsx_pci_write_register(pcr, SD_BUS_STAT,
+ SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
goto out;
+ }
}
rtsx_pci_init_cmd(pcr);
@@ -436,7 +440,8 @@ static void sd_get_rsp(unsigned long host_addr)
if (!cmd) {
dev_err(sdmmc_dev(host), "error: cmd not exist\n");
- goto out;
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
}
spin_lock(&pcr->lock);
@@ -446,16 +451,18 @@ static void sd_get_rsp(unsigned long host_addr)
err = -EINVAL;
spin_unlock(&pcr->lock);
- if (err < 0)
+ if (err < 0) {
+ rtsx_pci_stop_cmd(host->pcr);
+ sd_print_debug_regs(host);
+ sd_clear_error(host);
goto out;
+ }
rsp_type = host->rsp_type;
stat_idx = host->rsp_len;
- if (rsp_type == SD_RSP_TYPE_R0) {
- err = 0;
+ if (rsp_type == SD_RSP_TYPE_R0)
goto out;
- }
/* Eliminate returned value of CHECK_REG_CMD */
ptr = rtsx_pci_get_cmd_data(pcr) + 1;
@@ -498,14 +505,19 @@ static void sd_get_rsp(unsigned long host_addr)
goto out;
if (cmd->data) {
- sd_start_multi_rw(host, host->mrq);
+ err = sd_start_multi_rw(host, host->mrq);
+ if (err) {
+ cmd->data->error = err;
+ dev_err(sdmmc_dev(host),
+ "error: start data transfer failed\n");
+ tasklet_schedule(&host->data_tasklet);
+ }
spin_unlock_irqrestore(&host->lock, flags);
return;
}
out:
cmd->error = err;
-
tasklet_schedule(&host->finish_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -525,7 +537,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
data->host_cookie = 0;
}
- if (next || (!next && data->host_cookie != host->next_data.cookie))
+ if (next || data->host_cookie != host->next_data.cookie)
sg_count = rtsx_pci_dma_map_sg(pcr,
data->sg, data->sg_len, read);
else
@@ -580,7 +592,6 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
int uhs = mmc_card_uhs(card);
int read = data->flags & MMC_DATA_READ;
u8 cfg2, trans_mode;
- int err;
size_t data_len = data->blksz * data->blocks;
if (host->data)
@@ -641,12 +652,7 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
mod_timer(&host->timer, jiffies + 10 * HZ);
rtsx_pci_send_cmd_no_wait(pcr);
- err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read);
- if (err < 0) {
- data->error = err;
- tasklet_schedule(&host->finish_tasklet);
- }
- return 0;
+ return rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read);
}
static void sd_finish_multi_rw(unsigned long host_addr)
@@ -660,8 +666,9 @@ static void sd_finish_multi_rw(unsigned long host_addr)
spin_lock_irqsave(&host->lock, flags);
if (!host->data) {
- dev_err(sdmmc_dev(host), "error: no data exist\n");
- goto out;
+ dev_err(sdmmc_dev(host), "error: data not exist\n");
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
}
data = host->data;
@@ -672,19 +679,22 @@ static void sd_finish_multi_rw(unsigned long host_addr)
else if (pcr->trans_result != TRANS_RESULT_OK)
err = -EINVAL;
- if (err < 0) {
+ if (err < 0)
data->error = err;
- goto out;
+
+ if (data->error) {
+ rtsx_pci_stop_cmd(host->pcr);
+ sd_print_debug_regs(host);
+ sd_clear_error(host);
+ dev_dbg(sdmmc_dev(host), "data transfer failed %d\n",
+ data->error);
}
- if (!host->mrq->sbc && data->stop) {
+ if (!host->mrq->sbc && data->stop)
sd_send_cmd(host, data->stop);
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
+ else
+ tasklet_schedule(&host->finish_tasklet);
-out:
- tasklet_schedule(&host->finish_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
}