forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/i915/intel_wopcm.c
....@@ -1,7 +1,6 @@
1
+// SPDX-License-Identifier: MIT
12 /*
2
- * SPDX-License-Identifier: MIT
3
- *
4
- * Copyright © 2017-2018 Intel Corporation
3
+ * Copyright © 2017-2019 Intel Corporation
54 */
65
76 #include "intel_wopcm.h"
....@@ -41,27 +40,33 @@
4140 * context).
4241 */
4342
44
-/* Default WOPCM size 1MB. */
45
-#define GEN9_WOPCM_SIZE (1024 * 1024)
43
+/* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */
44
+#define GEN11_WOPCM_SIZE SZ_2M
45
+#define GEN9_WOPCM_SIZE SZ_1M
4646 /* 16KB WOPCM (RSVD WOPCM) is reserved from HuC firmware top. */
47
-#define WOPCM_RESERVED_SIZE (16 * 1024)
47
+#define WOPCM_RESERVED_SIZE SZ_16K
4848
4949 /* 16KB reserved at the beginning of GuC WOPCM. */
50
-#define GUC_WOPCM_RESERVED (16 * 1024)
50
+#define GUC_WOPCM_RESERVED SZ_16K
5151 /* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */
52
-#define GUC_WOPCM_STACK_RESERVED (8 * 1024)
52
+#define GUC_WOPCM_STACK_RESERVED SZ_8K
5353
5454 /* GuC WOPCM Offset value needs to be aligned to 16KB. */
5555 #define GUC_WOPCM_OFFSET_ALIGNMENT (1UL << GUC_WOPCM_OFFSET_SHIFT)
5656
5757 /* 24KB at the end of WOPCM is reserved for RC6 CTX on BXT. */
58
-#define BXT_WOPCM_RC6_CTX_RESERVED (24 * 1024)
58
+#define BXT_WOPCM_RC6_CTX_RESERVED (SZ_16K + SZ_8K)
5959 /* 36KB WOPCM reserved at the end of WOPCM on CNL. */
60
-#define CNL_WOPCM_HW_CTX_RESERVED (36 * 1024)
60
+#define CNL_WOPCM_HW_CTX_RESERVED (SZ_32K + SZ_4K)
6161
6262 /* 128KB from GUC_WOPCM_RESERVED is reserved for FW on Gen9. */
63
-#define GEN9_GUC_FW_RESERVED (128 * 1024)
63
+#define GEN9_GUC_FW_RESERVED SZ_128K
6464 #define GEN9_GUC_WOPCM_OFFSET (GUC_WOPCM_RESERVED + GEN9_GUC_FW_RESERVED)
65
+
66
+static inline struct drm_i915_private *wopcm_to_i915(struct intel_wopcm *wopcm)
67
+{
68
+ return container_of(wopcm, struct drm_i915_private, wopcm);
69
+}
6570
6671 /**
6772 * intel_wopcm_init_early() - Early initialization of the WOPCM.
....@@ -71,12 +76,20 @@
7176 */
7277 void intel_wopcm_init_early(struct intel_wopcm *wopcm)
7378 {
74
- wopcm->size = GEN9_WOPCM_SIZE;
79
+ struct drm_i915_private *i915 = wopcm_to_i915(wopcm);
7580
76
- DRM_DEBUG_DRIVER("WOPCM size: %uKiB\n", wopcm->size / 1024);
81
+ if (!HAS_GT_UC(i915))
82
+ return;
83
+
84
+ if (INTEL_GEN(i915) >= 11)
85
+ wopcm->size = GEN11_WOPCM_SIZE;
86
+ else
87
+ wopcm->size = GEN9_WOPCM_SIZE;
88
+
89
+ drm_dbg(&i915->drm, "WOPCM: %uK\n", wopcm->size / 1024);
7790 }
7891
79
-static inline u32 context_reserved_size(struct drm_i915_private *i915)
92
+static u32 context_reserved_size(struct drm_i915_private *i915)
8093 {
8194 if (IS_GEN9_LP(i915))
8295 return BXT_WOPCM_RC6_CTX_RESERVED;
....@@ -86,7 +99,8 @@
8699 return 0;
87100 }
88101
89
-static inline int gen9_check_dword_gap(u32 guc_wopcm_base, u32 guc_wopcm_size)
102
+static bool gen9_check_dword_gap(struct drm_i915_private *i915,
103
+ u32 guc_wopcm_base, u32 guc_wopcm_size)
90104 {
91105 u32 offset;
92106
....@@ -98,16 +112,18 @@
98112 offset = guc_wopcm_base + GEN9_GUC_WOPCM_OFFSET;
99113 if (offset > guc_wopcm_size ||
100114 (guc_wopcm_size - offset) < sizeof(u32)) {
101
- DRM_ERROR("GuC WOPCM size %uKiB is too small. %uKiB needed.\n",
102
- guc_wopcm_size / 1024,
103
- (u32)(offset + sizeof(u32)) / 1024);
104
- return -E2BIG;
115
+ drm_err(&i915->drm,
116
+ "WOPCM: invalid GuC region size: %uK < %uK\n",
117
+ guc_wopcm_size / SZ_1K,
118
+ (u32)(offset + sizeof(u32)) / SZ_1K);
119
+ return false;
105120 }
106121
107
- return 0;
122
+ return true;
108123 }
109124
110
-static inline int gen9_check_huc_fw_fits(u32 guc_wopcm_size, u32 huc_fw_size)
125
+static bool gen9_check_huc_fw_fits(struct drm_i915_private *i915,
126
+ u32 guc_wopcm_size, u32 huc_fw_size)
111127 {
112128 /*
113129 * On Gen9 & CNL A0, hardware requires the total available GuC WOPCM
....@@ -115,29 +131,80 @@
115131 * firmware uploading would fail.
116132 */
117133 if (huc_fw_size > guc_wopcm_size - GUC_WOPCM_RESERVED) {
118
- DRM_ERROR("HuC FW (%uKiB) won't fit in GuC WOPCM (%uKiB).\n",
119
- huc_fw_size / 1024,
120
- (guc_wopcm_size - GUC_WOPCM_RESERVED) / 1024);
121
- return -E2BIG;
134
+ drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n",
135
+ intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC),
136
+ (guc_wopcm_size - GUC_WOPCM_RESERVED) / SZ_1K,
137
+ huc_fw_size / 1024);
138
+ return false;
122139 }
123140
124
- return 0;
141
+ return true;
125142 }
126143
127
-static inline int check_hw_restriction(struct drm_i915_private *i915,
128
- u32 guc_wopcm_base, u32 guc_wopcm_size,
129
- u32 huc_fw_size)
144
+static bool check_hw_restrictions(struct drm_i915_private *i915,
145
+ u32 guc_wopcm_base, u32 guc_wopcm_size,
146
+ u32 huc_fw_size)
130147 {
131
- int err = 0;
148
+ if (IS_GEN(i915, 9) && !gen9_check_dword_gap(i915, guc_wopcm_base,
149
+ guc_wopcm_size))
150
+ return false;
132151
133
- if (IS_GEN9(i915))
134
- err = gen9_check_dword_gap(guc_wopcm_base, guc_wopcm_size);
152
+ if (IS_GEN(i915, 9) &&
153
+ !gen9_check_huc_fw_fits(i915, guc_wopcm_size, huc_fw_size))
154
+ return false;
135155
136
- if (!err &&
137
- (IS_GEN9(i915) || IS_CNL_REVID(i915, CNL_REVID_A0, CNL_REVID_A0)))
138
- err = gen9_check_huc_fw_fits(guc_wopcm_size, huc_fw_size);
156
+ return true;
157
+}
139158
140
- return err;
159
+static bool __check_layout(struct drm_i915_private *i915, u32 wopcm_size,
160
+ u32 guc_wopcm_base, u32 guc_wopcm_size,
161
+ u32 guc_fw_size, u32 huc_fw_size)
162
+{
163
+ const u32 ctx_rsvd = context_reserved_size(i915);
164
+ u32 size;
165
+
166
+ size = wopcm_size - ctx_rsvd;
167
+ if (unlikely(range_overflows(guc_wopcm_base, guc_wopcm_size, size))) {
168
+ drm_err(&i915->drm,
169
+ "WOPCM: invalid GuC region layout: %uK + %uK > %uK\n",
170
+ guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K,
171
+ size / SZ_1K);
172
+ return false;
173
+ }
174
+
175
+ size = guc_fw_size + GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED;
176
+ if (unlikely(guc_wopcm_size < size)) {
177
+ drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n",
178
+ intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_GUC),
179
+ guc_wopcm_size / SZ_1K, size / SZ_1K);
180
+ return false;
181
+ }
182
+
183
+ size = huc_fw_size + WOPCM_RESERVED_SIZE;
184
+ if (unlikely(guc_wopcm_base < size)) {
185
+ drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n",
186
+ intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC),
187
+ guc_wopcm_base / SZ_1K, size / SZ_1K);
188
+ return false;
189
+ }
190
+
191
+ return check_hw_restrictions(i915, guc_wopcm_base, guc_wopcm_size,
192
+ huc_fw_size);
193
+}
194
+
195
+static bool __wopcm_regs_locked(struct intel_uncore *uncore,
196
+ u32 *guc_wopcm_base, u32 *guc_wopcm_size)
197
+{
198
+ u32 reg_base = intel_uncore_read(uncore, DMA_GUC_WOPCM_OFFSET);
199
+ u32 reg_size = intel_uncore_read(uncore, GUC_WOPCM_SIZE);
200
+
201
+ if (!(reg_size & GUC_WOPCM_SIZE_LOCKED) ||
202
+ !(reg_base & GUC_WOPCM_OFFSET_VALID))
203
+ return false;
204
+
205
+ *guc_wopcm_base = reg_base & GUC_WOPCM_OFFSET_MASK;
206
+ *guc_wopcm_size = reg_size & GUC_WOPCM_SIZE_MASK;
207
+ return true;
141208 }
142209
143210 /**
....@@ -147,129 +214,64 @@
147214 * This function will partition WOPCM space based on GuC and HuC firmware sizes
148215 * and will allocate max remaining for use by GuC. This function will also
149216 * enforce platform dependent hardware restrictions on GuC WOPCM offset and
150
- * size. It will fail the WOPCM init if any of these checks were failed, so that
151
- * the following GuC firmware uploading would be aborted.
152
- *
153
- * Return: 0 on success, non-zero error code on failure.
217
+ * size. It will fail the WOPCM init if any of these checks fail, so that the
218
+ * following WOPCM registers setup and GuC firmware uploading would be aborted.
154219 */
155
-int intel_wopcm_init(struct intel_wopcm *wopcm)
220
+void intel_wopcm_init(struct intel_wopcm *wopcm)
156221 {
157222 struct drm_i915_private *i915 = wopcm_to_i915(wopcm);
158
- u32 guc_fw_size = intel_uc_fw_get_upload_size(&i915->guc.fw);
159
- u32 huc_fw_size = intel_uc_fw_get_upload_size(&i915->huc.fw);
223
+ struct intel_gt *gt = &i915->gt;
224
+ u32 guc_fw_size = intel_uc_fw_get_upload_size(&gt->uc.guc.fw);
225
+ u32 huc_fw_size = intel_uc_fw_get_upload_size(&gt->uc.huc.fw);
160226 u32 ctx_rsvd = context_reserved_size(i915);
161227 u32 guc_wopcm_base;
162228 u32 guc_wopcm_size;
163
- u32 guc_wopcm_rsvd;
164
- int err;
229
+
230
+ if (!guc_fw_size)
231
+ return;
165232
166233 GEM_BUG_ON(!wopcm->size);
234
+ GEM_BUG_ON(wopcm->guc.base);
235
+ GEM_BUG_ON(wopcm->guc.size);
236
+ GEM_BUG_ON(guc_fw_size >= wopcm->size);
237
+ GEM_BUG_ON(huc_fw_size >= wopcm->size);
238
+ GEM_BUG_ON(ctx_rsvd + WOPCM_RESERVED_SIZE >= wopcm->size);
167239
168
- if (guc_fw_size >= wopcm->size) {
169
- DRM_ERROR("GuC FW (%uKiB) is too big to fit in WOPCM.",
170
- guc_fw_size / 1024);
171
- return -E2BIG;
240
+ if (i915_inject_probe_failure(i915))
241
+ return;
242
+
243
+ if (__wopcm_regs_locked(gt->uncore, &guc_wopcm_base, &guc_wopcm_size)) {
244
+ drm_dbg(&i915->drm, "GuC WOPCM is already locked [%uK, %uK)\n",
245
+ guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K);
246
+ goto check;
172247 }
173248
174
- if (huc_fw_size >= wopcm->size) {
175
- DRM_ERROR("HuC FW (%uKiB) is too big to fit in WOPCM.",
176
- huc_fw_size / 1024);
177
- return -E2BIG;
178
- }
249
+ /*
250
+ * Aligned value of guc_wopcm_base will determine available WOPCM space
251
+ * for HuC firmware and mandatory reserved area.
252
+ */
253
+ guc_wopcm_base = huc_fw_size + WOPCM_RESERVED_SIZE;
254
+ guc_wopcm_base = ALIGN(guc_wopcm_base, GUC_WOPCM_OFFSET_ALIGNMENT);
179255
180
- guc_wopcm_base = ALIGN(huc_fw_size + WOPCM_RESERVED_SIZE,
181
- GUC_WOPCM_OFFSET_ALIGNMENT);
182
- if ((guc_wopcm_base + ctx_rsvd) >= wopcm->size) {
183
- DRM_ERROR("GuC WOPCM base (%uKiB) is too big.\n",
184
- guc_wopcm_base / 1024);
185
- return -E2BIG;
186
- }
256
+ /*
257
+ * Need to clamp guc_wopcm_base now to make sure the following math is
258
+ * correct. Formal check of whole WOPCM layout will be done below.
259
+ */
260
+ guc_wopcm_base = min(guc_wopcm_base, wopcm->size - ctx_rsvd);
187261
188
- guc_wopcm_size = wopcm->size - guc_wopcm_base - ctx_rsvd;
262
+ /* Aligned remainings of usable WOPCM space can be assigned to GuC. */
263
+ guc_wopcm_size = wopcm->size - ctx_rsvd - guc_wopcm_base;
189264 guc_wopcm_size &= GUC_WOPCM_SIZE_MASK;
190265
191
- DRM_DEBUG_DRIVER("Calculated GuC WOPCM Region: [%uKiB, %uKiB)\n",
192
- guc_wopcm_base / 1024, guc_wopcm_size / 1024);
266
+ drm_dbg(&i915->drm, "Calculated GuC WOPCM [%uK, %uK)\n",
267
+ guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K);
193268
194
- guc_wopcm_rsvd = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED;
195
- if ((guc_fw_size + guc_wopcm_rsvd) > guc_wopcm_size) {
196
- DRM_ERROR("Need %uKiB WOPCM for GuC, %uKiB available.\n",
197
- (guc_fw_size + guc_wopcm_rsvd) / 1024,
198
- guc_wopcm_size / 1024);
199
- return -E2BIG;
269
+check:
270
+ if (__check_layout(i915, wopcm->size, guc_wopcm_base, guc_wopcm_size,
271
+ guc_fw_size, huc_fw_size)) {
272
+ wopcm->guc.base = guc_wopcm_base;
273
+ wopcm->guc.size = guc_wopcm_size;
274
+ GEM_BUG_ON(!wopcm->guc.base);
275
+ GEM_BUG_ON(!wopcm->guc.size);
200276 }
201
-
202
- err = check_hw_restriction(i915, guc_wopcm_base, guc_wopcm_size,
203
- huc_fw_size);
204
- if (err)
205
- return err;
206
-
207
- wopcm->guc.base = guc_wopcm_base;
208
- wopcm->guc.size = guc_wopcm_size;
209
-
210
- return 0;
211
-}
212
-
213
-static inline int write_and_verify(struct drm_i915_private *dev_priv,
214
- i915_reg_t reg, u32 val, u32 mask,
215
- u32 locked_bit)
216
-{
217
- u32 reg_val;
218
-
219
- GEM_BUG_ON(val & ~mask);
220
-
221
- I915_WRITE(reg, val);
222
-
223
- reg_val = I915_READ(reg);
224
-
225
- return (reg_val & mask) != (val | locked_bit) ? -EIO : 0;
226
-}
227
-
228
-/**
229
- * intel_wopcm_init_hw() - Setup GuC WOPCM registers.
230
- * @wopcm: pointer to intel_wopcm.
231
- *
232
- * Setup the GuC WOPCM size and offset registers with the calculated values. It
233
- * will verify the register values to make sure the registers are locked with
234
- * correct values.
235
- *
236
- * Return: 0 on success. -EIO if registers were locked with incorrect values.
237
- */
238
-int intel_wopcm_init_hw(struct intel_wopcm *wopcm)
239
-{
240
- struct drm_i915_private *dev_priv = wopcm_to_i915(wopcm);
241
- u32 huc_agent;
242
- u32 mask;
243
- int err;
244
-
245
- if (!USES_GUC(dev_priv))
246
- return 0;
247
-
248
- GEM_BUG_ON(!HAS_GUC(dev_priv));
249
- GEM_BUG_ON(!wopcm->guc.size);
250
- GEM_BUG_ON(!wopcm->guc.base);
251
-
252
- err = write_and_verify(dev_priv, GUC_WOPCM_SIZE, wopcm->guc.size,
253
- GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED,
254
- GUC_WOPCM_SIZE_LOCKED);
255
- if (err)
256
- goto err_out;
257
-
258
- huc_agent = USES_HUC(dev_priv) ? HUC_LOADING_AGENT_GUC : 0;
259
- mask = GUC_WOPCM_OFFSET_MASK | GUC_WOPCM_OFFSET_VALID | huc_agent;
260
- err = write_and_verify(dev_priv, DMA_GUC_WOPCM_OFFSET,
261
- wopcm->guc.base | huc_agent, mask,
262
- GUC_WOPCM_OFFSET_VALID);
263
- if (err)
264
- goto err_out;
265
-
266
- return 0;
267
-
268
-err_out:
269
- DRM_ERROR("Failed to init WOPCM registers:\n");
270
- DRM_ERROR("DMA_GUC_WOPCM_OFFSET=%#x\n",
271
- I915_READ(DMA_GUC_WOPCM_OFFSET));
272
- DRM_ERROR("GUC_WOPCM_SIZE=%#x\n", I915_READ(GUC_WOPCM_SIZE));
273
-
274
- return err;
275277 }