linux/drivers/gpu/drm/msm/msm_gem.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * Copyright (C) 2013 Red Hat
   4 * Author: Rob Clark <robdclark@gmail.com>
   5 */
   6
   7#ifndef __MSM_GEM_H__
   8#define __MSM_GEM_H__
   9
  10#include <linux/kref.h>
  11#include <linux/dma-resv.h>
  12#include "drm/gpu_scheduler.h"
  13#include "msm_drv.h"
  14
  15/* Make all GEM related WARN_ON()s ratelimited.. when things go wrong they
  16 * tend to go wrong 1000s of times in a short timespan.
  17 */
  18#define GEM_WARN_ON(x)  WARN_RATELIMIT(x, "%s", __stringify(x))
  19
  20/* Additional internal-use only BO flags: */
  21#define MSM_BO_STOLEN        0x10000000    /* try to use stolen/splash memory */
  22#define MSM_BO_MAP_PRIV      0x20000000    /* use IOMMU_PRIV when mapping */
  23
  24struct msm_gem_address_space {
  25        const char *name;
  26        /* NOTE: mm managed at the page level, size is in # of pages
  27         * and position mm_node->start is in # of pages:
  28         */
  29        struct drm_mm mm;
  30        spinlock_t lock; /* Protects drm_mm node allocation/removal */
  31        struct msm_mmu *mmu;
  32        struct kref kref;
  33
  34        /* For address spaces associated with a specific process, this
  35         * will be non-NULL:
  36         */
  37        struct pid *pid;
  38};
  39
  40struct msm_gem_vma {
  41        struct drm_mm_node node;
  42        uint64_t iova;
  43        struct msm_gem_address_space *aspace;
  44        struct list_head list;    /* node in msm_gem_object::vmas */
  45        bool mapped;
  46        int inuse;
  47};
  48
  49struct msm_gem_object {
  50        struct drm_gem_object base;
  51
  52        uint32_t flags;
  53
  54        /**
  55         * Advice: are the backing pages purgeable?
  56         */
  57        uint8_t madv;
  58
  59        /**
  60         * Is object on inactive_dontneed list (ie. counted in priv->shrinkable_count)?
  61         */
  62        bool dontneed : 1;
  63
  64        /**
  65         * Is object evictable (ie. counted in priv->evictable_count)?
  66         */
  67        bool evictable : 1;
  68
  69        /**
  70         * count of active vmap'ing
  71         */
  72        uint8_t vmap_count;
  73
  74        /**
  75         * Node in list of all objects (mainly for debugfs, protected by
  76         * priv->obj_lock
  77         */
  78        struct list_head node;
  79
  80        /**
  81         * An object is either:
  82         *  inactive - on priv->inactive_dontneed or priv->inactive_willneed
  83         *     (depending on purgeability status)
  84         *  active   - on one one of the gpu's active_list..  well, at
  85         *     least for now we don't have (I don't think) hw sync between
  86         *     2d and 3d one devices which have both, meaning we need to
  87         *     block on submit if a bo is already on other ring
  88         */
  89        struct list_head mm_list;
  90
  91        struct page **pages;
  92        struct sg_table *sgt;
  93        void *vaddr;
  94
  95        struct list_head vmas;    /* list of msm_gem_vma */
  96
  97        /* For physically contiguous buffers.  Used when we don't have
  98         * an IOMMU.  Also used for stolen/splashscreen buffer.
  99         */
 100        struct drm_mm_node *vram_node;
 101
 102        char name[32]; /* Identifier to print for the debugfs files */
 103
 104        int active_count;
 105        int pin_count;
 106};
 107#define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
 108
 109uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj);
 110int msm_gem_get_iova(struct drm_gem_object *obj,
 111                struct msm_gem_address_space *aspace, uint64_t *iova);
 112int msm_gem_get_and_pin_iova_range(struct drm_gem_object *obj,
 113                struct msm_gem_address_space *aspace, uint64_t *iova,
 114                u64 range_start, u64 range_end);
 115int msm_gem_get_and_pin_iova_locked(struct drm_gem_object *obj,
 116                struct msm_gem_address_space *aspace, uint64_t *iova);
 117int msm_gem_get_and_pin_iova(struct drm_gem_object *obj,
 118                struct msm_gem_address_space *aspace, uint64_t *iova);
 119uint64_t msm_gem_iova(struct drm_gem_object *obj,
 120                struct msm_gem_address_space *aspace);
 121void msm_gem_unpin_iova_locked(struct drm_gem_object *obj,
 122                struct msm_gem_address_space *aspace);
 123void msm_gem_unpin_iova(struct drm_gem_object *obj,
 124                struct msm_gem_address_space *aspace);
 125struct page **msm_gem_get_pages(struct drm_gem_object *obj);
 126void msm_gem_put_pages(struct drm_gem_object *obj);
 127int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
 128                struct drm_mode_create_dumb *args);
 129int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
 130                uint32_t handle, uint64_t *offset);
 131void *msm_gem_get_vaddr_locked(struct drm_gem_object *obj);
 132void *msm_gem_get_vaddr(struct drm_gem_object *obj);
 133void *msm_gem_get_vaddr_active(struct drm_gem_object *obj);
 134void msm_gem_put_vaddr_locked(struct drm_gem_object *obj);
 135void msm_gem_put_vaddr(struct drm_gem_object *obj);
 136int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv);
 137void msm_gem_active_get(struct drm_gem_object *obj, struct msm_gpu *gpu);
 138void msm_gem_active_put(struct drm_gem_object *obj);
 139int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout);
 140int msm_gem_cpu_fini(struct drm_gem_object *obj);
 141void msm_gem_free_object(struct drm_gem_object *obj);
 142int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
 143                uint32_t size, uint32_t flags, uint32_t *handle, char *name);
 144struct drm_gem_object *msm_gem_new(struct drm_device *dev,
 145                uint32_t size, uint32_t flags);
 146void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
 147                uint32_t flags, struct msm_gem_address_space *aspace,
 148                struct drm_gem_object **bo, uint64_t *iova);
 149void msm_gem_kernel_put(struct drm_gem_object *bo,
 150                struct msm_gem_address_space *aspace);
 151struct drm_gem_object *msm_gem_import(struct drm_device *dev,
 152                struct dma_buf *dmabuf, struct sg_table *sgt);
 153__printf(2, 3)
 154void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...);
 155
 156#ifdef CONFIG_DEBUG_FS
 157struct msm_gem_stats {
 158        struct {
 159                unsigned count;
 160                size_t size;
 161        } all, active, resident, purgeable, purged;
 162};
 163
 164void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m,
 165                struct msm_gem_stats *stats);
 166void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
 167#endif
 168
 169static inline void
 170msm_gem_lock(struct drm_gem_object *obj)
 171{
 172        dma_resv_lock(obj->resv, NULL);
 173}
 174
 175static inline bool __must_check
 176msm_gem_trylock(struct drm_gem_object *obj)
 177{
 178        return dma_resv_trylock(obj->resv);
 179}
 180
 181static inline int
 182msm_gem_lock_interruptible(struct drm_gem_object *obj)
 183{
 184        return dma_resv_lock_interruptible(obj->resv, NULL);
 185}
 186
 187static inline void
 188msm_gem_unlock(struct drm_gem_object *obj)
 189{
 190        dma_resv_unlock(obj->resv);
 191}
 192
 193static inline bool
 194msm_gem_is_locked(struct drm_gem_object *obj)
 195{
 196        return dma_resv_is_locked(obj->resv);
 197}
 198
 199static inline bool is_active(struct msm_gem_object *msm_obj)
 200{
 201        GEM_WARN_ON(!msm_gem_is_locked(&msm_obj->base));
 202        return msm_obj->active_count;
 203}
 204
 205/* imported/exported objects are not purgeable: */
 206static inline bool is_unpurgeable(struct msm_gem_object *msm_obj)
 207{
 208        return msm_obj->base.import_attach || msm_obj->pin_count;
 209}
 210
 211static inline bool is_purgeable(struct msm_gem_object *msm_obj)
 212{
 213        return (msm_obj->madv == MSM_MADV_DONTNEED) && msm_obj->sgt &&
 214                        !is_unpurgeable(msm_obj);
 215}
 216
 217static inline bool is_vunmapable(struct msm_gem_object *msm_obj)
 218{
 219        GEM_WARN_ON(!msm_gem_is_locked(&msm_obj->base));
 220        return (msm_obj->vmap_count == 0) && msm_obj->vaddr;
 221}
 222
 223static inline void mark_purgeable(struct msm_gem_object *msm_obj)
 224{
 225        struct msm_drm_private *priv = msm_obj->base.dev->dev_private;
 226
 227        GEM_WARN_ON(!mutex_is_locked(&priv->mm_lock));
 228
 229        if (is_unpurgeable(msm_obj))
 230                return;
 231
 232        if (GEM_WARN_ON(msm_obj->dontneed))
 233                return;
 234
 235        priv->shrinkable_count += msm_obj->base.size >> PAGE_SHIFT;
 236        msm_obj->dontneed = true;
 237}
 238
 239static inline void mark_unpurgeable(struct msm_gem_object *msm_obj)
 240{
 241        struct msm_drm_private *priv = msm_obj->base.dev->dev_private;
 242
 243        GEM_WARN_ON(!mutex_is_locked(&priv->mm_lock));
 244
 245        if (is_unpurgeable(msm_obj))
 246                return;
 247
 248        if (GEM_WARN_ON(!msm_obj->dontneed))
 249                return;
 250
 251        priv->shrinkable_count -= msm_obj->base.size >> PAGE_SHIFT;
 252        GEM_WARN_ON(priv->shrinkable_count < 0);
 253        msm_obj->dontneed = false;
 254}
 255
 256static inline bool is_unevictable(struct msm_gem_object *msm_obj)
 257{
 258        return is_unpurgeable(msm_obj) || msm_obj->vaddr;
 259}
 260
 261static inline void mark_evictable(struct msm_gem_object *msm_obj)
 262{
 263        struct msm_drm_private *priv = msm_obj->base.dev->dev_private;
 264
 265        WARN_ON(!mutex_is_locked(&priv->mm_lock));
 266
 267        if (is_unevictable(msm_obj))
 268                return;
 269
 270        if (WARN_ON(msm_obj->evictable))
 271                return;
 272
 273        priv->evictable_count += msm_obj->base.size >> PAGE_SHIFT;
 274        msm_obj->evictable = true;
 275}
 276
 277static inline void mark_unevictable(struct msm_gem_object *msm_obj)
 278{
 279        struct msm_drm_private *priv = msm_obj->base.dev->dev_private;
 280
 281        WARN_ON(!mutex_is_locked(&priv->mm_lock));
 282
 283        if (is_unevictable(msm_obj))
 284                return;
 285
 286        if (WARN_ON(!msm_obj->evictable))
 287                return;
 288
 289        priv->evictable_count -= msm_obj->base.size >> PAGE_SHIFT;
 290        WARN_ON(priv->evictable_count < 0);
 291        msm_obj->evictable = false;
 292}
 293
 294void msm_gem_purge(struct drm_gem_object *obj);
 295void msm_gem_evict(struct drm_gem_object *obj);
 296void msm_gem_vunmap(struct drm_gem_object *obj);
 297
 298/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
 299 * associated with the cmdstream submission for synchronization (and
 300 * make it easier to unwind when things go wrong, etc).
 301 */
 302struct msm_gem_submit {
 303        struct drm_sched_job base;
 304        struct kref ref;
 305        struct drm_device *dev;
 306        struct msm_gpu *gpu;
 307        struct msm_gem_address_space *aspace;
 308        struct list_head node;   /* node in ring submit list */
 309        struct ww_acquire_ctx ticket;
 310        uint32_t seqno;         /* Sequence number of the submit on the ring */
 311
 312        /* Array of struct dma_fence * to block on before submitting this job.
 313         */
 314        struct xarray deps;
 315        unsigned long last_dep;
 316
 317        /* Hw fence, which is created when the scheduler executes the job, and
 318         * is signaled when the hw finishes (via seqno write from cmdstream)
 319         */
 320        struct dma_fence *hw_fence;
 321
 322        /* Userspace visible fence, which is signaled by the scheduler after
 323         * the hw_fence is signaled.
 324         */
 325        struct dma_fence *user_fence;
 326
 327        int fence_id;       /* key into queue->fence_idr */
 328        struct msm_gpu_submitqueue *queue;
 329        struct pid *pid;    /* submitting process */
 330        bool fault_dumped;  /* Limit devcoredump dumping to one per submit */
 331        bool valid;         /* true if no cmdstream patching needed */
 332        bool in_rb;         /* "sudo" mode, copy cmds into RB */
 333        struct msm_ringbuffer *ring;
 334        struct msm_file_private *ctx;
 335        unsigned int nr_cmds;
 336        unsigned int nr_bos;
 337        u32 ident;         /* A "identifier" for the submit for logging */
 338        struct {
 339                uint32_t type;
 340                uint32_t size;  /* in dwords */
 341                uint64_t iova;
 342                uint32_t offset;/* in dwords */
 343                uint32_t idx;   /* cmdstream buffer idx in bos[] */
 344                uint32_t nr_relocs;
 345                struct drm_msm_gem_submit_reloc *relocs;
 346        } *cmd;  /* array of size nr_cmds */
 347        struct {
 348                uint32_t flags;
 349                union {
 350                        struct msm_gem_object *obj;
 351                        uint32_t handle;
 352                };
 353                uint64_t iova;
 354        } bos[];
 355};
 356
 357static inline struct msm_gem_submit *to_msm_submit(struct drm_sched_job *job)
 358{
 359        return container_of(job, struct msm_gem_submit, base);
 360}
 361
 362void __msm_gem_submit_destroy(struct kref *kref);
 363
 364static inline void msm_gem_submit_get(struct msm_gem_submit *submit)
 365{
 366        kref_get(&submit->ref);
 367}
 368
 369static inline void msm_gem_submit_put(struct msm_gem_submit *submit)
 370{
 371        kref_put(&submit->ref, __msm_gem_submit_destroy);
 372}
 373
 374void msm_submit_retire(struct msm_gem_submit *submit);
 375
 376/* helper to determine of a buffer in submit should be dumped, used for both
 377 * devcoredump and debugfs cmdstream dumping:
 378 */
 379static inline bool
 380should_dump(struct msm_gem_submit *submit, int idx)
 381{
 382        extern bool rd_full;
 383        return rd_full || (submit->bos[idx].flags & MSM_SUBMIT_BO_DUMP);
 384}
 385
 386#endif /* __MSM_GEM_H__ */
 387