276 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2013-2021 Intel Corporation4 */5 6#include "i915_drv.h"7#include "i915_reg.h"8#include "intel_pcode.h"9 10static int gen6_check_mailbox_status(u32 mbox)11{12 switch (mbox & GEN6_PCODE_ERROR_MASK) {13 case GEN6_PCODE_SUCCESS:14 return 0;15 case GEN6_PCODE_UNIMPLEMENTED_CMD:16 return -ENODEV;17 case GEN6_PCODE_ILLEGAL_CMD:18 return -ENXIO;19 case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:20 case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:21 return -EOVERFLOW;22 case GEN6_PCODE_TIMEOUT:23 return -ETIMEDOUT;24 default:25 MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK);26 return 0;27 }28}29 30static int gen7_check_mailbox_status(u32 mbox)31{32 switch (mbox & GEN6_PCODE_ERROR_MASK) {33 case GEN6_PCODE_SUCCESS:34 return 0;35 case GEN6_PCODE_ILLEGAL_CMD:36 return -ENXIO;37 case GEN7_PCODE_TIMEOUT:38 return -ETIMEDOUT;39 case GEN7_PCODE_ILLEGAL_DATA:40 return -EINVAL;41 case GEN11_PCODE_ILLEGAL_SUBCOMMAND:42 return -ENXIO;43 case GEN11_PCODE_LOCKED:44 return -EBUSY;45 case GEN11_PCODE_REJECTED:46 return -EACCES;47 case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:48 return -EOVERFLOW;49 default:50 MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK);51 return 0;52 }53}54 55static int __snb_pcode_rw(struct intel_uncore *uncore, u32 mbox,56 u32 *val, u32 *val1,57 int fast_timeout_us, int slow_timeout_ms,58 bool is_read)59{60 lockdep_assert_held(&uncore->i915->sb_lock);61 62 /*63 * GEN6_PCODE_* are outside of the forcewake domain, we can use64 * intel_uncore_read/write_fw variants to reduce the amount of work65 * required when reading/writing.66 */67 68 if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY)69 return -EAGAIN;70 71 intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val);72 intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0);73 intel_uncore_write_fw(uncore,74 GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);75 76 if (__intel_wait_for_register_fw(uncore,77 GEN6_PCODE_MAILBOX,78 GEN6_PCODE_READY, 0,79 fast_timeout_us,80 slow_timeout_ms,81 &mbox))82 return -ETIMEDOUT;83 84 if (is_read)85 *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA);86 if (is_read && val1)87 *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1);88 89 if (GRAPHICS_VER(uncore->i915) > 6)90 return gen7_check_mailbox_status(mbox);91 else92 return gen6_check_mailbox_status(mbox);93}94 95int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val, u32 *val1)96{97 int err;98 99 mutex_lock(&uncore->i915->sb_lock);100 err = __snb_pcode_rw(uncore, mbox, val, val1, 500, 20, true);101 mutex_unlock(&uncore->i915->sb_lock);102 103 if (err) {104 drm_dbg(&uncore->i915->drm,105 "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n",106 mbox, __builtin_return_address(0), err);107 }108 109 return err;110}111 112int snb_pcode_write_timeout(struct intel_uncore *uncore, u32 mbox, u32 val,113 int fast_timeout_us, int slow_timeout_ms)114{115 int err;116 117 mutex_lock(&uncore->i915->sb_lock);118 err = __snb_pcode_rw(uncore, mbox, &val, NULL,119 fast_timeout_us, slow_timeout_ms, false);120 mutex_unlock(&uncore->i915->sb_lock);121 122 if (err) {123 drm_dbg(&uncore->i915->drm,124 "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n",125 val, mbox, __builtin_return_address(0), err);126 }127 128 return err;129}130 131static bool skl_pcode_try_request(struct intel_uncore *uncore, u32 mbox,132 u32 request, u32 reply_mask, u32 reply,133 u32 *status)134{135 *status = __snb_pcode_rw(uncore, mbox, &request, NULL, 500, 0, true);136 137 return (*status == 0) && ((request & reply_mask) == reply);138}139 140/**141 * skl_pcode_request - send PCODE request until acknowledgment142 * @uncore: uncore143 * @mbox: PCODE mailbox ID the request is targeted for144 * @request: request ID145 * @reply_mask: mask used to check for request acknowledgment146 * @reply: value used to check for request acknowledgment147 * @timeout_base_ms: timeout for polling with preemption enabled148 *149 * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE150 * reports an error or an overall timeout of @timeout_base_ms+50 ms expires.151 * The request is acknowledged once the PCODE reply dword equals @reply after152 * applying @reply_mask. Polling is first attempted with preemption enabled153 * for @timeout_base_ms and if this times out for another 50 ms with154 * preemption disabled.155 *156 * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some157 * other error as reported by PCODE.158 */159int skl_pcode_request(struct intel_uncore *uncore, u32 mbox, u32 request,160 u32 reply_mask, u32 reply, int timeout_base_ms)161{162 u32 status;163 int ret;164 165 mutex_lock(&uncore->i915->sb_lock);166 167#define COND \168 skl_pcode_try_request(uncore, mbox, request, reply_mask, reply, &status)169 170 /*171 * Prime the PCODE by doing a request first. Normally it guarantees172 * that a subsequent request, at most @timeout_base_ms later, succeeds.173 * _wait_for() doesn't guarantee when its passed condition is evaluated174 * first, so send the first request explicitly.175 */176 if (COND) {177 ret = 0;178 goto out;179 }180 ret = _wait_for(COND, timeout_base_ms * 1000, 10, 10);181 if (!ret)182 goto out;183 184 /*185 * The above can time out if the number of requests was low (2 in the186 * worst case) _and_ PCODE was busy for some reason even after a187 * (queued) request and @timeout_base_ms delay. As a workaround retry188 * the poll with preemption disabled to maximize the number of189 * requests. Increase the timeout from @timeout_base_ms to 50ms to190 * account for interrupts that could reduce the number of these191 * requests, and for any quirks of the PCODE firmware that delays192 * the request completion.193 */194 drm_dbg_kms(&uncore->i915->drm,195 "PCODE timeout, retrying with preemption disabled\n");196 drm_WARN_ON_ONCE(&uncore->i915->drm, timeout_base_ms > 3);197 preempt_disable();198 ret = wait_for_atomic(COND, 50);199 preempt_enable();200 201out:202 mutex_unlock(&uncore->i915->sb_lock);203 return status ? status : ret;204#undef COND205}206 207static int pcode_init_wait(struct intel_uncore *uncore, int timeout_ms)208{209 if (__intel_wait_for_register_fw(uncore,210 GEN6_PCODE_MAILBOX,211 GEN6_PCODE_READY, 0,212 500, timeout_ms,213 NULL))214 return -EPROBE_DEFER;215 216 return skl_pcode_request(uncore,217 DG1_PCODE_STATUS,218 DG1_UNCORE_GET_INIT_STATUS,219 DG1_UNCORE_INIT_STATUS_COMPLETE,220 DG1_UNCORE_INIT_STATUS_COMPLETE, timeout_ms);221}222 223int intel_pcode_init(struct intel_uncore *uncore)224{225 int err;226 227 if (!IS_DGFX(uncore->i915))228 return 0;229 230 /*231 * Wait 10 seconds so that the punit to settle and complete232 * any outstanding transactions upon module load233 */234 err = pcode_init_wait(uncore, 10000);235 236 if (err) {237 drm_notice(&uncore->i915->drm,238 "Waiting for HW initialisation...\n");239 err = pcode_init_wait(uncore, 180000);240 }241 242 return err;243}244 245int snb_pcode_read_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u32 *val)246{247 intel_wakeref_t wakeref;248 u32 mbox;249 int err;250 251 mbox = REG_FIELD_PREP(GEN6_PCODE_MB_COMMAND, mbcmd)252 | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM1, p1)253 | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM2, p2);254 255 with_intel_runtime_pm(uncore->rpm, wakeref)256 err = snb_pcode_read(uncore, mbox, val, NULL);257 258 return err;259}260 261int snb_pcode_write_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u32 val)262{263 intel_wakeref_t wakeref;264 u32 mbox;265 int err;266 267 mbox = REG_FIELD_PREP(GEN6_PCODE_MB_COMMAND, mbcmd)268 | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM1, p1)269 | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM2, p2);270 271 with_intel_runtime_pm(uncore->rpm, wakeref)272 err = snb_pcode_write(uncore, mbox, val);273 274 return err;275}276