aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs
diff options
context:
space:
mode:
authorDolev Raviv <draviv@codeaurora.org>2014-07-01 05:22:37 -0400
committerChristoph Hellwig <hch@lst.de>2014-07-25 17:17:01 -0400
commite9d501b154ff62030670f7a210ed00d4cc2cae26 (patch)
tree939a814fa231dc2566f90374350f24b44af34842 /drivers/scsi/ufs
parent4264fd613a6a4b9c1c91d9291653d0fdaf4fd288 (diff)
ufs: read door bell register after clearing interrupt aggregation
In interrupt context, after reading and comparing the UTRLDBR to hba->outstanding_request and before resetting the interrupt aggregation, there might be completion of another transfer request (TR). Such TRs might get stuck, pending, until the next interrupt is generated (if any). Changing the sequence of resetting the interrupt aggregation first and then reading UTRLDBR status, will assure that completed TRs won't get stuck pending. Signed-off-by: Dolev Raviv <draviv@codeaurora.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r--drivers/scsi/ufs/ufshcd.c67
1 files changed, 34 insertions, 33 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b103e950db3c..b533ff8afe24 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2231,47 +2231,42 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
2231 u32 tr_doorbell; 2231 u32 tr_doorbell;
2232 int result; 2232 int result;
2233 int index; 2233 int index;
2234 bool int_aggr_reset = false; 2234
2235 /* Resetting interrupt aggregation counters first and reading the
2236 * DOOR_BELL afterward allows us to handle all the completed requests.
2237 * In order to prevent other interrupts starvation the DB is read once
2238 * after reset. The down side of this solution is the possibility of
2239 * false interrupt if device completes another request after resetting
2240 * aggregation and before reading the DB.
2241 */
2242 ufshcd_reset_intr_aggr(hba);
2235 2243
2236 tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); 2244 tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
2237 completed_reqs = tr_doorbell ^ hba->outstanding_reqs; 2245 completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
2238 2246
2239 for (index = 0; index < hba->nutrs; index++) { 2247 for_each_set_bit(index, &completed_reqs, hba->nutrs) {
2240 if (test_bit(index, &completed_reqs)) { 2248 lrbp = &hba->lrb[index];
2241 lrbp = &hba->lrb[index]; 2249 cmd = lrbp->cmd;
2242 cmd = lrbp->cmd; 2250 if (cmd) {
2243 /* 2251 result = ufshcd_transfer_rsp_status(hba, lrbp);
2244 * Don't skip resetting interrupt aggregation counters 2252 scsi_dma_unmap(cmd);
2245 * if a regular command is present. 2253 cmd->result = result;
2246 */ 2254 /* Mark completed command as NULL in LRB */
2247 int_aggr_reset |= !lrbp->intr_cmd; 2255 lrbp->cmd = NULL;
2248 2256 clear_bit_unlock(index, &hba->lrb_in_use);
2249 if (cmd) { 2257 /* Do not touch lrbp after scsi done */
2250 result = ufshcd_transfer_rsp_status(hba, lrbp); 2258 cmd->scsi_done(cmd);
2251 scsi_dma_unmap(cmd); 2259 } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) {
2252 cmd->result = result; 2260 if (hba->dev_cmd.complete)
2253 /* Mark completed command as NULL in LRB */ 2261 complete(hba->dev_cmd.complete);
2254 lrbp->cmd = NULL; 2262 }
2255 clear_bit_unlock(index, &hba->lrb_in_use); 2263 }
2256 /* Do not touch lrbp after scsi done */
2257 cmd->scsi_done(cmd);
2258 } else if (lrbp->command_type ==
2259 UTP_CMD_TYPE_DEV_MANAGE) {
2260 if (hba->dev_cmd.complete)
2261 complete(hba->dev_cmd.complete);
2262 }
2263 } /* end of if */
2264 } /* end of for */
2265 2264
2266 /* clear corresponding bits of completed commands */ 2265 /* clear corresponding bits of completed commands */
2267 hba->outstanding_reqs ^= completed_reqs; 2266 hba->outstanding_reqs ^= completed_reqs;
2268 2267
2269 /* we might have free'd some tags above */ 2268 /* we might have free'd some tags above */
2270 wake_up(&hba->dev_cmd.tag_wq); 2269 wake_up(&hba->dev_cmd.tag_wq);
2271
2272 /* Reset interrupt aggregation counters */
2273 if (int_aggr_reset)
2274 ufshcd_reset_intr_aggr(hba);
2275} 2270}
2276 2271
2277/** 2272/**
@@ -2876,6 +2871,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
2876 int poll_cnt; 2871 int poll_cnt;
2877 u8 resp = 0xF; 2872 u8 resp = 0xF;
2878 struct ufshcd_lrb *lrbp; 2873 struct ufshcd_lrb *lrbp;
2874 u32 reg;
2879 2875
2880 host = cmd->device->host; 2876 host = cmd->device->host;
2881 hba = shost_priv(host); 2877 hba = shost_priv(host);
@@ -2885,6 +2881,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
2885 if (!(test_bit(tag, &hba->outstanding_reqs))) 2881 if (!(test_bit(tag, &hba->outstanding_reqs)))
2886 goto out; 2882 goto out;
2887 2883
2884 reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
2885 if (!(reg & (1 << tag))) {
2886 dev_err(hba->dev,
2887 "%s: cmd was completed, but without a notifying intr, tag = %d",
2888 __func__, tag);
2889 }
2890
2888 lrbp = &hba->lrb[tag]; 2891 lrbp = &hba->lrb[tag];
2889 for (poll_cnt = 100; poll_cnt; poll_cnt--) { 2892 for (poll_cnt = 100; poll_cnt; poll_cnt--) {
2890 err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, 2893 err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
@@ -2893,8 +2896,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
2893 /* cmd pending in the device */ 2896 /* cmd pending in the device */
2894 break; 2897 break;
2895 } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) { 2898 } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
2896 u32 reg;
2897
2898 /* 2899 /*
2899 * cmd not pending in the device, check if it is 2900 * cmd not pending in the device, check if it is
2900 * in transition. 2901 * in transition.