16
#include "tegra241-cmdqv.h"
17
#include "trace.h"
18
19
+static void tegra241_cmdqv_reset_vcmdq_cache(Tegra241CMDQV *cmdqv, int index)
20
+{
21
+ cmdqv->vcmdq_cons_indx[index] = 0;
22
+ cmdqv->vcmdq_prod_indx[index] = 0;
23
+ cmdqv->vcmdq_config[index] = 0;
24
+ cmdqv->vcmdq_status[index] = 0;
25
+ cmdqv->vcmdq_gerror[index] = 0;
26
+ cmdqv->vcmdq_gerrorn[index] = 0;
27
+}
28
+
29
static void tegra241_cmdqv_free_vcmdq(Tegra241CMDQV *cmdqv, int index)
30
{
31
IOMMUFDViommu *viommu = cmdqv->s_accel->viommu;
37
iommufd_backend_free_id(viommu->iommufd, vcmdq->hw_queue_id);
38
g_free(vcmdq);
39
cmdqv->vcmdq[index] = NULL;
40
+ tegra241_cmdqv_reset_vcmdq_cache(cmdqv, index);
41
}
42
43
/*
56
tegra241_cmdqv_enabled(cmdqv) && tegra241_vintf_enabled(cmdqv);
57
}
58
59
+/*
60
+ * Return a pointer into the mmap'd VINTF page0 for the VCMDQ Page 0
61
+ * register at @offset0 in VCMDQ slot @index, or NULL when the VCMDQ
62
+ * has no hw_queue allocated or the host VINTF page0 is not mmap'd.
63
+ */
64
+static inline uint32_t *tegra241_cmdqv_vintf_lvcmdq_ptr(Tegra241CMDQV *cmdqv,
65
+ int index, hwaddr offset0)
66
+{
67
+ if (!cmdqv->vcmdq[index] || !cmdqv->vintf_page0) {
68
+ return NULL;
69
+ }
70
+ return (uint32_t *)(cmdqv->vintf_page0 +
71
+ (index * CMDQV_VCMDQ_STRIDE) +
72
+ (offset0 - CMDQV_VCMDQ_PAGE0_BASE));
73
+}
74
+
75
+/*
76
+ * Flush cached register writes into the mmap'd host VINTF page0 after a
77
+ * successful HW_QUEUE_ALLOC, so the guest's earlier writes survive
78
+ * the cache-to-hardware transition.
79
+ */
80
+static void tegra241_cmdqv_sync_vcmdq(Tegra241CMDQV *cmdqv, int index)
81
+{
82
+ uint32_t *ptr;
83
+
84
+ ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_CONS_INDX);
85
+ if (!ptr) {
86
+ return;
87
+ }
88
+ *ptr = cmdqv->vcmdq_cons_indx[index];
89
+
90
+ ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_PROD_INDX);
91
+ *ptr = cmdqv->vcmdq_prod_indx[index];
92
+
93
+ ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_CONFIG);
94
+ *ptr = cmdqv->vcmdq_config[index];
95
+
96
+ ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_GERRORN);
97
+ *ptr = cmdqv->vcmdq_gerrorn[index];
98
+}
99
+
100
/*
101
* Allocate a host HW VCMDQ from the current cached BASE / size for @index.
102
* No-op (returns true) until the VCMDQ is ready to be allocated.
137
cmdqv->vcmdq_gerror[index] &= ~R_VCMDQ0_GERROR_CMDQ_INIT_ERR_MASK;
138
cmdqv->vcmdq_status[index] |= R_VCMDQ0_STATUS_CMDQ_EN_OK_MASK;
139
140
+ /* Push cached writes to HW; freeing resets the cache. */
141
+ tegra241_cmdqv_sync_vcmdq(cmdqv, index);
142
+
143
return true;
144
}
145
166
*
167
* The caller normalizes the MMIO offset such that @offset0 always refers
168
* to a VCMDQ0_* register, while @index selects the VCMDQ instance.
169
+ *
170
+ * If the VCMDQ is allocated and the host VINTF page0 is mmap'd, read
171
+ * directly from the host VINTF page0 backing. Otherwise, fall back to
172
+ * the cache.
173
*/
174
static uint64_t tegra241_cmdqv_read_vcmdq_page0(Tegra241CMDQV *cmdqv,
175
hwaddr offset0, int index,
176
bool direct)
177
{
178
+ uint32_t *ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, offset0);
179
uint64_t val = 0;
180
181
+ if (ptr) {
182
+ val = *ptr;
183
+ goto out;
184
+ }
185
+
186
switch (offset0) {
187
case A_VCMDQ0_CONS_INDX:
188
val = cmdqv->vcmdq_cons_indx[index];
207
"%s unhandled read access at 0x%" PRIx64 "\n",
208
__func__, offset0);
209
}
210
+out:
211
trace_tegra241_cmdqv_read_vcmdq_page0(index, direct ? "direct" : "vi",
212
+ ptr ? "hw" : "cache",
213
offset0, val);
214
return val;
215
}
285
*
286
* Page 0 registers are all 32-bit; this helper is only called for 4-byte
287
* writes.
288
+ *
289
+ * If the VCMDQ is allocated and the host VINTF page0 is mmap'd, write
290
+ * directly to the VINTF page0 backing. Otherwise, update the cache.
291
*/
292
static void tegra241_cmdqv_write_vcmdq_page0(Tegra241CMDQV *cmdqv,
293
hwaddr offset0, int index,
294
uint32_t value, bool direct)
295
{
296
+ uint32_t *ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, offset0);
297
+ bool hw = false;
298
+
299
+ if (ptr) {
300
+ switch (offset0) {
301
+ case A_VCMDQ0_CONS_INDX:
302
+ case A_VCMDQ0_PROD_INDX:
303
+ case A_VCMDQ0_CONFIG:
304
+ case A_VCMDQ0_GERRORN:
305
+ *ptr = value;
306
+ hw = true;
307
+ goto out;
308
+ default:
309
+ break;
310
+ }
311
+ }
312
+
313
switch (offset0) {
314
case A_VCMDQ0_CONS_INDX:
315
cmdqv->vcmdq_cons_indx[index] = value;
340
"%s unhandled write access at 0x%" PRIx64 "\n",
341
__func__, offset0);
342
}
343
+out:
344
trace_tegra241_cmdqv_write_vcmdq_page0(index, direct ? "direct" : "vi",
345
+ hw ? "hw" : "cache",
346
offset0, value);
347
}
348