master
c 1,123 lines 41.2 KB
Raw
1 /*
2 * Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved
3 * NVIDIA Tegra241 CMDQ-Virtualization extension for SMMUv3
4 *
5 * Written by Nicolin Chen, Shameer Kolothum
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 /*
11 * Tegra241 CMDQV - overview
12 * =========================
13 *
14 * NVIDIA Tegra241 extends SMMUv3 with a Command Queue Virtualization (CMDQ-V)
15 * block. It lets a guest issue SMMU invalidation commands directly to
16 * dedicated hardware queues (vCMDQs) without trapping into the hypervisor on
17 * the fast path. vCMDQs are exclusively allocated to Virtual Interfaces
18 * (VINTFs); the host kernel allocates one VINTF per emulated SMMUv3 instance
19 * via iommufd. QEMU emulates the CMDQV MMIO region and drives the host kernel
20 * calls (VIOMMU_ALLOC, HW_QUEUE_ALLOC, mmap); the actual command processing
21 * happens on real hardware.
22 *
23 * A vCMDQ becomes functional only once allocated to the host VINTF; until then
24 * no command processing happens, and trapped register accesses fall back to a
25 * QEMU-side cache. After allocation, the cached register state is migrated to
26 * the hardware and command processing runs on the host; guest accesses to the
27 * live control/status registers then bypass QEMU and reach the host directly.
28 *
29 * MMIO layout (64KB pages, total TEGRA241_CMDQV_IO_LEN)
30 * -----------------------------------------------------
31 * 0x00000 CMDQV Config page: QEMU-trapped.
32 * 0x10000 Direct vCMDQ Page 0 (control/status): QEMU-trapped and routed
33 * to either the mmap'd host VINTF Page 0 (if the vCMDQ has been
34 * allocated to a VINTF) or a per-vCMDQ register cache (otherwise).
35 * 0x20000 Direct vCMDQ Page 1 (BASE / DRAM addresses): QEMU-trapped.
36 * 0x30000 VINTF Page 0 (per-VINTF control/status): the guest's virtual
37 * VINTF Page 0 aperture, backed by the host VINTF Page 0 (mmap'd
38 * via iommufd) and installed into guest MMIO as a RAM-device
39 * subregion when VINTF is enabled; subsequent accesses bypass QEMU.
40 * 0x40000 VINTF Page 1 (per-VINTF BASE): QEMU-trapped. Although this is
41 * a HW alias of the direct Page 1, the kernel only exposes mmap
42 * for the host VINTF Page 0; the host VINTF Page 1 is not mmap'd
43 * and stays trapped.
44 *
45 * The direct vCMDQ apertures (0x10000/0x20000) are HW aliases of the VINTF
46 * apertures (0x30000/0x40000); they expose the same per-vCMDQ register slots
47 * under different addressing.
48 *
49 * The direct vCMDQ Page 0 stays trapped rather than aliased to the host VINTF
50 * Page 0 mmap. The CMDQV architecture allows software to program a vCMDQ
51 * through the direct aperture before allocating it to a VINTF; aliasing to
52 * the host VINTF Page 0 mmap would route those accesses into unallocated
53 * logical slots where the hardware silently drops them, so trapping keeps
54 * accesses well-defined for an unallocated vCMDQ.
55 *
56 * Lifecycle (driven by guest events)
57 * ----------------------------------
58 * 1. First vfio-pci device attach (.set_iommu_device) triggers:
59 * - tegra241_cmdqv_probe(): IOMMU_GET_HW_INFO confirms host CMDQV support.
60 * - IOMMU_VIOMMU_ALLOC: the kernel allocates and enables a VINTF for this
61 * VM, configures the VM's VMID (from its stage-2 HWPT) in VINTF_CONFIG,
62 * forces HYP_OWN=0, and returns the mmap offset/length for the host
63 * VINTF Page 0, which QEMU then mmap()s.
64 *
65 * 2. Guest writes VINTF_CONFIG.ENABLE = 1:
66 * QEMU installs the mmap'd host VINTF Page 0 into guest MMIO as the guest's
67 * virtual VINTF Page 0 aperture (a RAM-device subregion) and reports
68 * STATUS.ENABLE_OK = 1. The aperture is now a direct window onto the host
69 * page, so accesses no longer trap into QEMU; a vCMDQ within it operates as
70 * a real command queue only once it has been allocated (step 3).
71 *
72 * 3. Guest completes vCMDQ setup (BASE, CMDQ_ALLOC_MAP.ALLOC, CMDQV_EN,
73 * VINTF.ENABLE, in any order; each precondition write retries the HW queue
74 * allocation):
75 * IOMMU_HW_QUEUE_ALLOC grants the guest a new host vCMDQ in this VM's
76 * VINTF, binding the guest BASE GPA (translated through stage-2 and pinned
77 * by the kernel) to it.
78 *
79 * 4. Guest SMMU driver programs a Stream Table Entry for a passthrough
80 * device: IOMMU_VDEVICE_ALLOC programs SID_MATCH/SID_REPLACE in this VM's
81 * VINTF so that the HW translates the device's guest vSID into its host
82 * pSID. Commands referencing unmapped SIDs are rejected by HW.
83 *
84 * This reflects the current accel SMMUv3 design, which allocates the
85 * vDEVICE when the guest programs the STE.
86 *
87 * Per-VM isolation
88 * ----------------
89 * - Each VM has its own iommufd FD; all iommufd objects (VINTF, vdevices,
90 * hw_queues, mmap regions) belong to that FD. Cross-FD lookups fail, so
91 * one VM cannot reach another VM's IDs.
92 * - IOMMU_VIOMMU_ALLOC configures the VM's VMID in VINTF_CONFIG; the CMDQV
93 * hardware substitutes / checks VMID on every command the guest issues.
94 * - The kernel allocates the VINTF with HYP_OWN = 0, which restricts the
95 * guest to a safe subset of commands.
96 * - IOMMU_VDEVICE_ALLOC populates SID_MATCH/SID_REPLACE so invalidations
97 * only reach the host StreamIDs assigned to this VM (see step 4).
98 * - IOMMU_HW_QUEUE_ALLOC binds each vCMDQ to a single VINTF, so a guest
99 * cannot reach a vCMDQ that belongs to another VM.
100 *
101 * Limits exposed to the guest
102 * ---------------------------
103 * One VINTF per emulated SMMUv3 and two vCMDQs per VINTF. The HW maximum
104 * vCMDQ size is 8MiB, but the size QEMU exposes to the guest may be smaller.
105 * The queue must be physically contiguous in host memory, so QEMU caps the
106 * exposed size to the host memory-backend page size. Use hugepage backing to
107 * reach the 8MiB maximum.
108 */
109
110 #include "qemu/osdep.h"
111 #include "qemu/log.h"
112
113 #include "hw/arm/smmuv3.h"
114 #include "hw/arm/smmuv3-common.h"
115 #include "hw/core/irq.h"
116 #include "smmuv3-accel.h"
117 #include "smmuv3-internal.h"
118 #include "system/hostmem.h"
119 #include "tegra241-cmdqv.h"
120 #include "trace.h"
121
122 static void tegra241_cmdqv_reset_vcmdq_cache(Tegra241CMDQV *cmdqv, int index)
123 {
124 cmdqv->vcmdq_cons_indx[index] = 0;
125 cmdqv->vcmdq_prod_indx[index] = 0;
126 cmdqv->vcmdq_config[index] = 0;
127 cmdqv->vcmdq_status[index] = 0;
128 cmdqv->vcmdq_gerror[index] = 0;
129 cmdqv->vcmdq_gerrorn[index] = 0;
130 }
131
132 static void tegra241_cmdqv_guest_unmap_vintf_page0(Tegra241CMDQV *cmdqv)
133 {
134 if (!cmdqv->mr_vintf_page0) {
135 return;
136 }
137
138 memory_region_del_subregion(&cmdqv->mmio_cmdqv, cmdqv->mr_vintf_page0);
139 object_unparent(OBJECT(cmdqv->mr_vintf_page0));
140 g_free(cmdqv->mr_vintf_page0);
141 cmdqv->mr_vintf_page0 = NULL;
142 }
143
144 static void tegra241_cmdqv_guest_map_vintf_page0(Tegra241CMDQV *cmdqv)
145 {
146 char *name;
147
148 if (cmdqv->mr_vintf_page0) {
149 return;
150 }
151
152 name = g_strdup_printf("%s vintf-page0",
153 memory_region_name(&cmdqv->mmio_cmdqv));
154 cmdqv->mr_vintf_page0 = g_malloc0(sizeof(*cmdqv->mr_vintf_page0));
155 memory_region_init_ram_device_ptr(cmdqv->mr_vintf_page0,
156 memory_region_owner(&cmdqv->mmio_cmdqv),
157 name, VINTF_PAGE_SIZE,
158 cmdqv->vintf_page0);
159 memory_region_set_skip_iommu_map(cmdqv->mr_vintf_page0, true);
160 memory_region_add_subregion_overlap(&cmdqv->mmio_cmdqv,
161 CMDQV_VINTF_PAGE0_BASE,
162 cmdqv->mr_vintf_page0, 1);
163 g_free(name);
164 }
165
166 static void tegra241_cmdqv_free_vcmdq(Tegra241CMDQV *cmdqv, int index)
167 {
168 IOMMUFDViommu *viommu = cmdqv->s_accel->viommu;
169 IOMMUFDHWqueue *vcmdq = cmdqv->vcmdq[index];
170
171 if (!vcmdq) {
172 return;
173 }
174 iommufd_backend_free_id(viommu->iommufd, vcmdq->hw_queue_id);
175 g_free(vcmdq);
176 cmdqv->vcmdq[index] = NULL;
177 tegra241_cmdqv_reset_vcmdq_cache(cmdqv, index);
178 }
179
180 /*
181 * A VCMDQ's HW queue can be allocated once the guest has programmed:
182 * - VCMDQ_BASE (ring buffer GPA and size). This only checks that BASE is
183 * non-zero, not that both the _L and _H halves have been written; a
184 * half-written BASE may pass here, but the write of the second half
185 * re-runs setup and reallocates with the complete address.
186 * - the VINTF mapping (CMDQ_ALLOC_MAP.ALLOC).
187 * - both the CMDQV global enable and the VINTF enable.
188 */
189 static bool tegra241_cmdqv_vcmdq_ready_to_alloc(Tegra241CMDQV *cmdqv, int index)
190 {
191 return cmdqv->vcmdq_base[index] &&
192 (cmdqv->cmdq_alloc_map[index] & R_CMDQ_ALLOC_MAP_0_ALLOC_MASK) &&
193 tegra241_cmdqv_enabled(cmdqv) && tegra241_vintf_enabled(cmdqv);
194 }
195
196 /*
197 * Return a pointer into the mmap'd VINTF page0 for the VCMDQ Page 0
198 * register at @offset0 in VCMDQ slot @index, or NULL when the VCMDQ
199 * has no hw_queue allocated or the host VINTF page0 is not mmap'd.
200 */
201 static inline uint32_t *tegra241_cmdqv_vintf_lvcmdq_ptr(Tegra241CMDQV *cmdqv,
202 int index, hwaddr offset0)
203 {
204 if (!cmdqv->vcmdq[index] || !cmdqv->vintf_page0) {
205 return NULL;
206 }
207 return (uint32_t *)(cmdqv->vintf_page0 +
208 (index * CMDQV_VCMDQ_STRIDE) +
209 (offset0 - CMDQV_VCMDQ_PAGE0_BASE));
210 }
211
212 /*
213 * Flush cached register writes into the mmap'd host VINTF page0 after a
214 * successful HW_QUEUE_ALLOC, so the guest's earlier writes survive
215 * the cache-to-hardware transition. GERRORN is intentionally not synced,
216 * as overwriting it with the cached value could recreate a GERROR != GERRORN
217 * mismatch and stall the VCMDQ.
218 */
219 static void tegra241_cmdqv_sync_vcmdq(Tegra241CMDQV *cmdqv, int index)
220 {
221 uint32_t *ptr;
222
223 ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_CONS_INDX);
224 if (!ptr) {
225 return;
226 }
227 *ptr = cmdqv->vcmdq_cons_indx[index];
228
229 ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_PROD_INDX);
230 *ptr = cmdqv->vcmdq_prod_indx[index];
231
232 ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_CONFIG);
233 *ptr = cmdqv->vcmdq_config[index];
234 }
235
236 /*
237 * Allocate a host HW VCMDQ from the current cached BASE / size for @index.
238 * No-op (returns true) until the VCMDQ is ready to be allocated.
239 */
240 static bool tegra241_cmdqv_setup_vcmdq(Tegra241CMDQV *cmdqv, int index,
241 Error **errp)
242 {
243 SMMUv3AccelState *accel = cmdqv->s_accel;
244 uint64_t base_mask = (uint64_t)R_VCMDQ0_BASE_L_ADDR_MASK |
245 (uint64_t)R_VCMDQ0_BASE_H_ADDR_MASK << 32;
246 uint64_t addr = cmdqv->vcmdq_base[index] & base_mask;
247 uint64_t log2 = cmdqv->vcmdq_base[index] & R_VCMDQ0_BASE_L_LOG2SIZE_MASK;
248 uint64_t size = 1ULL << (log2 + 4);
249 IOMMUFDViommu *viommu = accel->viommu;
250 IOMMUFDHWqueue *hw_queue;
251 uint32_t hw_queue_id;
252
253 if (!tegra241_cmdqv_vcmdq_ready_to_alloc(cmdqv, index)) {
254 return true;
255 }
256
257 tegra241_cmdqv_free_vcmdq(cmdqv, index);
258
259 if (!iommufd_backend_alloc_hw_queue(viommu->iommufd, viommu->viommu_id,
260 IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV,
261 index, addr, size, &hw_queue_id,
262 errp)) {
263 /* Record the failure in the cache. */
264 cmdqv->vcmdq_gerror[index] |= R_VCMDQ0_GERROR_CMDQ_INIT_ERR_MASK;
265 cmdqv->vcmdq_status[index] &= ~R_VCMDQ0_STATUS_CMDQ_EN_OK_MASK;
266 return false;
267 }
268 hw_queue = g_new(IOMMUFDHWqueue, 1);
269 hw_queue->hw_queue_id = hw_queue_id;
270 hw_queue->viommu = viommu;
271 cmdqv->vcmdq[index] = hw_queue;
272
273 cmdqv->vcmdq_gerror[index] &= ~R_VCMDQ0_GERROR_CMDQ_INIT_ERR_MASK;
274 cmdqv->vcmdq_status[index] |= R_VCMDQ0_STATUS_CMDQ_EN_OK_MASK;
275
276 /* Push cached writes to HW; freeing resets the cache. */
277 tegra241_cmdqv_sync_vcmdq(cmdqv, index);
278
279 return true;
280 }
281
282 static void tegra241_cmdqv_free_all_vcmdq(Tegra241CMDQV *cmdqv)
283 {
284 /* uapi/linux/iommufd.h: hw_queue destroy must be in descending @index. */
285 for (int i = (TEGRA241_CMDQV_MAX_CMDQ - 1); i >= 0; i--) {
286 tegra241_cmdqv_free_vcmdq(cmdqv, i);
287 }
288 }
289
290 static void tegra241_cmdqv_setup_all_vcmdq(Tegra241CMDQV *cmdqv,
291 Error **errp)
292 {
293 for (int i = 0; i < TEGRA241_CMDQV_MAX_CMDQ; i++) {
294 if (!tegra241_cmdqv_setup_vcmdq(cmdqv, i, errp)) {
295 return;
296 }
297 }
298 }
299
300 /*
301 * Read a VCMDQ Page 0 register (control/status) using VCMDQ0_* offsets.
302 *
303 * The caller normalizes the MMIO offset such that @offset0 always refers
304 * to a VCMDQ0_* register, while @index selects the VCMDQ instance.
305 *
306 * If the VCMDQ is allocated and the host VINTF page0 is mmap'd, read
307 * directly from the host VINTF page0 backing. Otherwise, fall back to
308 * the cache.
309 */
310 static uint64_t tegra241_cmdqv_read_vcmdq_page0(Tegra241CMDQV *cmdqv,
311 hwaddr offset0, int index,
312 bool direct)
313 {
314 uint32_t *ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, offset0);
315 uint64_t val = 0;
316
317 if (ptr) {
318 val = *ptr;
319 goto out;
320 }
321
322 switch (offset0) {
323 case A_VCMDQ0_CONS_INDX:
324 val = cmdqv->vcmdq_cons_indx[index];
325 break;
326 case A_VCMDQ0_PROD_INDX:
327 val = cmdqv->vcmdq_prod_indx[index];
328 break;
329 case A_VCMDQ0_CONFIG:
330 val = cmdqv->vcmdq_config[index];
331 break;
332 case A_VCMDQ0_STATUS:
333 val = cmdqv->vcmdq_status[index];
334 break;
335 case A_VCMDQ0_GERROR:
336 val = cmdqv->vcmdq_gerror[index];
337 break;
338 case A_VCMDQ0_GERRORN:
339 val = cmdqv->vcmdq_gerrorn[index];
340 break;
341 default:
342 qemu_log_mask(LOG_UNIMP,
343 "%s unhandled read access at 0x%" PRIx64 "\n",
344 __func__, offset0);
345 }
346 out:
347 trace_tegra241_cmdqv_read_vcmdq_page0(index, direct ? "direct" : "vi",
348 ptr ? "hw" : "cache",
349 offset0, val);
350 return val;
351 }
352
353 /*
354 * Read a VCMDQ Page 1 register (base / DRAM address) using VCMDQ0_* offsets.
355 */
356 static uint64_t tegra241_cmdqv_read_vcmdq_page1(Tegra241CMDQV *cmdqv,
357 hwaddr offset0, int index,
358 bool direct)
359 {
360 uint64_t val = 0;
361
362 switch (offset0) {
363 case A_VCMDQ0_BASE_L:
364 val = cmdqv->vcmdq_base[index];
365 break;
366 case A_VCMDQ0_BASE_H:
367 val = cmdqv->vcmdq_base[index] >> 32;
368 break;
369 case A_VCMDQ0_CONS_INDX_BASE_DRAM_L:
370 val = cmdqv->vcmdq_cons_indx_base[index];
371 break;
372 case A_VCMDQ0_CONS_INDX_BASE_DRAM_H:
373 val = cmdqv->vcmdq_cons_indx_base[index] >> 32;
374 break;
375 default:
376 qemu_log_mask(LOG_UNIMP,
377 "%s unhandled read access at 0x%" PRIx64 "\n",
378 __func__, offset0);
379 }
380 trace_tegra241_cmdqv_read_vcmdq_page1(index, direct ? "direct" : "vi",
381 offset0, val);
382 return val;
383 }
384
385 static uint64_t tegra241_cmdqv_config_vintf_read(Tegra241CMDQV *cmdqv,
386 hwaddr offset)
387 {
388 int i;
389
390 switch (offset) {
391 case A_VINTF0_CONFIG:
392 return cmdqv->vintf_config;
393 case A_VINTF0_STATUS:
394 return cmdqv->vintf_status;
395 case A_VINTF0_SID_MATCH_0 ... A_VINTF0_SID_MATCH_15:
396 i = (offset - A_VINTF0_SID_MATCH_0) / 4;
397 return cmdqv->vintf_sid_match[i];
398 case A_VINTF0_SID_REPLACE_0 ... A_VINTF0_SID_REPLACE_15:
399 i = (offset - A_VINTF0_SID_REPLACE_0) / 4;
400 return cmdqv->vintf_sid_replace[i];
401 case A_VINTF0_LVCMDQ_ERR_MAP_0 ... A_VINTF0_LVCMDQ_ERR_MAP_3:
402 i = (offset - A_VINTF0_LVCMDQ_ERR_MAP_0) / 4;
403 return cmdqv->vintf_cmdq_err_map[i];
404 default:
405 /*
406 * GLB_FILT_CFG_0 (offset 0xC) and GLB_FILT_DATA_0 (offset 0x10) are
407 * filter config and filter data registers. They are not required for
408 * normal VINTF operation and are not emulated.
409 */
410 qemu_log_mask(LOG_UNIMP, "%s unhandled read access at 0x%" PRIx64 "\n",
411 __func__, offset);
412 return 0;
413 }
414 }
415
416 /*
417 * Write a VCMDQ Page 0 register (control/status) using VCMDQ0_* offsets.
418 *
419 * The caller normalizes the MMIO offset such that @offset0 always refers
420 * to a VCMDQ0_* register, while @index selects the VCMDQ instance.
421 *
422 * Page 0 registers are all 32-bit; this helper is only called for 4-byte
423 * writes.
424 *
425 * If the VCMDQ is allocated and the host VINTF page0 is mmap'd, write
426 * directly to the VINTF page0 backing. Otherwise, update the cache.
427 */
428 static void tegra241_cmdqv_write_vcmdq_page0(Tegra241CMDQV *cmdqv,
429 hwaddr offset0, int index,
430 uint32_t value, bool direct)
431 {
432 uint32_t *ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, offset0);
433 bool hw = false;
434
435 if (ptr) {
436 switch (offset0) {
437 case A_VCMDQ0_CONS_INDX:
438 case A_VCMDQ0_PROD_INDX:
439 case A_VCMDQ0_CONFIG:
440 case A_VCMDQ0_GERRORN:
441 *ptr = value;
442 hw = true;
443 goto out;
444 default:
445 break;
446 }
447 }
448
449 switch (offset0) {
450 case A_VCMDQ0_CONS_INDX:
451 cmdqv->vcmdq_cons_indx[index] = value;
452 break;
453 case A_VCMDQ0_PROD_INDX:
454 /* VCMDQ is functional only once allocated to a VINTF; cache only. */
455 cmdqv->vcmdq_prod_indx[index] = value;
456 break;
457 case A_VCMDQ0_CONFIG:
458 if (value & R_VCMDQ0_CONFIG_CMDQ_EN_MASK) {
459 /* Report init error if any. */
460 if (!(cmdqv->vcmdq_gerror[index] &
461 R_VCMDQ0_GERROR_CMDQ_INIT_ERR_MASK)) {
462 cmdqv->vcmdq_status[index] |=
463 R_VCMDQ0_STATUS_CMDQ_EN_OK_MASK;
464 }
465 } else {
466 cmdqv->vcmdq_status[index] &= ~R_VCMDQ0_STATUS_CMDQ_EN_OK_MASK;
467 }
468 cmdqv->vcmdq_config[index] = value;
469 break;
470 case A_VCMDQ0_GERRORN:
471 /* VCMDQ is functional only once allocated to a VINTF; cache only. */
472 cmdqv->vcmdq_gerrorn[index] = value;
473 break;
474 default:
475 qemu_log_mask(LOG_UNIMP,
476 "%s unhandled write access at 0x%" PRIx64 "\n",
477 __func__, offset0);
478 }
479 out:
480 trace_tegra241_cmdqv_write_vcmdq_page0(index, direct ? "direct" : "vi",
481 hw ? "hw" : "cache",
482 offset0, value);
483 }
484
485 /*
486 * Write a VCMDQ Page 1 register (base / DRAM address) - 4-byte access.
487 */
488 static void tegra241_cmdqv_write_vcmdq_page1(Tegra241CMDQV *cmdqv,
489 hwaddr offset0, int index,
490 uint32_t value, bool direct,
491 Error **errp)
492 {
493 switch (offset0) {
494 case A_VCMDQ0_BASE_L:
495 cmdqv->vcmdq_base[index] =
496 deposit64(cmdqv->vcmdq_base[index], 0, 32, value);
497 tegra241_cmdqv_setup_vcmdq(cmdqv, index, errp);
498 break;
499 case A_VCMDQ0_BASE_H:
500 cmdqv->vcmdq_base[index] =
501 deposit64(cmdqv->vcmdq_base[index], 32, 32, value);
502 tegra241_cmdqv_setup_vcmdq(cmdqv, index, errp);
503 break;
504 case A_VCMDQ0_CONS_INDX_BASE_DRAM_L:
505 cmdqv->vcmdq_cons_indx_base[index] =
506 deposit64(cmdqv->vcmdq_cons_indx_base[index], 0, 32, value);
507 break;
508 case A_VCMDQ0_CONS_INDX_BASE_DRAM_H:
509 cmdqv->vcmdq_cons_indx_base[index] =
510 deposit64(cmdqv->vcmdq_cons_indx_base[index], 32, 32, value);
511 break;
512 default:
513 qemu_log_mask(LOG_UNIMP,
514 "%s unhandled write access at 0x%" PRIx64 "\n",
515 __func__, offset0);
516 }
517 trace_tegra241_cmdqv_write_vcmdq_page1(index, direct ? "direct" : "vi",
518 offset0, value);
519 }
520
521 /*
522 * Write a VCMDQ Page 1 register - 8-byte access at BASE_L or DRAM_L.
523 */
524 static void tegra241_cmdqv_write_vcmdq_page1_64(Tegra241CMDQV *cmdqv,
525 hwaddr offset0, int index,
526 uint64_t value, bool direct,
527 Error **errp)
528 {
529 switch (offset0) {
530 case A_VCMDQ0_BASE_L:
531 cmdqv->vcmdq_base[index] = value;
532 tegra241_cmdqv_setup_vcmdq(cmdqv, index, errp);
533 break;
534 case A_VCMDQ0_CONS_INDX_BASE_DRAM_L:
535 cmdqv->vcmdq_cons_indx_base[index] = value;
536 break;
537 default:
538 qemu_log_mask(LOG_UNIMP,
539 "%s unhandled 64-bit write at 0x%" PRIx64 "\n",
540 __func__, offset0);
541 }
542 trace_tegra241_cmdqv_write_vcmdq_page1(index, direct ? "direct" : "vi",
543 offset0, value);
544 }
545
546 static void tegra241_cmdqv_config_vintf_write(Tegra241CMDQV *cmdqv,
547 hwaddr offset, uint64_t value,
548 Error **errp)
549 {
550 int i;
551
552 switch (offset) {
553 case A_VINTF0_CONFIG:
554 /*
555 * Mask out HYP_OWN on guest writes. This bit selects Hypervisor (1) vs
556 * Guest (0) ownership of the CMDQ. Force it to 0 so the VINTF always
557 * remains guest-owned.
558 */
559 value &= ~R_VINTF0_CONFIG_HYP_OWN_MASK;
560
561 cmdqv->vintf_config = value;
562 if (value & R_VINTF0_CONFIG_ENABLE_MASK) {
563 cmdqv->vintf_status |= R_VINTF0_STATUS_ENABLE_OK_MASK;
564 /*
565 * VCMDQs whose BASE was programmed before VINTF was
566 * enabled need their hw_queue allocated now.
567 */
568 tegra241_cmdqv_setup_all_vcmdq(cmdqv, errp);
569 tegra241_cmdqv_guest_map_vintf_page0(cmdqv);
570 } else {
571 tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
572 tegra241_cmdqv_free_all_vcmdq(cmdqv);
573 cmdqv->vintf_status &= ~R_VINTF0_STATUS_ENABLE_OK_MASK;
574 }
575 break;
576 case A_VINTF0_SID_MATCH_0 ... A_VINTF0_SID_MATCH_15:
577 i = (offset - A_VINTF0_SID_MATCH_0) / 4;
578 cmdqv->vintf_sid_match[i] = value;
579 break;
580 case A_VINTF0_SID_REPLACE_0 ... A_VINTF0_SID_REPLACE_15:
581 i = (offset - A_VINTF0_SID_REPLACE_0) / 4;
582 cmdqv->vintf_sid_replace[i] = value;
583 break;
584 default:
585 /*
586 * GLB_FILT_CFG_0 (offset 0xC) and GLB_FILT_DATA_0 (offset 0x10) are
587 * filter config and filter data registers. They are not required for
588 * normal VINTF operation and are not emulated.
589 */
590 qemu_log_mask(LOG_UNIMP, "%s unhandled write access at 0x%" PRIx64 "\n",
591 __func__, offset);
592 return;
593 }
594 }
595
596 static uint64_t tegra241_cmdqv_read_mmio(void *opaque, hwaddr offset,
597 unsigned size)
598 {
599 Tegra241CMDQV *cmdqv = (Tegra241CMDQV *)opaque;
600 uint64_t val = 0;
601 int index;
602
603 if (offset >= TEGRA241_CMDQV_IO_LEN) {
604 qemu_log_mask(LOG_UNIMP,
605 "%s offset 0x%" PRIx64 " off limit (0x%x)\n", __func__,
606 offset, TEGRA241_CMDQV_IO_LEN);
607 goto out;
608 }
609
610 switch (offset) {
611 case A_CONFIG:
612 val = cmdqv->config;
613 break;
614 case A_PARAM:
615 val = cmdqv->param;
616 break;
617 case A_STATUS:
618 val = cmdqv->status;
619 break;
620 case A_VI_ERR_MAP_0 ... A_VI_ERR_MAP_1:
621 val = cmdqv->vi_err_map[(offset - A_VI_ERR_MAP_0) / 4];
622 break;
623 case A_VI_INT_MASK_0 ... A_VI_INT_MASK_1:
624 val = cmdqv->vi_int_mask[(offset - A_VI_INT_MASK_0) / 4];
625 break;
626 case A_CMDQ_ERR_MAP_0 ... A_CMDQ_ERR_MAP_3:
627 val = cmdqv->cmdq_err_map[(offset - A_CMDQ_ERR_MAP_0) / 4];
628 break;
629 case A_CMDQ_ALLOC_MAP_0 ... A_CMDQ_ALLOC_MAP_1:
630 val = cmdqv->cmdq_alloc_map[(offset - A_CMDQ_ALLOC_MAP_0) / 4];
631 break;
632 case A_VINTF0_CONFIG ... A_VINTF0_LVCMDQ_ERR_MAP_3:
633 val = tegra241_cmdqv_config_vintf_read(cmdqv, offset);
634 break;
635 case A_VI_VCMDQ0_CONS_INDX ... A_VI_VCMDQ1_GERRORN:
636 /*
637 * VINTF Page0 registers are hardware aliases of VCMDQ Page0 registers.
638 * Translate the VINTF aperture offset to its VCMDQ Page0 equivalent
639 * before dispatching to the Page 0 helper.
640 */
641 offset -= CMDQV_VINTF_PAGE0_BASE - CMDQV_VCMDQ_PAGE0_BASE;
642 index = (offset - CMDQV_VCMDQ_PAGE0_BASE) / CMDQV_VCMDQ_STRIDE;
643 return tegra241_cmdqv_read_vcmdq_page0(cmdqv,
644 offset - index * CMDQV_VCMDQ_STRIDE, index, false);
645 case A_VCMDQ0_CONS_INDX ... A_VCMDQ1_GERRORN:
646 /*
647 * Decode a per-VCMDQ Page 0 access. Each VCMDQ occupies a
648 * CMDQV_VCMDQ_STRIDE-byte window; extract the index and normalize
649 * to the VCMDQ0_* offset before calling the Page 0 helper.
650 */
651 index = (offset - CMDQV_VCMDQ_PAGE0_BASE) / CMDQV_VCMDQ_STRIDE;
652 return tegra241_cmdqv_read_vcmdq_page0(cmdqv,
653 offset - index * CMDQV_VCMDQ_STRIDE, index, true);
654 case A_VI_VCMDQ0_BASE_L ... A_VI_VCMDQ1_CONS_INDX_BASE_DRAM_H:
655 /* Same VINTF-to-VCMDQ translation as VINTF Page0 case above. */
656 offset -= CMDQV_VINTF_PAGE1_BASE - CMDQV_VCMDQ_PAGE1_BASE;
657 index = (offset - CMDQV_VCMDQ_PAGE1_BASE) / CMDQV_VCMDQ_STRIDE;
658 return tegra241_cmdqv_read_vcmdq_page1(cmdqv,
659 offset - index * CMDQV_VCMDQ_STRIDE, index, false);
660 case A_VCMDQ0_BASE_L ... A_VCMDQ1_CONS_INDX_BASE_DRAM_H:
661 index = (offset - CMDQV_VCMDQ_PAGE1_BASE) / CMDQV_VCMDQ_STRIDE;
662 return tegra241_cmdqv_read_vcmdq_page1(cmdqv,
663 offset - index * CMDQV_VCMDQ_STRIDE, index, true);
664 default:
665 qemu_log_mask(LOG_UNIMP, "%s unhandled read access at 0x%" PRIx64 "\n",
666 __func__, offset);
667 }
668
669 out:
670 trace_tegra241_cmdqv_read_mmio(offset, val, size);
671 return val;
672 }
673
674 /* 4-byte MMIO write handler. */
675 static void tegra241_cmdqv_writel_mmio(Tegra241CMDQV *cmdqv, hwaddr offset,
676 uint32_t value)
677 {
678 Error *local_err = NULL;
679 int index;
680
681 switch (offset) {
682 case A_CONFIG:
683 cmdqv->config = value;
684 if (value & R_CONFIG_CMDQV_EN_MASK) {
685 cmdqv->status |= R_STATUS_CMDQV_ENABLED_MASK;
686 /*
687 * VCMDQs whose BASE was programmed before CMDQV was enabled
688 * need their hw_queue allocated now.
689 */
690 tegra241_cmdqv_setup_all_vcmdq(cmdqv, &local_err);
691 } else {
692 tegra241_cmdqv_free_all_vcmdq(cmdqv);
693 cmdqv->status &= ~R_STATUS_CMDQV_ENABLED_MASK;
694 }
695 break;
696 case A_VI_INT_MASK_0 ... A_VI_INT_MASK_1:
697 cmdqv->vi_int_mask[(offset - A_VI_INT_MASK_0) / 4] = value;
698 break;
699 case A_CMDQ_ALLOC_MAP_0 ... A_CMDQ_ALLOC_MAP_1: {
700 int idx = (offset - A_CMDQ_ALLOC_MAP_0) / 4;
701 bool was_alloc = cmdqv->cmdq_alloc_map[idx] &
702 R_CMDQ_ALLOC_MAP_0_ALLOC_MASK;
703 bool now_alloc = value & R_CMDQ_ALLOC_MAP_0_ALLOC_MASK;
704
705 cmdqv->cmdq_alloc_map[idx] = value;
706 /*
707 * If the VCMDQ was already programmed (BASE) before mapping, fire
708 * setup on the ALLOC 0->1 transition; tear down on 1->0.
709 */
710 if (!was_alloc && now_alloc) {
711 tegra241_cmdqv_setup_vcmdq(cmdqv, idx, &local_err);
712 } else if (was_alloc && !now_alloc) {
713 tegra241_cmdqv_free_vcmdq(cmdqv, idx);
714 }
715 break;
716 }
717 case A_VINTF0_CONFIG ... A_VINTF0_LVCMDQ_ERR_MAP_3:
718 tegra241_cmdqv_config_vintf_write(cmdqv, offset, value, &local_err);
719 break;
720 case A_VI_VCMDQ0_CONS_INDX ... A_VI_VCMDQ1_GERRORN:
721 /*
722 * VINTF Page0 registers are hardware aliases of VCMDQ Page0 registers.
723 * Translate the VINTF aperture offset to its VCMDQ Page0 equivalent
724 * before dispatching to the Page 0 helper.
725 */
726 offset -= CMDQV_VINTF_PAGE0_BASE - CMDQV_VCMDQ_PAGE0_BASE;
727 index = (offset - CMDQV_VCMDQ_PAGE0_BASE) / CMDQV_VCMDQ_STRIDE;
728 tegra241_cmdqv_write_vcmdq_page0(cmdqv,
729 offset - index * CMDQV_VCMDQ_STRIDE, index, value, false);
730 break;
731 case A_VCMDQ0_CONS_INDX ... A_VCMDQ1_GERRORN:
732 /*
733 * Decode a per-VCMDQ Page 0 access. Each VCMDQ occupies a
734 * CMDQV_VCMDQ_STRIDE-byte window; extract the index and normalize
735 * to the VCMDQ0_* offset before calling the Page 0 helper.
736 */
737 index = (offset - CMDQV_VCMDQ_PAGE0_BASE) / CMDQV_VCMDQ_STRIDE;
738 tegra241_cmdqv_write_vcmdq_page0(cmdqv,
739 offset - index * CMDQV_VCMDQ_STRIDE, index, value, true);
740 break;
741 case A_VI_VCMDQ0_BASE_L ... A_VI_VCMDQ1_CONS_INDX_BASE_DRAM_H:
742 /* Same VINTF-to-VCMDQ translation as VINTF Page0 case above. */
743 offset -= CMDQV_VINTF_PAGE1_BASE - CMDQV_VCMDQ_PAGE1_BASE;
744 index = (offset - CMDQV_VCMDQ_PAGE1_BASE) / CMDQV_VCMDQ_STRIDE;
745 tegra241_cmdqv_write_vcmdq_page1(cmdqv,
746 offset - index * CMDQV_VCMDQ_STRIDE, index, value, false,
747 &local_err);
748 break;
749 case A_VCMDQ0_BASE_L ... A_VCMDQ1_CONS_INDX_BASE_DRAM_H:
750 index = (offset - CMDQV_VCMDQ_PAGE1_BASE) / CMDQV_VCMDQ_STRIDE;
751 tegra241_cmdqv_write_vcmdq_page1(cmdqv,
752 offset - index * CMDQV_VCMDQ_STRIDE, index, value, true,
753 &local_err);
754 break;
755 default:
756 qemu_log_mask(LOG_UNIMP, "%s unhandled write access at 0x%" PRIx64 "\n",
757 __func__, offset);
758 }
759
760 if (local_err) {
761 error_report_err(local_err);
762 }
763 }
764
765 /*
766 * 8-byte MMIO write handler. Only Page 1 BASE / CONS_INDX_BASE_DRAM accept
767 * full 64-bit writes; other offsets are write-ignored.
768 */
769 static void tegra241_cmdqv_writell_mmio(Tegra241CMDQV *cmdqv, hwaddr offset,
770 uint64_t value)
771 {
772 Error *local_err = NULL;
773 int index;
774
775 switch (offset) {
776 case A_VI_VCMDQ0_BASE_L ... A_VI_VCMDQ1_CONS_INDX_BASE_DRAM_H:
777 /*
778 * VINTF Page1 registers are hardware aliases of VCMDQ Page1 registers.
779 * Translate the VINTF aperture offset to its VCMDQ Page1 equivalent
780 * before dispatching to the Page 1 helper.
781 */
782 offset -= CMDQV_VINTF_PAGE1_BASE - CMDQV_VCMDQ_PAGE1_BASE;
783 index = (offset - CMDQV_VCMDQ_PAGE1_BASE) / CMDQV_VCMDQ_STRIDE;
784 tegra241_cmdqv_write_vcmdq_page1_64(cmdqv,
785 offset - index * CMDQV_VCMDQ_STRIDE, index, value, false,
786 &local_err);
787 break;
788 case A_VCMDQ0_BASE_L ... A_VCMDQ1_CONS_INDX_BASE_DRAM_H:
789 index = (offset - CMDQV_VCMDQ_PAGE1_BASE) / CMDQV_VCMDQ_STRIDE;
790 tegra241_cmdqv_write_vcmdq_page1_64(cmdqv,
791 offset - index * CMDQV_VCMDQ_STRIDE, index, value, true,
792 &local_err);
793 break;
794 default:
795 qemu_log_mask(LOG_UNIMP,
796 "%s unhandled 64-bit write at 0x%" PRIx64 " (WI)\n",
797 __func__, offset);
798 }
799
800 if (local_err) {
801 error_report_err(local_err);
802 }
803 }
804
805 static void tegra241_cmdqv_write_mmio(void *opaque, hwaddr offset,
806 uint64_t value, unsigned size)
807 {
808 Tegra241CMDQV *cmdqv = (Tegra241CMDQV *)opaque;
809
810 if (offset >= TEGRA241_CMDQV_IO_LEN) {
811 qemu_log_mask(LOG_UNIMP,
812 "%s offset 0x%" PRIx64 " off limit (0x%x)\n", __func__,
813 offset, TEGRA241_CMDQV_IO_LEN);
814 goto out;
815 }
816
817 switch (size) {
818 case 4:
819 tegra241_cmdqv_writel_mmio(cmdqv, offset, value);
820 break;
821 case 8:
822 tegra241_cmdqv_writell_mmio(cmdqv, offset, value);
823 break;
824 default:
825 qemu_log_mask(LOG_GUEST_ERROR,
826 "%s bad write size %u at 0x%" PRIx64 "\n",
827 __func__, size, offset);
828 }
829
830 out:
831 trace_tegra241_cmdqv_write_mmio(offset, value, size);
832 }
833
834 static void tegra241_cmdqv_event_read(void *opaque)
835 {
836 Tegra241CMDQV *cmdqv = opaque;
837 IOMMUFDVeventq *veventq = cmdqv->veventq;
838 struct {
839 struct iommufd_vevent_header hdr;
840 struct iommu_vevent_tegra241_cmdqv vevent;
841 } buf;
842 Error *local_err = NULL;
843 int ret;
844
845 ret = smmuv3_accel_event_read_validate(veventq,
846 IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV,
847 &buf, sizeof(buf), &local_err);
848 if (ret < 0) {
849 warn_report_err_once(local_err);
850 return;
851 }
852 if (ret > 0) {
853 return; /* EAGAIN/EINTR */
854 }
855
856 if (buf.vevent.lvcmdq_err_map[0] || buf.vevent.lvcmdq_err_map[1]) {
857 cmdqv->vintf_cmdq_err_map[0] =
858 extract64(buf.vevent.lvcmdq_err_map[0], 0, 32);
859 cmdqv->vintf_cmdq_err_map[1] =
860 extract64(buf.vevent.lvcmdq_err_map[0], 32, 32);
861 cmdqv->vintf_cmdq_err_map[2] =
862 extract64(buf.vevent.lvcmdq_err_map[1], 0, 32);
863 cmdqv->vintf_cmdq_err_map[3] =
864 extract64(buf.vevent.lvcmdq_err_map[1], 32, 32);
865 /*
866 * CMDQV_CMDQ_ERR_MAP and VINTF0_LVCMDQ_ERR_MAP are distinct
867 * registers (different MMIO offsets). With only VINTF0 exposed
868 * they carry the same data, so mirror.
869 */
870 for (int i = 0; i < 4; i++) {
871 cmdqv->cmdq_err_map[i] = cmdqv->vintf_cmdq_err_map[i];
872 }
873 /* Set the VINTF0 bit in VI_ERR_MAP_0 (only VINTF0 is exposed). */
874 cmdqv->vi_err_map[0] |= BIT(0);
875 if (!(cmdqv->vi_int_mask[0] & BIT(0))) {
876 qemu_irq_pulse(cmdqv->irq);
877 }
878 trace_tegra241_cmdqv_err_map(
879 cmdqv->vintf_cmdq_err_map[3], cmdqv->vintf_cmdq_err_map[2],
880 cmdqv->vintf_cmdq_err_map[1], cmdqv->vintf_cmdq_err_map[0]);
881 }
882 }
883
884 static void tegra241_cmdqv_free_viommu(SMMUv3State *s)
885 {
886 SMMUv3AccelState *accel = s->s_accel;
887 IOMMUFDViommu *viommu = accel->viommu;
888 Tegra241CMDQV *cmdqv = accel->cmdqv;
889 IOMMUFDVeventq *veventq = cmdqv->veventq;
890
891 if (!viommu) {
892 return;
893 }
894 if (veventq) {
895 qemu_set_fd_handler(veventq->veventq_fd, NULL, NULL, NULL);
896 close(veventq->veventq_fd);
897 iommufd_backend_free_id(viommu->iommufd, veventq->veventq_id);
898 g_free(veventq);
899 cmdqv->veventq = NULL;
900 }
901 if (cmdqv->vintf_page0) {
902 munmap(cmdqv->vintf_page0, VINTF_PAGE_SIZE);
903 cmdqv->vintf_page0 = NULL;
904 }
905 iommufd_backend_free_id(viommu->iommufd, viommu->viommu_id);
906 }
907
908 static bool
909 tegra241_cmdqv_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
910 uint32_t *out_viommu_id, Error **errp)
911 {
912 Tegra241CMDQV *cmdqv = s->s_accel->cmdqv;
913 uint32_t viommu_id, veventq_id, veventq_fd;
914 IOMMUFDVeventq *veventq;
915 int flags;
916
917 if (!iommufd_backend_alloc_viommu(idev->iommufd, idev->devid,
918 IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV,
919 idev->hwpt_id, cmdqv->cmdqv_data,
920 sizeof(*cmdqv->cmdqv_data), &viommu_id,
921 errp)) {
922 return false;
923 }
924
925 if (!iommufd_backend_viommu_mmap(idev->iommufd, viommu_id, VINTF_PAGE_SIZE,
926 cmdqv->cmdqv_data->out_vintf_mmap_offset,
927 &cmdqv->vintf_page0, errp)) {
928 error_append_hint(errp, "Tegra241 CMDQV: failed to mmap VINTF page0");
929 goto free_viommu;
930 }
931
932 if (!iommufd_backend_alloc_veventq(idev->iommufd, viommu_id,
933 IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV,
934 1 << SMMU_EVENTQS, &veventq_id,
935 &veventq_fd,
936 errp)) {
937 error_append_hint(errp, "Tegra241 CMDQV: failed to alloc veventq");
938 goto munmap_page0;
939 }
940
941 flags = fcntl(veventq_fd, F_GETFL);
942 if (flags < 0) {
943 error_setg(errp, "Failed to get flags for vEVENTQ fd");
944 goto free_veventq;
945 }
946 if (fcntl(veventq_fd, F_SETFL, O_NONBLOCK | flags) < 0) {
947 error_setg(errp, "Failed to set O_NONBLOCK on vEVENTQ fd");
948 goto free_veventq;
949 }
950
951 veventq = g_new(IOMMUFDVeventq, 1);
952 veventq->veventq_id = veventq_id;
953 veventq->veventq_fd = veventq_fd;
954 cmdqv->veventq = veventq;
955
956 /* Set up event handler for veventq fd */
957 qemu_set_fd_handler(veventq_fd, tegra241_cmdqv_event_read, NULL, cmdqv);
958 *out_viommu_id = viommu_id;
959 return true;
960
961 free_veventq:
962 close(veventq_fd);
963 iommufd_backend_free_id(idev->iommufd, veventq_id);
964 munmap_page0:
965 munmap(cmdqv->vintf_page0, VINTF_PAGE_SIZE);
966 cmdqv->vintf_page0 = NULL;
967 free_viommu:
968 iommufd_backend_free_id(idev->iommufd, viommu_id);
969 return false;
970 }
971
972 static void tegra241_cmdqv_init_regs(SMMUv3State *s, Tegra241CMDQV *cmdqv)
973 {
974 int i;
975 long pgsize;
976 uint32_t val;
977
978 cmdqv->config = V_CONFIG_RESET;
979 cmdqv->param = FIELD_DP32(0, PARAM, CMDQV_VER, CMDQV_VER);
980 cmdqv->param = FIELD_DP32(cmdqv->param, PARAM, CMDQV_NUM_CMDQ_LOG2,
981 CMDQV_NUM_CMDQ_LOG2);
982 cmdqv->param = FIELD_DP32(cmdqv->param, PARAM, CMDQV_NUM_SID_PER_VI_LOG2,
983 CMDQV_NUM_SID_PER_VI_LOG2);
984 trace_tegra241_cmdqv_init_regs(cmdqv->param);
985 cmdqv->status = R_STATUS_CMDQV_ENABLED_MASK;
986
987 for (i = 0; i < 2; i++) {
988 cmdqv->vi_err_map[i] = 0;
989 cmdqv->vi_int_mask[i] = 0;
990 }
991 for (i = 0; i < 4; i++) {
992 cmdqv->cmdq_err_map[i] = 0;
993 cmdqv->vintf_cmdq_err_map[i] = 0;
994 }
995 cmdqv->vintf_config = 0;
996 cmdqv->vintf_status = 0;
997 for (i = 0; i < TEGRA241_CMDQV_MAX_CMDQ; i++) {
998 cmdqv->cmdq_alloc_map[i] = 0;
999 cmdqv->vcmdq_cons_indx[i] = 0;
1000 cmdqv->vcmdq_prod_indx[i] = 0;
1001 cmdqv->vcmdq_config[i] = 0;
1002 cmdqv->vcmdq_status[i] = 0;
1003 cmdqv->vcmdq_gerror[i] = 0;
1004 cmdqv->vcmdq_gerrorn[i] = 0;
1005 cmdqv->vcmdq_base[i] = 0;
1006 cmdqv->vcmdq_cons_indx_base[i] = 0;
1007 }
1008
1009 /*
1010 * CMDQ must not cross a physical RAM backend page. Adjust CMDQS so the
1011 * queue fits entirely within the smallest backend page size, ensuring
1012 * the command queue is physically contiguous in host memory.
1013 *
1014 * IDR1.CMDQS = log2(max_qsz) - entry_shift
1015 *
1016 * where entry_shift = 4 (each CMDQ entry is 16 bytes = 2^4).
1017 */
1018 pgsize = qemu_minrampagesize();
1019 if (pgsize == LONG_MAX) {
1020 pgsize = qemu_real_host_page_size();
1021 }
1022 val = FIELD_EX32(s->idr[1], IDR1, CMDQS);
1023 s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, MIN(ctz64(pgsize) - 4, val));
1024 }
1025
1026 static void tegra241_cmdqv_reset(SMMUv3State *s)
1027 {
1028 Tegra241CMDQV *cmdqv = s->s_accel->cmdqv;
1029
1030 if (!cmdqv) {
1031 return;
1032 }
1033
1034 tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
1035 tegra241_cmdqv_free_all_vcmdq(cmdqv);
1036
1037 tegra241_cmdqv_init_regs(s, cmdqv);
1038 }
1039
1040 static const MemoryRegionOps mmio_cmdqv_ops = {
1041 .read = tegra241_cmdqv_read_mmio,
1042 .write = tegra241_cmdqv_write_mmio,
1043 .endianness = DEVICE_LITTLE_ENDIAN,
1044 .valid = {
1045 .min_access_size = 4,
1046 .max_access_size = 8,
1047 },
1048 .impl = {
1049 .min_access_size = 4,
1050 .max_access_size = 8,
1051 },
1052 };
1053
1054 static bool tegra241_cmdqv_init(SMMUv3State *s, Error **errp)
1055 {
1056 SysBusDevice *sbd = SYS_BUS_DEVICE(OBJECT(s));
1057 SMMUv3AccelState *accel = s->s_accel;
1058 Tegra241CMDQV *cmdqv;
1059
1060 cmdqv = g_new0(Tegra241CMDQV, 1);
1061 cmdqv->cmdqv_data = g_new0(struct iommu_viommu_tegra241_cmdqv, 1);
1062 memory_region_init_io(&cmdqv->mmio_cmdqv, OBJECT(s), &mmio_cmdqv_ops, cmdqv,
1063 "tegra241-cmdqv", TEGRA241_CMDQV_IO_LEN);
1064 sysbus_init_mmio(sbd, &cmdqv->mmio_cmdqv);
1065 sysbus_init_irq(sbd, &cmdqv->irq);
1066 cmdqv->s_accel = accel;
1067 accel->cmdqv = cmdqv;
1068 return true;
1069 }
1070
1071 static SMMUv3AccelCmdqvType tegra241_cmdqv_get_type(void)
1072 {
1073 return SMMUV3_CMDQV_TEGRA241;
1074 }
1075
1076 static bool tegra241_cmdqv_probe(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
1077 Error **errp)
1078 {
1079 uint32_t data_type = IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV;
1080 struct iommu_hw_info_tegra241_cmdqv cmdqv_info;
1081 uint64_t caps;
1082
1083 if (!iommufd_backend_get_device_info(idev->iommufd, idev->devid, &data_type,
1084 &cmdqv_info, sizeof(cmdqv_info), &caps,
1085 NULL, errp)) {
1086 return false;
1087 }
1088 if (data_type != IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV) {
1089 error_setg(errp, "Host CMDQV: unexpected data type %u (expected %u)",
1090 data_type, IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV);
1091 return false;
1092 }
1093 if (cmdqv_info.version != CMDQV_VER) {
1094 error_setg(errp, "Host CMDQV: unsupported version %u (expected %u)",
1095 cmdqv_info.version, CMDQV_VER);
1096 return false;
1097 }
1098 if (cmdqv_info.log2vcmdqs < CMDQV_NUM_CMDQ_LOG2) {
1099 error_setg(errp, "Host CMDQV: insufficient vCMDQs log2=%u (need >= %u)",
1100 cmdqv_info.log2vcmdqs, CMDQV_NUM_CMDQ_LOG2);
1101 return false;
1102 }
1103 if (cmdqv_info.log2vsids < CMDQV_NUM_SID_PER_VI_LOG2) {
1104 error_setg(errp, "Host CMDQV: insufficient SIDs log2=%u (need >= %u)",
1105 cmdqv_info.log2vsids, CMDQV_NUM_SID_PER_VI_LOG2);
1106 return false;
1107 }
1108 return true;
1109 }
1110
1111 static const SMMUv3AccelCmdqvOps tegra241_cmdqv_ops = {
1112 .probe = tegra241_cmdqv_probe,
1113 .init = tegra241_cmdqv_init,
1114 .alloc_viommu = tegra241_cmdqv_alloc_viommu,
1115 .free_viommu = tegra241_cmdqv_free_viommu,
1116 .get_type = tegra241_cmdqv_get_type,
1117 .reset = tegra241_cmdqv_reset,
1118 };
1119
1120 const SMMUv3AccelCmdqvOps *tegra241_cmdqv_get_ops(void)
1121 {
1122 return &tegra241_cmdqv_ops;
1123 }