/* SPDX-License-Identifier: GPL-2.0-only *//* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> */ #ifndef __MSM_GPU_H__#define __MSM_GPU_H__ #include <linux/adreno-smmu-priv.h>#include <linux/clk.h>#include <linux/devfreq.h>#include <linux/interconnect.h>#include <linux/pm_opp.h>#include <linux/regulator/consumer.h> #include "msm_drv.h"#include "msm_fence.h"#include "msm_gpu_trace.h"#include "msm_ringbuffer.h"#include "msm_gem.h" struct msm_gem_submit;struct msm_gem_vm_log_entry;struct msm_gpu_state;struct msm_context;struct msm_perfcntr_group;struct msm_perfcntr_stream; struct msm_gpu_config { const char *ioname; unsigned int nr_rings;}; /* So far, with hardware that I've seen to date, we can have: * + zero, one, or two z180 2d cores * + a3xx or a2xx 3d core, which share a common CP (the firmware * for the CP seems to implement some different PM4 packet types * but the basics of cmdstream submission are the same) * * Which means that the eventual complete "class" hierarchy, once * support for all past and present hw is in place, becomes: * + msm_gpu * + adreno_gpu * + a3xx_gpu * + a2xx_gpu * + z180_gpu */struct msm_gpu_funcs { int (*get_param)(struct msm_gpu *gpu, struct msm_context *ctx, uint32_t param, uint64_t *value, uint32_t *len); int (*set_param)(struct msm_gpu *gpu, struct msm_context *ctx, uint32_t param, uint64_t value, uint32_t len); int (*hw_init)(struct msm_gpu *gpu); /** * @ucode_load: Optional hook to upload fw to GEM objs */ int (*ucode_load)(struct msm_gpu *gpu); int (*pm_suspend)(struct msm_gpu *gpu); int (*pm_resume)(struct msm_gpu *gpu); void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit); void (*flush)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); irqreturn_t (*irq)(struct msm_gpu *irq); struct msm_ringbuffer *(*active_ring)(struct msm_gpu *gpu); void (*recover)(struct msm_gpu *gpu); void (*destroy)(struct msm_gpu *gpu);#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state, struct drm_printer *p); /* for generation specific debugfs: */ void (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor);#endif /* note: gpu_busy() can assume that we have been pm_resumed */ u64 (*gpu_busy)(struct msm_gpu *gpu, unsigned long *out_sample_rate); struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu); int (*gpu_state_put)(struct msm_gpu_state *state); unsigned long (*gpu_get_freq)(struct msm_gpu *gpu); /* note: gpu_set_freq() can assume that we have been pm_resumed */ void (*gpu_set_freq)(struct msm_gpu *gpu, struct dev_pm_opp *opp, bool suspended); struct drm_gpuvm *(*create_vm)(struct msm_gpu *gpu, struct platform_device *pdev); struct drm_gpuvm *(*create_private_vm)(struct msm_gpu *gpu, bool kernel_managed); uint32_t (*get_rptr)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); /** * progress: Has the GPU made progress? * * Return true if GPU position in cmdstream has advanced (or changed) * since the last call. To avoid false negatives, this should account * for cmdstream that is buffered in this FIFO upstream of the CP fw. */ bool (*progress)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); void (*sysprof_setup)(struct msm_gpu *gpu, bool force_on); /* Configure perfcntr SELect regs: */ void (*perfcntr_configure)(struct msm_gpu *gpu, struct msm_ringbuffer *ring, const struct msm_perfcntr_stream *stream); /* Flush perfcntrs before reading (optional): */ void (*perfcntr_flush)(struct msm_gpu *gpu);}; /* Additional state for iommu faults: */struct msm_gpu_fault_info { u64 ttbr0; unsigned long iova; int flags; const char *type; const char *block; /* Information about what we think/expect is the current SMMU state, * for example expected_ttbr0 should match smmu_info.ttbr0 which * was read back from SMMU registers. */ phys_addr_t pgtbl_ttbr0; u64 ptes[4]; int asid;}; /** * struct msm_gpu_devfreq - devfreq related state */struct msm_gpu_devfreq { /** @devfreq: devfreq instance */ struct devfreq *devfreq; /** @lock: lock for "suspended", "busy_cycles", and "time" */ struct mutex lock; /** * @idle_freq: * Shadow frequency used while the GPU is idle. From the PoV of * the devfreq governor, we are continuing to sample busyness and * adjust frequency while the GPU is idle, but we use this shadow * value as the GPU is actually clamped to minimum frequency while * it is inactive. */ unsigned long idle_freq; /** * @boost_freq: * A PM QoS constraint to boost min freq for a period of time * until the boost expires. */ struct dev_pm_qos_request boost_freq; /** * @busy_cycles: Last busy counter value, for calculating elapsed busy * cycles since last sampling period. */ u64 busy_cycles; /** @time: Time of last sampling period. */ ktime_t time; /** @idle_time: Time of last transition to idle. */ ktime_t idle_time; /** * @idle_work: * Used to delay clamping to idle freq on active->idle transition. */ struct msm_hrtimer_work idle_work; /** * @boost_work: * Used to reset the boost_constraint after the boost period has * elapsed */ struct msm_hrtimer_work boost_work; /** @suspended: tracks if we're suspended */ bool suspended;}; struct msm_gpu { const char *name; struct drm_device *dev; struct platform_device *pdev; const struct msm_gpu_funcs *funcs; struct adreno_smmu_priv adreno_smmu; struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS]; int nr_rings; /** * sysprof_active: * * The count of contexts that have enabled system profiling. */ refcount_t sysprof_active; /** * lock: * * General lock for serializing all the gpu things. * * TODO move to per-ring locking where feasible (ie. submit/retire * path, etc) */ struct mutex lock; /** * active_submits: * * The number of submitted but not yet retired submits, used to * determine transitions between active and idle. * * Protected by active_lock */ int active_submits; /** lock: protects active_submits and idle/active transitions */ struct mutex active_lock; /* does gpu need hw_init? */ bool needs_hw_init; /** * global_faults: number of GPU hangs not attributed to a particular * address space */ int global_faults; void __iomem *mmio; int irq; struct drm_gpuvm *vm; /* Power Control: */ struct regulator *gpu_reg, *gpu_cx; struct clk_bulk_data *grp_clks; int nr_clocks; struct clk *ebi1_clk, *core_clk, *rbbmtimer_clk; uint32_t fast_rate; /* Hang and Inactivity Detection: */#define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ #define DRM_MSM_HANGCHECK_DEFAULT_PERIOD 500 /* in ms */#define DRM_MSM_HANGCHECK_PROGRESS_RETRIES 3 struct timer_list hangcheck_timer; /* work for handling GPU recovery: */ struct kthread_work recover_work; /** retire_event: notified when submits are retired: */ wait_queue_head_t retire_event; /* work for handling active-list retiring: */ struct kthread_work retire_work; /* worker for retire/recover: */ struct kthread_worker *worker; struct drm_gem_object *memptrs_bo; struct msm_gpu_devfreq devfreq; uint32_t suspend_count; struct msm_gpu_state *crashstate; /* True if the hardware supports expanded apriv (a650 and newer) */ bool hw_apriv; /** * @allow_relocs: allow relocs in SUBMIT ioctl * * Mesa won't use relocs for driver version 1.4.0 and later. This * switch-over happened early enough in mesa a6xx bringup that we * can disallow relocs for a6xx and newer. */ bool allow_relocs; struct thermal_cooling_device *cooling; const struct msm_perfcntr_group *perfcntr_groups; unsigned num_perfcntr_groups; struct msm_perfcntr_state *perfcntrs; /** @perfcntr_lock: protects perfcntr related state */ struct mutex perfcntr_lock;}; static inline struct msm_gpu *dev_to_gpu(struct device *dev){ struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev); if (!adreno_smmu) return NULL; return container_of(adreno_smmu, struct msm_gpu, adreno_smmu);} static inline booladreno_smmu_has_prr(struct msm_gpu *gpu){ struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(&gpu->pdev->dev); if (!adreno_smmu) return false; return adreno_smmu && adreno_smmu->set_prr_addr;} /* It turns out that all targets use the same ringbuffer size */#define MSM_GPU_RINGBUFFER_SZ SZ_32K#define MSM_GPU_RINGBUFFER_BLKSIZE 32 #define MSM_GPU_RB_CNTL_DEFAULT \ (AXXX_CP_RB_CNTL_BUFSZ(ilog2(MSM_GPU_RINGBUFFER_SZ / 8)) | \ AXXX_CP_RB_CNTL_BLKSZ(ilog2(MSM_GPU_RINGBUFFER_BLKSIZE / 8))) static inline bool msm_gpu_active(struct msm_gpu *gpu){ int i; for (i = 0; i < gpu->nr_rings; i++) { struct msm_ringbuffer *ring = gpu->rb[i]; if (fence_after(ring->fctx->last_fence, ring->memptrs->fence)) return true; } return false;} /** * struct msm_perfcntr_group_state - Tracking for the currently allocated counter state */struct msm_perfcntr_group_state { /** * @allocated_counters: * * allocated counters for global counter collection. The * corresponding counters are allocated from highest to * lowest, to minimize chance of conflict with old userspace * allocating from lowest to highest. */ unsigned allocated_counters; /** * @countables: * * The corresponding SELect reg values for the allocated counters */ uint32_t countables[];}; /** * struct msm_perfcntr_state - overall global perfcntr state */struct msm_perfcntr_state { /** @stream: current global counter stream if active */ struct msm_perfcntr_stream *stream; /** @sel_seqno: counter for sel_fence */ uint32_t sel_seqno; /** * @groups: Global perfcntr stream group state. * * Conceptually this is part of msm_perfcntr_stream state, but is * statically pre-allocated when the gpu is initialized to simplify * error path cleanup in PERFCNTR_CONFIG ioctl. (__free(kfree) * doesn't really help with variable length arrays of allocated * pointers.) */ struct msm_perfcntr_group_state *groups[];}; static inline boolmsm_gpu_sysprof_no_perfcntr_zap(struct msm_gpu *gpu){ return (refcount_read(&gpu->sysprof_active) > 1) || (gpu->perfcntrs && READ_ONCE(gpu->perfcntrs->stream));} static inline boolmsm_gpu_sysprof_no_ifpc(struct msm_gpu *gpu){ return refcount_read(&gpu->sysprof_active) > 1;} /* * The number of priority levels provided by drm gpu scheduler. The * DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some * cases, so we don't use it (no need for kernel generated jobs). */#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_LOW - DRM_SCHED_PRIORITY_HIGH) /** * struct msm_context - per-drm_file context */struct msm_context { /** @ctxlock: synchronizes access to submitqueues list, etc */ struct rw_semaphore ctxlock; /** @submitqueues: list of &msm_gpu_submitqueue created by userspace */ struct list_head submitqueues; /** * @queueid: * Counter incremented each time a submitqueue is created, used to * assign &msm_gpu_submitqueue.id */ int queueid; /** * @closed: The device file associated with this context has been closed. * Once the device is closed, any submits that have not been written * to the ring buffer are no-op'd. */ bool closed; /** * @userspace_managed_vm: * Has userspace opted-in to userspace managed VM (ie. VM_BIND) via * MSM_PARAM_EN_VM_BIND? */ bool userspace_managed_vm; /** * @vm: * The per-process GPU address-space. Do not access directly, use * msm_context_vm(). */ struct drm_gpuvm *vm; /** @ref: the reference count */ struct kref ref; /** * @seqno: * A unique per-process sequence number. Used to detect context * switches, without relying on keeping a, potentially dangling, * pointer to the previous context. */ int seqno; /** * @sysprof: * The value of MSM_PARAM_SYSPROF set by userspace. This is * intended to be used by system profiling tools like Mesa's * pps-producer (perfetto), and restricted to CAP_SYS_ADMIN. * * Setting a value of 1 will preserve performance counters across * context switches. Setting a value of 2 will in addition * suppress suspend. (Performance counters lose state across * power collapse, which is undesirable for profiling in some * cases.) * * The value automatically reverts to zero when the drm device * file is closed. */ int sysprof; /** * @comm: Overridden task comm, see MSM_PARAM_COMM * * Accessed under msm_gpu::lock */ char *comm; /** * @cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE * * Accessed under msm_gpu::lock */ char *cmdline; /** * @elapsed_ns: * The total (cumulative) elapsed time GPU was busy with rendering * from this context in ns. */ uint64_t elapsed_ns; /** * @cycles: * The total (cumulative) GPU cycles elapsed attributed to this * context. */ uint64_t cycles; /** * @entities: * Table of per-priority-level sched entities used by submitqueues * associated with this &drm_file. Because some userspace apps * make assumptions about rendering from multiple gl contexts * (of the same priority) within the process happening in FIFO * order without requiring any fencing beyond MakeCurrent(), we * create at most one &drm_sched_entity per-process per-priority- * level. */ struct drm_sched_entity *entities[NR_SCHED_PRIORITIES * MSM_GPU_MAX_RINGS]; /** * @ctx_mem: * Total amount of memory of GEM buffers with handles attached for * this context. */ atomic64_t ctx_mem; /** * @perfcntrs: Per-context reserved perfcntrs state */ struct msm_perfcntr_context_state *perfctx;}; struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx); /** * msm_context_is_vmbind() - has userspace opted in to VM_BIND? *Lines 1–500 of 807. Load more
/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> */ #ifndef __MSM_GPU_H__ #define __MSM_GPU_H__ #include <linux/adreno-smmu-priv.h> #include <linux/clk.h> #include <linux/devfreq.h> #include <linux/interconnect.h> #include <linux/pm_opp.h> #include <linux/regulator/consumer.h> #include "msm_drv.h" #include "msm_fence.h" #include "msm_gpu_trace.h" #include "msm_ringbuffer.h" #include "msm_gem.h" struct msm_gem_submit; struct msm_gem_vm_log_entry; struct msm_gpu_state; struct msm_context; struct msm_perfcntr_group; struct msm_perfcntr_stream; struct msm_gpu_config { const char *ioname; unsigned int nr_rings; }; /* So far, with hardware that I've seen to date, we can have: * + zero, one, or two z180 2d cores * + a3xx or a2xx 3d core, which share a common CP (the firmware * for the CP seems to implement some different PM4 packet types * but the basics of cmdstream submission are the same) * * Which means that the eventual complete "class" hierarchy, once * support for all past and present hw is in place, becomes: * + msm_gpu * + adreno_gpu * + a3xx_gpu * + a2xx_gpu * + z180_gpu */ struct msm_gpu_funcs { int (*get_param)(struct msm_gpu *gpu, struct msm_context *ctx, uint32_t param, uint64_t *value, uint32_t *len); int (*set_param)(struct msm_gpu *gpu, struct msm_context *ctx, uint32_t param, uint64_t value, uint32_t len); int (*hw_init)(struct msm_gpu *gpu); /** * @ucode_load: Optional hook to upload fw to GEM objs */ int (*ucode_load)(struct msm_gpu *gpu); int (*pm_suspend)(struct msm_gpu *gpu); int (*pm_resume)(struct msm_gpu *gpu); void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit); void (*flush)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); irqreturn_t (*irq)(struct msm_gpu *irq); struct msm_ringbuffer *(*active_ring)(struct msm_gpu *gpu); void (*recover)(struct msm_gpu *gpu); void (*destroy)(struct msm_gpu *gpu); #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state, struct drm_printer *p); /* for generation specific debugfs: */ void (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif /* note: gpu_busy() can assume that we have been pm_resumed */ u64 (*gpu_busy)(struct msm_gpu *gpu, unsigned long *out_sample_rate); struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu); int (*gpu_state_put)(struct msm_gpu_state *state); unsigned long (*gpu_get_freq)(struct msm_gpu *gpu); /* note: gpu_set_freq() can assume that we have been pm_resumed */ void (*gpu_set_freq)(struct msm_gpu *gpu, struct dev_pm_opp *opp, bool suspended); struct drm_gpuvm *(*create_vm)(struct msm_gpu *gpu, struct platform_device *pdev); struct drm_gpuvm *(*create_private_vm)(struct msm_gpu *gpu, bool kernel_managed); uint32_t (*get_rptr)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); /** * progress: Has the GPU made progress? * * Return true if GPU position in cmdstream has advanced (or changed) * since the last call. To avoid false negatives, this should account * for cmdstream that is buffered in this FIFO upstream of the CP fw. */ bool (*progress)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); void (*sysprof_setup)(struct msm_gpu *gpu, bool force_on); /* Configure perfcntr SELect regs: */ void (*perfcntr_configure)(struct msm_gpu *gpu, struct msm_ringbuffer *ring, const struct msm_perfcntr_stream *stream); /* Flush perfcntrs before reading (optional): */ void (*perfcntr_flush)(struct msm_gpu *gpu); }; /* Additional state for iommu faults: */ struct msm_gpu_fault_info { u64 ttbr0; unsigned long iova; int flags; const char *type; const char *block; /* Information about what we think/expect is the current SMMU state, * for example expected_ttbr0 should match smmu_info.ttbr0 which * was read back from SMMU registers. */ phys_addr_t pgtbl_ttbr0; u64 ptes[4]; int asid; }; /** * struct msm_gpu_devfreq - devfreq related state */ struct msm_gpu_devfreq { /** @devfreq: devfreq instance */ struct devfreq *devfreq; /** @lock: lock for "suspended", "busy_cycles", and "time" */ struct mutex lock; /** * @idle_freq: * Shadow frequency used while the GPU is idle. From the PoV of * the devfreq governor, we are continuing to sample busyness and * adjust frequency while the GPU is idle, but we use this shadow * value as the GPU is actually clamped to minimum frequency while * it is inactive. */ unsigned long idle_freq; /** * @boost_freq: * A PM QoS constraint to boost min freq for a period of time * until the boost expires. */ struct dev_pm_qos_request boost_freq; /** * @busy_cycles: Last busy counter value, for calculating elapsed busy * cycles since last sampling period. */ u64 busy_cycles; /** @time: Time of last sampling period. */ ktime_t time; /** @idle_time: Time of last transition to idle. */ ktime_t idle_time; /** * @idle_work: * Used to delay clamping to idle freq on active->idle transition. */ struct msm_hrtimer_work idle_work; /** * @boost_work: * Used to reset the boost_constraint after the boost period has * elapsed */ struct msm_hrtimer_work boost_work; /** @suspended: tracks if we're suspended */ bool suspended; }; struct msm_gpu { const char *name; struct drm_device *dev; struct platform_device *pdev; const struct msm_gpu_funcs *funcs; struct adreno_smmu_priv adreno_smmu; struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS]; int nr_rings; /** * sysprof_active: * * The count of contexts that have enabled system profiling. */ refcount_t sysprof_active; /** * lock: * * General lock for serializing all the gpu things. * * TODO move to per-ring locking where feasible (ie. submit/retire * path, etc) */ struct mutex lock; /** * active_submits: * * The number of submitted but not yet retired submits, used to * determine transitions between active and idle. * * Protected by active_lock */ int active_submits; /** lock: protects active_submits and idle/active transitions */ struct mutex active_lock; /* does gpu need hw_init? */ bool needs_hw_init; /** * global_faults: number of GPU hangs not attributed to a particular * address space */ int global_faults; void __iomem *mmio; int irq; struct drm_gpuvm *vm; /* Power Control: */ struct regulator *gpu_reg, *gpu_cx; struct clk_bulk_data *grp_clks; int nr_clocks; struct clk *ebi1_clk, *core_clk, *rbbmtimer_clk; uint32_t fast_rate; /* Hang and Inactivity Detection: */ #define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ #define DRM_MSM_HANGCHECK_DEFAULT_PERIOD 500 /* in ms */ #define DRM_MSM_HANGCHECK_PROGRESS_RETRIES 3 struct timer_list hangcheck_timer; /* work for handling GPU recovery: */ struct kthread_work recover_work; /** retire_event: notified when submits are retired: */ wait_queue_head_t retire_event; /* work for handling active-list retiring: */ struct kthread_work retire_work; /* worker for retire/recover: */ struct kthread_worker *worker; struct drm_gem_object *memptrs_bo; struct msm_gpu_devfreq devfreq; uint32_t suspend_count; struct msm_gpu_state *crashstate; /* True if the hardware supports expanded apriv (a650 and newer) */ bool hw_apriv; /** * @allow_relocs: allow relocs in SUBMIT ioctl * * Mesa won't use relocs for driver version 1.4.0 and later. This * switch-over happened early enough in mesa a6xx bringup that we * can disallow relocs for a6xx and newer. */ bool allow_relocs; struct thermal_cooling_device *cooling; const struct msm_perfcntr_group *perfcntr_groups; unsigned num_perfcntr_groups; struct msm_perfcntr_state *perfcntrs; /** @perfcntr_lock: protects perfcntr related state */ struct mutex perfcntr_lock; }; static inline struct msm_gpu *dev_to_gpu(struct device *dev) { struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev); if (!adreno_smmu) return NULL; return container_of(adreno_smmu, struct msm_gpu, adreno_smmu); } static inline bool adreno_smmu_has_prr(struct msm_gpu *gpu) { struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(&gpu->pdev->dev); if (!adreno_smmu) return false; return adreno_smmu && adreno_smmu->set_prr_addr; } /* It turns out that all targets use the same ringbuffer size */ #define MSM_GPU_RINGBUFFER_SZ SZ_32K #define MSM_GPU_RINGBUFFER_BLKSIZE 32 #define MSM_GPU_RB_CNTL_DEFAULT \ (AXXX_CP_RB_CNTL_BUFSZ(ilog2(MSM_GPU_RINGBUFFER_SZ / 8)) | \ AXXX_CP_RB_CNTL_BLKSZ(ilog2(MSM_GPU_RINGBUFFER_BLKSIZE / 8))) static inline bool msm_gpu_active(struct msm_gpu *gpu) { int i; for (i = 0; i < gpu->nr_rings; i++) { struct msm_ringbuffer *ring = gpu->rb[i]; if (fence_after(ring->fctx->last_fence, ring->memptrs->fence)) return true; } return false; } /** * struct msm_perfcntr_group_state - Tracking for the currently allocated counter state */ struct msm_perfcntr_group_state { /** * @allocated_counters: * * allocated counters for global counter collection. The * corresponding counters are allocated from highest to * lowest, to minimize chance of conflict with old userspace * allocating from lowest to highest. */ unsigned allocated_counters; /** * @countables: * * The corresponding SELect reg values for the allocated counters */ uint32_t countables[]; }; /** * struct msm_perfcntr_state - overall global perfcntr state */ struct msm_perfcntr_state { /** @stream: current global counter stream if active */ struct msm_perfcntr_stream *stream; /** @sel_seqno: counter for sel_fence */ uint32_t sel_seqno; /** * @groups: Global perfcntr stream group state. * * Conceptually this is part of msm_perfcntr_stream state, but is * statically pre-allocated when the gpu is initialized to simplify * error path cleanup in PERFCNTR_CONFIG ioctl. (__free(kfree) * doesn't really help with variable length arrays of allocated * pointers.) */ struct msm_perfcntr_group_state *groups[]; }; static inline bool msm_gpu_sysprof_no_perfcntr_zap(struct msm_gpu *gpu) { return (refcount_read(&gpu->sysprof_active) > 1) || (gpu->perfcntrs && READ_ONCE(gpu->perfcntrs->stream)); } static inline bool msm_gpu_sysprof_no_ifpc(struct msm_gpu *gpu) { return refcount_read(&gpu->sysprof_active) > 1; } /* * The number of priority levels provided by drm gpu scheduler. The * DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some * cases, so we don't use it (no need for kernel generated jobs). */ #define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_LOW - DRM_SCHED_PRIORITY_HIGH) /** * struct msm_context - per-drm_file context */ struct msm_context { /** @ctxlock: synchronizes access to submitqueues list, etc */ struct rw_semaphore ctxlock; /** @submitqueues: list of &msm_gpu_submitqueue created by userspace */ struct list_head submitqueues; /** * @queueid: * Counter incremented each time a submitqueue is created, used to * assign &msm_gpu_submitqueue.id */ int queueid; /** * @closed: The device file associated with this context has been closed. * Once the device is closed, any submits that have not been written * to the ring buffer are no-op'd. */ bool closed; /** * @userspace_managed_vm: * Has userspace opted-in to userspace managed VM (ie. VM_BIND) via * MSM_PARAM_EN_VM_BIND? */ bool userspace_managed_vm; /** * @vm: * The per-process GPU address-space. Do not access directly, use * msm_context_vm(). */ struct drm_gpuvm *vm; /** @ref: the reference count */ struct kref ref; /** * @seqno: * A unique per-process sequence number. Used to detect context * switches, without relying on keeping a, potentially dangling, * pointer to the previous context. */ int seqno; /** * @sysprof: * The value of MSM_PARAM_SYSPROF set by userspace. This is * intended to be used by system profiling tools like Mesa's * pps-producer (perfetto), and restricted to CAP_SYS_ADMIN. * * Setting a value of 1 will preserve performance counters across * context switches. Setting a value of 2 will in addition * suppress suspend. (Performance counters lose state across * power collapse, which is undesirable for profiling in some * cases.) * * The value automatically reverts to zero when the drm device * file is closed. */ int sysprof; /** * @comm: Overridden task comm, see MSM_PARAM_COMM * * Accessed under msm_gpu::lock */ char *comm; /** * @cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE * * Accessed under msm_gpu::lock */ char *cmdline; /** * @elapsed_ns: * The total (cumulative) elapsed time GPU was busy with rendering * from this context in ns. */ uint64_t elapsed_ns; /** * @cycles: * The total (cumulative) GPU cycles elapsed attributed to this * context. */ uint64_t cycles; /** * @entities: * Table of per-priority-level sched entities used by submitqueues * associated with this &drm_file. Because some userspace apps * make assumptions about rendering from multiple gl contexts * (of the same priority) within the process happening in FIFO * order without requiring any fencing beyond MakeCurrent(), we * create at most one &drm_sched_entity per-process per-priority- * level. */ struct drm_sched_entity *entities[NR_SCHED_PRIORITIES * MSM_GPU_MAX_RINGS]; /** * @ctx_mem: * Total amount of memory of GEM buffers with handles attached for * this context. */ atomic64_t ctx_mem; /** * @perfcntrs: Per-context reserved perfcntrs state */ struct msm_perfcntr_context_state *perfctx; }; struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx); /** * msm_context_is_vmbind() - has userspace opted in to VM_BIND? *