Index | Thread | Search

From:
Jonathan Gray <jsg@jsg.id.au>
Subject:
Re: [PATCH 0/4] i915 dg2 patches
To:
kisekinopureya <kisekinopureya@disroot.org>
Cc:
tech@openbsd.org
Date:
Mon, 14 Sep 2026 20:52:15 +1000

Download raw body.

Thread
On Fri, Sep 11, 2026 at 09:54:43PM +0300, kisekinopureya wrote:
> I tested your patches as is on latest codebase, it throws uvm_fault and
> system
> hard locks:
> 
> i915_tt_get_st: stub
> i915_tt_get_st: stub
> uvm_fault(0xffffffff82b3a700, 0xffffffffffffffda, 0, 1) -> e

I set up my dg2 again:
inteldrm0 at pci12 dev 0 function 0 "Intel Arc Pro A40/A50" rev 0x05
drm0 at inteldrm0
inteldrm0: msi, DG2, gen 12
...
intel_slicemask_from_xehp_dssmask: stub
intel_slicemask_from_xehp_dssmask: stub
i915_resize_lmem_bar: stub
intel_slicemask_from_xehp_dssmask: stub
drm:pid0:wa_verify *ERROR* [drm] *ERROR* GT0: GT workaround lost on init! (reg[b188]=0x0, relevant bits were 0x0 vs expected 0x8)
gsc_init_one: stub
gsc_init_one: stub
inteldrm0: 1280x1024, 32bpp

The problem was with dma_map_sgtable() and another in i915_ttm_purge().

With the below diff X starts and glxinfo/glxgears work.
Disabling HuC not required.

diff --git sys/dev/pci/drm/drm_linux.c sys/dev/pci/drm/drm_linux.c
index 53a6efd90e2..faca11e360d 100644
--- sys/dev/pci/drm/drm_linux.c
+++ sys/dev/pci/drm/drm_linux.c
@@ -1251,6 +1251,38 @@ sg_free_table(struct sg_table *table)
 	table->sgl = NULL;
 }
 
+int
+sg_alloc_table_from_pages_segment(struct sg_table *table, struct vm_page **pages,
+    unsigned int npages, unsigned int off, unsigned long size,
+    unsigned int max_segs, gfp_t gfp_mask)
+{
+	struct scatterlist *sg;
+	int r, i;
+	unsigned int len;
+
+	r = sg_alloc_table(table, npages, gfp_mask);
+	if (r != 0)
+		return r;
+
+	sg = table->sgl;
+	table->nents = 0;
+	len = PAGE_SIZE - off;
+	for (i = 0; i < npages; i++) {
+		if (i)
+			sg = sg_next(sg);
+		sg_set_page(sg, pages[i], len, off);
+		off = 0;
+		table->nents++;
+		size -= len;
+		if (size > PAGE_SIZE)
+			len = PAGE_SIZE;
+		else
+			len = size;
+	}
+
+	return 0;
+}
+
 int
 i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
@@ -3487,6 +3519,19 @@ dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
 	STUB();
 }
 
+int
+dma_map_sgtable(struct device *dev, struct sg_table *sgt,
+    enum dma_data_direction dir, unsigned long attrs)
+{
+	return 0;
+}
+
+void
+dma_unmap_sgtable(struct device *dev, struct sg_table *sgt,
+    enum dma_data_direction dir, unsigned long attrs)
+{
+}
+
 #ifdef BUS_DMA_FIXED
 
 #include <linux/iommu.h>
diff --git sys/dev/pci/drm/i915/gem/i915_gem_object.h sys/dev/pci/drm/i915/gem/i915_gem_object.h
index b266814d3fb..0fb18d0aa43 100644
--- sys/dev/pci/drm/i915/gem/i915_gem_object.h
+++ sys/dev/pci/drm/i915/gem/i915_gem_object.h
@@ -855,10 +855,10 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
 			 size_t size, struct intel_memory_region *mr,
 			 struct address_space *mapping,
 			 unsigned int max_segment,
