| .. | .. |
|---|
| 731 | 731 | } |
|---|
| 732 | 732 | |
|---|
| 733 | 733 | /** |
|---|
| 734 | | - * ufshcd_outstanding_req_clear - Clear a bit in outstanding request field |
|---|
| 735 | | - * @hba: per adapter instance |
|---|
| 736 | | - * @tag: position of the bit to be cleared |
|---|
| 737 | | - */ |
|---|
| 738 | | -static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag) |
|---|
| 739 | | -{ |
|---|
| 740 | | - clear_bit(tag, &hba->outstanding_reqs); |
|---|
| 741 | | -} |
|---|
| 742 | | - |
|---|
| 743 | | -/** |
|---|
| 744 | 734 | * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY |
|---|
| 745 | 735 | * @reg: Register value of host controller status |
|---|
| 746 | 736 | * |
|---|
| .. | .. |
|---|
| 2882 | 2872 | static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, |
|---|
| 2883 | 2873 | struct ufshcd_lrb *lrbp, int max_timeout) |
|---|
| 2884 | 2874 | { |
|---|
| 2885 | | - int err = 0; |
|---|
| 2886 | | - unsigned long time_left; |
|---|
| 2875 | + unsigned long time_left = msecs_to_jiffies(max_timeout); |
|---|
| 2887 | 2876 | unsigned long flags; |
|---|
| 2877 | + bool pending; |
|---|
| 2878 | + int err; |
|---|
| 2888 | 2879 | |
|---|
| 2880 | +retry: |
|---|
| 2889 | 2881 | time_left = wait_for_completion_timeout(hba->dev_cmd.complete, |
|---|
| 2890 | | - msecs_to_jiffies(max_timeout)); |
|---|
| 2882 | + time_left); |
|---|
| 2891 | 2883 | |
|---|
| 2892 | 2884 | /* Make sure descriptors are ready before ringing the doorbell */ |
|---|
| 2893 | 2885 | wmb(); |
|---|
| 2894 | | - spin_lock_irqsave(hba->host->host_lock, flags); |
|---|
| 2895 | | - hba->dev_cmd.complete = NULL; |
|---|
| 2896 | 2886 | if (likely(time_left)) { |
|---|
| 2887 | + /* |
|---|
| 2888 | + * The completion handler called complete() and the caller of |
|---|
| 2889 | + * this function still owns the @lrbp tag so the code below does |
|---|
| 2890 | + * not trigger any race conditions. |
|---|
| 2891 | + */ |
|---|
| 2892 | + hba->dev_cmd.complete = NULL; |
|---|
| 2897 | 2893 | err = ufshcd_get_tr_ocs(lrbp); |
|---|
| 2898 | 2894 | if (!err) |
|---|
| 2899 | 2895 | err = ufshcd_dev_cmd_completion(hba, lrbp); |
|---|
| 2900 | | - } |
|---|
| 2901 | | - spin_unlock_irqrestore(hba->host->host_lock, flags); |
|---|
| 2902 | | - |
|---|
| 2903 | | - if (!time_left) { |
|---|
| 2896 | + } else { |
|---|
| 2904 | 2897 | err = -ETIMEDOUT; |
|---|
| 2905 | 2898 | dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n", |
|---|
| 2906 | 2899 | __func__, lrbp->task_tag); |
|---|
| 2907 | | - if (!ufshcd_clear_cmd(hba, lrbp->task_tag)) |
|---|
| 2900 | + if (ufshcd_clear_cmd(hba, lrbp->task_tag) == 0) { |
|---|
| 2908 | 2901 | /* successfully cleared the command, retry if needed */ |
|---|
| 2909 | 2902 | err = -EAGAIN; |
|---|
| 2910 | | - /* |
|---|
| 2911 | | - * in case of an error, after clearing the doorbell, |
|---|
| 2912 | | - * we also need to clear the outstanding_request |
|---|
| 2913 | | - * field in hba |
|---|
| 2914 | | - */ |
|---|
| 2915 | | - ufshcd_outstanding_req_clear(hba, lrbp->task_tag); |
|---|
| 2903 | + /* |
|---|
| 2904 | + * Since clearing the command succeeded we also need to |
|---|
| 2905 | + * clear the task tag bit from the outstanding_reqs |
|---|
| 2906 | + * variable. |
|---|
| 2907 | + */ |
|---|
| 2908 | + spin_lock_irqsave(hba->host->host_lock, flags); |
|---|
| 2909 | + pending = test_bit(lrbp->task_tag, |
|---|
| 2910 | + &hba->outstanding_reqs); |
|---|
| 2911 | + if (pending) { |
|---|
| 2912 | + hba->dev_cmd.complete = NULL; |
|---|
| 2913 | + __clear_bit(lrbp->task_tag, |
|---|
| 2914 | + &hba->outstanding_reqs); |
|---|
| 2915 | + } |
|---|
| 2916 | + spin_unlock_irqrestore(hba->host->host_lock, flags); |
|---|
| 2917 | + |
|---|
| 2918 | + if (!pending) { |
|---|
| 2919 | + /* |
|---|
| 2920 | + * The completion handler ran while we tried to |
|---|
| 2921 | + * clear the command. |
|---|
| 2922 | + */ |
|---|
| 2923 | + time_left = 1; |
|---|
| 2924 | + goto retry; |
|---|
| 2925 | + } |
|---|
| 2926 | + } else { |
|---|
| 2927 | + dev_err(hba->dev, "%s: failed to clear tag %d\n", |
|---|
| 2928 | + __func__, lrbp->task_tag); |
|---|
| 2929 | + spin_lock_irqsave(hba->host->host_lock, flags); |
|---|
| 2930 | + pending = test_bit(lrbp->task_tag, |
|---|
| 2931 | + &hba->outstanding_reqs); |
|---|
| 2932 | + if (pending) |
|---|
| 2933 | + hba->dev_cmd.complete = NULL; |
|---|
| 2934 | + spin_unlock_irqrestore(hba->host->host_lock, flags); |
|---|
| 2935 | + |
|---|
| 2936 | + if (!pending) { |
|---|
| 2937 | + /* |
|---|
| 2938 | + * The completion handler ran while we tried to |
|---|
| 2939 | + * clear the command. |
|---|
| 2940 | + */ |
|---|
| 2941 | + time_left = 1; |
|---|
| 2942 | + goto retry; |
|---|
| 2943 | + } |
|---|
| 2944 | + } |
|---|
| 2916 | 2945 | } |
|---|
| 2917 | 2946 | |
|---|
| 2918 | 2947 | return err; |
|---|
| .. | .. |
|---|
| 9485 | 9514 | MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); |
|---|
| 9486 | 9515 | MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); |
|---|
| 9487 | 9516 | MODULE_DESCRIPTION("Generic UFS host controller driver Core"); |
|---|
| 9517 | +MODULE_SOFTDEP("pre: governor_simpleondemand"); |
|---|
| 9488 | 9518 | MODULE_LICENSE("GPL"); |
|---|
| 9489 | 9519 | MODULE_VERSION(UFSHCD_DRIVER_VERSION); |
|---|