@@ -812,6 +812,31 @@ __drm_gpuvm_bo_list_add(struct drm_gpuvm *gpuvm, spinlock_t *lock,
812812 cond_spin_unlock (lock , !!lock );
813813}
814814
815+ /**
816+ * drm_gpuvm_bo_is_zombie() - check whether this vm_bo is scheduled for cleanup
817+ * @vm_bo: the &drm_gpuvm_bo
818+ *
819+ * When a vm_bo is scheduled for cleanup using the bo_defer list, it is not
820+ * immediately removed from the evict and extobj lists. Therefore, anyone
821+ * iterating these lists should skip entries that are being destroyed.
822+ *
823+ * Checking the refcount without incrementing it is okay as long as the lock
824+ * protecting the evict/extobj list is held for as long as you are using the
825+ * vm_bo, because even if the refcount hits zero while you are using it, freeing
826+ * the vm_bo requires taking the list's lock.
827+ *
828+ * Zombie entries can be observed on the evict and extobj lists regardless of
829+ * whether DRM_GPUVM_RESV_PROTECTED is used, but they remain on the lists for a
830+ * longer time when the resv lock is used because we can't take the resv lock
831+ * during run_job() in immediate mode, meaning that they need to remain on the
832+ * lists until drm_gpuvm_bo_deferred_cleanup() is called.
833+ */
834+ static bool
835+ drm_gpuvm_bo_is_zombie (struct drm_gpuvm_bo * vm_bo )
836+ {
837+ return !kref_read (& vm_bo -> kref );
838+ }
839+
815840/**
816841 * drm_gpuvm_bo_list_add() - insert a vm_bo into the given list
817842 * @__vm_bo: the &drm_gpuvm_bo
@@ -1017,6 +1042,8 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name,
10171042 INIT_LIST_HEAD (& gpuvm -> evict .list );
10181043 spin_lock_init (& gpuvm -> evict .lock );
10191044
1045+ init_llist_head (& gpuvm -> bo_defer );
1046+
10201047 kref_init (& gpuvm -> kref );
10211048
10221049 gpuvm -> name = name ? name : "unknown" ;
@@ -1058,6 +1085,8 @@ drm_gpuvm_fini(struct drm_gpuvm *gpuvm)
10581085 "Extobj list should be empty.\n" );
10591086 drm_WARN (gpuvm -> drm , !list_empty (& gpuvm -> evict .list ),
10601087 "Evict list should be empty.\n" );
1088+ drm_WARN (gpuvm -> drm , !llist_empty (& gpuvm -> bo_defer ),
1089+ "VM BO cleanup list should be empty.\n" );
10611090
10621091 drm_gem_object_put (gpuvm -> r_obj );
10631092}
@@ -1153,6 +1182,9 @@ drm_gpuvm_prepare_objects_locked(struct drm_gpuvm *gpuvm,
11531182
11541183 drm_gpuvm_resv_assert_held (gpuvm );
11551184 list_for_each_entry (vm_bo , & gpuvm -> extobj .list , list .entry .extobj ) {
1185+ if (drm_gpuvm_bo_is_zombie (vm_bo ))
1186+ continue ;
1187+
11561188 ret = exec_prepare_obj (exec , vm_bo -> obj , num_fences );
11571189 if (ret )
11581190 break ;
@@ -1396,6 +1428,9 @@ drm_gpuvm_validate_locked(struct drm_gpuvm *gpuvm, struct drm_exec *exec)
13961428
13971429 list_for_each_entry_safe (vm_bo , next , & gpuvm -> evict .list ,
13981430 list .entry .evict ) {
1431+ if (drm_gpuvm_bo_is_zombie (vm_bo ))
1432+ continue ;
1433+
13991434 ret = ops -> vm_bo_validate (vm_bo , exec );
14001435 if (ret )
14011436 break ;
@@ -1496,6 +1531,7 @@ drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm,
14961531
14971532 INIT_LIST_HEAD (& vm_bo -> list .entry .extobj );
14981533 INIT_LIST_HEAD (& vm_bo -> list .entry .evict );
1534+ init_llist_node (& vm_bo -> list .entry .bo_defer );
14991535
15001536 return vm_bo ;
15011537}
@@ -1557,6 +1593,126 @@ drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo)
15571593}
15581594EXPORT_SYMBOL_GPL (drm_gpuvm_bo_put );
15591595
1596+ /*
1597+ * drm_gpuvm_bo_into_zombie() - called when the vm_bo becomes a zombie due to
1598+ * deferred cleanup
1599+ *
1600+ * If deferred cleanup is used, then this must be called right after the vm_bo
1601+ * refcount drops to zero. Must be called with GEM mutex held. After releasing
1602+ * the GEM mutex, drm_gpuvm_bo_defer_zombie_cleanup() must be called.
1603+ */
1604+ static void
1605+ drm_gpuvm_bo_into_zombie (struct kref * kref )
1606+ {
1607+ struct drm_gpuvm_bo * vm_bo = container_of (kref , struct drm_gpuvm_bo ,
1608+ kref );
1609+
1610+ if (!drm_gpuvm_resv_protected (vm_bo -> vm )) {
1611+ drm_gpuvm_bo_list_del (vm_bo , extobj , true);
1612+ drm_gpuvm_bo_list_del (vm_bo , evict , true);
1613+ }
1614+
1615+ list_del (& vm_bo -> list .entry .gem );
1616+ }
1617+
1618+ /*
1619+ * drm_gpuvm_bo_defer_zombie_cleanup() - adds a new zombie vm_bo to the
1620+ * bo_defer list
1621+ *
1622+ * Called after drm_gpuvm_bo_into_zombie(). GEM mutex must not be held.
1623+ *
1624+ * It's important that the GEM stays alive for the duration in which we hold
1625+ * the mutex, but the instant we add the vm_bo to bo_defer, another thread
1626+ * might call drm_gpuvm_bo_deferred_cleanup() and put the GEM. Therefore, to
1627+ * avoid kfreeing a mutex we are holding, the GEM mutex must be released
1628+ * *before* calling this function.
1629+ */
1630+ static void
1631+ drm_gpuvm_bo_defer_zombie_cleanup (struct drm_gpuvm_bo * vm_bo )
1632+ {
1633+ llist_add (& vm_bo -> list .entry .bo_defer , & vm_bo -> vm -> bo_defer );
1634+ }
1635+
1636+ static void
1637+ drm_gpuvm_bo_defer_free (struct kref * kref )
1638+ {
1639+ struct drm_gpuvm_bo * vm_bo = container_of (kref , struct drm_gpuvm_bo ,
1640+ kref );
1641+
1642+ drm_gpuvm_bo_into_zombie (kref );
1643+ mutex_unlock (& vm_bo -> obj -> gpuva .lock );
1644+ drm_gpuvm_bo_defer_zombie_cleanup (vm_bo );
1645+ }
1646+
1647+ /**
1648+ * drm_gpuvm_bo_put_deferred() - drop a struct drm_gpuvm_bo reference with
1649+ * deferred cleanup
1650+ * @vm_bo: the &drm_gpuvm_bo to release the reference of
1651+ *
1652+ * This releases a reference to @vm_bo.
1653+ *
1654+ * This might take and release the GEMs GPUVA lock. You should call
1655+ * drm_gpuvm_bo_deferred_cleanup() later to complete the cleanup process.
1656+ *
1657+ * Returns: true if vm_bo is being destroyed, false otherwise.
1658+ */
1659+ bool
1660+ drm_gpuvm_bo_put_deferred (struct drm_gpuvm_bo * vm_bo )
1661+ {
1662+ if (!vm_bo )
1663+ return false;
1664+
1665+ drm_WARN_ON (vm_bo -> vm -> drm , !drm_gpuvm_immediate_mode (vm_bo -> vm ));
1666+
1667+ return !!kref_put_mutex (& vm_bo -> kref ,
1668+ drm_gpuvm_bo_defer_free ,
1669+ & vm_bo -> obj -> gpuva .lock );
1670+ }
1671+ EXPORT_SYMBOL_GPL (drm_gpuvm_bo_put_deferred );
1672+
1673+ /**
1674+ * drm_gpuvm_bo_deferred_cleanup() - clean up BOs in the deferred list
1675+ * deferred cleanup
1676+ * @gpuvm: the VM to clean up
1677+ *
1678+ * Cleans up &drm_gpuvm_bo instances in the deferred cleanup list.
1679+ */
1680+ void
1681+ drm_gpuvm_bo_deferred_cleanup (struct drm_gpuvm * gpuvm )
1682+ {
1683+ const struct drm_gpuvm_ops * ops = gpuvm -> ops ;
1684+ struct drm_gpuvm_bo * vm_bo ;
1685+ struct drm_gem_object * obj ;
1686+ struct llist_node * bo_defer ;
1687+
1688+ bo_defer = llist_del_all (& gpuvm -> bo_defer );
1689+ if (!bo_defer )
1690+ return ;
1691+
1692+ if (drm_gpuvm_resv_protected (gpuvm )) {
1693+ dma_resv_lock (drm_gpuvm_resv (gpuvm ), NULL );
1694+ llist_for_each_entry (vm_bo , bo_defer , list .entry .bo_defer ) {
1695+ drm_gpuvm_bo_list_del (vm_bo , extobj , false);
1696+ drm_gpuvm_bo_list_del (vm_bo , evict , false);
1697+ }
1698+ dma_resv_unlock (drm_gpuvm_resv (gpuvm ));
1699+ }
1700+
1701+ while (bo_defer ) {
1702+ vm_bo = llist_entry (bo_defer , struct drm_gpuvm_bo , list .entry .bo_defer );
1703+ bo_defer = bo_defer -> next ;
1704+ obj = vm_bo -> obj ;
1705+ if (ops && ops -> vm_bo_free )
1706+ ops -> vm_bo_free (vm_bo );
1707+ else
1708+ kfree (vm_bo );
1709+
1710+ drm_gpuvm_put (gpuvm );
1711+ drm_gem_object_put (obj );
1712+ }
1713+ }
1714+ EXPORT_SYMBOL_GPL (drm_gpuvm_bo_deferred_cleanup );
1715+
15601716static struct drm_gpuvm_bo *
15611717__drm_gpuvm_bo_find (struct drm_gpuvm * gpuvm ,
15621718 struct drm_gem_object * obj )
@@ -1884,6 +2040,40 @@ drm_gpuva_unlink(struct drm_gpuva *va)
18842040}
18852041EXPORT_SYMBOL_GPL (drm_gpuva_unlink );
18862042
2043+ /**
2044+ * drm_gpuva_unlink_defer() - unlink a &drm_gpuva with deferred vm_bo cleanup
2045+ * @va: the &drm_gpuva to unlink
2046+ *
2047+ * Similar to drm_gpuva_unlink(), but uses drm_gpuvm_bo_put_deferred() and takes
2048+ * the lock for the caller.
2049+ */
2050+ void
2051+ drm_gpuva_unlink_defer (struct drm_gpuva * va )
2052+ {
2053+ struct drm_gem_object * obj = va -> gem .obj ;
2054+ struct drm_gpuvm_bo * vm_bo = va -> vm_bo ;
2055+ bool should_defer_bo ;
2056+
2057+ if (unlikely (!obj ))
2058+ return ;
2059+
2060+ drm_WARN_ON (vm_bo -> vm -> drm , !drm_gpuvm_immediate_mode (vm_bo -> vm ));
2061+
2062+ mutex_lock (& obj -> gpuva .lock );
2063+ list_del_init (& va -> gem .entry );
2064+
2065+ /*
2066+ * This is drm_gpuvm_bo_put_deferred() except we already hold the mutex.
2067+ */
2068+ should_defer_bo = kref_put (& vm_bo -> kref , drm_gpuvm_bo_into_zombie );
2069+ mutex_unlock (& obj -> gpuva .lock );
2070+ if (should_defer_bo )
2071+ drm_gpuvm_bo_defer_zombie_cleanup (vm_bo );
2072+
2073+ va -> vm_bo = NULL ;
2074+ }
2075+ EXPORT_SYMBOL_GPL (drm_gpuva_unlink_defer );
2076+
18872077/**
18882078 * drm_gpuva_find_first() - find the first &drm_gpuva in the given range
18892079 * @gpuvm: the &drm_gpuvm to search in
0 commit comments