-			 struct drm_i915_gem_object *obj);
+			 struct uvm_object *);
 void shmem_sg_free_table(struct sg_table *st, struct address_space *mapping,
 			 bool dirty, bool backup,
-			 struct drm_i915_gem_object *obj);
+			 struct uvm_object *, size_t);
 #endif
 void __shmem_writeback(size_t size, struct address_space *mapping);
 
diff --git sys/dev/pci/drm/i915/gem/i915_gem_shmem.c sys/dev/pci/drm/i915/gem/i915_gem_shmem.c
index ee8034c9c63..970b47f8fd6 100644
--- sys/dev/pci/drm/i915/gem/i915_gem_shmem.c
+++ sys/dev/pci/drm/i915/gem/i915_gem_shmem.c
@@ -34,7 +34,7 @@ static void check_release_folio_batch(struct folio_batch *fbatch)
 
 void shmem_sg_free_table(struct sg_table *st, struct address_space *mapping,
 			 bool dirty, bool backup,
-			 struct drm_i915_gem_object *obj)
+			 struct uvm_object *uao, size_t uao_size)
 {
 	struct sgt_iter sgt_iter;
 	struct folio_batch fbatch;
@@ -69,7 +69,7 @@ void shmem_sg_free_table(struct sg_table *st, struct address_space *mapping,
 	if (fbatch.nr)
 		check_release_folio_batch(&fbatch);
 #else
-	uvm_obj_unwire(obj->base.uao, 0, obj->base.size);
+	uvm_obj_unwire(uao, 0, uao_size);
 #endif
 
 	sg_free_table(st);
@@ -79,7 +79,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
 			 size_t size, struct intel_memory_region *mr,
 			 struct address_space *mapping,
 			 unsigned int max_segment,
-			 struct drm_i915_gem_object *obj)
+			 struct uvm_object *uao)
 {
 	unsigned int page_count; /* restricted by sg_alloc_table */
 	unsigned long i;
@@ -201,7 +201,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
 	st->nents = 0;
 
 	TAILQ_INIT(&plist);
-	if (uvm_obj_wire(obj->base.uao, 0, obj->base.size, &plist)) {
+	if (uvm_obj_wire(uao, 0, size, &plist)) {
 		ret = -ENOMEM;
 		goto err_sg;
 	}
@@ -225,7 +225,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
 err_sg:
 	sg_mark_end(sg);
 	if (sg != st->sgl) {
-		shmem_sg_free_table(st, mapping, false, false, obj);
+		shmem_sg_free_table(st, mapping, false, false, uao, size);
 	} else {
 		mapping_clear_unevictable(mapping);
 		sg_free_table(st);
@@ -275,7 +275,7 @@ rebuild_st:
 				   max_segment);
 #else
 	ret = shmem_sg_alloc_table(i915, st, obj->base.size, mem, NULL,
-				   max_segment, obj);
+				   max_segment, obj->base.uao);
 #endif
 	if (ret)
 		goto err_st;
@@ -291,7 +291,7 @@ rebuild_st:
 #ifdef __linux__
 			shmem_sg_free_table(st, mapping, false, false);
 #else
-			shmem_sg_free_table(st, NULL, false, false, obj);
+			shmem_sg_free_table(st, NULL, false, false, obj->base.uao, obj->base.size);
 #endif
 			sg_free_table(st);
 			kfree(st);
@@ -320,7 +320,7 @@ err_pages:
 #ifdef __linux__
 	shmem_sg_free_table(st, mapping, false, false);
 #else
-	shmem_sg_free_table(st, NULL, false, false, obj);
+	shmem_sg_free_table(st, NULL, false, false, obj->base.uao, obj->base.size);
 #endif
 	/*
 	 * shmemfs first checks if there is enough memory to allocate the page
@@ -459,7 +459,8 @@ void i915_gem_object_put_pages_shmem(struct drm_i915_gem_object *obj, struct sg_
 			    obj->mm.dirty, obj->mm.madv == I915_MADV_WILLNEED);
 #else
 	shmem_sg_free_table(pages, NULL,
-			    obj->mm.dirty, obj->mm.madv == I915_MADV_WILLNEED, obj);
+			    obj->mm.dirty, obj->mm.madv == I915_MADV_WILLNEED,
+			    obj->base.uao, obj->base.size);
 #endif
 	kfree(pages);
 	obj->mm.dirty = false;
diff --git sys/dev/pci/drm/i915/gem/i915_gem_ttm.c sys/dev/pci/drm/i915/gem/i915_gem_ttm.c
index 570d0971fd4..d6676d6d3c3 100644
--- sys/dev/pci/drm/i915/gem/i915_gem_ttm.c
+++ sys/dev/pci/drm/i915/gem/i915_gem_ttm.c
@@ -53,7 +53,11 @@ struct i915_ttm_tt {
 	struct i915_refct_sgt cached_rsgt;
 
 	bool is_shmem;
+#ifdef __linux__
 	struct file *filp;
+#else
+	struct uvm_object *filp;
+#endif
 };
 
 static const struct ttm_place sys_placement_flags = {
@@ -179,13 +183,11 @@ i915_ttm_placement_from_obj(const struct drm_i915_gem_object *obj,
 	placement->placement = places;
 }
 
+#ifdef __linux__
 static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
 				      struct ttm_tt *ttm,
 				      struct ttm_operation_ctx *ctx)
 {
-	STUB();
-	return -ENOSYS;
-#ifdef notyet
 	struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
 	struct intel_memory_region *mr = i915->mm.regions[INTEL_MEMORY_SYSTEM];
 	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
@@ -239,19 +241,71 @@ err_free_st:
 	shmem_sg_free_table(st, filp->f_mapping, false, false);
 
 	return err;
-#endif
 }
+#else /* !__linux__ */
+static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
+				      struct ttm_tt *ttm,
+				      struct ttm_operation_ctx *ctx)
+{
+	struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
+	struct intel_memory_region *mr = i915->mm.regions[INTEL_MEMORY_SYSTEM];
+	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
+	const unsigned int max_segment = i915_sg_segment_size(i915->drm.dev);
+	const size_t size = (size_t)ttm->num_pages << PAGE_SHIFT;
+	struct uvm_object *uao = i915_tt->filp;
+	struct sgt_iter sgt_iter;
+	struct sg_table *st;
+	struct vm_page *page;
+	unsigned long i;
+	int err;
+
+	if (!uao) {
+		uao = uao_create(size, 0);
+		if (uao == NULL)
+			return -ENOMEM;
+
+		i915_tt->filp = uao;
+	}
+
+	st = &i915_tt->cached_rsgt.table;
+	err = shmem_sg_alloc_table(i915, st, size, mr, /*filp->f_mapping*/NULL,
+				   max_segment, uao);
+	if (err)
+		return err;
+
+	err = dma_map_sgtable(i915_tt->dev, st, DMA_BIDIRECTIONAL,
+			      DMA_ATTR_SKIP_CPU_SYNC);
+	if (err)
+		goto err_free_st;
+
+	i = 0;
+	for_each_sgt_page(page, sgt_iter, st)
+		ttm->pages[i++] = page;
+
+	if (ttm->page_flags & TTM_TT_FLAG_SWAPPED)
+		ttm->page_flags &= ~TTM_TT_FLAG_SWAPPED;
+
+	return 0;
+
+err_free_st:
+	shmem_sg_free_table(st, NULL, false, false, uao, size);
+
+	return err;
+}
+#endif /* !__linux__ */
 
 static void i915_ttm_tt_shmem_unpopulate(struct ttm_tt *ttm)
 {
-	STUB();
-#ifdef notyet
 	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
 	bool backup = ttm->page_flags & TTM_TT_FLAG_SWAPPED;
 	struct sg_table *st = &i915_tt->cached_rsgt.table;
 
+#ifdef __linux__
 	shmem_sg_free_table(st, file_inode(i915_tt->filp)->i_mapping,
 			    backup, backup);
+#else
+	const size_t size = (size_t)ttm->num_pages << PAGE_SHIFT;
+	shmem_sg_free_table(st, NULL, backup, backup, i915_tt->filp, size);
 #endif
 }
 
