File: | dev/pci/drm/i915/intel_pcode.c |
Warning: | line 247, column 2 Undefined or garbage value returned to caller |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // SPDX-License-Identifier: MIT | |||
2 | /* | |||
3 | * Copyright © 2013-2021 Intel Corporation | |||
4 | */ | |||
5 | ||||
6 | #include "i915_drv.h" | |||
7 | #include "i915_reg.h" | |||
8 | #include "intel_pcode.h" | |||
9 | ||||
10 | static int gen6_check_mailbox_status(u32 mbox) | |||
11 | { | |||
12 | switch (mbox & GEN6_PCODE_ERROR_MASK0xFF) { | |||
13 | case GEN6_PCODE_SUCCESS0x0: | |||
14 | return 0; | |||
15 | case GEN6_PCODE_UNIMPLEMENTED_CMD0xFF: | |||
16 | return -ENODEV19; | |||
17 | case GEN6_PCODE_ILLEGAL_CMD0x1: | |||
18 | return -ENXIO6; | |||
19 | case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE0x2: | |||
20 | case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE0x10: | |||
21 | return -EOVERFLOW87; | |||
22 | case GEN6_PCODE_TIMEOUT0x3: | |||
23 | return -ETIMEDOUT60; | |||
24 | default: | |||
25 | MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "mbox & 0xFF", (long)(mbox & 0xFF)); __builtin_expect (!!(__ret), 0); }); | |||
26 | return 0; | |||
27 | } | |||
28 | } | |||
29 | ||||
30 | static int gen7_check_mailbox_status(u32 mbox) | |||
31 | { | |||
32 | switch (mbox & GEN6_PCODE_ERROR_MASK0xFF) { | |||
33 | case GEN6_PCODE_SUCCESS0x0: | |||
34 | return 0; | |||
35 | case GEN6_PCODE_ILLEGAL_CMD0x1: | |||
36 | return -ENXIO6; | |||
37 | case GEN7_PCODE_TIMEOUT0x2: | |||
38 | return -ETIMEDOUT60; | |||
39 | case GEN7_PCODE_ILLEGAL_DATA0x3: | |||
40 | return -EINVAL22; | |||
41 | case GEN11_PCODE_ILLEGAL_SUBCOMMAND0x4: | |||
42 | return -ENXIO6; | |||
43 | case GEN11_PCODE_LOCKED0x6: | |||
44 | return -EBUSY16; | |||
45 | case GEN11_PCODE_REJECTED0x11: | |||
46 | return -EACCES13; | |||
47 | case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE0x10: | |||
48 | return -EOVERFLOW87; | |||
49 | default: | |||
50 | MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "mbox & 0xFF", (long)(mbox & 0xFF)); __builtin_expect (!!(__ret), 0); }); | |||
51 | return 0; | |||
52 | } | |||
53 | } | |||
54 | ||||
55 | static 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_Bool is_read) | |||
59 | { | |||
60 | lockdep_assert_held(&uncore->i915->sb_lock)do { (void)(&uncore->i915->sb_lock); } while(0); | |||
61 | ||||
62 | /* | |||
63 | * GEN6_PCODE_* are outside of the forcewake domain, we can use | |||
64 | * intel_uncore_read/write_fw variants to reduce the amount of work | |||
65 | * required when reading/writing. | |||
66 | */ | |||
67 | ||||
68 | if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX)__raw_uncore_read32(uncore, ((const i915_reg_t){ .reg = (0x138124 ) })) & GEN6_PCODE_READY(1 << 31)) | |||
69 | return -EAGAIN35; | |||
70 | ||||
71 | intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val)__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0x138128 ) }), *val); | |||
72 | intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0)__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0x13812C ) }), val1 ? *val1 : 0); | |||
73 | intel_uncore_write_fw(uncore,__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0x138124 ) }), (1 << 31) | mbox) | |||
74 | GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox)__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0x138124 ) }), (1 << 31) | mbox); | |||
75 | ||||
76 | if (__intel_wait_for_register_fw(uncore, | |||
77 | GEN6_PCODE_MAILBOX((const i915_reg_t){ .reg = (0x138124) }), | |||
78 | GEN6_PCODE_READY(1 << 31), 0, | |||
79 | fast_timeout_us, | |||
80 | slow_timeout_ms, | |||
81 | &mbox)) | |||
82 | return -ETIMEDOUT60; | |||
83 | ||||
84 | if (is_read) | |||
85 | *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA)__raw_uncore_read32(uncore, ((const i915_reg_t){ .reg = (0x138128 ) })); | |||
86 | if (is_read && val1) | |||
87 | *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1)__raw_uncore_read32(uncore, ((const i915_reg_t){ .reg = (0x13812C ) })); | |||
88 | ||||
89 | if (GRAPHICS_VER(uncore->i915)((&(uncore->i915)->__runtime)->graphics.ip.ver) > 6) | |||
90 | return gen7_check_mailbox_status(mbox); | |||
91 | else | |||
92 | return gen6_check_mailbox_status(mbox); | |||
93 | } | |||
94 | ||||
95 | int 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)rw_enter_write(&uncore->i915->sb_lock); | |||
100 | err = __snb_pcode_rw(uncore, mbox, val, val1, 500, 20, true1); | |||
101 | mutex_unlock(&uncore->i915->sb_lock)rw_exit_write(&uncore->i915->sb_lock); | |||
102 | ||||
103 | if (err) { | |||
104 | drm_dbg(&uncore->i915->drm,__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_DRIVER , "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n" , mbox, __builtin_return_address(0), err) | |||
105 | "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n",__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_DRIVER , "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n" , mbox, __builtin_return_address(0), err) | |||
106 | mbox, __builtin_return_address(0), err)__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_DRIVER , "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n" , mbox, __builtin_return_address(0), err); | |||
107 | } | |||
108 | ||||
109 | return err; | |||
110 | } | |||
111 | ||||
112 | int 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)rw_enter_write(&uncore->i915->sb_lock); | |||
118 | err = __snb_pcode_rw(uncore, mbox, &val, NULL((void *)0), | |||
119 | fast_timeout_us, slow_timeout_ms, false0); | |||
120 | mutex_unlock(&uncore->i915->sb_lock)rw_exit_write(&uncore->i915->sb_lock); | |||
121 | ||||
122 | if (err) { | |||
123 | drm_dbg(&uncore->i915->drm,__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_DRIVER , "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n" , val, mbox, __builtin_return_address(0), err) | |||
124 | "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n",__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_DRIVER , "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n" , val, mbox, __builtin_return_address(0), err) | |||
125 | val, mbox, __builtin_return_address(0), err)__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_DRIVER , "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n" , val, mbox, __builtin_return_address(0), err); | |||
126 | } | |||
127 | ||||
128 | return err; | |||
129 | } | |||
130 | ||||
131 | static bool_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((void *)0), 500, 0, true1); | |||
136 | ||||
137 | return (*status == 0) && ((request & reply_mask) == reply); | |||
138 | } | |||
139 | ||||
140 | /** | |||
141 | * skl_pcode_request - send PCODE request until acknowledgment | |||
142 | * @uncore: uncore | |||
143 | * @mbox: PCODE mailbox ID the request is targeted for | |||
144 | * @request: request ID | |||
145 | * @reply_mask: mask used to check for request acknowledgment | |||
146 | * @reply: value used to check for request acknowledgment | |||
147 | * @timeout_base_ms: timeout for polling with preemption enabled | |||
148 | * | |||
149 | * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE | |||
150 | * 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 after | |||
152 | * applying @reply_mask. Polling is first attempted with preemption enabled | |||
153 | * for @timeout_base_ms and if this times out for another 50 ms with | |||
154 | * preemption disabled. | |||
155 | * | |||
156 | * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some | |||
157 | * other error as reported by PCODE. | |||
158 | */ | |||
159 | int 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)rw_enter_write(&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 guarantees | |||
172 | * that a subsequent request, at most @timeout_base_ms later, succeeds. | |||
173 | * _wait_for() doesn't guarantee when its passed condition is evaluated | |||
174 | * 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)({ const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll * ((timeout_base_ms * 1000))); long wait__ = ((10)); int ret__ ; assertwaitok(); for (;;) { const _Bool expired__ = ktime_after (ktime_get_raw(), end__); ; __asm volatile("" : : : "memory") ; if ((COND)) { ret__ = 0; break; } if (expired__) { ret__ = - 60; break; } usleep_range(wait__, wait__ * 2); if (wait__ < ((10))) wait__ <<= 1; } ret__; }); | |||
181 | if (!ret) | |||
182 | goto out; | |||
183 | ||||
184 | /* | |||
185 | * The above can time out if the number of requests was low (2 in the | |||
186 | * worst case) _and_ PCODE was busy for some reason even after a | |||
187 | * (queued) request and @timeout_base_ms delay. As a workaround retry | |||
188 | * the poll with preemption disabled to maximize the number of | |||
189 | * requests. Increase the timeout from @timeout_base_ms to 50ms to | |||
190 | * account for interrupts that could reduce the number of these | |||
191 | * requests, and for any quirks of the PCODE firmware that delays | |||
192 | * the request completion. | |||
193 | */ | |||
194 | drm_dbg_kms(&uncore->i915->drm,__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_KMS , "PCODE timeout, retrying with preemption disabled\n") | |||
195 | "PCODE timeout, retrying with preemption disabled\n")__drm_dev_dbg(((void *)0), (&uncore->i915->drm) ? ( &uncore->i915->drm)->dev : ((void *)0), DRM_UT_KMS , "PCODE timeout, retrying with preemption disabled\n"); | |||
196 | drm_WARN_ON_ONCE(&uncore->i915->drm, timeout_base_ms > 3)({ static int __warned; int __ret = !!((timeout_base_ms > 3 )); if (__ret && !__warned) { printf("%s %s: " "%s", dev_driver_string (((&uncore->i915->drm))->dev), "", "drm_WARN_ON_ONCE(" "timeout_base_ms > 3" ")"); __warned = 1; } __builtin_expect (!!(__ret), 0); }); | |||
197 | preempt_disable(); | |||
198 | ret = wait_for_atomic(COND, 50)({ extern char _ctassert[(!(!__builtin_constant_p((50) * 1000 ))) ? 1 : -1 ] __attribute__((__unused__)); extern char _ctassert [(!(((50) * 1000) > 50000)) ? 1 : -1 ] __attribute__((__unused__ )); ({ int cpu, ret, timeout = (((50) * 1000)) * 1000; u64 base ; do { } while (0); if (!(1)) { preempt_disable(); cpu = (({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci ) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci; })->ci_cpuid); } base = local_clock(); for (;;) { u64 now = local_clock(); if (!(1)) preempt_enable(); __asm volatile("" : : : "memory"); if (((COND))) { ret = 0; break; } if (now - base >= timeout) { ret = -60; break; } cpu_relax(); if (! (1)) { preempt_disable(); if (__builtin_expect(!!(cpu != (({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci ) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci; })->ci_cpuid)), 0)) { timeout -= now - base; cpu = (({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci ) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci; })->ci_cpuid); base = local_clock(); } } } ret; }); }); | |||
199 | preempt_enable(); | |||
200 | ||||
201 | out: | |||
202 | mutex_unlock(&uncore->i915->sb_lock)rw_exit_write(&uncore->i915->sb_lock); | |||
203 | return status ? status : ret; | |||
204 | #undef COND | |||
205 | } | |||
206 | ||||
207 | int intel_pcode_init(struct intel_uncore *uncore) | |||
208 | { | |||
209 | if (!IS_DGFX(uncore->i915)((&(uncore->i915)->__info)->is_dgfx)) | |||
210 | return 0; | |||
211 | ||||
212 | return skl_pcode_request(uncore, DG1_PCODE_STATUS0x7E, | |||
213 | DG1_UNCORE_GET_INIT_STATUS0x0, | |||
214 | DG1_UNCORE_INIT_STATUS_COMPLETE0x1, | |||
215 | DG1_UNCORE_INIT_STATUS_COMPLETE0x1, 180000); | |||
216 | } | |||
217 | ||||
218 | int snb_pcode_read_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u32 *val) | |||
219 | { | |||
220 | intel_wakeref_t wakeref; | |||
221 | u32 mbox; | |||
222 | int err; | |||
223 | ||||
224 | mbox = REG_FIELD_PREP(GEN6_PCODE_MB_COMMAND, mbcmd)((u32)((((typeof(((u32)((((~0UL) >> (64 - (7) - 1)) & ((~0UL) << (0))) + 0))))(mbcmd) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (7) - 1)) & ((~0UL) << (0))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (7) - 1)) & ((~0UL) << (0))) + 0)))) + 0 + 0 + 0 + 0)) | |||
225 | | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM1, p1)((u32)((((typeof(((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))))(p1) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (15 ) - 1)) & ((~0UL) << (8))) + 0)))) + 0 + 0 + 0 + 0) ) | |||
226 | | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM2, p2)((u32)((((typeof(((u32)((((~0UL) >> (64 - (23) - 1)) & ((~0UL) << (16))) + 0))))(p2) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (23) - 1)) & ((~0UL) << (16))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (23 ) - 1)) & ((~0UL) << (16))) + 0)))) + 0 + 0 + 0 + 0 )); | |||
227 | ||||
228 | with_intel_runtime_pm(uncore->rpm, wakeref)for ((wakeref) = intel_runtime_pm_get(uncore->rpm); (wakeref ); intel_runtime_pm_put((uncore->rpm), (wakeref)), (wakeref ) = 0) | |||
229 | err = snb_pcode_read(uncore, mbox, val, NULL((void *)0)); | |||
230 | ||||
231 | return err; | |||
232 | } | |||
233 | ||||
234 | int snb_pcode_write_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u32 val) | |||
235 | { | |||
236 | intel_wakeref_t wakeref; | |||
237 | u32 mbox; | |||
238 | int err; | |||
| ||||
239 | ||||
240 | mbox = REG_FIELD_PREP(GEN6_PCODE_MB_COMMAND, mbcmd)((u32)((((typeof(((u32)((((~0UL) >> (64 - (7) - 1)) & ((~0UL) << (0))) + 0))))(mbcmd) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (7) - 1)) & ((~0UL) << (0))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (7) - 1)) & ((~0UL) << (0))) + 0)))) + 0 + 0 + 0 + 0)) | |||
241 | | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM1, p1)((u32)((((typeof(((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))))(p1) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (15) - 1)) & ((~0UL) << (8))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (15 ) - 1)) & ((~0UL) << (8))) + 0)))) + 0 + 0 + 0 + 0) ) | |||
242 | | REG_FIELD_PREP(GEN6_PCODE_MB_PARAM2, p2)((u32)((((typeof(((u32)((((~0UL) >> (64 - (23) - 1)) & ((~0UL) << (16))) + 0))))(p2) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (23) - 1)) & ((~0UL) << (16))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (23 ) - 1)) & ((~0UL) << (16))) + 0)))) + 0 + 0 + 0 + 0 )); | |||
243 | ||||
244 | with_intel_runtime_pm(uncore->rpm, wakeref)for ((wakeref) = intel_runtime_pm_get(uncore->rpm); (wakeref ); intel_runtime_pm_put((uncore->rpm), (wakeref)), (wakeref ) = 0) | |||
245 | err = snb_pcode_write(uncore, mbox, val)snb_pcode_write_timeout(uncore, mbox, val, 500, 0); | |||
246 | ||||
247 | return err; | |||
| ||||
248 | } |