From: Micky Ching <[email protected]>
This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
commit <mmc: rtsx: add support for pre_req and post_req> did use
mutex_unlock() in tasklet, but mutex_unlock() can't used in
tasklet(atomic context). The driver need use mutex to avoid concurrency,
so we can't use tasklet here, the patch need to be removed.
The spinlock host->lock and pcr->lock may deadlock, one way to solve the
deadlock is remove host->lock in sd_isr_done_transfer(), but if using
workqueue the we can avoid using the spinlock and also avoid the problem.
Signed-off-by: Micky Ching <[email protected]>
---
drivers/mfd/rtsx_pcr.c | 132 ++++--------
drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
include/linux/mfd/rtsx_common.h | 1 -
include/linux/mfd/rtsx_pci.h | 6 -
4 files changed, 109 insertions(+), 448 deletions(-)
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index c9de3d5..1d15735 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -338,28 +338,58 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read, int timeout)
{
struct completion trans_done;
- int err = 0, count;
+ u8 dir;
+ int err = 0, i, count;
long timeleft;
unsigned long flags;
+ struct scatterlist *sg;
+ enum dma_data_direction dma_dir;
+ u32 val;
+ dma_addr_t addr;
+ unsigned int len;
+
+ dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg);
+
+ /* don't transfer data during abort processing */
+ if (pcr->remove_pci)
+ return -EINVAL;
+
+ if ((sglist == NULL) || (num_sg <= 0))
+ return -EINVAL;
- count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
+ if (read) {
+ dir = DEVICE_TO_HOST;
+ dma_dir = DMA_FROM_DEVICE;
+ } else {
+ dir = HOST_TO_DEVICE;
+ dma_dir = DMA_TO_DEVICE;
+ }
+
+ count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
if (count < 1) {
dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
return -EINVAL;
}
dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
+ val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
+ pcr->sgi = 0;
+ for_each_sg(sglist, sg, count, i) {
+ addr = sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
+ }
spin_lock_irqsave(&pcr->lock, flags);
pcr->done = &trans_done;
pcr->trans_result = TRANS_NOT_READY;
init_completion(&trans_done);
+ rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
+ rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
spin_unlock_irqrestore(&pcr->lock, flags);
- rtsx_pci_dma_transfer(pcr, sglist, count, read);
-
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
@@ -383,7 +413,7 @@ out:
pcr->done = NULL;
spin_unlock_irqrestore(&pcr->lock, flags);
- rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
+ dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
if ((err < 0) && (err != -ENODEV))
rtsx_pci_stop_cmd(pcr);
@@ -395,73 +425,6 @@ out:
}
EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
-int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int num_sg, bool read)
-{
- enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
- if (pcr->remove_pci)
- return -EINVAL;
-
- if ((sglist == NULL) || num_sg < 1)
- return -EINVAL;
-
- return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
-
-int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int num_sg, bool read)
-{
- enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
- if (pcr->remove_pci)
- return -EINVAL;
-
- if (sglist == NULL || num_sg < 1)
- return -EINVAL;
-
- dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
- return num_sg;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
-
-int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int sg_count, bool read)
-{
- struct scatterlist *sg;
- dma_addr_t addr;
- unsigned int len;
- int i;
- u32 val;
- u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
- unsigned long flags;
-
- if (pcr->remove_pci)
- return -EINVAL;
-
- if ((sglist == NULL) || (sg_count < 1))
- return -EINVAL;
-
- val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
- pcr->sgi = 0;
- for_each_sg(sglist, sg, sg_count, i) {
- addr = sg_dma_address(sg);
- len = sg_dma_len(sg);
- rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1);
- }
-
- spin_lock_irqsave(&pcr->lock, flags);
-
- rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
- rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
-
- spin_unlock_irqrestore(&pcr->lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
-
int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
{
int err;
@@ -873,8 +836,6 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
/* Clear interrupt flag */
rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
- dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg);
-
if ((int_reg & pcr->bier) == 0) {
spin_unlock(&pcr->lock);
return IRQ_NONE;
@@ -905,28 +866,17 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
}
if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
- if (int_reg & (TRANS_FAIL_INT | DELINK_INT))
+ if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
pcr->trans_result = TRANS_RESULT_FAIL;
- else if (int_reg & TRANS_OK_INT)
+ if (pcr->done)
+ complete(pcr->done);
+ } else if (int_reg & TRANS_OK_INT) {
pcr->trans_result = TRANS_RESULT_OK;
-
- if (pcr->done)
- complete(pcr->done);
-
- if (int_reg & SD_EXIST) {
- struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
- if (slot && slot->done_transfer)
- slot->done_transfer(slot->p_dev);
- }
-
- if (int_reg & MS_EXIST) {
- struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
- if (slot && slot->done_transfer)
- slot->done_transfer(slot->p_dev);
+ if (pcr->done)
+ complete(pcr->done);
}
}
-
if (pcr->card_inserted || pcr->card_removed)
schedule_delayed_work(&pcr->carddet_work,
msecs_to_jiffies(200));
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 5fb994f..0b9ded1 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -31,28 +31,14 @@
#include <linux/mfd/rtsx_pci.h>
#include <asm/unaligned.h>
-struct realtek_next {
- unsigned int sg_count;
- s32 cookie;
-};
-
struct realtek_pci_sdmmc {
struct platform_device *pdev;
struct rtsx_pcr *pcr;
struct mmc_host *mmc;
struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- spinlock_t lock;
- struct timer_list timer;
- struct tasklet_struct cmd_tasklet;
- struct tasklet_struct data_tasklet;
- struct tasklet_struct finish_tasklet;
-
- u8 rsp_type;
- u8 rsp_len;
- int sg_count;
+
+ struct mutex host_mutex;
+
u8 ssc_depth;
unsigned int clock;
bool vpclk;
@@ -62,13 +48,8 @@ struct realtek_pci_sdmmc {
int power_state;
#define SDMMC_POWER_ON 1
#define SDMMC_POWER_OFF 0
-
- struct realtek_next next_data;
};
-static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
- struct mmc_request *mrq);
-
static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
{
return &(host->pdev->dev);
@@ -105,95 +86,6 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
#define sd_print_debug_regs(host)
#endif /* DEBUG */
-static void sd_isr_done_transfer(struct platform_device *pdev)
-{
- struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
-
- spin_lock(&host->lock);
- if (host->cmd)
- tasklet_schedule(&host->cmd_tasklet);
- if (host->data)
- tasklet_schedule(&host->data_tasklet);
- spin_unlock(&host->lock);
-}
-
-static void sd_request_timeout(unsigned long host_addr)
-{
- struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (!host->mrq) {
- dev_err(sdmmc_dev(host), "error: no request exist\n");
- goto out;
- }
-
- if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- if (host->data)
- host->data->error = -ETIMEDOUT;
-
- dev_dbg(sdmmc_dev(host), "timeout for request\n");
-
-out:
- tasklet_schedule(&host->finish_tasklet);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sd_finish_request(unsigned long host_addr)
-{
- struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
- struct rtsx_pcr *pcr = host->pcr;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- unsigned long flags;
- bool any_error;
-
- spin_lock_irqsave(&host->lock, flags);
-
- del_timer(&host->timer);
- mrq = host->mrq;
- if (!mrq) {
- dev_err(sdmmc_dev(host), "error: no request need finish\n");
- goto out;
- }
-
- cmd = mrq->cmd;
- data = mrq->data;
-
- any_error = (mrq->sbc && mrq->sbc->error) ||
- (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;
- else
- data->bytes_xfered = data->blocks * data->blksz;
-
- if (!data->host_cookie)
- rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len,
- data->flags & MMC_DATA_READ);
-
- }
-
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
-
-out:
- spin_unlock_irqrestore(&host->lock, flags);
- mutex_unlock(&pcr->pcr_mutex);
- mmc_request_done(host->mmc, mrq);
-}
-
static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
u8 *buf, int buf_len, int timeout)
{
@@ -311,7 +203,8 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
return 0;
}
-static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
+static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
+ struct mmc_command *cmd)
{
struct rtsx_pcr *pcr = host->pcr;
u8 cmd_idx = (u8)cmd->opcode;
@@ -319,14 +212,11 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
int err = 0;
int timeout = 100;
int i;
+ u8 *ptr;
+ int stat_idx = 0;
u8 rsp_type;
int rsp_len = 5;
- unsigned long flags;
-
- if (host->cmd)
- dev_err(sdmmc_dev(host), "error: cmd already exist\n");
-
- host->cmd = cmd;
+ bool clock_toggled = false;
dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
__func__, cmd_idx, arg);
@@ -361,8 +251,6 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
err = -EINVAL;
goto out;
}
- host->rsp_type = rsp_type;
- host->rsp_len = rsp_len;
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
@@ -372,6 +260,8 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
0xFF, SD_CLK_TOGGLE_EN);
if (err < 0)
goto out;
+
+ clock_toggled = true;
}
rtsx_pci_init_cmd(pcr);
@@ -395,60 +285,25 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
/* Read data from ping-pong buffer */
for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
+ stat_idx = 16;
} else if (rsp_type != SD_RSP_TYPE_R0) {
/* Read data from SD_CMDx registers */
for (i = SD_CMD0; i <= SD_CMD4; i++)
rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
+ stat_idx = 5;
}
rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);
- mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
-
- spin_lock_irqsave(&pcr->lock, flags);
- pcr->trans_result = TRANS_NOT_READY;
- rtsx_pci_send_cmd_no_wait(pcr);
- spin_unlock_irqrestore(&pcr->lock, flags);
-
- return;
-
-out:
- cmd->error = err;
- tasklet_schedule(&host->finish_tasklet);
-}
-
-static void sd_get_rsp(unsigned long host_addr)
-{
- struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
- struct rtsx_pcr *pcr = host->pcr;
- struct mmc_command *cmd;
- int i, err = 0, stat_idx;
- u8 *ptr, rsp_type;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- cmd = host->cmd;
- host->cmd = NULL;
-
- if (!cmd) {
- dev_err(sdmmc_dev(host), "error: cmd not exist\n");
+ err = rtsx_pci_send_cmd(pcr, timeout);
+ if (err < 0) {
+ sd_print_debug_regs(host);
+ sd_clear_error(host);
+ dev_dbg(sdmmc_dev(host),
+ "rtsx_pci_send_cmd error (err = %d)\n", err);
goto out;
}
- spin_lock(&pcr->lock);
- if (pcr->trans_result == TRANS_NO_DEVICE)
- err = -ENODEV;
- else if (pcr->trans_result != TRANS_RESULT_OK)
- err = -EINVAL;
- spin_unlock(&pcr->lock);
-
- if (err < 0)
- goto out;
-
- rsp_type = host->rsp_type;
- stat_idx = host->rsp_len;
-
if (rsp_type == SD_RSP_TYPE_R0) {
err = 0;
goto out;
@@ -485,106 +340,26 @@ static void sd_get_rsp(unsigned long host_addr)
cmd->resp[0]);
}
- if (cmd == host->mrq->sbc) {
- sd_send_cmd(host, host->mrq->cmd);
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- if (cmd == host->mrq->stop)
- goto out;
-
- if (cmd->data) {
- sd_start_multi_rw(host, host->mrq);
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
out:
cmd->error = err;
- tasklet_schedule(&host->finish_tasklet);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
- struct mmc_data *data, struct realtek_next *next)
-{
- struct rtsx_pcr *pcr = host->pcr;
- int read = data->flags & MMC_DATA_READ;
- int sg_count = 0;
-
- if (!next && data->host_cookie &&
- data->host_cookie != host->next_data.cookie) {
- dev_err(sdmmc_dev(host),
- "error: invalid cookie data[%d] host[%d]\n",
- data->host_cookie, host->next_data.cookie);
- data->host_cookie = 0;
- }
-
- if (next || (!next && data->host_cookie != host->next_data.cookie))
- sg_count = rtsx_pci_dma_map_sg(pcr,
- data->sg, data->sg_len, read);
- else
- sg_count = host->next_data.sg_count;
-
- if (next) {
- next->sg_count = sg_count;
- if (++next->cookie < 0)
- next->cookie = 1;
- data->host_cookie = next->cookie;
- }
-
- return sg_count;
-}
-
-static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
-{
- struct realtek_pci_sdmmc *host = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
-
- if (data->host_cookie) {
- dev_err(sdmmc_dev(host),
- "error: descard already cookie data[%d]\n",
- data->host_cookie);
- data->host_cookie = 0;
- }
-
- dev_dbg(sdmmc_dev(host), "dma sg prepared: %d\n",
- sd_pre_dma_transfer(host, data, &host->next_data));
-}
-
-static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
- int err)
-{
- struct realtek_pci_sdmmc *host = mmc_priv(mmc);
- struct rtsx_pcr *pcr = host->pcr;
- struct mmc_data *data = mrq->data;
- int read = data->flags & MMC_DATA_READ;
-
- rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read);
- data->host_cookie = 0;
+ if (err && clock_toggled)
+ rtsx_pci_write_register(pcr, SD_BUS_STAT,
+ SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
}
-static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
- struct mmc_request *mrq)
+static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
{
struct rtsx_pcr *pcr = host->pcr;
struct mmc_host *mmc = host->mmc;
struct mmc_card *card = mmc->card;
struct mmc_data *data = mrq->data;
int uhs = mmc_card_uhs(card);
- int read = data->flags & MMC_DATA_READ;
+ int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
u8 cfg2, trans_mode;
int err;
size_t data_len = data->blksz * data->blocks;
- if (host->data)
- dev_err(sdmmc_dev(host), "error: data already exist\n");
-
- host->data = data;
-
if (read) {
cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
@@ -635,54 +410,15 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
- 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;
-}
-
-static void sd_finish_multi_rw(unsigned long host_addr)
-{
- struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
- struct rtsx_pcr *pcr = host->pcr;
- struct mmc_data *data;
- int err = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (!host->data) {
- dev_err(sdmmc_dev(host), "error: no data exist\n");
- goto out;
- }
-
- data = host->data;
- host->data = NULL;
-
- if (pcr->trans_result == TRANS_NO_DEVICE)
- err = -ENODEV;
- else if (pcr->trans_result != TRANS_RESULT_OK)
- err = -EINVAL;
-
+ err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000);
if (err < 0) {
- data->error = err;
- goto out;
- }
-
- if (!host->mrq->sbc && data->stop) {
- sd_send_cmd(host, data->stop);
- spin_unlock_irqrestore(&host->lock, flags);
- return;
+ sd_clear_error(host);
+ return err;
}
-out:
- tasklet_schedule(&host->finish_tasklet);
- spin_unlock_irqrestore(&host->lock, flags);
+ return 0;
}
static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
@@ -901,13 +637,6 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
return 0;
}
-static inline bool sd_use_muti_rw(struct mmc_command *cmd)
-{
- return mmc_op_multi(cmd->opcode) ||
- (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
- (cmd->opcode == MMC_WRITE_BLOCK);
-}
-
static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
@@ -916,14 +645,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct mmc_data *data = mrq->data;
unsigned int data_size = 0;
int err;
- unsigned long flags;
-
- mutex_lock(&pcr->pcr_mutex);
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->mrq)
- dev_err(sdmmc_dev(host), "error: request already exist\n");
- host->mrq = mrq;
if (host->eject) {
cmd->error = -ENOMEDIUM;
@@ -936,6 +657,8 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
goto finish;
}
+ mutex_lock(&pcr->pcr_mutex);
+
rtsx_pci_start_run(pcr);
rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth,
@@ -944,28 +667,46 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
CARD_SHARE_MASK, CARD_SHARE_48_SD);
+ mutex_lock(&host->host_mutex);
+ host->mrq = mrq;
+ mutex_unlock(&host->host_mutex);
+
if (mrq->data)
data_size = data->blocks * data->blksz;
- if (sd_use_muti_rw(cmd))
- host->sg_count = sd_pre_dma_transfer(host, data, NULL);
+ if (!data_size || mmc_op_multi(cmd->opcode) ||
+ (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
+ (cmd->opcode == MMC_WRITE_BLOCK)) {
+ sd_send_cmd_get_rsp(host, cmd);
- if (!data_size || sd_use_muti_rw(cmd)) {
- if (mrq->sbc)
- sd_send_cmd(host, mrq->sbc);
- else
- sd_send_cmd(host, cmd);
- spin_unlock_irqrestore(&host->lock, flags);
+ if (!cmd->error && data_size) {
+ sd_rw_multi(host, mrq);
+
+ if (mmc_op_multi(cmd->opcode) && mrq->stop)
+ sd_send_cmd_get_rsp(host, mrq->stop);
+ }
} else {
- spin_unlock_irqrestore(&host->lock, flags);
sd_normal_rw(host, mrq);
- tasklet_schedule(&host->finish_tasklet);
}
- return;
+
+ if (mrq->data) {
+ if (cmd->error || data->error)
+ data->bytes_xfered = 0;
+ else
+ data->bytes_xfered = data->blocks * data->blksz;
+ }
+
+ mutex_unlock(&pcr->pcr_mutex);
finish:
- tasklet_schedule(&host->finish_tasklet);
- spin_unlock_irqrestore(&host->lock, flags);
+ if (cmd->error)
+ dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
+
+ mutex_lock(&host->host_mutex);
+ host->mrq = NULL;
+ mutex_unlock(&host->host_mutex);
+
+ mmc_request_done(mmc, mrq);
}
static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
@@ -1400,8 +1141,6 @@ out:
}
static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
- .pre_req = sdmmc_pre_req,
- .post_req = sdmmc_post_req,
.request = sdmmc_request,
.set_ios = sdmmc_set_ios,
.get_ro = sdmmc_get_ro,
@@ -1465,7 +1204,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
struct realtek_pci_sdmmc *host;
struct rtsx_pcr *pcr;
struct pcr_handle *handle = pdev->dev.platform_data;
- unsigned long host_addr;
if (!handle)
return -ENXIO;
@@ -1489,15 +1227,8 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
pcr->slots[RTSX_SD_CARD].p_dev = pdev;
pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
- host_addr = (unsigned long)host;
- host->next_data.cookie = 1;
- setup_timer(&host->timer, sd_request_timeout, host_addr);
- tasklet_init(&host->cmd_tasklet, sd_get_rsp, host_addr);
- tasklet_init(&host->data_tasklet, sd_finish_multi_rw, host_addr);
- tasklet_init(&host->finish_tasklet, sd_finish_request, host_addr);
- spin_lock_init(&host->lock);
+ mutex_init(&host->host_mutex);
- pcr->slots[RTSX_SD_CARD].done_transfer = sd_isr_done_transfer;
realtek_init_host(host);
mmc_add_host(mmc);
@@ -1510,8 +1241,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
struct rtsx_pcr *pcr;
struct mmc_host *mmc;
- struct mmc_request *mrq;
- unsigned long flags;
if (!host)
return 0;
@@ -1519,33 +1248,22 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
pcr = host->pcr;
pcr->slots[RTSX_SD_CARD].p_dev = NULL;
pcr->slots[RTSX_SD_CARD].card_event = NULL;
- pcr->slots[RTSX_SD_CARD].done_transfer = NULL;
mmc = host->mmc;
- mrq = host->mrq;
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->host_mutex);
if (host->mrq) {
dev_dbg(&(pdev->dev),
"%s: Controller removed during transfer\n",
mmc_hostname(mmc));
- if (mrq->sbc)
- mrq->sbc->error = -ENOMEDIUM;
- if (mrq->cmd)
- mrq->cmd->error = -ENOMEDIUM;
- if (mrq->stop)
- mrq->stop->error = -ENOMEDIUM;
- if (mrq->data)
- mrq->data->error = -ENOMEDIUM;
+ rtsx_pci_complete_unfinished_transfer(pcr);
- tasklet_schedule(&host->finish_tasklet);
+ host->mrq->cmd->error = -ENOMEDIUM;
+ if (host->mrq->stop)
+ host->mrq->stop->error = -ENOMEDIUM;
+ mmc_request_done(mmc, host->mrq);
}
- spin_unlock_irqrestore(&host->lock, flags);
-
- del_timer_sync(&host->timer);
- tasklet_kill(&host->cmd_tasklet);
- tasklet_kill(&host->data_tasklet);
- tasklet_kill(&host->finish_tasklet);
+ mutex_unlock(&host->host_mutex);
mmc_remove_host(mmc);
host->eject = true;
diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h
index 7c36cc5..443176e 100644
--- a/include/linux/mfd/rtsx_common.h
+++ b/include/linux/mfd/rtsx_common.h
@@ -45,7 +45,6 @@ struct platform_device;
struct rtsx_slot {
struct platform_device *p_dev;
void (*card_event)(struct platform_device *p_dev);
- void (*done_transfer)(struct platform_device *p_dev);
};
#endif
diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h
index 8d6bbd6..a383597 100644
--- a/include/linux/mfd/rtsx_pci.h
+++ b/include/linux/mfd/rtsx_pci.h
@@ -943,12 +943,6 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read, int timeout);
-int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int num_sg, bool read);
-int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int num_sg, bool read);
-int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int sg_count, bool read);
int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
--
1.7.9.5
Hi Chris and Ulf,
Since the original commit is merged into kernel 3.15-rc, we want this patch
apply to the 3.15-rc to avoid cause serious problem.
Is there any thing I need do?
Best Regards.
micky.
On 04/28/2014 03:36 PM, [email protected] wrote:
> From: Micky Ching <[email protected]>
>
> This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
>
> commit <mmc: rtsx: add support for pre_req and post_req> did use
> mutex_unlock() in tasklet, but mutex_unlock() can't used in
> tasklet(atomic context). The driver need use mutex to avoid concurrency,
> so we can't use tasklet here, the patch need to be removed.
>
> The spinlock host->lock and pcr->lock may deadlock, one way to solve the
> deadlock is remove host->lock in sd_isr_done_transfer(), but if using
> workqueue the we can avoid using the spinlock and also avoid the problem.
>
> Signed-off-by: Micky Ching <[email protected]>
> ---
> drivers/mfd/rtsx_pcr.c | 132 ++++--------
> drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
> include/linux/mfd/rtsx_common.h | 1 -
> include/linux/mfd/rtsx_pci.h | 6 -
> 4 files changed, 109 insertions(+), 448 deletions(-)
>
> diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
> index c9de3d5..1d15735 100644
> --- a/drivers/mfd/rtsx_pcr.c
> +++ b/drivers/mfd/rtsx_pcr.c
> @@ -338,28 +338,58 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> int num_sg, bool read, int timeout)
> {
> struct completion trans_done;
> - int err = 0, count;
> + u8 dir;
> + int err = 0, i, count;
> long timeleft;
> unsigned long flags;
> + struct scatterlist *sg;
> + enum dma_data_direction dma_dir;
> + u32 val;
> + dma_addr_t addr;
> + unsigned int len;
> +
> + dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg);
> +
> + /* don't transfer data during abort processing */
> + if (pcr->remove_pci)
> + return -EINVAL;
> +
> + if ((sglist == NULL) || (num_sg <= 0))
> + return -EINVAL;
>
> - count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
> + if (read) {
> + dir = DEVICE_TO_HOST;
> + dma_dir = DMA_FROM_DEVICE;
> + } else {
> + dir = HOST_TO_DEVICE;
> + dma_dir = DMA_TO_DEVICE;
> + }
> +
> + count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
> if (count < 1) {
> dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
> return -EINVAL;
> }
> dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
>
> + val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
> + pcr->sgi = 0;
> + for_each_sg(sglist, sg, count, i) {
> + addr = sg_dma_address(sg);
> + len = sg_dma_len(sg);
> + rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
> + }
>
> spin_lock_irqsave(&pcr->lock, flags);
>
> pcr->done = &trans_done;
> pcr->trans_result = TRANS_NOT_READY;
> init_completion(&trans_done);
> + rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
> + rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
>
> spin_unlock_irqrestore(&pcr->lock, flags);
>
> - rtsx_pci_dma_transfer(pcr, sglist, count, read);
> -
> timeleft = wait_for_completion_interruptible_timeout(
> &trans_done, msecs_to_jiffies(timeout));
> if (timeleft <= 0) {
> @@ -383,7 +413,7 @@ out:
> pcr->done = NULL;
> spin_unlock_irqrestore(&pcr->lock, flags);
>
> - rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
> + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
>
> if ((err < 0) && (err != -ENODEV))
> rtsx_pci_stop_cmd(pcr);
> @@ -395,73 +425,6 @@ out:
> }
> EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
>
> -int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read)
> -{
> - enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> -
> - if (pcr->remove_pci)
> - return -EINVAL;
> -
> - if ((sglist == NULL) || num_sg < 1)
> - return -EINVAL;
> -
> - return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
> -}
> -EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
> -
> -int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read)
> -{
> - enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> -
> - if (pcr->remove_pci)
> - return -EINVAL;
> -
> - if (sglist == NULL || num_sg < 1)
> - return -EINVAL;
> -
> - dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
> - return num_sg;
> -}
> -EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
> -
> -int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int sg_count, bool read)
> -{
> - struct scatterlist *sg;
> - dma_addr_t addr;
> - unsigned int len;
> - int i;
> - u32 val;
> - u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
> - unsigned long flags;
> -
> - if (pcr->remove_pci)
> - return -EINVAL;
> -
> - if ((sglist == NULL) || (sg_count < 1))
> - return -EINVAL;
> -
> - val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
> - pcr->sgi = 0;
> - for_each_sg(sglist, sg, sg_count, i) {
> - addr = sg_dma_address(sg);
> - len = sg_dma_len(sg);
> - rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1);
> - }
> -
> - spin_lock_irqsave(&pcr->lock, flags);
> -
> - rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
> - rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
> -
> - spin_unlock_irqrestore(&pcr->lock, flags);
> -
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
> -
> int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
> {
> int err;
> @@ -873,8 +836,6 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
> int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
> /* Clear interrupt flag */
> rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
> - dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg);
> -
> if ((int_reg & pcr->bier) == 0) {
> spin_unlock(&pcr->lock);
> return IRQ_NONE;
> @@ -905,28 +866,17 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
> }
>
> if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
> - if (int_reg & (TRANS_FAIL_INT | DELINK_INT))
> + if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
> pcr->trans_result = TRANS_RESULT_FAIL;
> - else if (int_reg & TRANS_OK_INT)
> + if (pcr->done)
> + complete(pcr->done);
> + } else if (int_reg & TRANS_OK_INT) {
> pcr->trans_result = TRANS_RESULT_OK;
> -
> - if (pcr->done)
> - complete(pcr->done);
> -
> - if (int_reg & SD_EXIST) {
> - struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
> - if (slot && slot->done_transfer)
> - slot->done_transfer(slot->p_dev);
> - }
> -
> - if (int_reg & MS_EXIST) {
> - struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
> - if (slot && slot->done_transfer)
> - slot->done_transfer(slot->p_dev);
> + if (pcr->done)
> + complete(pcr->done);
> }
> }
>
> -
> if (pcr->card_inserted || pcr->card_removed)
> schedule_delayed_work(&pcr->carddet_work,
> msecs_to_jiffies(200));
> diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
> index 5fb994f..0b9ded1 100644
> --- a/drivers/mmc/host/rtsx_pci_sdmmc.c
> +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
> @@ -31,28 +31,14 @@
> #include <linux/mfd/rtsx_pci.h>
> #include <asm/unaligned.h>
>
> -struct realtek_next {
> - unsigned int sg_count;
> - s32 cookie;
> -};
> -
> struct realtek_pci_sdmmc {
> struct platform_device *pdev;
> struct rtsx_pcr *pcr;
> struct mmc_host *mmc;
> struct mmc_request *mrq;
> - struct mmc_command *cmd;
> - struct mmc_data *data;
> -
> - spinlock_t lock;
> - struct timer_list timer;
> - struct tasklet_struct cmd_tasklet;
> - struct tasklet_struct data_tasklet;
> - struct tasklet_struct finish_tasklet;
> -
> - u8 rsp_type;
> - u8 rsp_len;
> - int sg_count;
> +
> + struct mutex host_mutex;
> +
> u8 ssc_depth;
> unsigned int clock;
> bool vpclk;
> @@ -62,13 +48,8 @@ struct realtek_pci_sdmmc {
> int power_state;
> #define SDMMC_POWER_ON 1
> #define SDMMC_POWER_OFF 0
> -
> - struct realtek_next next_data;
> };
>
> -static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
> - struct mmc_request *mrq);
> -
> static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
> {
> return &(host->pdev->dev);
> @@ -105,95 +86,6 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
> #define sd_print_debug_regs(host)
> #endif /* DEBUG */
>
> -static void sd_isr_done_transfer(struct platform_device *pdev)
> -{
> - struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
> -
> - spin_lock(&host->lock);
> - if (host->cmd)
> - tasklet_schedule(&host->cmd_tasklet);
> - if (host->data)
> - tasklet_schedule(&host->data_tasklet);
> - spin_unlock(&host->lock);
> -}
> -
> -static void sd_request_timeout(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - if (!host->mrq) {
> - dev_err(sdmmc_dev(host), "error: no request exist\n");
> - goto out;
> - }
> -
> - if (host->cmd)
> - host->cmd->error = -ETIMEDOUT;
> - if (host->data)
> - host->data->error = -ETIMEDOUT;
> -
> - dev_dbg(sdmmc_dev(host), "timeout for request\n");
> -
> -out:
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> -}
> -
> -static void sd_finish_request(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_request *mrq;
> - struct mmc_command *cmd;
> - struct mmc_data *data;
> - unsigned long flags;
> - bool any_error;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - del_timer(&host->timer);
> - mrq = host->mrq;
> - if (!mrq) {
> - dev_err(sdmmc_dev(host), "error: no request need finish\n");
> - goto out;
> - }
> -
> - cmd = mrq->cmd;
> - data = mrq->data;
> -
> - any_error = (mrq->sbc && mrq->sbc->error) ||
> - (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;
> - else
> - data->bytes_xfered = data->blocks * data->blksz;
> -
> - if (!data->host_cookie)
> - rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len,
> - data->flags & MMC_DATA_READ);
> -
> - }
> -
> - host->mrq = NULL;
> - host->cmd = NULL;
> - host->data = NULL;
> -
> -out:
> - spin_unlock_irqrestore(&host->lock, flags);
> - mutex_unlock(&pcr->pcr_mutex);
> - mmc_request_done(host->mmc, mrq);
> -}
> -
> static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
> u8 *buf, int buf_len, int timeout)
> {
> @@ -311,7 +203,8 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
> return 0;
> }
>
> -static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> +static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
> + struct mmc_command *cmd)
> {
> struct rtsx_pcr *pcr = host->pcr;
> u8 cmd_idx = (u8)cmd->opcode;
> @@ -319,14 +212,11 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> int err = 0;
> int timeout = 100;
> int i;
> + u8 *ptr;
> + int stat_idx = 0;
> u8 rsp_type;
> int rsp_len = 5;
> - unsigned long flags;
> -
> - if (host->cmd)
> - dev_err(sdmmc_dev(host), "error: cmd already exist\n");
> -
> - host->cmd = cmd;
> + bool clock_toggled = false;
>
> dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
> __func__, cmd_idx, arg);
> @@ -361,8 +251,6 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> err = -EINVAL;
> goto out;
> }
> - host->rsp_type = rsp_type;
> - host->rsp_len = rsp_len;
>
> if (rsp_type == SD_RSP_TYPE_R1b)
> timeout = 3000;
> @@ -372,6 +260,8 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> 0xFF, SD_CLK_TOGGLE_EN);
> if (err < 0)
> goto out;
> +
> + clock_toggled = true;
> }
>
> rtsx_pci_init_cmd(pcr);
> @@ -395,60 +285,25 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> /* Read data from ping-pong buffer */
> for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
> rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
> + stat_idx = 16;
> } else if (rsp_type != SD_RSP_TYPE_R0) {
> /* Read data from SD_CMDx registers */
> for (i = SD_CMD0; i <= SD_CMD4; i++)
> rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
> + stat_idx = 5;
> }
>
> rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);
>
> - mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
> -
> - spin_lock_irqsave(&pcr->lock, flags);
> - pcr->trans_result = TRANS_NOT_READY;
> - rtsx_pci_send_cmd_no_wait(pcr);
> - spin_unlock_irqrestore(&pcr->lock, flags);
> -
> - return;
> -
> -out:
> - cmd->error = err;
> - tasklet_schedule(&host->finish_tasklet);
> -}
> -
> -static void sd_get_rsp(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_command *cmd;
> - int i, err = 0, stat_idx;
> - u8 *ptr, rsp_type;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - cmd = host->cmd;
> - host->cmd = NULL;
> -
> - if (!cmd) {
> - dev_err(sdmmc_dev(host), "error: cmd not exist\n");
> + err = rtsx_pci_send_cmd(pcr, timeout);
> + if (err < 0) {
> + sd_print_debug_regs(host);
> + sd_clear_error(host);
> + dev_dbg(sdmmc_dev(host),
> + "rtsx_pci_send_cmd error (err = %d)\n", err);
> goto out;
> }
>
> - spin_lock(&pcr->lock);
> - if (pcr->trans_result == TRANS_NO_DEVICE)
> - err = -ENODEV;
> - else if (pcr->trans_result != TRANS_RESULT_OK)
> - err = -EINVAL;
> - spin_unlock(&pcr->lock);
> -
> - if (err < 0)
> - goto out;
> -
> - rsp_type = host->rsp_type;
> - stat_idx = host->rsp_len;
> -
> if (rsp_type == SD_RSP_TYPE_R0) {
> err = 0;
> goto out;
> @@ -485,106 +340,26 @@ static void sd_get_rsp(unsigned long host_addr)
> cmd->resp[0]);
> }
>
> - if (cmd == host->mrq->sbc) {
> - sd_send_cmd(host, host->mrq->cmd);
> - spin_unlock_irqrestore(&host->lock, flags);
> - return;
> - }
> -
> - if (cmd == host->mrq->stop)
> - goto out;
> -
> - if (cmd->data) {
> - sd_start_multi_rw(host, host->mrq);
> - spin_unlock_irqrestore(&host->lock, flags);
> - return;
> - }
> -
> out:
> cmd->error = err;
>
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> -}
> -
> -static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
> - struct mmc_data *data, struct realtek_next *next)
> -{
> - struct rtsx_pcr *pcr = host->pcr;
> - int read = data->flags & MMC_DATA_READ;
> - int sg_count = 0;
> -
> - if (!next && data->host_cookie &&
> - data->host_cookie != host->next_data.cookie) {
> - dev_err(sdmmc_dev(host),
> - "error: invalid cookie data[%d] host[%d]\n",
> - data->host_cookie, host->next_data.cookie);
> - data->host_cookie = 0;
> - }
> -
> - if (next || (!next && data->host_cookie != host->next_data.cookie))
> - sg_count = rtsx_pci_dma_map_sg(pcr,
> - data->sg, data->sg_len, read);
> - else
> - sg_count = host->next_data.sg_count;
> -
> - if (next) {
> - next->sg_count = sg_count;
> - if (++next->cookie < 0)
> - next->cookie = 1;
> - data->host_cookie = next->cookie;
> - }
> -
> - return sg_count;
> -}
> -
> -static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
> - bool is_first_req)
> -{
> - struct realtek_pci_sdmmc *host = mmc_priv(mmc);
> - struct mmc_data *data = mrq->data;
> -
> - if (data->host_cookie) {
> - dev_err(sdmmc_dev(host),
> - "error: descard already cookie data[%d]\n",
> - data->host_cookie);
> - data->host_cookie = 0;
> - }
> -
> - dev_dbg(sdmmc_dev(host), "dma sg prepared: %d\n",
> - sd_pre_dma_transfer(host, data, &host->next_data));
> -}
> -
> -static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
> - int err)
> -{
> - struct realtek_pci_sdmmc *host = mmc_priv(mmc);
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_data *data = mrq->data;
> - int read = data->flags & MMC_DATA_READ;
> -
> - rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read);
> - data->host_cookie = 0;
> + if (err && clock_toggled)
> + rtsx_pci_write_register(pcr, SD_BUS_STAT,
> + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
> }
>
> -static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
> - struct mmc_request *mrq)
> +static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
> {
> struct rtsx_pcr *pcr = host->pcr;
> struct mmc_host *mmc = host->mmc;
> struct mmc_card *card = mmc->card;
> struct mmc_data *data = mrq->data;
> int uhs = mmc_card_uhs(card);
> - int read = data->flags & MMC_DATA_READ;
> + int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
> u8 cfg2, trans_mode;
> int err;
> size_t data_len = data->blksz * data->blocks;
>
> - if (host->data)
> - dev_err(sdmmc_dev(host), "error: data already exist\n");
> -
> - host->data = data;
> -
> if (read) {
> cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
> SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
> @@ -635,54 +410,15 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
> rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
> SD_TRANSFER_END, SD_TRANSFER_END);
>
> - 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;
> -}
> -
> -static void sd_finish_multi_rw(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_data *data;
> - int err = 0;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - if (!host->data) {
> - dev_err(sdmmc_dev(host), "error: no data exist\n");
> - goto out;
> - }
> -
> - data = host->data;
> - host->data = NULL;
> -
> - if (pcr->trans_result == TRANS_NO_DEVICE)
> - err = -ENODEV;
> - else if (pcr->trans_result != TRANS_RESULT_OK)
> - err = -EINVAL;
> -
> + err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000);
> if (err < 0) {
> - data->error = err;
> - goto out;
> - }
> -
> - if (!host->mrq->sbc && data->stop) {
> - sd_send_cmd(host, data->stop);
> - spin_unlock_irqrestore(&host->lock, flags);
> - return;
> + sd_clear_error(host);
> + return err;
> }
>
> -out:
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> + return 0;
> }
>
> static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
> @@ -901,13 +637,6 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
> return 0;
> }
>
> -static inline bool sd_use_muti_rw(struct mmc_command *cmd)
> -{
> - return mmc_op_multi(cmd->opcode) ||
> - (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
> - (cmd->opcode == MMC_WRITE_BLOCK);
> -}
> -
> static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> {
> struct realtek_pci_sdmmc *host = mmc_priv(mmc);
> @@ -916,14 +645,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> struct mmc_data *data = mrq->data;
> unsigned int data_size = 0;
> int err;
> - unsigned long flags;
> -
> - mutex_lock(&pcr->pcr_mutex);
> - spin_lock_irqsave(&host->lock, flags);
> -
> - if (host->mrq)
> - dev_err(sdmmc_dev(host), "error: request already exist\n");
> - host->mrq = mrq;
>
> if (host->eject) {
> cmd->error = -ENOMEDIUM;
> @@ -936,6 +657,8 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> goto finish;
> }
>
> + mutex_lock(&pcr->pcr_mutex);
> +
> rtsx_pci_start_run(pcr);
>
> rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth,
> @@ -944,28 +667,46 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
> CARD_SHARE_MASK, CARD_SHARE_48_SD);
>
> + mutex_lock(&host->host_mutex);
> + host->mrq = mrq;
> + mutex_unlock(&host->host_mutex);
> +
> if (mrq->data)
> data_size = data->blocks * data->blksz;
>
> - if (sd_use_muti_rw(cmd))
> - host->sg_count = sd_pre_dma_transfer(host, data, NULL);
> + if (!data_size || mmc_op_multi(cmd->opcode) ||
> + (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
> + (cmd->opcode == MMC_WRITE_BLOCK)) {
> + sd_send_cmd_get_rsp(host, cmd);
>
> - if (!data_size || sd_use_muti_rw(cmd)) {
> - if (mrq->sbc)
> - sd_send_cmd(host, mrq->sbc);
> - else
> - sd_send_cmd(host, cmd);
> - spin_unlock_irqrestore(&host->lock, flags);
> + if (!cmd->error && data_size) {
> + sd_rw_multi(host, mrq);
> +
> + if (mmc_op_multi(cmd->opcode) && mrq->stop)
> + sd_send_cmd_get_rsp(host, mrq->stop);
> + }
> } else {
> - spin_unlock_irqrestore(&host->lock, flags);
> sd_normal_rw(host, mrq);
> - tasklet_schedule(&host->finish_tasklet);
> }
> - return;
> +
> + if (mrq->data) {
> + if (cmd->error || data->error)
> + data->bytes_xfered = 0;
> + else
> + data->bytes_xfered = data->blocks * data->blksz;
> + }
> +
> + mutex_unlock(&pcr->pcr_mutex);
>
> finish:
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> + if (cmd->error)
> + dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
> +
> + mutex_lock(&host->host_mutex);
> + host->mrq = NULL;
> + mutex_unlock(&host->host_mutex);
> +
> + mmc_request_done(mmc, mrq);
> }
>
> static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
> @@ -1400,8 +1141,6 @@ out:
> }
>
> static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
> - .pre_req = sdmmc_pre_req,
> - .post_req = sdmmc_post_req,
> .request = sdmmc_request,
> .set_ios = sdmmc_set_ios,
> .get_ro = sdmmc_get_ro,
> @@ -1465,7 +1204,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
> struct realtek_pci_sdmmc *host;
> struct rtsx_pcr *pcr;
> struct pcr_handle *handle = pdev->dev.platform_data;
> - unsigned long host_addr;
>
> if (!handle)
> return -ENXIO;
> @@ -1489,15 +1227,8 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
> pcr->slots[RTSX_SD_CARD].p_dev = pdev;
> pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
>
> - host_addr = (unsigned long)host;
> - host->next_data.cookie = 1;
> - setup_timer(&host->timer, sd_request_timeout, host_addr);
> - tasklet_init(&host->cmd_tasklet, sd_get_rsp, host_addr);
> - tasklet_init(&host->data_tasklet, sd_finish_multi_rw, host_addr);
> - tasklet_init(&host->finish_tasklet, sd_finish_request, host_addr);
> - spin_lock_init(&host->lock);
> + mutex_init(&host->host_mutex);
>
> - pcr->slots[RTSX_SD_CARD].done_transfer = sd_isr_done_transfer;
> realtek_init_host(host);
>
> mmc_add_host(mmc);
> @@ -1510,8 +1241,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
> struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
> struct rtsx_pcr *pcr;
> struct mmc_host *mmc;
> - struct mmc_request *mrq;
> - unsigned long flags;
>
> if (!host)
> return 0;
> @@ -1519,33 +1248,22 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
> pcr = host->pcr;
> pcr->slots[RTSX_SD_CARD].p_dev = NULL;
> pcr->slots[RTSX_SD_CARD].card_event = NULL;
> - pcr->slots[RTSX_SD_CARD].done_transfer = NULL;
> mmc = host->mmc;
> - mrq = host->mrq;
>
> - spin_lock_irqsave(&host->lock, flags);
> + mutex_lock(&host->host_mutex);
> if (host->mrq) {
> dev_dbg(&(pdev->dev),
> "%s: Controller removed during transfer\n",
> mmc_hostname(mmc));
>
> - if (mrq->sbc)
> - mrq->sbc->error = -ENOMEDIUM;
> - if (mrq->cmd)
> - mrq->cmd->error = -ENOMEDIUM;
> - if (mrq->stop)
> - mrq->stop->error = -ENOMEDIUM;
> - if (mrq->data)
> - mrq->data->error = -ENOMEDIUM;
> + rtsx_pci_complete_unfinished_transfer(pcr);
>
> - tasklet_schedule(&host->finish_tasklet);
> + host->mrq->cmd->error = -ENOMEDIUM;
> + if (host->mrq->stop)
> + host->mrq->stop->error = -ENOMEDIUM;
> + mmc_request_done(mmc, host->mrq);
> }
> - spin_unlock_irqrestore(&host->lock, flags);
> -
> - del_timer_sync(&host->timer);
> - tasklet_kill(&host->cmd_tasklet);
> - tasklet_kill(&host->data_tasklet);
> - tasklet_kill(&host->finish_tasklet);
> + mutex_unlock(&host->host_mutex);
>
> mmc_remove_host(mmc);
> host->eject = true;
> diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h
> index 7c36cc5..443176e 100644
> --- a/include/linux/mfd/rtsx_common.h
> +++ b/include/linux/mfd/rtsx_common.h
> @@ -45,7 +45,6 @@ struct platform_device;
> struct rtsx_slot {
> struct platform_device *p_dev;
> void (*card_event)(struct platform_device *p_dev);
> - void (*done_transfer)(struct platform_device *p_dev);
> };
>
> #endif
> diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h
> index 8d6bbd6..a383597 100644
> --- a/include/linux/mfd/rtsx_pci.h
> +++ b/include/linux/mfd/rtsx_pci.h
> @@ -943,12 +943,6 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
> int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
> int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> int num_sg, bool read, int timeout);
> -int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read);
> -int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read);
> -int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int sg_count, bool read);
> int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
> int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
> int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
On 28 April 2014 09:36, <[email protected]> wrote:
> From: Micky Ching <[email protected]>
>
> This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
>
> commit <mmc: rtsx: add support for pre_req and post_req> did use
> mutex_unlock() in tasklet, but mutex_unlock() can't used in
> tasklet(atomic context). The driver need use mutex to avoid concurrency,
> so we can't use tasklet here, the patch need to be removed.
>
> The spinlock host->lock and pcr->lock may deadlock, one way to solve the
> deadlock is remove host->lock in sd_isr_done_transfer(), but if using
> workqueue the we can avoid using the spinlock and also avoid the problem.
>
> Signed-off-by: Micky Ching <[email protected]>
Acked-by: Ulf Hansson <[email protected]>
Chris, could you pick up this for "fixes" instead of queuing it for 3.16?
Kind regards
Uffe
> ---
> drivers/mfd/rtsx_pcr.c | 132 ++++--------
> drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
> include/linux/mfd/rtsx_common.h | 1 -
> include/linux/mfd/rtsx_pci.h | 6 -
> 4 files changed, 109 insertions(+), 448 deletions(-)
>
> diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
> index c9de3d5..1d15735 100644
> --- a/drivers/mfd/rtsx_pcr.c
> +++ b/drivers/mfd/rtsx_pcr.c
> @@ -338,28 +338,58 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> int num_sg, bool read, int timeout)
> {
> struct completion trans_done;
> - int err = 0, count;
> + u8 dir;
> + int err = 0, i, count;
> long timeleft;
> unsigned long flags;
> + struct scatterlist *sg;
> + enum dma_data_direction dma_dir;
> + u32 val;
> + dma_addr_t addr;
> + unsigned int len;
> +
> + dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg);
> +
> + /* don't transfer data during abort processing */
> + if (pcr->remove_pci)
> + return -EINVAL;
> +
> + if ((sglist == NULL) || (num_sg <= 0))
> + return -EINVAL;
>
> - count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
> + if (read) {
> + dir = DEVICE_TO_HOST;
> + dma_dir = DMA_FROM_DEVICE;
> + } else {
> + dir = HOST_TO_DEVICE;
> + dma_dir = DMA_TO_DEVICE;
> + }
> +
> + count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
> if (count < 1) {
> dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
> return -EINVAL;
> }
> dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
>
> + val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
> + pcr->sgi = 0;
> + for_each_sg(sglist, sg, count, i) {
> + addr = sg_dma_address(sg);
> + len = sg_dma_len(sg);
> + rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
> + }
>
> spin_lock_irqsave(&pcr->lock, flags);
>
> pcr->done = &trans_done;
> pcr->trans_result = TRANS_NOT_READY;
> init_completion(&trans_done);
> + rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
> + rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
>
> spin_unlock_irqrestore(&pcr->lock, flags);
>
> - rtsx_pci_dma_transfer(pcr, sglist, count, read);
> -
> timeleft = wait_for_completion_interruptible_timeout(
> &trans_done, msecs_to_jiffies(timeout));
> if (timeleft <= 0) {
> @@ -383,7 +413,7 @@ out:
> pcr->done = NULL;
> spin_unlock_irqrestore(&pcr->lock, flags);
>
> - rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
> + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
>
> if ((err < 0) && (err != -ENODEV))
> rtsx_pci_stop_cmd(pcr);
> @@ -395,73 +425,6 @@ out:
> }
> EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
>
> -int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read)
> -{
> - enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> -
> - if (pcr->remove_pci)
> - return -EINVAL;
> -
> - if ((sglist == NULL) || num_sg < 1)
> - return -EINVAL;
> -
> - return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
> -}
> -EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
> -
> -int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read)
> -{
> - enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> -
> - if (pcr->remove_pci)
> - return -EINVAL;
> -
> - if (sglist == NULL || num_sg < 1)
> - return -EINVAL;
> -
> - dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
> - return num_sg;
> -}
> -EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
> -
> -int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int sg_count, bool read)
> -{
> - struct scatterlist *sg;
> - dma_addr_t addr;
> - unsigned int len;
> - int i;
> - u32 val;
> - u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
> - unsigned long flags;
> -
> - if (pcr->remove_pci)
> - return -EINVAL;
> -
> - if ((sglist == NULL) || (sg_count < 1))
> - return -EINVAL;
> -
> - val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
> - pcr->sgi = 0;
> - for_each_sg(sglist, sg, sg_count, i) {
> - addr = sg_dma_address(sg);
> - len = sg_dma_len(sg);
> - rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1);
> - }
> -
> - spin_lock_irqsave(&pcr->lock, flags);
> -
> - rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
> - rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
> -
> - spin_unlock_irqrestore(&pcr->lock, flags);
> -
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
> -
> int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
> {
> int err;
> @@ -873,8 +836,6 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
> int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
> /* Clear interrupt flag */
> rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
> - dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg);
> -
> if ((int_reg & pcr->bier) == 0) {
> spin_unlock(&pcr->lock);
> return IRQ_NONE;
> @@ -905,28 +866,17 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
> }
>
> if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
> - if (int_reg & (TRANS_FAIL_INT | DELINK_INT))
> + if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
> pcr->trans_result = TRANS_RESULT_FAIL;
> - else if (int_reg & TRANS_OK_INT)
> + if (pcr->done)
> + complete(pcr->done);
> + } else if (int_reg & TRANS_OK_INT) {
> pcr->trans_result = TRANS_RESULT_OK;
> -
> - if (pcr->done)
> - complete(pcr->done);
> -
> - if (int_reg & SD_EXIST) {
> - struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
> - if (slot && slot->done_transfer)
> - slot->done_transfer(slot->p_dev);
> - }
> -
> - if (int_reg & MS_EXIST) {
> - struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
> - if (slot && slot->done_transfer)
> - slot->done_transfer(slot->p_dev);
> + if (pcr->done)
> + complete(pcr->done);
> }
> }
>
> -
> if (pcr->card_inserted || pcr->card_removed)
> schedule_delayed_work(&pcr->carddet_work,
> msecs_to_jiffies(200));
> diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
> index 5fb994f..0b9ded1 100644
> --- a/drivers/mmc/host/rtsx_pci_sdmmc.c
> +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
> @@ -31,28 +31,14 @@
> #include <linux/mfd/rtsx_pci.h>
> #include <asm/unaligned.h>
>
> -struct realtek_next {
> - unsigned int sg_count;
> - s32 cookie;
> -};
> -
> struct realtek_pci_sdmmc {
> struct platform_device *pdev;
> struct rtsx_pcr *pcr;
> struct mmc_host *mmc;
> struct mmc_request *mrq;
> - struct mmc_command *cmd;
> - struct mmc_data *data;
> -
> - spinlock_t lock;
> - struct timer_list timer;
> - struct tasklet_struct cmd_tasklet;
> - struct tasklet_struct data_tasklet;
> - struct tasklet_struct finish_tasklet;
> -
> - u8 rsp_type;
> - u8 rsp_len;
> - int sg_count;
> +
> + struct mutex host_mutex;
> +
> u8 ssc_depth;
> unsigned int clock;
> bool vpclk;
> @@ -62,13 +48,8 @@ struct realtek_pci_sdmmc {
> int power_state;
> #define SDMMC_POWER_ON 1
> #define SDMMC_POWER_OFF 0
> -
> - struct realtek_next next_data;
> };
>
> -static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
> - struct mmc_request *mrq);
> -
> static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
> {
> return &(host->pdev->dev);
> @@ -105,95 +86,6 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
> #define sd_print_debug_regs(host)
> #endif /* DEBUG */
>
> -static void sd_isr_done_transfer(struct platform_device *pdev)
> -{
> - struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
> -
> - spin_lock(&host->lock);
> - if (host->cmd)
> - tasklet_schedule(&host->cmd_tasklet);
> - if (host->data)
> - tasklet_schedule(&host->data_tasklet);
> - spin_unlock(&host->lock);
> -}
> -
> -static void sd_request_timeout(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - if (!host->mrq) {
> - dev_err(sdmmc_dev(host), "error: no request exist\n");
> - goto out;
> - }
> -
> - if (host->cmd)
> - host->cmd->error = -ETIMEDOUT;
> - if (host->data)
> - host->data->error = -ETIMEDOUT;
> -
> - dev_dbg(sdmmc_dev(host), "timeout for request\n");
> -
> -out:
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> -}
> -
> -static void sd_finish_request(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_request *mrq;
> - struct mmc_command *cmd;
> - struct mmc_data *data;
> - unsigned long flags;
> - bool any_error;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - del_timer(&host->timer);
> - mrq = host->mrq;
> - if (!mrq) {
> - dev_err(sdmmc_dev(host), "error: no request need finish\n");
> - goto out;
> - }
> -
> - cmd = mrq->cmd;
> - data = mrq->data;
> -
> - any_error = (mrq->sbc && mrq->sbc->error) ||
> - (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;
> - else
> - data->bytes_xfered = data->blocks * data->blksz;
> -
> - if (!data->host_cookie)
> - rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len,
> - data->flags & MMC_DATA_READ);
> -
> - }
> -
> - host->mrq = NULL;
> - host->cmd = NULL;
> - host->data = NULL;
> -
> -out:
> - spin_unlock_irqrestore(&host->lock, flags);
> - mutex_unlock(&pcr->pcr_mutex);
> - mmc_request_done(host->mmc, mrq);
> -}
> -
> static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
> u8 *buf, int buf_len, int timeout)
> {
> @@ -311,7 +203,8 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
> return 0;
> }
>
> -static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> +static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
> + struct mmc_command *cmd)
> {
> struct rtsx_pcr *pcr = host->pcr;
> u8 cmd_idx = (u8)cmd->opcode;
> @@ -319,14 +212,11 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> int err = 0;
> int timeout = 100;
> int i;
> + u8 *ptr;
> + int stat_idx = 0;
> u8 rsp_type;
> int rsp_len = 5;
> - unsigned long flags;
> -
> - if (host->cmd)
> - dev_err(sdmmc_dev(host), "error: cmd already exist\n");
> -
> - host->cmd = cmd;
> + bool clock_toggled = false;
>
> dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
> __func__, cmd_idx, arg);
> @@ -361,8 +251,6 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> err = -EINVAL;
> goto out;
> }
> - host->rsp_type = rsp_type;
> - host->rsp_len = rsp_len;
>
> if (rsp_type == SD_RSP_TYPE_R1b)
> timeout = 3000;
> @@ -372,6 +260,8 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> 0xFF, SD_CLK_TOGGLE_EN);
> if (err < 0)
> goto out;
> +
> + clock_toggled = true;
> }
>
> rtsx_pci_init_cmd(pcr);
> @@ -395,60 +285,25 @@ static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
> /* Read data from ping-pong buffer */
> for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
> rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
> + stat_idx = 16;
> } else if (rsp_type != SD_RSP_TYPE_R0) {
> /* Read data from SD_CMDx registers */
> for (i = SD_CMD0; i <= SD_CMD4; i++)
> rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
> + stat_idx = 5;
> }
>
> rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);
>
> - mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
> -
> - spin_lock_irqsave(&pcr->lock, flags);
> - pcr->trans_result = TRANS_NOT_READY;
> - rtsx_pci_send_cmd_no_wait(pcr);
> - spin_unlock_irqrestore(&pcr->lock, flags);
> -
> - return;
> -
> -out:
> - cmd->error = err;
> - tasklet_schedule(&host->finish_tasklet);
> -}
> -
> -static void sd_get_rsp(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_command *cmd;
> - int i, err = 0, stat_idx;
> - u8 *ptr, rsp_type;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - cmd = host->cmd;
> - host->cmd = NULL;
> -
> - if (!cmd) {
> - dev_err(sdmmc_dev(host), "error: cmd not exist\n");
> + err = rtsx_pci_send_cmd(pcr, timeout);
> + if (err < 0) {
> + sd_print_debug_regs(host);
> + sd_clear_error(host);
> + dev_dbg(sdmmc_dev(host),
> + "rtsx_pci_send_cmd error (err = %d)\n", err);
> goto out;
> }
>
> - spin_lock(&pcr->lock);
> - if (pcr->trans_result == TRANS_NO_DEVICE)
> - err = -ENODEV;
> - else if (pcr->trans_result != TRANS_RESULT_OK)
> - err = -EINVAL;
> - spin_unlock(&pcr->lock);
> -
> - if (err < 0)
> - goto out;
> -
> - rsp_type = host->rsp_type;
> - stat_idx = host->rsp_len;
> -
> if (rsp_type == SD_RSP_TYPE_R0) {
> err = 0;
> goto out;
> @@ -485,106 +340,26 @@ static void sd_get_rsp(unsigned long host_addr)
> cmd->resp[0]);
> }
>
> - if (cmd == host->mrq->sbc) {
> - sd_send_cmd(host, host->mrq->cmd);
> - spin_unlock_irqrestore(&host->lock, flags);
> - return;
> - }
> -
> - if (cmd == host->mrq->stop)
> - goto out;
> -
> - if (cmd->data) {
> - sd_start_multi_rw(host, host->mrq);
> - spin_unlock_irqrestore(&host->lock, flags);
> - return;
> - }
> -
> out:
> cmd->error = err;
>
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> -}
> -
> -static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
> - struct mmc_data *data, struct realtek_next *next)
> -{
> - struct rtsx_pcr *pcr = host->pcr;
> - int read = data->flags & MMC_DATA_READ;
> - int sg_count = 0;
> -
> - if (!next && data->host_cookie &&
> - data->host_cookie != host->next_data.cookie) {
> - dev_err(sdmmc_dev(host),
> - "error: invalid cookie data[%d] host[%d]\n",
> - data->host_cookie, host->next_data.cookie);
> - data->host_cookie = 0;
> - }
> -
> - if (next || (!next && data->host_cookie != host->next_data.cookie))
> - sg_count = rtsx_pci_dma_map_sg(pcr,
> - data->sg, data->sg_len, read);
> - else
> - sg_count = host->next_data.sg_count;
> -
> - if (next) {
> - next->sg_count = sg_count;
> - if (++next->cookie < 0)
> - next->cookie = 1;
> - data->host_cookie = next->cookie;
> - }
> -
> - return sg_count;
> -}
> -
> -static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
> - bool is_first_req)
> -{
> - struct realtek_pci_sdmmc *host = mmc_priv(mmc);
> - struct mmc_data *data = mrq->data;
> -
> - if (data->host_cookie) {
> - dev_err(sdmmc_dev(host),
> - "error: descard already cookie data[%d]\n",
> - data->host_cookie);
> - data->host_cookie = 0;
> - }
> -
> - dev_dbg(sdmmc_dev(host), "dma sg prepared: %d\n",
> - sd_pre_dma_transfer(host, data, &host->next_data));
> -}
> -
> -static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
> - int err)
> -{
> - struct realtek_pci_sdmmc *host = mmc_priv(mmc);
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_data *data = mrq->data;
> - int read = data->flags & MMC_DATA_READ;
> -
> - rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read);
> - data->host_cookie = 0;
> + if (err && clock_toggled)
> + rtsx_pci_write_register(pcr, SD_BUS_STAT,
> + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
> }
>
> -static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
> - struct mmc_request *mrq)
> +static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
> {
> struct rtsx_pcr *pcr = host->pcr;
> struct mmc_host *mmc = host->mmc;
> struct mmc_card *card = mmc->card;
> struct mmc_data *data = mrq->data;
> int uhs = mmc_card_uhs(card);
> - int read = data->flags & MMC_DATA_READ;
> + int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
> u8 cfg2, trans_mode;
> int err;
> size_t data_len = data->blksz * data->blocks;
>
> - if (host->data)
> - dev_err(sdmmc_dev(host), "error: data already exist\n");
> -
> - host->data = data;
> -
> if (read) {
> cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
> SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
> @@ -635,54 +410,15 @@ static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
> rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
> SD_TRANSFER_END, SD_TRANSFER_END);
>
> - 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;
> -}
> -
> -static void sd_finish_multi_rw(unsigned long host_addr)
> -{
> - struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
> - struct rtsx_pcr *pcr = host->pcr;
> - struct mmc_data *data;
> - int err = 0;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&host->lock, flags);
> -
> - if (!host->data) {
> - dev_err(sdmmc_dev(host), "error: no data exist\n");
> - goto out;
> - }
> -
> - data = host->data;
> - host->data = NULL;
> -
> - if (pcr->trans_result == TRANS_NO_DEVICE)
> - err = -ENODEV;
> - else if (pcr->trans_result != TRANS_RESULT_OK)
> - err = -EINVAL;
> -
> + err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000);
> if (err < 0) {
> - data->error = err;
> - goto out;
> - }
> -
> - if (!host->mrq->sbc && data->stop) {
> - sd_send_cmd(host, data->stop);
> - spin_unlock_irqrestore(&host->lock, flags);
> - return;
> + sd_clear_error(host);
> + return err;
> }
>
> -out:
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> + return 0;
> }
>
> static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
> @@ -901,13 +637,6 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
> return 0;
> }
>
> -static inline bool sd_use_muti_rw(struct mmc_command *cmd)
> -{
> - return mmc_op_multi(cmd->opcode) ||
> - (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
> - (cmd->opcode == MMC_WRITE_BLOCK);
> -}
> -
> static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> {
> struct realtek_pci_sdmmc *host = mmc_priv(mmc);
> @@ -916,14 +645,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> struct mmc_data *data = mrq->data;
> unsigned int data_size = 0;
> int err;
> - unsigned long flags;
> -
> - mutex_lock(&pcr->pcr_mutex);
> - spin_lock_irqsave(&host->lock, flags);
> -
> - if (host->mrq)
> - dev_err(sdmmc_dev(host), "error: request already exist\n");
> - host->mrq = mrq;
>
> if (host->eject) {
> cmd->error = -ENOMEDIUM;
> @@ -936,6 +657,8 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> goto finish;
> }
>
> + mutex_lock(&pcr->pcr_mutex);
> +
> rtsx_pci_start_run(pcr);
>
> rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth,
> @@ -944,28 +667,46 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
> CARD_SHARE_MASK, CARD_SHARE_48_SD);
>
> + mutex_lock(&host->host_mutex);
> + host->mrq = mrq;
> + mutex_unlock(&host->host_mutex);
> +
> if (mrq->data)
> data_size = data->blocks * data->blksz;
>
> - if (sd_use_muti_rw(cmd))
> - host->sg_count = sd_pre_dma_transfer(host, data, NULL);
> + if (!data_size || mmc_op_multi(cmd->opcode) ||
> + (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
> + (cmd->opcode == MMC_WRITE_BLOCK)) {
> + sd_send_cmd_get_rsp(host, cmd);
>
> - if (!data_size || sd_use_muti_rw(cmd)) {
> - if (mrq->sbc)
> - sd_send_cmd(host, mrq->sbc);
> - else
> - sd_send_cmd(host, cmd);
> - spin_unlock_irqrestore(&host->lock, flags);
> + if (!cmd->error && data_size) {
> + sd_rw_multi(host, mrq);
> +
> + if (mmc_op_multi(cmd->opcode) && mrq->stop)
> + sd_send_cmd_get_rsp(host, mrq->stop);
> + }
> } else {
> - spin_unlock_irqrestore(&host->lock, flags);
> sd_normal_rw(host, mrq);
> - tasklet_schedule(&host->finish_tasklet);
> }
> - return;
> +
> + if (mrq->data) {
> + if (cmd->error || data->error)
> + data->bytes_xfered = 0;
> + else
> + data->bytes_xfered = data->blocks * data->blksz;
> + }
> +
> + mutex_unlock(&pcr->pcr_mutex);
>
> finish:
> - tasklet_schedule(&host->finish_tasklet);
> - spin_unlock_irqrestore(&host->lock, flags);
> + if (cmd->error)
> + dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
> +
> + mutex_lock(&host->host_mutex);
> + host->mrq = NULL;
> + mutex_unlock(&host->host_mutex);
> +
> + mmc_request_done(mmc, mrq);
> }
>
> static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
> @@ -1400,8 +1141,6 @@ out:
> }
>
> static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
> - .pre_req = sdmmc_pre_req,
> - .post_req = sdmmc_post_req,
> .request = sdmmc_request,
> .set_ios = sdmmc_set_ios,
> .get_ro = sdmmc_get_ro,
> @@ -1465,7 +1204,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
> struct realtek_pci_sdmmc *host;
> struct rtsx_pcr *pcr;
> struct pcr_handle *handle = pdev->dev.platform_data;
> - unsigned long host_addr;
>
> if (!handle)
> return -ENXIO;
> @@ -1489,15 +1227,8 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
> pcr->slots[RTSX_SD_CARD].p_dev = pdev;
> pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
>
> - host_addr = (unsigned long)host;
> - host->next_data.cookie = 1;
> - setup_timer(&host->timer, sd_request_timeout, host_addr);
> - tasklet_init(&host->cmd_tasklet, sd_get_rsp, host_addr);
> - tasklet_init(&host->data_tasklet, sd_finish_multi_rw, host_addr);
> - tasklet_init(&host->finish_tasklet, sd_finish_request, host_addr);
> - spin_lock_init(&host->lock);
> + mutex_init(&host->host_mutex);
>
> - pcr->slots[RTSX_SD_CARD].done_transfer = sd_isr_done_transfer;
> realtek_init_host(host);
>
> mmc_add_host(mmc);
> @@ -1510,8 +1241,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
> struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
> struct rtsx_pcr *pcr;
> struct mmc_host *mmc;
> - struct mmc_request *mrq;
> - unsigned long flags;
>
> if (!host)
> return 0;
> @@ -1519,33 +1248,22 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
> pcr = host->pcr;
> pcr->slots[RTSX_SD_CARD].p_dev = NULL;
> pcr->slots[RTSX_SD_CARD].card_event = NULL;
> - pcr->slots[RTSX_SD_CARD].done_transfer = NULL;
> mmc = host->mmc;
> - mrq = host->mrq;
>
> - spin_lock_irqsave(&host->lock, flags);
> + mutex_lock(&host->host_mutex);
> if (host->mrq) {
> dev_dbg(&(pdev->dev),
> "%s: Controller removed during transfer\n",
> mmc_hostname(mmc));
>
> - if (mrq->sbc)
> - mrq->sbc->error = -ENOMEDIUM;
> - if (mrq->cmd)
> - mrq->cmd->error = -ENOMEDIUM;
> - if (mrq->stop)
> - mrq->stop->error = -ENOMEDIUM;
> - if (mrq->data)
> - mrq->data->error = -ENOMEDIUM;
> + rtsx_pci_complete_unfinished_transfer(pcr);
>
> - tasklet_schedule(&host->finish_tasklet);
> + host->mrq->cmd->error = -ENOMEDIUM;
> + if (host->mrq->stop)
> + host->mrq->stop->error = -ENOMEDIUM;
> + mmc_request_done(mmc, host->mrq);
> }
> - spin_unlock_irqrestore(&host->lock, flags);
> -
> - del_timer_sync(&host->timer);
> - tasklet_kill(&host->cmd_tasklet);
> - tasklet_kill(&host->data_tasklet);
> - tasklet_kill(&host->finish_tasklet);
> + mutex_unlock(&host->host_mutex);
>
> mmc_remove_host(mmc);
> host->eject = true;
> diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h
> index 7c36cc5..443176e 100644
> --- a/include/linux/mfd/rtsx_common.h
> +++ b/include/linux/mfd/rtsx_common.h
> @@ -45,7 +45,6 @@ struct platform_device;
> struct rtsx_slot {
> struct platform_device *p_dev;
> void (*card_event)(struct platform_device *p_dev);
> - void (*done_transfer)(struct platform_device *p_dev);
> };
>
> #endif
> diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h
> index 8d6bbd6..a383597 100644
> --- a/include/linux/mfd/rtsx_pci.h
> +++ b/include/linux/mfd/rtsx_pci.h
> @@ -943,12 +943,6 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
> int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
> int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> int num_sg, bool read, int timeout);
> -int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read);
> -int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int num_sg, bool read);
> -int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
> - int sg_count, bool read);
> int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
> int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
> int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
> --
> 1.7.9.5
>
> From: Micky Ching <[email protected]>
>
> This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
Why was this patch even merged without an MFD Ack?
> commit <mmc: rtsx: add support for pre_req and post_req> did use
> mutex_unlock() in tasklet, but mutex_unlock() can't used in
> tasklet(atomic context). The driver need use mutex to avoid concurrency,
> so we can't use tasklet here, the patch need to be removed.
>
> The spinlock host->lock and pcr->lock may deadlock, one way to solve the
> deadlock is remove host->lock in sd_isr_done_transfer(), but if using
> workqueue the we can avoid using the spinlock and also avoid the problem.
>
> Signed-off-by: Micky Ching <[email protected]>
> ---
> drivers/mfd/rtsx_pcr.c | 132 ++++--------
> drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
> include/linux/mfd/rtsx_common.h | 1 -
> include/linux/mfd/rtsx_pci.h | 6 -
> 4 files changed, 109 insertions(+), 448 deletions(-)
This patch should be sent to the -rcs as soon as possible:
Acked-by: Lee Jones <[email protected]>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
On 28 April 2014 12:53, Lee Jones <[email protected]> wrote:
>> From: Micky Ching <[email protected]>
>>
>> This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
>
> Why was this patch even merged without an MFD Ack?
>
>> commit <mmc: rtsx: add support for pre_req and post_req> did use
>> mutex_unlock() in tasklet, but mutex_unlock() can't used in
>> tasklet(atomic context). The driver need use mutex to avoid concurrency,
>> so we can't use tasklet here, the patch need to be removed.
>>
>> The spinlock host->lock and pcr->lock may deadlock, one way to solve the
>> deadlock is remove host->lock in sd_isr_done_transfer(), but if using
>> workqueue the we can avoid using the spinlock and also avoid the problem.
>>
>> Signed-off-by: Micky Ching <[email protected]>
>> ---
>> drivers/mfd/rtsx_pcr.c | 132 ++++--------
>> drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
>> include/linux/mfd/rtsx_common.h | 1 -
>> include/linux/mfd/rtsx_pci.h | 6 -
>> 4 files changed, 109 insertions(+), 448 deletions(-)
>
> This patch should be sent to the -rcs as soon as possible:
Do you mind helping out doing it here Lee? Not sure how busy Chris is
at the moment.
Kind regards
Ulf Hansson
>
> Acked-by: Lee Jones <[email protected]>
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
On Mon, Apr 28, 2014 at 11:53:50AM +0100, Lee Jones wrote:
> > From: Micky Ching <[email protected]>
> >
> > This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
>
> Why was this patch even merged without an MFD Ack?
I think process questions like this are very important.
These patches touch both mmc and mfd but they're mostly mmc patches.
They were first sent to LKML in January. Samuel was on the CC list but
you were left off. There were no replies to the thread. The patches
were then resent in February and Micky complained that they had been
sent "many times" and no one was responding. So then Chris took them.
You should have been included on the CC list and Chris should have asked
you or Sam for a response explicitly instead of waiting for a month and
giving up.
Also Micky, please, when you do a new version of a patch please put an
explanation of what changed between version 3 and version 4.
http://kernelnewbies.org/PatchTipsAndTricks
regards,
dan carpenter
> >> From: Micky Ching <[email protected]>
> >>
> >> This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
> >
> > Why was this patch even merged without an MFD Ack?
> >
> >> commit <mmc: rtsx: add support for pre_req and post_req> did use
> >> mutex_unlock() in tasklet, but mutex_unlock() can't used in
> >> tasklet(atomic context). The driver need use mutex to avoid concurrency,
> >> so we can't use tasklet here, the patch need to be removed.
> >>
> >> The spinlock host->lock and pcr->lock may deadlock, one way to solve the
> >> deadlock is remove host->lock in sd_isr_done_transfer(), but if using
> >> workqueue the we can avoid using the spinlock and also avoid the problem.
> >>
> >> Signed-off-by: Micky Ching <[email protected]>
> >> ---
> >> drivers/mfd/rtsx_pcr.c | 132 ++++--------
> >> drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
> >> include/linux/mfd/rtsx_common.h | 1 -
> >> include/linux/mfd/rtsx_pci.h | 6 -
> >> 4 files changed, 109 insertions(+), 448 deletions(-)
> >
> > This patch should be sent to the -rcs as soon as possible:
>
> Do you mind helping out doing it here Lee? Not sure how busy Chris is
> at the moment.
I don't mind. I just need a maintainer Ack from one of you guys.
> >
> > Acked-by: Lee Jones <[email protected]>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
On 28 April 2014 14:29, Lee Jones <[email protected]> wrote:
>> >> From: Micky Ching <[email protected]>
>> >>
>> >> This reverts commit c42deffd5b53c9e583d83c7964854ede2f12410d.
>> >
>> > Why was this patch even merged without an MFD Ack?
>> >
>> >> commit <mmc: rtsx: add support for pre_req and post_req> did use
>> >> mutex_unlock() in tasklet, but mutex_unlock() can't used in
>> >> tasklet(atomic context). The driver need use mutex to avoid concurrency,
>> >> so we can't use tasklet here, the patch need to be removed.
>> >>
>> >> The spinlock host->lock and pcr->lock may deadlock, one way to solve the
>> >> deadlock is remove host->lock in sd_isr_done_transfer(), but if using
>> >> workqueue the we can avoid using the spinlock and also avoid the problem.
>> >>
>> >> Signed-off-by: Micky Ching <[email protected]>
>> >> ---
>> >> drivers/mfd/rtsx_pcr.c | 132 ++++--------
>> >> drivers/mmc/host/rtsx_pci_sdmmc.c | 418 ++++++-------------------------------
>> >> include/linux/mfd/rtsx_common.h | 1 -
>> >> include/linux/mfd/rtsx_pci.h | 6 -
>> >> 4 files changed, 109 insertions(+), 448 deletions(-)
>> >
>> > This patch should be sent to the -rcs as soon as possible:
>>
>> Do you mind helping out doing it here Lee? Not sure how busy Chris is
>> at the moment.
>
> I don't mind. I just need a maintainer Ack from one of you guys.
Thanks for helping out Lee. Please hold on until we sorted out exactly
what should be reverted, it seems like some additional patch should be
removed/reverted as well.
Kind regards
Uffe
>
>> >
>> > Acked-by: Lee Jones <[email protected]>
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog