diff options
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.c')
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 67 |
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. |