summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c65
1 files changed, 62 insertions, 3 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 2a241a5b12c4..249f07f30951 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -23,6 +23,8 @@
*/
#include <linux/dma-mapping.h>
+#include <linux/cgroup_dmem.h>
+#include <linux/pm_runtime.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/drm_drv.h>
#include <drm/drm_buddy.h>
@@ -905,6 +907,38 @@ static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
.debug = amdgpu_vram_mgr_debug
};
+static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops;
+
+static int amdgpu_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
+ u64 target_bytes, void *priv)
+{
+ struct ttm_resource_manager *man = priv;
+ struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
+ int ret, idx;
+
+ if (!drm_dev_enter(adev_to_drm(adev), &idx))
+ return -ENODEV;
+
+ ret = pm_runtime_get_sync(adev_to_drm(adev)->dev);
+ if (ret < 0) {
+ pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ goto out;
+ }
+
+ ret = ttm_resource_manager_dmem_reclaim(pool, target_bytes, priv);
+
+ pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
+ pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+
+out:
+ drm_dev_exit(idx);
+ return ret;
+}
+
+static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops = {
+ .reclaim = amdgpu_vram_mgr_dmem_reclaim,
+};
+
/**
* amdgpu_vram_mgr_init - init VRAM manager and DRM MM
*
@@ -916,11 +950,9 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{
struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
struct ttm_resource_manager *man = &mgr->manager;
+ struct dmem_cgroup_region *cg;
int err;
- man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram", adev->gmc.real_vram_size);
- if (IS_ERR(man->cg))
- return PTR_ERR(man->cg);
ttm_resource_manager_init(man, &adev->mman.bdev,
adev->gmc.real_vram_size);
@@ -935,6 +967,20 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
if (err)
return err;
+ cg = dmem_cgroup_register_region(&(struct dmem_cgroup_init){
+ .size = adev->gmc.real_vram_size,
+ .ops = &amdgpu_vram_mgr_dmem_ops,
+ .reclaim_priv = man,
+ },
+ "drm/%s/vram", adev_to_drm(adev)->unique);
+ if (IS_ERR(cg)) {
+ gpu_buddy_fini(&mgr->mm);
+ return PTR_ERR(cg);
+ }
+
+ mgr->cg_region = cg;
+ ttm_resource_manager_set_dmem_region(man, cg);
+
ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
ttm_resource_manager_set_used(man, true);
return 0;
@@ -958,6 +1004,19 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
ttm_resource_manager_set_used(man, false);
ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
+
+ /*
+ * Unregister the dmem cgroup region regardless of the evict_all()
+ * result and before any further teardown. This drains in-flight
+ * reclaim callbacks and blocks new ones, so no reclaim can reference
+ * the manager once we start freeing it. It must run after evict_all()
+ * so that ttm_resource_free() can still uncharge via man->cg during
+ * eviction. Clear man->cg afterwards.
+ */
+ dmem_cgroup_unregister_region(mgr->cg_region);
+ mgr->cg_region = NULL;
+ ttm_resource_manager_set_dmem_region(man, NULL);
+
if (ret)
return;