@@ -334,8 +388,6 @@ static int i915_ttm_tt_populate(struct ttm_device *bdev,
 
 static void i915_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
 {
-	STUB();
-#ifdef notyet
 	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
 	struct sg_table *st = &i915_tt->cached_rsgt.table;
 
@@ -348,7 +400,6 @@ static void i915_ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
 		sg_free_table(st);
 		ttm_pool_free(&bdev->pool, ttm);
 	}
-#endif
 }
 
 static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
@@ -356,7 +407,11 @@ static void i915_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
 	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
 
 	if (i915_tt->filp)
+#ifdef __linux__
 		fput(i915_tt->filp);
+#else
+		uao_detach(i915_tt->filp);
+#endif
 
 	ttm_tt_fini(ttm);
 	i915_refct_sgt_put(&i915_tt->cached_rsgt);
@@ -456,13 +511,14 @@ int i915_ttm_purge(struct drm_i915_gem_object *obj)
 #ifdef __linux__
 			shmem_truncate_range(file_inode(i915_tt->filp),
 					     0, (loff_t)-1);
+			fput(fetch_and_zero(&i915_tt->filp));
 #else
-			rw_enter(obj->base.uao->vmobjlock, RW_WRITE);
-			obj->base.uao->pgops->pgo_flush(obj->base.uao, 0,
+			rw_enter(i915_tt->filp->vmobjlock, RW_WRITE);
+			i915_tt->filp->pgops->pgo_flush(i915_tt->filp, 0,
 			    obj->base.size, PGO_ALLPAGES | PGO_FREE);
-			rw_exit(obj->base.uao->vmobjlock);
+			rw_exit(i915_tt->filp->vmobjlock);
+			uao_detach(fetch_and_zero(&i915_tt->filp));
 #endif
-			fput(fetch_and_zero(&i915_tt->filp));
 		}
 	}
 
