mmc: cmdq_hci: fix race between req completion and clearing CQTCN

CQ irq handler first calls completion path for every notified tag and then
clears CQTCN register for all completed tags. This approach could cause
following problem:
1) issue context (unblocked by tag completion) issues next
request, CQE successfully completes it and notifies task completion
through CQTCN again for the same tag.
2) CQ irq handler proceeds to clear CQTCN for the original request.

In the above scenario clear of CQTCN register will mask next
request completion and issue context will be never unblocked.
Hence clear CQTCN first and then notify the request completion.

Change-Id: Ie644e24279ca30de42bbc9f8e1ae4326609d38a5
Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
Konstantin Dorfman 2015-10-06 13:25:45 +03:00 committed by Subhash Jadavani
parent 0044c4d39c
commit 9a4df9847e

View file

@ -737,18 +737,28 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
}
if (status & CQIS_TCC) {
/* read QCTCN and complete the request */
/* read CQTCN and complete the request */
comp_status = cmdq_readl(cq_host, CQTCN);
if (!comp_status)
goto out;
/*
* The CQTCN must be cleared before notifying req completion
* to upper layers to avoid missing completion notification
* of new requests with the same tag.
*/
cmdq_writel(cq_host, comp_status, CQTCN);
/*
* A write memory barrier is necessary to guarantee that CQTCN
* gets cleared first before next doorbell for the same tag is
* set but that is already achieved by the barrier present
* before setting doorbell, hence one is not needed here.
*/
for_each_set_bit(tag, &comp_status, cq_host->num_slots) {
/* complete the corresponding mrq */
pr_debug("%s: completing tag -> %lu\n",
mmc_hostname(mmc), tag);
cmdq_finish_data(mmc, tag);
}
cmdq_writel(cq_host, comp_status, CQTCN);
}
if (status & CQIS_HAC) {