projects/linux·blob master · refs

384 lines · 10.6 KiB

1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2022 Intel Corporation
4 */
5
6#include "xe_pcode.h"
7
8#include <linux/delay.h>
9#include <linux/errno.h>
10#include <linux/error-injection.h>
11
12#include <drm/drm_managed.h>
13
14#include "regs/xe_pmt.h"
15#include "xe_assert.h"
16#include "xe_device.h"
17#include "xe_mmio.h"
18#include "xe_pcode_api.h"
19#include "xe_pm.h"
20#include "xe_printk.h"
21#include "xe_vsec.h"
22
23/**
24 * DOC: PCODE
25 *
26 * Xe PCODE is the component responsible for interfacing with the PCODE
27 * firmware.
28 * It shall provide a very simple ABI to other Xe components, but be the
29 * single and consolidated place that will communicate with PCODE. All read
30 * and write operations to PCODE will be internal and private to this component.
31 *
32 * What's next:
33 * - PCODE hw metrics
34 * - PCODE for display operations
35 */
36
37static int pcode_mailbox_status(struct xe_tile *tile)
38{
39 const char *err_str;
40 int err_decode;
41 u32 err;
42
43#define CASE_ERR(_err, _err_decode, _err_str) \
44 case _err: \
45 err_decode = _err_decode; \
46 err_str = _err_str; \
47 break
48
49 err = xe_mmio_read32(&tile->mmio, PCODE_MAILBOX) & PCODE_ERROR_MASK;
50 switch (err) {
51 CASE_ERR(PCODE_ILLEGAL_CMD, -ENXIO, "Illegal Command");
52 CASE_ERR(PCODE_TIMEOUT, -ETIMEDOUT, "Timed out");
53 CASE_ERR(PCODE_ILLEGAL_DATA, -EINVAL, "Illegal Data");
54 CASE_ERR(PCODE_ILLEGAL_SUBCOMMAND, -ENXIO, "Illegal Subcommand");
55 CASE_ERR(PCODE_LOCKED, -EBUSY, "PCODE Locked");
56 CASE_ERR(PCODE_GT_RATIO_OUT_OF_RANGE, -EOVERFLOW, "GT ratio out of range");
57 CASE_ERR(PCODE_REJECTED, -EACCES, "PCODE Rejected");
58 default:
59 err_decode = -EPROTO;
60 err_str = "Unknown";
61 }
62
63 if (err) {
64 drm_err(&tile_to_xe(tile)->drm, "PCODE Mailbox failed: %d %s",
65 err_decode, err_str);
66
67 return err_decode;
68 }
69
70 return 0;
71#undef CASE_ERR
72}
73
74static int __pcode_mailbox_rw(struct xe_tile *tile, u32 mbox, u32 *data0, u32 *data1,
75 unsigned int timeout_ms, bool return_data,
76 bool atomic)
77{
78 struct xe_mmio *mmio = &tile->mmio;
79 int err;
80
81 if (tile_to_xe(tile)->info.skip_pcode)
82 return 0;
83
84 if ((xe_mmio_read32(mmio, PCODE_MAILBOX) & PCODE_READY) != 0)
85 return -EAGAIN;
86
87 xe_mmio_write32(mmio, PCODE_DATA0, *data0);
88 xe_mmio_write32(mmio, PCODE_DATA1, data1 ? *data1 : 0);
89 xe_mmio_write32(mmio, PCODE_MAILBOX, PCODE_READY | mbox);
90
91 err = xe_mmio_wait32(mmio, PCODE_MAILBOX, PCODE_READY, 0,
92 timeout_ms * USEC_PER_MSEC, NULL, atomic);
93 if (err)
94 return err;
95
96 if (return_data) {
97 *data0 = xe_mmio_read32(mmio, PCODE_DATA0);
98 if (data1)
99 *data1 = xe_mmio_read32(mmio, PCODE_DATA1);
100 }
101
102 return pcode_mailbox_status(tile);
103}
104
105static int pcode_mailbox_rw(struct xe_tile *tile, u32 mbox, u32 *data0, u32 *data1,
106 unsigned int timeout_ms, bool return_data,
107 bool atomic)
108{
109 if (tile_to_xe(tile)->info.skip_pcode)
110 return 0;
111
112 lockdep_assert_held(&tile->pcode.lock);
113
114 return __pcode_mailbox_rw(tile, mbox, data0, data1, timeout_ms, return_data, atomic);
115}
116
117int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 data, int timeout)
118{
119 int err;
120
121 mutex_lock(&tile->pcode.lock);
122 err = pcode_mailbox_rw(tile, mbox, &data, NULL, timeout, false, false);
123 mutex_unlock(&tile->pcode.lock);
124
125 return err;
126}
127
128int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0, u32 data1, int timeout)
129{
130 int err;
131
132 mutex_lock(&tile->pcode.lock);
133 err = pcode_mailbox_rw(tile, mbox, &data0, &data1, timeout, false, false);
134 mutex_unlock(&tile->pcode.lock);
135
136 return err;
137}
138
139int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val, u32 *val1)
140{
141 int err;
142
143 mutex_lock(&tile->pcode.lock);
144 err = pcode_mailbox_rw(tile, mbox, val, val1, 1, true, false);
145 mutex_unlock(&tile->pcode.lock);
146
147 return err;
148}
149
150static int pcode_try_request(struct xe_tile *tile, u32 mbox,
151 u32 request, u32 reply_mask, u32 reply,
152 u32 *status, bool atomic, int timeout_us, bool locked)
153{
154 int slept, wait = 10;
155
156 xe_tile_assert(tile, timeout_us > 0);
157
158 for (slept = 0; slept < timeout_us; slept += wait) {
159 if (locked)
160 *status = pcode_mailbox_rw(tile, mbox, &request, NULL, 1, true,
161 atomic);
162 else
163 *status = __pcode_mailbox_rw(tile, mbox, &request, NULL, 1, true,
164 atomic);
165 if ((*status == 0) && ((request & reply_mask) == reply))
166 return 0;
167
168 if (atomic)
169 udelay(wait);
170 else
171 usleep_range(wait, wait << 1);
172 wait <<= 1;
173 }
174
175 return -ETIMEDOUT;
176}
177
178/**
179 * xe_pcode_request - send PCODE request until acknowledgment
180 * @tile: tile
181 * @mbox: PCODE mailbox ID the request is targeted for
182 * @request: request ID
183 * @reply_mask: mask used to check for request acknowledgment
184 * @reply: value used to check for request acknowledgment
185 * @timeout_base_ms: timeout for polling with preemption enabled
186 *
187 * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE
188 * reports an error or an overall timeout of @timeout_base_ms+50 ms expires.
189 * The request is acknowledged once the PCODE reply dword equals @reply after
190 * applying @reply_mask. Polling is first attempted with preemption enabled
191 * for @timeout_base_ms and if this times out for another 50 ms with
192 * preemption disabled.
193 *
194 * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some
195 * other error as reported by PCODE.
196 */
197int xe_pcode_request(struct xe_tile *tile, u32 mbox, u32 request,
198 u32 reply_mask, u32 reply, int timeout_base_ms)
199{
200 u32 status;
201 int ret;
202
203 xe_tile_assert(tile, timeout_base_ms <= 3);
204
205 mutex_lock(&tile->pcode.lock);
206
207 ret = pcode_try_request(tile, mbox, request, reply_mask, reply, &status,
208 false, timeout_base_ms * 1000, true);
209 if (!ret)
210 goto out;
211
212 /*
213 * The above can time out if the number of requests was low (2 in the
214 * worst case) _and_ PCODE was busy for some reason even after a
215 * (queued) request and @timeout_base_ms delay. As a workaround retry
216 * the poll with preemption disabled to maximize the number of
217 * requests. Increase the timeout from @timeout_base_ms to 50ms to
218 * account for interrupts that could reduce the number of these
219 * requests, and for any quirks of the PCODE firmware that delays
220 * the request completion.
221 */
222 drm_err(&tile_to_xe(tile)->drm,
223 "PCODE timeout, retrying with preemption disabled\n");
224 preempt_disable();
225 ret = pcode_try_request(tile, mbox, request, reply_mask, reply, &status,
226 true, 50 * 1000, true);
227 preempt_enable();
228
229out:
230 mutex_unlock(&tile->pcode.lock);
231 return status ? status : ret;
232}
233/**
234 * xe_pcode_init_min_freq_table - Initialize PCODE's QOS frequency table
235 * @tile: tile instance
236 * @min_gt_freq: Minimal (RPn) GT frequency in units of 50MHz.
237 * @max_gt_freq: Maximal (RP0) GT frequency in units of 50MHz.
238 *
239 * This function initialize PCODE's QOS frequency table for a proper minimal
240 * frequency/power steering decision, depending on the current requested GT
241 * frequency. For older platforms this was a more complete table including
242 * the IA freq. However for the latest platforms this table become a simple
243 * 1-1 Ring vs GT frequency. Even though, without setting it, PCODE might
244 * not take the right decisions for some memory frequencies and affect latency.
245 *
246 * It returns 0 on success, and -ERROR number on failure, -EINVAL if max
247 * frequency is higher then the minimal, and other errors directly translated
248 * from the PCODE Error returns:
249 * - -ENXIO: "Illegal Command"
250 * - -ETIMEDOUT: "Timed out"
251 * - -EINVAL: "Illegal Data"
252 * - -ENXIO, "Illegal Subcommand"
253 * - -EBUSY: "PCODE Locked"
254 * - -EOVERFLOW, "GT ratio out of range"
255 * - -EACCES, "PCODE Rejected"
256 * - -EPROTO, "Unknown"
257 */
258int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq,
259 u32 max_gt_freq)
260{
261 int ret;
262 u32 freq;
263
264 if (!tile_to_xe(tile)->info.has_llc)
265 return 0;
266
267 if (max_gt_freq <= min_gt_freq)
268 return -EINVAL;
269
270 mutex_lock(&tile->pcode.lock);
271 for (freq = min_gt_freq; freq <= max_gt_freq; freq++) {
272 u32 data = freq << PCODE_FREQ_RING_RATIO_SHIFT | freq;
273
274 ret = pcode_mailbox_rw(tile, PCODE_WRITE_MIN_FREQ_TABLE,
275 &data, NULL, 1, false, false);
276 if (ret)
277 goto unlock;
278 }
279
280unlock:
281 mutex_unlock(&tile->pcode.lock);
282 return ret;
283}
284
285/**
286 * xe_pcode_ready - Ensure PCODE is initialized
287 * @xe: xe instance
288 * @locked: true if lock held, false otherwise
289 *
290 * PCODE init mailbox is polled only on root gt of root tile
291 * as the root tile provides the initialization is complete only
292 * after all the tiles have completed the initialization.
293 * Called only on early probe without locks and with locks in
294 * resume path.
295 *
296 * Returns 0 on success, and -error number on failure.
297 */
298int xe_pcode_ready(struct xe_device *xe, bool locked)
299{
300 u32 status, request = DGFX_GET_INIT_STATUS;
301 struct xe_tile *tile = xe_device_get_root_tile(xe);
302 int timeout_us = 180000000; /* 3 min */
303 int ret;
304
305 if (xe->info.skip_pcode)
306 return 0;
307
308 if (!IS_DGFX(xe))
309 return 0;
310
311 if (locked)
312 mutex_lock(&tile->pcode.lock);
313
314 ret = pcode_try_request(tile, DGFX_PCODE_STATUS, request,
315 DGFX_INIT_STATUS_COMPLETE,
316 DGFX_INIT_STATUS_COMPLETE,
317 &status, false, timeout_us, locked);
318
319 if (locked)
320 mutex_unlock(&tile->pcode.lock);
321
322 if (ret)
323 drm_err(&xe->drm,
324 "PCODE initialization timedout after: 3 min\n");
325
326 return ret;
327}
328
329/**
330 * xe_pcode_init_early() - Initialize components of PCODE
331 * @tile: tile instance
332 *
333 * This function initializes the xe_pcode component.
334 * To be called once only during probe.
335 *
336 * Return: 0 on success or a negative error code on failure.
337 */
338int xe_pcode_init_early(struct xe_tile *tile)
339{
340 return drmm_mutex_init(&tile_to_xe(tile)->drm, &tile->pcode.lock);
341}
342
343/**
344 * xe_pcode_probe_early: initializes PCODE
345 * @xe: xe instance
346 *
347 * This function checks the initialization status of PCODE
348 * To be called once only during early probe without locks.
349 *
350 * Returns 0 on success, error code otherwise
351 */
352int xe_pcode_probe_early(struct xe_device *xe)
353{
354 return xe_pcode_ready(xe, false);
355}
356ALLOW_ERROR_INJECTION(xe_pcode_probe_early, ERRNO); /* See xe_pci_probe */
357
358/**
359 * xe_get_pcode_version - Read pcode version via PMT telemetry
360 * @xe: xe instance
361 * @version: pointer to struct xe_pcode_version to store version info
362 *
363 * Reads the pcode version from PMT telemetry and fills the
364 * provided @version structure.
365 *
366 * Return: 0 on success, negative error code on failure.
367 */
368int xe_get_pcode_version(struct xe_device *xe, struct xe_pcode_version *version)
369{
370 int ret = 0;
371
372 guard(xe_pm_runtime)(xe);
373
374 ret = xe_pmt_telem_read(xe->drm.dev,
375 xe_mmio_read32(xe_root_tile_mmio(xe), PUNIT_TELEMETRY_GUID),
376 (u64 *)version, PUNIT_VERSION_OFFSET, sizeof(*version));
377 if (ret != sizeof(*version)) {
378 xe_warn(xe, "pcode version read from PMT failed, ret %pe\n", ERR_PTR(ret));
379 return ret;
380 }
381 xe_dbg(xe, "pcode version major %u minor %u engg %u\n", version->major,
382 version->minor, version->engg);
383 return 0;
384}