brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · 3db2ba4 Raw
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