1*658ebeacSTomeu Vizoso // SPDX-License-Identifier: GPL-2.0-only 2*658ebeacSTomeu Vizoso /* Copyright 2024-2025 Tomeu Vizoso <tomeu@tomeuvizoso.net> */ 3*658ebeacSTomeu Vizoso 4*658ebeacSTomeu Vizoso #include <drm/drm_device.h> 5*658ebeacSTomeu Vizoso #include <drm/drm_utils.h> 6*658ebeacSTomeu Vizoso #include <drm/rocket_accel.h> 7*658ebeacSTomeu Vizoso #include <linux/dma-mapping.h> 8*658ebeacSTomeu Vizoso #include <linux/iommu.h> 9*658ebeacSTomeu Vizoso 10*658ebeacSTomeu Vizoso #include "rocket_drv.h" 11*658ebeacSTomeu Vizoso #include "rocket_gem.h" 12*658ebeacSTomeu Vizoso 13*658ebeacSTomeu Vizoso static void rocket_gem_bo_free(struct drm_gem_object *obj) 14*658ebeacSTomeu Vizoso { 15*658ebeacSTomeu Vizoso struct rocket_gem_object *bo = to_rocket_bo(obj); 16*658ebeacSTomeu Vizoso struct rocket_file_priv *rocket_priv = bo->driver_priv; 17*658ebeacSTomeu Vizoso size_t unmapped; 18*658ebeacSTomeu Vizoso 19*658ebeacSTomeu Vizoso drm_WARN_ON(obj->dev, refcount_read(&bo->base.pages_use_count) > 1); 20*658ebeacSTomeu Vizoso 21*658ebeacSTomeu Vizoso unmapped = iommu_unmap(bo->domain->domain, bo->mm.start, bo->size); 22*658ebeacSTomeu Vizoso drm_WARN_ON(obj->dev, unmapped != bo->size); 23*658ebeacSTomeu Vizoso 24*658ebeacSTomeu Vizoso mutex_lock(&rocket_priv->mm_lock); 25*658ebeacSTomeu Vizoso drm_mm_remove_node(&bo->mm); 26*658ebeacSTomeu Vizoso mutex_unlock(&rocket_priv->mm_lock); 27*658ebeacSTomeu Vizoso 28*658ebeacSTomeu Vizoso rocket_iommu_domain_put(bo->domain); 29*658ebeacSTomeu Vizoso bo->domain = NULL; 30*658ebeacSTomeu Vizoso 31*658ebeacSTomeu Vizoso drm_gem_shmem_free(&bo->base); 32*658ebeacSTomeu Vizoso } 33*658ebeacSTomeu Vizoso 34*658ebeacSTomeu Vizoso static const struct drm_gem_object_funcs rocket_gem_funcs = { 35*658ebeacSTomeu Vizoso .free = rocket_gem_bo_free, 36*658ebeacSTomeu Vizoso .print_info = drm_gem_shmem_object_print_info, 37*658ebeacSTomeu Vizoso .pin = drm_gem_shmem_object_pin, 38*658ebeacSTomeu Vizoso .unpin = drm_gem_shmem_object_unpin, 39*658ebeacSTomeu Vizoso .get_sg_table = drm_gem_shmem_object_get_sg_table, 40*658ebeacSTomeu Vizoso .vmap = drm_gem_shmem_object_vmap, 41*658ebeacSTomeu Vizoso .vunmap = drm_gem_shmem_object_vunmap, 42*658ebeacSTomeu Vizoso .mmap = drm_gem_shmem_object_mmap, 43*658ebeacSTomeu Vizoso .vm_ops = &drm_gem_shmem_vm_ops, 44*658ebeacSTomeu Vizoso }; 45*658ebeacSTomeu Vizoso 46*658ebeacSTomeu Vizoso struct drm_gem_object *rocket_gem_create_object(struct drm_device *dev, size_t size) 47*658ebeacSTomeu Vizoso { 48*658ebeacSTomeu Vizoso struct rocket_gem_object *obj; 49*658ebeacSTomeu Vizoso 50*658ebeacSTomeu Vizoso obj = kzalloc(sizeof(*obj), GFP_KERNEL); 51*658ebeacSTomeu Vizoso if (!obj) 52*658ebeacSTomeu Vizoso return ERR_PTR(-ENOMEM); 53*658ebeacSTomeu Vizoso 54*658ebeacSTomeu Vizoso obj->base.base.funcs = &rocket_gem_funcs; 55*658ebeacSTomeu Vizoso 56*658ebeacSTomeu Vizoso return &obj->base.base; 57*658ebeacSTomeu Vizoso } 58*658ebeacSTomeu Vizoso 59*658ebeacSTomeu Vizoso int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *file) 60*658ebeacSTomeu Vizoso { 61*658ebeacSTomeu Vizoso struct rocket_file_priv *rocket_priv = file->driver_priv; 62*658ebeacSTomeu Vizoso struct drm_rocket_create_bo *args = data; 63*658ebeacSTomeu Vizoso struct drm_gem_shmem_object *shmem_obj; 64*658ebeacSTomeu Vizoso struct rocket_gem_object *rkt_obj; 65*658ebeacSTomeu Vizoso struct drm_gem_object *gem_obj; 66*658ebeacSTomeu Vizoso struct sg_table *sgt; 67*658ebeacSTomeu Vizoso int ret; 68*658ebeacSTomeu Vizoso 69*658ebeacSTomeu Vizoso shmem_obj = drm_gem_shmem_create(dev, args->size); 70*658ebeacSTomeu Vizoso if (IS_ERR(shmem_obj)) 71*658ebeacSTomeu Vizoso return PTR_ERR(shmem_obj); 72*658ebeacSTomeu Vizoso 73*658ebeacSTomeu Vizoso gem_obj = &shmem_obj->base; 74*658ebeacSTomeu Vizoso rkt_obj = to_rocket_bo(gem_obj); 75*658ebeacSTomeu Vizoso 76*658ebeacSTomeu Vizoso rkt_obj->driver_priv = rocket_priv; 77*658ebeacSTomeu Vizoso rkt_obj->domain = rocket_iommu_domain_get(rocket_priv); 78*658ebeacSTomeu Vizoso rkt_obj->size = args->size; 79*658ebeacSTomeu Vizoso rkt_obj->offset = 0; 80*658ebeacSTomeu Vizoso 81*658ebeacSTomeu Vizoso ret = drm_gem_handle_create(file, gem_obj, &args->handle); 82*658ebeacSTomeu Vizoso drm_gem_object_put(gem_obj); 83*658ebeacSTomeu Vizoso if (ret) 84*658ebeacSTomeu Vizoso goto err; 85*658ebeacSTomeu Vizoso 86*658ebeacSTomeu Vizoso sgt = drm_gem_shmem_get_pages_sgt(shmem_obj); 87*658ebeacSTomeu Vizoso if (IS_ERR(sgt)) { 88*658ebeacSTomeu Vizoso ret = PTR_ERR(sgt); 89*658ebeacSTomeu Vizoso goto err; 90*658ebeacSTomeu Vizoso } 91*658ebeacSTomeu Vizoso 92*658ebeacSTomeu Vizoso mutex_lock(&rocket_priv->mm_lock); 93*658ebeacSTomeu Vizoso ret = drm_mm_insert_node_generic(&rocket_priv->mm, &rkt_obj->mm, 94*658ebeacSTomeu Vizoso rkt_obj->size, PAGE_SIZE, 95*658ebeacSTomeu Vizoso 0, 0); 96*658ebeacSTomeu Vizoso mutex_unlock(&rocket_priv->mm_lock); 97*658ebeacSTomeu Vizoso 98*658ebeacSTomeu Vizoso ret = iommu_map_sgtable(rocket_priv->domain->domain, 99*658ebeacSTomeu Vizoso rkt_obj->mm.start, 100*658ebeacSTomeu Vizoso shmem_obj->sgt, 101*658ebeacSTomeu Vizoso IOMMU_READ | IOMMU_WRITE); 102*658ebeacSTomeu Vizoso if (ret < 0 || ret < args->size) { 103*658ebeacSTomeu Vizoso drm_err(dev, "failed to map buffer: size=%d request_size=%u\n", 104*658ebeacSTomeu Vizoso ret, args->size); 105*658ebeacSTomeu Vizoso ret = -ENOMEM; 106*658ebeacSTomeu Vizoso goto err_remove_node; 107*658ebeacSTomeu Vizoso } 108*658ebeacSTomeu Vizoso 109*658ebeacSTomeu Vizoso /* iommu_map_sgtable might have aligned the size */ 110*658ebeacSTomeu Vizoso rkt_obj->size = ret; 111*658ebeacSTomeu Vizoso args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); 112*658ebeacSTomeu Vizoso args->dma_address = rkt_obj->mm.start; 113*658ebeacSTomeu Vizoso 114*658ebeacSTomeu Vizoso return 0; 115*658ebeacSTomeu Vizoso 116*658ebeacSTomeu Vizoso err_remove_node: 117*658ebeacSTomeu Vizoso mutex_lock(&rocket_priv->mm_lock); 118*658ebeacSTomeu Vizoso drm_mm_remove_node(&rkt_obj->mm); 119*658ebeacSTomeu Vizoso mutex_unlock(&rocket_priv->mm_lock); 120*658ebeacSTomeu Vizoso 121*658ebeacSTomeu Vizoso err: 122*658ebeacSTomeu Vizoso drm_gem_shmem_object_free(gem_obj); 123*658ebeacSTomeu Vizoso 124*658ebeacSTomeu Vizoso return ret; 125*658ebeacSTomeu Vizoso } 126