15
#include "qos-iommu-testdev.h"
16
#include "qos-intel-iommu.h"
17
18
+/* Bounded poll for the invalidation-wait Status Write. */
19
+#define QVTD_INV_WAIT_POLL_MAX_ITERS 1000
20
+#define QVTD_INV_WAIT_POLL_INTERVAL_US 1000
21
+
22
#define QVTD_AW_48BIT_ENCODING 2
23
24
uint32_t qvtd_expected_dma_result(QVTDTestContext *ctx)
236
return attrs;
237
}
238
239
+uint64_t qvtd_leaf_pte_addr(uint64_t iova)
240
+{
241
+ return qvtd_get_table_addr(QVTD_PT_L1_BASE, 1, iova);
242
+}
243
+
244
+uint64_t qvtd_make_leaf_pte(uint64_t pa, QVTDTransMode mode)
245
+{
246
+ uint64_t attrs;
247
+
248
+ /*
249
+ * Reuse the same leaf attributes qvtd_setup_translation_tables() writes,
250
+ * so a rewritten PTE stays consistent with the initial mapping. US=1 in
251
+ * the first-level format is required because the PASID entry runs with
252
+ * SRE=0, which makes every DMA appear as a user-mode access
253
+ * (VT-d 3.6.2 / 9.9).
254
+ */
255
+ if (mode == QVTD_TM_SCALABLE_FLT) {
256
+ attrs = qvtd_get_fl_pte_attrs(true);
257
+ } else {
258
+ attrs = qvtd_get_pte_attrs();
259
+ }
260
+ return (pa & VTD_PAGE_MASK_4K) | attrs;
261
+}
262
+
263
void qvtd_setup_translation_tables(QTestState *qts, uint64_t iova,
264
QVTDTransMode mode)
265
{
557
558
return dev;
559
}
560
+
561
+/*
562
+ * Write a 128-bit invalidation descriptor at the current tail and advance
563
+ * IQT_REG. Internal helper for the IOTLB / wait variants below.
564
+ */
565
+static uint32_t qvtd_submit_inv_desc(QTestState *qts, uint64_t iommu_base,
566
+ uint64_t desc_lo, uint64_t desc_hi,
567
+ uint32_t tail)
568
+{
569
+ uint64_t desc_addr = QVTD_IQ_BASE + (uint64_t)tail * QVTD_IQ_DESC_SIZE;
570
+
571
+ qtest_writeq(qts, desc_addr, desc_lo);
572
+ qtest_writeq(qts, desc_addr + 8, desc_hi);
573
+ tail++;
574
+
575
+ qtest_writeq(qts, iommu_base + DMAR_IQT_REG,
576
+ (uint64_t)tail << QVTD_IQT_SHIFT);
577
+ return tail;
578
+}
579
+
580
+uint32_t qvtd_submit_inv_wait_and_poll(QTestState *qts, uint64_t iommu_base,
581
+ uint32_t tail)
582
+{
583
+ uint64_t lo, hi;
584
+ uint32_t status = 0;
585
+ int i;
586
+
587
+ qtest_writel(qts, QVTD_INV_WAIT_ADDR, 0);
588
+
589
+ lo = VTD_INV_DESC_WAIT | VTD_INV_DESC_WAIT_SW |
590
+ ((uint64_t)QVTD_INV_WAIT_DATA << VTD_INV_DESC_WAIT_DATA_SHIFT);
591
+ hi = QVTD_INV_WAIT_ADDR;
592
+
593
+ tail = qvtd_submit_inv_desc(qts, iommu_base, lo, hi, tail);
594
+
595
+ for (i = 0; i < QVTD_INV_WAIT_POLL_MAX_ITERS; i++) {
596
+ status = qtest_readl(qts, QVTD_INV_WAIT_ADDR);
597
+ if (status == QVTD_INV_WAIT_DATA) {
598
+ return tail;
599
+ }
600
+ g_usleep(QVTD_INV_WAIT_POLL_INTERVAL_US);
601
+ }
602
+
603
+ g_assert_cmphex(status, ==, QVTD_INV_WAIT_DATA);
604
+ return tail;
605
+}
606
+
607
+uint32_t qvtd_submit_iotlb_global_inv(QTestState *qts, uint64_t iommu_base,
608
+ uint32_t tail)
609
+{
610
+ uint64_t lo = VTD_INV_DESC_IOTLB | VTD_INV_DESC_IOTLB_GLOBAL;
611
+
612
+ return qvtd_submit_inv_desc(qts, iommu_base, lo, 0, tail);
613
+}
614
+
615
+uint32_t qvtd_submit_iotlb_domain_inv(QTestState *qts, uint64_t iommu_base,
616
+ uint16_t domain_id, uint32_t tail)
617
+{
618
+ uint64_t lo = VTD_INV_DESC_IOTLB | VTD_INV_DESC_IOTLB_DOMAIN |
619
+ ((uint64_t)domain_id << 16);
620
+
621
+ return qvtd_submit_inv_desc(qts, iommu_base, lo, 0, tail);
622
+}
623
+
624
+uint32_t qvtd_submit_iotlb_page_inv(QTestState *qts, uint64_t iommu_base,
625
+ uint16_t domain_id, uint64_t addr,
626
+ uint8_t am, uint32_t tail)
627
+{
628
+ uint64_t lo = VTD_INV_DESC_IOTLB | VTD_INV_DESC_IOTLB_PAGE |
629
+ ((uint64_t)domain_id << 16);
630
+ /*
631
+ * AM selects the invalidation range per VT-d 6.5.2.4:
632
+ * am=0 → 4 KB, am=9 → 2 MB, am=18 → 1 GB.
633
+ * IH (hi[6]) is left clear, requesting full invalidation
634
+ * including non-leaf paging-structure caches.
635
+ */
636
+ uint64_t hi = (addr & ~0xfffULL) | (am & 0x3fULL);
637
+
638
+ return qvtd_submit_inv_desc(qts, iommu_base, lo, hi, tail);
639
+}