@@ -544,9 +600,6 @@ static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)
 
 static struct i915_refct_sgt *i915_ttm_tt_get_st(struct ttm_tt *ttm)
 {
-	STUB();
-	return ERR_PTR(-ENOSYS);
-#ifdef notyet
 	struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
 	struct sg_table *st;
 	int ret;
@@ -571,7 +624,6 @@ static struct i915_refct_sgt *i915_ttm_tt_get_st(struct ttm_tt *ttm)
 	}
 
 	return i915_refct_sgt_get(&i915_tt->cached_rsgt);
-#endif
 }
 
 /**
diff --git sys/dev/pci/drm/i915/i915_pci.c sys/dev/pci/drm/i915/i915_pci.c
index 37fe0367e7b..3aea0d1c4b2 100644
--- sys/dev/pci/drm/i915/i915_pci.c
+++ sys/dev/pci/drm/i915/i915_pci.c
@@ -738,7 +738,6 @@ static const struct intel_device_info adl_p_info = {
 
 static const struct intel_device_info dg2_info = {
 	DG2_FEATURES,
-	.require_force_probe = 1,
 };
 
 static const struct intel_device_info ats_m_info = {
diff --git sys/dev/pci/drm/include/linux/scatterlist.h sys/dev/pci/drm/include/linux/scatterlist.h
index fed5b3a399a..d1e02c69791 100644
--- sys/dev/pci/drm/include/linux/scatterlist.h
+++ sys/dev/pci/drm/include/linux/scatterlist.h
@@ -59,6 +59,9 @@ sg_next(struct scatterlist *sgl)
 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
 void sg_free_table(struct sg_table *);
 
+int sg_alloc_table_from_pages_segment(struct sg_table *, struct vm_page **,
+    unsigned int, unsigned int, unsigned long, unsigned int, gfp_t);
+
 static inline void
 sg_mark_end(struct scatterlist *sgl)
 {