@@ -73,6 +73,7 @@ struct vfio_iommu {
unsigned int vaddr_invalid_count;
uint64_t pgsize_bitmap;
uint64_t num_non_pinned_groups;
+ uint64_t num_non_hwdbm_domains;
wait_queue_head_t vaddr_wait;
bool v2;
bool nesting;
@@ -86,6 +87,7 @@ struct vfio_domain {
struct list_head group_list;
int prot; /* IOMMU_CACHE */
bool fgsp; /* Fine-grained super pages */
+ bool iommu_hwdbm; /* Hardware dirty management */
};
struct vfio_dma {
@@ -2238,6 +2240,26 @@ static void vfio_iommu_iova_insert_copy(struct vfio_iommu *iommu,
list_splice_tail(iova_copy, iova);
}
+/*
+ * Called after a new group is added to the iommu_domain, or an old group is
+ * removed from the iommu_domain. Update the HWDBM status of vfio_domain and
+ * vfio_iommu.
+ */
+static void vfio_iommu_update_hwdbm(struct vfio_iommu *iommu,
+ struct vfio_domain *domain,
+ bool attach)
+{
+ bool old_hwdbm = domain->iommu_hwdbm;
+ bool new_hwdbm = iommu_support_dirty_log(domain->domain);
+
+ if (old_hwdbm && !new_hwdbm && attach) {
+ iommu->num_non_hwdbm_domains++;
+ } else if (!old_hwdbm && new_hwdbm && !attach) {
+ iommu->num_non_hwdbm_domains--;
+ }
+ domain->iommu_hwdbm = new_hwdbm;
+}
+
static int vfio_iommu_type1_attach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
@@ -2391,6 +2413,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
vfio_iommu_detach_group(domain, group);
if (!vfio_iommu_attach_group(d, group)) {
list_add(&group->next, &d->group_list);
+ vfio_iommu_update_hwdbm(iommu, d, true);
iommu_domain_free(domain->domain);
kfree(domain);
goto done;
@@ -2417,6 +2440,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
list_add(&domain->next, &iommu->domain_list);
vfio_update_pgsize_bitmap(iommu);
+ vfio_iommu_update_hwdbm(iommu, domain, true);
done:
/* Delete the old one and insert new iova list */
vfio_iommu_iova_insert_copy(iommu, &iova_copy);
@@ -2599,6 +2623,7 @@ static void vfio_iommu_type1_detach_group(void *iommu_data,
continue;
vfio_iommu_detach_group(domain, group);
+ vfio_iommu_update_hwdbm(iommu, domain, false);
update_dirty_scope = !group->pinned_page_dirty_scope;
list_del(&group->next);
kfree(group);