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